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

+ *

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

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

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

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

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

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

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

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

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

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

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

    + * Useful in debugging. + *

    + */ +public class LoggingProxy implements InvocationHandler +{ + private final Object _target; + private final CircularBuffer _log; + + public LoggingProxy(Object target, int size) + { + _target = target; + _log = new CircularBuffer(size); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + try + { + entered(method, args); + Object result = method.invoke(_target, args); + returned(method, result); + return result; + } + catch(InvocationTargetException e) + { + dump(); + throw e.getTargetException(); + } + } + + void dump() + { + _log.dump(); + } + + CircularBuffer getBuffer() + { + return _log; + } + + private synchronized void entered(Method method, Object[] args) + { + if (args == null) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); + } + } + + private synchronized void returned(Method method, Object result) + { + if (method.getReturnType() == Void.TYPE) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); + } + } + + public Object getProxy(Class... c) + { + return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); + } + + public int getBufferSize() { + return _log.size(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java new file mode 100644 index 0000000000..2e77f33363 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -0,0 +1,109 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.NullAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.MapConfiguration; + +import java.util.HashMap; + +public class NullApplicationRegistry extends ApplicationRegistry +{ + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private ManagedObjectRegistry _managedObjectRegistry; + + private AuthenticationManager _authenticationManager; + + private MessageStore _messageStore; + + + public NullApplicationRegistry() + { + super(new MapConfiguration(new HashMap())); + } + + public void initialise() throws Exception + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + _queueRegistry = new DefaultQueueRegistry(); + _exchangeFactory = new DefaultExchangeFactory(); + _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _authenticationManager = new NullAuthenticationManager(); + _messageStore = new MemoryMessageStore(); + ((MemoryMessageStore)_messageStore).configure(); + + _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes + } + + public Configuration getConfiguration() + { + return _configuration; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } +} + -- cgit v1.2.1 From 6f3fbc6e525e9291bb00312f3e32d71c082baf60 Mon Sep 17 00:00:00 2001 From: Stephen Vinoski Date: Sat, 18 Nov 2006 03:48:15 +0000 Subject: complete bringing initial maven work to trunk git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@476431 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 87 ++++++++++------------ 1 file changed, 38 insertions(+), 49 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index d2dacb6140..a1dabcd964 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -46,6 +46,7 @@ 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; @@ -64,6 +65,7 @@ import java.util.List; /** * Main entry point for AMQPD. + * */ public class Main implements ProtocolVersionList { @@ -120,10 +122,10 @@ public class Main implements ProtocolVersionList 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"). + "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"); + "Zero means do not check for changes.").withLongOpt("logwatch").create("w"); options.addOption(help); options.addOption(version); @@ -147,12 +149,10 @@ public class Main implements ProtocolVersionList { String ver = "Qpid 0.9.0.0"; String protocol = "AMQP version(s) [major.minor]: "; - for (int i = 0; i < pv.length; i++) + for (int i=0; i 0) - { protocol += ", "; - } protocol += pv[i][PROTOCOL_MAJOR] + "." + pv[i][PROTOCOL_MINOR]; } System.out.println(ver + " (" + protocol + ")"); @@ -223,8 +223,7 @@ public class Main implements ProtocolVersionList ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). getConfiguredObject(ConnectorConfiguration.class); - // From old Mina - //ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); + 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 @@ -259,12 +258,12 @@ public class Main implements ProtocolVersionList int totalVHosts = ((Collection) virtualHosts).size(); for (int vhost = 0; vhost < totalVHosts; vhost++) { - setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost)); + setupVirtualHosts(configFile.getParent() , (String)((List)virtualHosts).get(vhost)); } } else { - setupVirtualHosts(configFile.getParent(), (String) virtualHosts); + setupVirtualHosts(configFile.getParent() , (String)virtualHosts); } } bind(port, connectorConfig); @@ -281,7 +280,7 @@ public class Main implements ProtocolVersionList configFilePath = configFileParent + configFilePath.substring(configVar.length()); } - if (configFilePath.indexOf(".xml") != -1) + if (configFilePath.indexOf(".xml") != -1 ) { VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath); vHostConfig.performBindings(); @@ -294,11 +293,11 @@ public class Main implements ProtocolVersionList String[] fileNames = virtualHostDir.list(); - for (int each = 0; each < fileNames.length; each++) + for (int each=0; each < fileNames.length; each++) { if (fileNames[each].endsWith(".xml")) { - VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); + VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath+"/"+fileNames[each]); vHostConfig.performBindings(); } } @@ -317,10 +316,8 @@ public class Main implements ProtocolVersionList { //IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); IoAcceptor acceptor = connectorConfig.createAcceptor(); - - SocketSessionConfig sc; - - sc = (SocketSessionConfig) acceptor.getSessionConfig(); + SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); + SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); @@ -330,7 +327,7 @@ public class Main implements ProtocolVersionList // implementation provided by MINA if (connectorConfig.enableExecutorPool) { - acceptor.setThreadModel(new ReadWriteThreadModel()); + sconfig.setThreadModel(new ReadWriteThreadModel()); } if (connectorConfig.enableNonSSL) @@ -345,9 +342,7 @@ public class Main implements ProtocolVersionList { bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); } - acceptor.setLocalAddress(bindAddress); - acceptor.setHandler(handler); - acceptor.bind(); + acceptor.bind(bindAddress, handler, sconfig); _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -357,9 +352,8 @@ public class Main implements ProtocolVersionList handler.setUseSSL(true); try { - acceptor.setLocalAddress(new InetSocketAddress(connectorConfig.sslPort)); - acceptor.setHandler(handler); - acceptor.bind(); + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), + handler, sconfig); _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); } catch (IOException e) @@ -414,16 +408,15 @@ public class Main implements ProtocolVersionList 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"); + "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"); + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); } @@ -448,7 +441,7 @@ public class Main implements ProtocolVersionList } catch (NotCompliantMBeanException ex) { - throw new AMQException("Exception occured in creating AMQBrokerManager MBean."); + throw new AMQException("Exception occured in creating AMQBrokerManager MBean."); } } @@ -458,24 +451,24 @@ public class Main implements ProtocolVersionList */ @MBeanDescription("This MBean exposes the broker level management features") private final class AMQBrokerManager extends AMQManagedObject - implements ManagedBroker + implements ManagedBroker { - private final QueueRegistry _queueRegistry; + private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; - private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; + private final ExchangeFactory _exchangeFactory; + private final MessageStore _messageStore; @MBeanConstructor("Creates the Broker Manager MBean") - protected AMQBrokerManager() throws NotCompliantMBeanException + protected AMQBrokerManager() throws NotCompliantMBeanException { super(ManagedBroker.class, ManagedBroker.TYPE); IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - _queueRegistry = appRegistry.getQueueRegistry(); + _queueRegistry = appRegistry.getQueueRegistry(); _exchangeRegistry = appRegistry.getExchangeRegistry(); - _exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); - _messageStore = ApplicationRegistry.getInstance().getMessageStore(); - } + _exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); + _messageStore = ApplicationRegistry.getInstance().getMessageStore(); + } public String getObjectInstanceName() { @@ -484,7 +477,6 @@ public class Main implements ProtocolVersionList /** * Creates new exchange and registers it with the registry. - * * @param exchangeName * @param type * @param durable @@ -495,7 +487,7 @@ public class Main implements ProtocolVersionList String type, boolean durable, boolean autoDelete) - throws JMException + throws JMException { try { @@ -506,10 +498,10 @@ public class Main implements ProtocolVersionList if (exchange == null) { exchange = _exchangeFactory.createExchange(exchangeName, - type, //eg direct - durable, - autoDelete, - 0); //ticket no + type, //eg direct + durable, + autoDelete, + 0); //ticket no _exchangeRegistry.registerExchange(exchange); } else @@ -518,7 +510,7 @@ public class Main implements ProtocolVersionList } } } - catch (AMQException ex) + catch(AMQException ex) { _logger.error("Error in creating exchange " + exchangeName, ex); throw new MBeanException(ex, ex.toString()); @@ -527,12 +519,11 @@ public class Main implements ProtocolVersionList /** * Unregisters the exchange from registry. - * * @param exchangeName * @throws JMException */ public void unregisterExchange(String exchangeName) - throws JMException + throws JMException { boolean inUse = false; // TODO @@ -543,7 +534,7 @@ public class Main implements ProtocolVersionList { _exchangeRegistry.unregisterExchange(exchangeName, false); } - catch (AMQException ex) + catch(AMQException ex) { _logger.error("Error in unregistering exchange " + exchangeName, ex); throw new MBeanException(ex, ex.toString()); @@ -553,7 +544,6 @@ public class Main implements ProtocolVersionList /** * 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 @@ -564,7 +554,7 @@ public class Main implements ProtocolVersionList boolean durable, String owner, boolean autoDelete) - throws JMException + throws JMException { AMQQueue queue = _queueRegistry.getQueue(queueName); if (queue == null) @@ -592,7 +582,6 @@ public class Main implements ProtocolVersionList /** * Deletes the queue from queue registry and persistant storage. - * * @param queueName * @throws JMException */ -- cgit v1.2.1 From f32c4fae81ec92991eb57938343d5cd3c53dba2f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Nov 2006 18:07:57 +0000 Subject: Changed logging from warn to info git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@478264 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 55 ++++++++++++---------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index f2f46d43dd..05fe8908c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -51,7 +51,7 @@ 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 +public class AMQQueue implements Managable, Comparable { private static final Logger _logger = Logger.getLogger(AMQQueue.class); @@ -119,6 +119,11 @@ public class AMQQueue implements Managable */ private long _totalMessagesReceived = 0; + public int compareTo(Object o) + { + return _name.compareTo(((AMQQueue) o).getName()); + } + /** * MBean class for AMQQueue. It implements all the management features exposed * for an AMQQueue. @@ -133,32 +138,32 @@ public class AMQQueue implements Managable "Header", "Size", "Redelivered" - }; + }; // AMQ Message attribute descriptions. private String[] _msgAttributeDescriptions = {"Message Id", "Header", "Message size in bytes", "Redelivered" - }; + }; private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private String[] _msgAttributeIndex = {"MessageId"}; // Messages will be indexed according to the messageId. + private String[] _msgAttributeIndex = {"MessageId"}; // Messages will be indexed according to the messageId. private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. private CompositeType _msgContentType = null; // For message content - private String[] _msgContentAttributes = {"MessageId", - "MimeType", - "Encoding", - "Content" - }; - private String[] _msgContentDescriptions = {"Message Id", - "MimeType", - "Encoding", - "Message content" - }; - private OpenType[] _msgContentAttributeTypes = new OpenType[4]; + private String[] _msgContentAttributes = {"MessageId", + "MimeType", + "Encoding", + "Content" + }; + private String[] _msgContentDescriptions = {"Message Id", + "MimeType", + "Encoding", + "Message content" + }; + private OpenType[] _msgContentAttributeTypes = new OpenType[4]; @MBeanConstructor("Creates an MBean exposing an AMQQueue.") @@ -178,10 +183,10 @@ public class AMQQueue implements Managable _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content _msgContentType = new CompositeType("MessageContent", - "AMQ Message Content", - _msgContentAttributes, - _msgContentDescriptions, - _msgContentAttributeTypes); + "AMQ Message Content", + _msgContentAttributes, + _msgContentDescriptions, + _msgContentAttributeTypes); _msgAttributeTypes[0] = SimpleType.LONG; // For message id @@ -414,7 +419,7 @@ public class AMQQueue implements Managable } // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; String mimeType = headerProperties.getContentType(); String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); @@ -423,7 +428,7 @@ public class AMQQueue implements Managable } else { - throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName ); + throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } return messageContent; @@ -466,7 +471,7 @@ public class AMQQueue implements Managable } // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; List headerAttribsList = new ArrayList(); headerAttribsList.add("App Id=" + headerProperties.getAppId()); headerAttribsList.add("MimeType=" + headerProperties.getContentType()); @@ -587,12 +592,12 @@ public class AMQQueue implements Managable //fixme - Pick one. if (Boolean.getBoolean("concurrentdeliverymanager")) { - _logger.warn("Using ConcurrentDeliveryManager"); + _logger.info("Using ConcurrentDeliveryManager"); _deliveryMgr = new ConcurrentDeliveryManager(_subscribers, this); } else { - _logger.warn("Using SynchronizedDeliveryManager"); + _logger.info("Using SynchronizedDeliveryManager"); _deliveryMgr = new SynchronizedDeliveryManager(_subscribers, this); } } -- cgit v1.2.1 From 5ca8dfad60086dd9363f79d979d72735b6d9e6fa Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 27 Nov 2006 16:51:44 +0000 Subject: QPID-129 MBeans updated with improved features, like AMQQueue mbean now has separate features for sending message header and message content. ( other details are in JIRA) git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@479686 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 112 ++++---- .../qpid/server/exchange/AbstractExchange.java | 16 +- .../qpid/server/exchange/DestNameExchange.java | 63 ++--- .../qpid/server/exchange/DestWildExchange.java | 71 ++--- .../qpid/server/exchange/HeadersExchange.java | 58 ++-- .../qpid/server/exchange/ManagedExchange.java | 20 +- .../qpid/server/management/ManagedBroker.java | 27 +- .../server/protocol/AMQMinaProtocolSession.java | 106 +++----- .../qpid/server/protocol/ManagedConnection.java | 89 +++---- .../org/apache/qpid/server/queue/AMQQueue.java | 295 ++++++++------------- .../org/apache/qpid/server/queue/ManagedQueue.java | 132 +++++---- 11 files changed, 403 insertions(+), 586 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index a1dabcd964..3470a5bb08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,25 +20,13 @@ */ 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.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; @@ -48,20 +36,40 @@ 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 org.apache.qpid.AMQException; +import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedBroker; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; +import org.apache.qpid.server.protocol.AMQPProtocolProvider; +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.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.url.URLSyntaxException; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; import javax.management.MalformedObjectNameException; - +import javax.management.ObjectName; 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; +import java.util.StringTokenizer; /** * Main entry point for AMQPD. @@ -439,9 +447,9 @@ public class Main implements ProtocolVersionList { new AMQBrokerManager().register(); } - catch (NotCompliantMBeanException ex) + catch (JMException ex) { - throw new AMQException("Exception occured in creating AMQBrokerManager MBean."); + throw new AMQException("Exception occured in creating AMQBrokerManager MBean"); } } @@ -450,8 +458,7 @@ public class Main implements ProtocolVersionList * 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 class AMQBrokerManager extends AMQManagedObject implements ManagedBroker { private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; @@ -459,10 +466,9 @@ public class Main implements ProtocolVersionList private final MessageStore _messageStore; @MBeanConstructor("Creates the Broker Manager MBean") - protected AMQBrokerManager() throws NotCompliantMBeanException + protected AMQBrokerManager() throws JMException { super(ManagedBroker.class, ManagedBroker.TYPE); - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); _queueRegistry = appRegistry.getQueueRegistry(); _exchangeRegistry = appRegistry.getExchangeRegistry(); @@ -483,10 +489,7 @@ public class Main implements ProtocolVersionList * @param autoDelete * @throws JMException */ - public void createNewExchange(String exchangeName, - String type, - boolean durable, - boolean autoDelete) + public void createNewExchange(String exchangeName, String type, boolean durable, boolean autoDelete) throws JMException { try @@ -494,14 +497,9 @@ public class Main implements ProtocolVersionList synchronized(_exchangeRegistry) { Exchange exchange = _exchangeRegistry.getExchange(exchangeName); - if (exchange == null) { - exchange = _exchangeFactory.createExchange(exchangeName, - type, //eg direct - durable, - autoDelete, - 0); //ticket no + exchange = _exchangeFactory.createExchange(exchangeName, type, durable, autoDelete, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -522,8 +520,7 @@ public class Main implements ProtocolVersionList * @param exchangeName * @throws JMException */ - public void unregisterExchange(String exchangeName) - throws JMException + public void unregisterExchange(String exchangeName) throws JMException { boolean inUse = false; // TODO @@ -550,33 +547,28 @@ public class Main implements ProtocolVersionList * @param autoDelete * @throws JMException */ - public void createQueue(String queueName, - boolean durable, - String owner, - boolean autoDelete) + public void createNewQueue(String queueName, boolean durable, String owner, boolean autoDelete) throws JMException { AMQQueue queue = _queueRegistry.getQueue(queueName); - if (queue == null) + 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) + throw new JMException("The queue \"" + queueName + "\" already exists."); + } + + try + { + queue = new AMQQueue(queueName, durable, owner, autoDelete, _queueRegistry); + if (queue.isDurable() && !queue.isAutoDelete()) { - _logger.error("Error in creating queue " + queueName, ex); - throw new MBeanException(ex, ex.toString()); + _messageStore.createQueue(queue); } + _queueRegistry.registerQueue(queue); } - else + catch (AMQException ex) { - throw new JMException("The queue \"" + queueName + "\" already exists."); + _logger.error("Error in creating queue " + queueName, ex); + throw new MBeanException(ex, ex.toString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 69f5e862d6..d5ca567308 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -25,14 +25,16 @@ import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; +import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; public abstract class AbstractExchange implements Exchange, Managable { private String _name; protected boolean _durable; - + protected String _exchangeType; protected int _ticket; protected ExchangeMBean _exchangeMbean; @@ -64,6 +66,11 @@ public abstract class AbstractExchange implements Exchange, Managable return _name; } + public String getExchangeType() + { + return _exchangeType; + } + public Integer getTicketNo() { return _ticket; @@ -79,6 +86,13 @@ public abstract class AbstractExchange implements Exchange, Managable return _autoDelete; } + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + _exchangeType; + return new ObjectName(objNameString); + } + } // End of MBean class public String getName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 085d0aad19..6dc97f9e48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -24,15 +24,14 @@ 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.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; import javax.management.openmbean.*; import java.util.ArrayList; import java.util.List; @@ -53,53 +52,36 @@ public class DestNameExchange extends AbstractExchange @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"}; + // open mbean data types for representing exchange bindings + private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; + private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; 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 + public DestNameExchangeMBean() throws JMException { super(); + _exchangeType = "direct"; init(); } /** * initialises the OpenType objects. */ - private void init() + private void init() throws OpenDataException { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - //_bindingItemTypes[1] = ArrayType.getArrayType(SimpleType.STRING); - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueBinding", - "Binding key and bound Queue names", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queue bindings for " + getName() , - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); } - public TabularData viewBindings() - throws OpenDataException + public TabularData bindings() throws OpenDataException { Map> bindings = _index.getBindingsMap(); _bindingList = new TabularDataSupport(_bindinglistDataType); @@ -116,20 +98,16 @@ public class DestNameExchange extends AbstractExchange } Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } return _bindingList; } - public void createBinding(String queueName, String binding) - throws JMException + public void createNewBinding(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."); @@ -155,10 +133,10 @@ public class DestNameExchange extends AbstractExchange { return new DestNameExchangeMBean(); } - catch (NotCompliantMBeanException ex) + catch (JMException ex) { - _logger.error("Exception occured in creating the DestNameExchenge", ex); - throw new AMQException("Exception occured in creating the DestNameExchenge", ex); + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); } } @@ -172,8 +150,7 @@ public class DestNameExchange extends AbstractExchange } else { - _logger.debug("Binding queue " + queue + " with routing key " + routingKey - + " to exchange " + this); + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index f6abd53076..a692f9ebca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -22,18 +22,17 @@ 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.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; -import 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 javax.management.openmbean.*; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -53,55 +52,41 @@ public class DestWildExchange extends AbstractExchange @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"}; + // open mbean data types for representing exchange bindings + private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; + private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; 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 + public DestWildExchangeMBean() throws JMException { super(); + _exchangeType = "topic"; init(); } /** * initialises the OpenType objects. */ - private void init() + private void init() throws OpenDataException { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueBinding", - "Binding key and bound Queue names", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queue bindings for " + getName(), - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); } - public TabularData viewBindings() - throws OpenDataException + /** + * returns exchange bindings in tabular form + */ + public TabularData bindings() throws OpenDataException { _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Map.Entry> entry : _routingKey2queues.entrySet()) { String key = entry.getKey(); @@ -114,20 +99,16 @@ public class DestWildExchange extends AbstractExchange } Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } return _bindingList; } - public void createBinding(String queueName, String binding) - throws JMException + public void createNewBinding(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."); @@ -217,10 +198,10 @@ public class DestWildExchange extends AbstractExchange { return new DestWildExchangeMBean(); } - catch (NotCompliantMBeanException ex) + catch (JMException ex) { - _logger.error("Exception occured in creating the DestWildExchenge", ex); - throw new AMQException("Exception occured in creating the DestWildExchenge", ex); + _logger.error("Exception occured in creating the topic exchenge mbean", ex); + throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 961d4ddf4c..586d6b8796 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -32,7 +32,6 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import javax.management.JMException; -import javax.management.NotCompliantMBeanException; import javax.management.openmbean.*; import java.util.ArrayList; import java.util.Iterator; @@ -80,53 +79,39 @@ public class HeadersExchange extends AbstractExchange @MBeanDescription("Management Bean for Headers Exchange") private final class HeadersExchangeMBean extends ExchangeMBean { - private String[] _bindingItemNames = {"Queue", "HeaderBinding"}; - private String[] _bindingItemDescriptions = {"Queue Name", "Header attribute bindings"}; - private String[] _bindingItemIndexNames = {"HeaderBinding"}; - private OpenType[] _bindingItemTypes = new OpenType[2]; - + // open mbean data types for representing exchange bindings + private String[] _bindingItemNames = {"S.No.", "Queue Name", "Header Bindings"}; + private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; + private OpenType[] _bindingItemTypes = new OpenType[3]; private CompositeType _bindingDataType = null; private TabularType _bindinglistDataType = null; private TabularDataSupport _bindingList = null; @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws NotCompliantMBeanException + public HeadersExchangeMBean() throws JMException { super(); + _exchangeType = "headers"; init(); } /** * initialises the OpenType objects. */ - private void init() + private void init() throws OpenDataException { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueAndHeaderAttributesBinding", - "Queue name and header bindings", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("HeaderBindings", - "List of queue bindings for " + getName(), - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } + _bindingItemTypes[0] = SimpleType.INTEGER; + _bindingItemTypes[1] = SimpleType.STRING; + _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); } - public TabularData viewBindings() - throws OpenDataException + public TabularData bindings() throws OpenDataException { _bindingList = new TabularDataSupport(_bindinglistDataType); + int count = 1; for (Iterator itr = _bindings.iterator(); itr.hasNext();) { Registration registration = itr.next(); @@ -144,10 +129,8 @@ public class HeadersExchange extends AbstractExchange mappingList.add(key + "=" + value); } - Object[] bindingItemValues = {queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -161,8 +144,7 @@ public class HeadersExchange extends AbstractExchange * @param binding * @throws JMException */ - public void createBinding(String queueName, String binding) - throws JMException + public void createNewBinding(String queueName, String binding) throws JMException { AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); @@ -240,7 +222,7 @@ public class HeadersExchange extends AbstractExchange { return new HeadersExchangeMBean(); } - catch (NotCompliantMBeanException ex) + catch (JMException ex) { _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index 3c2c105186..b61aa233f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -23,6 +23,7 @@ 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 org.apache.qpid.server.queue.ManagedQueue; import javax.management.openmbean.TabularData; import javax.management.JMException; @@ -44,9 +45,12 @@ public interface ManagedExchange * @return the name of the exchange. * @throws IOException */ - @MBeanAttribute(name="Name", description="Name of exchange") + @MBeanAttribute(name="Name", description=TYPE + " Name") String getName() throws IOException; + @MBeanAttribute(name="ExchangeType", description="Exchange Type") + String getExchangeType() throws IOException; + @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") Integer getTicketNo() throws IOException; @@ -74,8 +78,8 @@ public interface ManagedExchange * @throws IOException * @throws JMException */ - @MBeanOperation(name="viewBindings", description="view the queue bindings for this exchange") - TabularData viewBindings() throws IOException, JMException; + @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") + TabularData bindings() throws IOException, JMException; /** * Creates new binding with the given queue and binding. @@ -83,11 +87,11 @@ public interface ManagedExchange * @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) + @MBeanOperation(name="createNewBinding", + description="create a new binding with this exchange", + impact= MBeanOperationInfo.ACTION) + void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, + @MBeanOperationParameter(name="Binding", description="New binding")String binding) throws JMException; } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index 266fb62fd8..aec7d6cb73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.management; +import org.apache.qpid.server.exchange.ManagedExchange; +import org.apache.qpid.server.queue.ManagedQueue; + import javax.management.JMException; import javax.management.MBeanOperationInfo; import java.io.IOException; @@ -45,10 +48,9 @@ public interface ManagedBroker * @throws IOException * @throws JMException */ - @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", - impact= MBeanOperationInfo.ACTION) + @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="ExchangeType", 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; @@ -61,9 +63,9 @@ public interface ManagedBroker * @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) + description="Unregisters all the related channels and queuebindings of this exchange", + impact= MBeanOperationInfo.ACTION) + void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) throws IOException, JMException; /** @@ -75,12 +77,11 @@ public interface ManagedBroker * @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) + @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) + void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, + @MBeanOperationParameter(name="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; /** @@ -93,6 +94,6 @@ public interface ManagedBroker @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) + void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) throws IOException, JMException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 966af77d64..be8d2c4c82 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -52,7 +52,6 @@ import org.apache.qpid.server.state.AMQStateManager; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.CompositeData; @@ -122,66 +121,35 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, * 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 final class ManagedAMQProtocolSession extends AMQManagedObject implements ManagedConnection { private String _name = null; - /** - * Represents the channel attributes sent with channel data. - */ - private String[] _channelAtttibuteNames = { "ChannelId", - "Transactional", - "DefaultQueue", - "UnacknowledgedMessageCount"}; - private String[] _channelAttributeDescriptions = { "Channel Identifier", - "is Channel Transactional?", - "Default Queue Name", - "Unacknowledged Message Count"}; - private OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, - SimpleType.BOOLEAN, - SimpleType.STRING, - SimpleType.INTEGER}; - - private String[] _indexNames = { "ChannelId" }; //Channels in the list will be indexed according to channelId. - private CompositeType _channelType = null; // represents the data type for channel data - private TabularType _channelsType = null; // Datatype for list of channelsType + //openmbean data types for representing the channel attributes + private String[] _channelAtttibuteNames = { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; + private String[] _indexNames = {_channelAtttibuteNames[0]}; + private OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; + private CompositeType _channelType = null; // represents the data type for channel data + private TabularType _channelsType = null; // Data type for list of channels type private TabularDataSupport _channelsList = null; @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public ManagedAMQProtocolSession() throws NotCompliantMBeanException + public ManagedAMQProtocolSession() throws JMException { super(ManagedConnection.class, ManagedConnection.TYPE); init(); } /** - * initialises the CompositeTypes and TabularType attributes. + * initialises the openmbean data types */ - private void init() + private void init() throws OpenDataException { String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? remote + hashCode() : remote; _name = jmxEncode(new StringBuffer(remote), 0).toString(); - - try - { - _channelType = new CompositeType("channel", - "Channel Details", - _channelAtttibuteNames, - _channelAttributeDescriptions, - _channelAttributeTypes); - - _channelsType = new TabularType("channelsType", - "List of available channels", - _channelType, - _indexNames); - } - catch(OpenDataException ex) - { - // It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } + _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, + _channelAtttibuteNames, _channelAttributeTypes); + _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); } public Date getLastIoTime() @@ -204,12 +172,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _minaProtocolSession.getReadBytes(); } - public Long getMaximumNumberOfAllowedChannels() + public Long getMaximumNumberOfChannels() { return _maxNoOfChannels; } - public void setMaximumNumberOfAllowedChannels(Long value) + public void setMaximumNumberOfChannels(Long value) { _maxNoOfChannels = value; } @@ -264,30 +232,25 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, * @return list of channels in tabular form. * @throws OpenDataException */ - public TabularData getChannels() throws OpenDataException + public TabularData channels() throws OpenDataException { _channelsList = new TabularDataSupport(_channelsType); for (Map.Entry entry : _channelMap.entrySet()) { AMQChannel channel = entry.getValue(); - Object[] itemValues = {channel.getChannelId(), - channel.isTransactional(), + Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, channel.getUnacknowledgedMessageMap().size()}; - CompositeData channelData = new CompositeDataSupport(_channelType, - _channelAtttibuteNames, - itemValues); - + CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); _channelsList.put(channelData); } return _channelsList; } - - public void closeChannel(int id) - throws Exception + + public void closeChannel(int id) throws Exception { try { @@ -299,8 +262,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } } - public void closeConnection() - throws Exception + public void closeConnection() throws Exception { try { @@ -315,13 +277,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[] - {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + 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); + String description = "Channel count has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); return new MBeanNotificationInfo[] {info1}; } @@ -329,14 +288,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private void checkForNotification() { int channelsCount = _channelMap.size(); - if (channelsCount >= getMaximumNumberOfAllowedChannels()) + if (channelsCount >= getMaximumNumberOfChannels()) { - Notification n = new Notification( - MonitorNotification.THRESHOLD_VALUE_EXCEEDED, - this, - ++_notificationSequenceNumber, - System.currentTimeMillis(), - "ChannelsCount = " + channelsCount + ", ChannelsCount has reached the threshold value"); + Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, + ++_notificationSequenceNumber, System.currentTimeMillis(), + "Channel count (" + channelsCount + ") has reached the threshold value"); _broadcaster.sendNotification(n); } @@ -372,10 +328,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { return new ManagedAMQProtocolSession(); } - catch(NotCompliantMBeanException ex) + catch(JMException ex) { - _logger.error("AMQProtocolSession MBean creation has failed.", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed.", ex); + _logger.error("AMQProtocolSession MBean creation has failed ", ex); + throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 889acd0142..2f3102b048 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -41,83 +41,57 @@ 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 + * Tells the remote address of this connection. + * @return remote address */ - @MBeanAttribute(name="Channels", - description="channel details of all the channels opened for this connection") - TabularData getChannels() throws IOException, JMException; + @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") + String getRemoteAddress(); /** * Tells the last time, the IO operation was done. * @return last IO time. */ - @MBeanAttribute(name="LastIOTime", - description="The last time, the IO operation was done") + @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") + @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") + @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 + * Threshold high value for no of channels. This is useful in setting notifications or * taking required action is there are more channels being created. - * @return maximum number of channels allowed to be created. + * @return threshold limit for no of channels */ - Long getMaximumNumberOfAllowedChannels(); + Long getMaximumNumberOfChannels(); /** - * Sets the maximum number of channels allowed to be created using - * this connection. + * Sets the threshold high value for number of channels for a connection * @param value */ - @MBeanAttribute(name="MaximumNumberOfAllowedChannels", - description="The maximum number of channels that can be opened using this connection") - void setMaximumNumberOfAllowedChannels(Long value); + @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") + void setMaximumNumberOfChannels(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. + * channel details of all the channels opened for this connection. + * @return general channel details + * @throws IOException + * @throws JMException */ - @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; + @MBeanOperation(name="channels", description="Channel details for this connection") + TabularData channels() throws IOException, JMException; /** * Commits the transactions if the channel is transactional. @@ -125,8 +99,8 @@ public interface ManagedConnection * @throws JMException */ @MBeanOperation(name="commitTransaction", - description="Commits the transactions for given channelID, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) + description="Commits the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; /** @@ -135,7 +109,24 @@ public interface ManagedConnection * @throws JMException */ @MBeanOperation(name="rollbackTransactions", - description="Rollsback the transactions for given channelId, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) + description="Rollsback the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Unsubscribes the consumers and unregisters the channel from managed objects. + */ + @MBeanOperation(name="closeChannel", + description="Closes the channel with given channel Id and connected consumers will be unsubscribed", + impact= MBeanOperationInfo.ACTION) + void closeChannel(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) + throws Exception; + + /** + * Closes all the related channels and unregisters this connection from managed objects. + */ + @MBeanOperation(name="closeConnection", + description="Closes this connection and all related channels", + impact= MBeanOperationInfo.ACTION) + void closeConnection() throws Exception; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 05fe8908c3..353a2007c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -25,6 +25,7 @@ import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -38,7 +39,6 @@ import org.apache.qpid.server.txn.TxnOp; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.*; @@ -100,19 +100,19 @@ public class AMQQueue implements Managable, Comparable private final AMQQueueMBean _managedObject; /** - * max allowed size of a single message(in KBytes). + * max allowed size(KB) of a single message */ - private long _maxAllowedMessageSize = 10000; // 10 MB + private long _maxMessageSize = 10000; /** * max allowed number of messages on a queue. */ - private Integer _maxAllowedMessageCount = 10000; + private Integer _maxMessageCount = 10000; /** - * max allowed size in KBytes for all the messages combined together in a queue. + * max queue depth(KB) for the queue */ - private long _queueDepth = 10000000; // 10 GB + private long _maxQueueDepth = 10000000; /** * total messages received by the queue since startup. @@ -132,83 +132,45 @@ public class AMQQueue implements Managable, Comparable private final class AMQQueueMBean extends AMQManagedObject implements ManagedQueue { private String _queueName = null; + // OpenMBean data types for viewMessages method + private String[] _msgAttributeNames = {"Message Id", "Header", "Size(bytes)", "Redelivered"}; + private String[] _msgAttributeIndex = {_msgAttributeNames[0]}; + private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - // AMQ message attribute names - private String[] _msgAttributeNames = {"MessageId", - "Header", - "Size", - "Redelivered" - }; - // AMQ Message attribute descriptions. - private String[] _msgAttributeDescriptions = {"Message Id", - "Header", - "Message size in bytes", - "Redelivered" - }; - - private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private String[] _msgAttributeIndex = {"MessageId"}; // Messages will be indexed according to the messageId. - private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - - private CompositeType _msgContentType = null; // For message content - private String[] _msgContentAttributes = {"MessageId", - "MimeType", - "Encoding", - "Content" - }; - private String[] _msgContentDescriptions = {"Message Id", - "MimeType", - "Encoding", - "Message content" - }; - private OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - - @MBeanConstructor("Creates an MBean exposing an AMQQueue.") - public AMQQueueMBean() throws NotCompliantMBeanException + // OpenMBean data types for viewMessageContent method + private CompositeType _msgContentType = null; + private String[] _msgContentAttributes = {"Message Id", "MimeType", "Encoding", "Content"}; + private OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + @MBeanConstructor("Creates an MBean exposing an AMQQueue") + public AMQQueueMBean() throws JMException { super(ManagedQueue.class, ManagedQueue.TYPE); init(); } - private void init() + /** + * initialises the openmbean data types + */ + private void init() throws OpenDataException { _queueName = jmxEncode(new StringBuffer(_name), 0).toString(); - try - { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("MessageContent", - "AMQ Message Content", - _msgContentAttributes, - _msgContentDescriptions, - _msgContentAttributeTypes); - - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = new CompositeType("Message", - "AMQ Message", - _msgAttributeNames, - _msgAttributeDescriptions, - _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", - "List of messages", - _messageDataType, - _msgAttributeIndex); - } - catch (OpenDataException ex) - { - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, + _msgContentAttributes, _msgContentAttributeTypes); + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = new CompositeType("Message","AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); } public String getObjectInstanceName() @@ -243,12 +205,12 @@ public class AMQQueue implements Managable, Comparable public Long getMaximumMessageSize() { - return _maxAllowedMessageSize; + return _maxMessageSize; } public void setMaximumMessageSize(Long value) { - _maxAllowedMessageSize = value; + _maxMessageSize = value; } public Integer getConsumerCount() @@ -268,27 +230,29 @@ public class AMQQueue implements Managable, Comparable public Integer getMaximumMessageCount() { - return _maxAllowedMessageCount; + return _maxMessageCount; } public void setMaximumMessageCount(Integer value) { - _maxAllowedMessageCount = value; + _maxMessageCount = value; } - public Long getQueueDepth() + public Long getMaximumQueueDepth() { - return _queueDepth; + return _maxQueueDepth; } // Sets the queue depth, the max queue size - public void setQueueDepth(Long value) + public void setMaximumQueueDepth(Long value) { - _queueDepth = value; + _maxQueueDepth = value; } - // Returns the size of messages in the queue - public Long getQueueSize() + /** + * returns the size of messages(KB) in the queue. + */ + public Long getQueueDepth() { List list = _deliveryMgr.getMessages(); if (list.size() == 0) @@ -296,15 +260,17 @@ public class AMQQueue implements Managable, Comparable return 0l; } - long queueSize = 0; + long queueDepth = 0; for (AMQMessage message : list) { - queueSize = queueSize + getMessageSize(message); + queueDepth = queueDepth + getMessageSize(message); } - return new Long(Math.round(queueSize / 100)); + return (long)Math.round(queueDepth / 1000); } - // calculates the size of an AMQMessage + /** + * returns size of message in bytes + */ private long getMessageSize(AMQMessage msg) { if (msg == null) @@ -312,53 +278,43 @@ public class AMQQueue implements Managable, Comparable return 0l; } - List cBodies = msg.getContentBodies(); - long messageSize = 0; - for (ContentBody body : cBodies) - { - if (body != null) - { - messageSize = messageSize + body.getSize(); - } - } - return messageSize; + return msg.getContentHeaderBody().bodySize; } - // Checks if there is any notification to be send to the listeners + /** + * Checks if there is any notification to be send to the listeners + */ private void checkForNotification(AMQMessage msg) { - // Check for message count + // Check for threshold message count Integer msgCount = getMessageCount(); if (msgCount >= getMaximumMessageCount()) { - notifyClients("MessageCount = " + msgCount + ", Queue has reached its size limit and is now full."); + notifyClients("Message count(" + msgCount + ") has reached or exceeded the threshold high value"); } - // Check for received message size + // Check for threshold message size long messageSize = getMessageSize(msg); - if (messageSize >= getMaximumMessageSize()) + if (messageSize >= _maxMessageSize) { - notifyClients("MessageSize = " + messageSize + ", Message size (MessageID=" + msg.getMessageId() + - ")is higher than the threshold value"); + notifyClients("Message size(ID=" + msg.getMessageId() + ", size=" + messageSize + " bytes) is higher than the threshold value"); } - // Check for queue size in bytes - long queueSize = getQueueSize(); - if (queueSize >= getQueueDepth()) + // Check for threshold queue depth in bytes + long queueDepth = getQueueDepth(); + if (queueDepth >= _maxQueueDepth) { - notifyClients("QueueSize = " + queueSize + ", Queue size has reached the threshold value"); + notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value"); } } - // Send the notification to the listeners + /** + * Sends the notification to the listeners + */ private void notifyClients(String notificationMsg) { - Notification n = new Notification( - MonitorNotification.THRESHOLD_VALUE_EXCEEDED, - this, - ++_notificationSequenceNumber, - System.currentTimeMillis(), - notificationMsg); + Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, + ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); _broadcaster.sendNotification(n); } @@ -387,10 +343,12 @@ public class AMQQueue implements Managable, Comparable } } + /** + * returns message content as byte array and related attributes for the given message id. + */ public CompositeData viewMessageContent(long msgId) throws JMException { List list = _deliveryMgr.getMessages(); - CompositeData messageContent = null; AMQMessage msg = null; for (AMQMessage message : list) { @@ -401,77 +359,55 @@ public class AMQQueue implements Managable, Comparable } } - if (msg != null) + if (msg == null) { - // get message content - List cBodies = msg.getContentBodies(); - List msgContent = new ArrayList(); - for (ContentBody body : cBodies) + throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName ); + } + // get message content + List cBodies = msg.getContentBodies(); + List msgContent = new ArrayList(); + for (ContentBody body : cBodies) + { + if (body.getSize() != 0) { - if (body.getSize() != 0) + ByteBuffer slice = body.payload.slice(); + for (int j = 0; j < slice.limit(); j++) { - ByteBuffer slice = body.payload.slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } + msgContent.add(slice.get()); } } - - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = headerProperties.getContentType(); - String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); - - Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; - messageContent = new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - else - { - throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } - return messageContent; + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; + String mimeType = headerProperties.getContentType(); + String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; + + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); } /** - * Returns the messages stored in this queue in tabular form. - * - * @param beginIndex - * @param endIndex - * @return AMQ messages in tabular form. - * @throws JMException + * Returns the header contents of the messages stored in this queue in tabular form. */ 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"); + throw new JMException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\nFrom Index should be greater than 0 and less than To Index"); } List list = _deliveryMgr.getMessages(); TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - if (beginIndex > list.size()) - { - return _messageList; - } - endIndex = endIndex < list.size() ? endIndex : list.size(); - - for (int i = beginIndex; i <= endIndex; i++) + // Create the tabular list of message header contents + for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) { AMQMessage msg = list.get(i - 1); - long size = 0; - // get message content - List cBodies = msg.getContentBodies(); - for (ContentBody body : cBodies) - { - size = size + body.getSize(); - } - + ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)headerBody.properties; List headerAttribsList = new ArrayList(); headerAttribsList.add("App Id=" + headerProperties.getAppId()); headerAttribsList.add("MimeType=" + headerProperties.getContentType()); @@ -479,13 +415,9 @@ public class AMQQueue implements Managable, Comparable headerAttribsList.add("Encoding=" + headerProperties.getEncoding()); headerAttribsList.add(headerProperties.toString()); - Object[] itemValues = {msg.getMessageId(), - headerAttribsList.toArray(new String[0]), - size, msg.isRedelivered()}; - - CompositeData messageData = new CompositeDataSupport(_messageDataType, - _msgAttributeNames, - itemValues); + Object[] itemValues = {msg.getMessageId(), headerAttribsList.toArray(new String[0]), + headerBody.bodySize, msg.isRedelivered()}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); _messageList.put(messageData); } @@ -493,20 +425,15 @@ public class AMQQueue implements Managable, Comparable } /** - * Creates all the notifications this MBean can send. - * - * @return Notifications broadcasted by this MBean. + * returns Notifications sent by this MBean. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[] - {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + 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); + String description = "Either Message count or Queue depth or Message size has reached threshold high value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); return new MBeanNotificationInfo[]{info1}; } @@ -608,9 +535,9 @@ public class AMQQueue implements Managable, Comparable { return new AMQQueueMBean(); } - catch (NotCompliantMBeanException ex) + catch (JMException ex) { - throw new AMQException("AMQQueue MBean creation has failed.", ex); + throw new AMQException("AMQQueue MBean creation has failed ", ex); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 3a818cf31a..de5d0f55a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -45,16 +45,48 @@ public interface ManagedQueue * @return the name of the managedQueue. * @throws IOException */ - @MBeanAttribute(name="Name", description = "Name of the " + TYPE) + @MBeanAttribute(name="Name", description = TYPE + " Name") String getName() throws IOException; /** - * Tells whether this ManagedQueue is durable or not. - * @return true if this ManagedQueue is a durable queue. + * 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="Durable", description = "true if the AMQQueue is durable") - boolean isDurable() throws IOException; + @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") + Integer getMessageCount() throws IOException; + + /** + * Tells the total number of messages receieved by the queue since startup. + * @return total number of messages received. + * @throws IOException + */ + @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") + Long getReceivedMessageCount() throws IOException; + + /** + * Size of messages in the queue + * @return + * @throws IOException + */ + @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue") + Long getQueueDepth() throws IOException; + + /** + * Returns the total number of active subscribers to the queue. + * @return the number of active subscribers + * @throws IOException + */ + @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") + Integer getActiveConsumerCount() throws IOException; + + /** + * Returns the total number of subscribers to the queue. + * @return the number of subscribers. + * @throws IOException + */ + @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") + Integer getConsumerCount() throws IOException; /** * Tells the Owner of the ManagedQueue. @@ -65,21 +97,20 @@ public interface ManagedQueue String getOwner() throws IOException; /** - * Tells if the ManagedQueue is set to AutoDelete. - * @return true if the ManagedQueue is set to AutoDelete. + * Tells whether this ManagedQueue is durable or not. + * @return true if this ManagedQueue is a durable queue. * @throws IOException */ - @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") - boolean isAutoDelete() throws IOException; + @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") + boolean isDurable() 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. + * Tells if the ManagedQueue is set to AutoDelete. + * @return true if the ManagedQueue is set to AutoDelete. * @throws IOException */ - @MBeanAttribute(name="MessageCount", - description = "Total number of undelivered messages on the queue") - Integer getMessageCount() throws IOException; + @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") + boolean isAutoDelete() throws IOException; /** * Returns the maximum size of a message (in kbytes) allowed to be accepted by the @@ -98,35 +129,9 @@ public interface ManagedQueue * @param size maximum size of message. * @throws IOException */ - @MBeanAttribute(name="MaximumMessageSize", - description="Maximum size(KB) of a message allowed for this Queue") + @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(KB) for a message size") 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 @@ -141,27 +146,16 @@ public interface ManagedQueue * @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") + @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") void setMaximumMessageCount(Integer value) throws IOException; /** - * Size of messages in the queue - * @return - * @throws IOException - */ - @MBeanAttribute(name="QueueSize", description="Size of messages(KB) in the queue") - Long getQueueSize() throws IOException; - - /** - * Tells the maximum size of all the messages combined together, - * that can be stored in the queue. This is useful for setting notifications - * or taking required action if the size of messages stored in the queue - * increases over this limit. - * @return maximum size of the all the messages allowed for the queue. + * This is useful for setting notifications or taking required action if the size of messages + * stored in the queue increases over this limit. + * @return threshold high value for Queue Depth * @throws IOException */ - Long getQueueDepth() throws IOException; + Long getMaximumQueueDepth() throws IOException; /** * Sets the maximum size of all the messages together, that can be stored @@ -169,9 +163,8 @@ public interface ManagedQueue * @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; + @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth") + void setMaximumQueueDepth(Long value) throws IOException; @@ -188,19 +181,22 @@ public interface ManagedQueue * @throws JMException */ @MBeanOperation(name="viewMessages", - description="shows messages in this queue with given indexes. eg. from index 1 - 100") + description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, @MBeanOperationParameter(name="to index", description="to index")int toIndex) throws IOException, JMException; + @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") + CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) + throws IOException, JMException; + /** * Deletes the first message from top. * @throws IOException * @throws JMException */ - @MBeanOperation(name="deleteMessageFromTop", - description="Deletes the first message from top", - impact= MBeanOperationInfo.ACTION) + @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", + impact= MBeanOperationInfo.ACTION) void deleteMessageFromTop() throws IOException, JMException; /** @@ -209,12 +205,8 @@ public interface ManagedQueue * @throws JMException */ @MBeanOperation(name="clearQueue", - description="Clears the queue by deleting all the undelivered messages from the queue", - impact= MBeanOperationInfo.ACTION) + description="Clears the queue by deleting all the undelivered messages from the queue", + impact= MBeanOperationInfo.ACTION) void clearQueue() throws IOException, JMException; - @MBeanOperation(name="viewMessageContent", - description="Returns the message content along with MimeType and Encoding") - CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) - throws IOException, JMException; } -- cgit v1.2.1 From e444e3ed015fa503501c81a2d024338ee0d1fa62 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 4 Dec 2006 16:38:10 +0000 Subject: QPID-148 AMQMinaProtocolSession.java - updated comment AbstractJMSMessage.java - removed a lot of getHeaders() == null checks. Updated logic accordingly.. Now a request for a property that doesn't exist will be consistent with calls on an empty table rather than just creating a default value. BasicContentHeaderProperties.java - the culprit for QPID-148 changed new FieldTable() to setHeaders(new FieldTable()) to ensure propertyFlag is set to write headers to the wire. Added PropertyValueTest.java - that tests all the valid values on the Message. *NOTE*: A number of the tests are commented out as AMQP and therefore the FieldTable do not support these values. QPID-9 Added SVN ignores for the target directories. Updated AbstractJMSMessage.java _readableProperties to be set correctly in the constructor. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@482238 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index be8d2c4c82..1aa62dbfa4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -367,6 +367,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, 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?) + // ritchiem 2006-12-04 will this not do? +// WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); +// future.join(); +// close connection + } } else -- cgit v1.2.1 From 2e4d9c40a39cb0a89cfaae57a3aaca97ce133fbc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 5 Dec 2006 18:37:18 +0000 Subject: FieldTable change. FieldTable is now an interface with a PropertyFieldTable.java implementation. This PropertyFieldTable has been updated to handle the wire level encoding and decoding of the underlying map. It also allows XML encoding of the data as used by JMSMapMessage. Currently the AMQP doesn't support all the Java primitives as a result all values are written out as XML using a prefix of 'X'. (See QPID-9 for further details) Changes where not specified are changes from new FieldTable() to FieldTableFactory.newFieldTable() AbstractJMSMessage.java - the type prefixing of properties is now not requried as all the functionality has been moved to PropertyFieldTable.java. In addition set/getObjectProperty is now implemented as PFT does this. basic Tests have been updated to send all property values. FieldTableKeyEnumeration.java has been removed as it is nolonger required. The PFT handles this internally. ToDo: The Tests need to be consolidated so that there is a clear view of the code coverage. QPID-158 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@482733 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java | 3 ++- .../apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 586d6b8796..ccb2211a55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -25,6 +25,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -154,7 +155,7 @@ public class HeadersExchange extends AbstractExchange } String[] bindings = binding.split(","); - FieldTable fieldTable = new FieldTable(); + FieldTable fieldTable = FieldTableFactory.newFieldTable(); for (int i = 0; i < bindings.length; i++) { String[] keyAndValue = bindings[i].split("="); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java index 3ad74ce180..c364ca1d8d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.security.auth.amqplain; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTableFactory; import org.apache.mina.common.ByteBuffer; import javax.security.sasl.SaslServer; @@ -54,7 +55,7 @@ public class AmqPlainSaslServer implements SaslServer { try { - final FieldTable ft = new FieldTable(ByteBuffer.wrap(response), response.length); + final FieldTable ft = FieldTableFactory.newFieldTable(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); -- cgit v1.2.1 From e24dc32963cb8433e5b4e2f7bf3c715eec46619f Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 12 Dec 2006 13:22:45 +0000 Subject: QPID-95 : Patch supplied by Rob Godfrey - throws correct exception when encountering a non-routable mandatory message git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@486132 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/HeadersExchange.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index ccb2211a55..3fa73aa2e2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -206,7 +206,18 @@ public class HeadersExchange extends AbstractExchange } if (!delivered) { - _logger.warn("Exchange " + getName() + ": message not routable."); + + String msg = "Exchange " + getName() + ": message not routable."; + + if (payload.getPublishBody().mandatory) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn(msg); + } + } } -- cgit v1.2.1 From 8b77115288e3cbe693a11fd1d6b2c9e2d9026fde Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 13 Dec 2006 13:27:47 +0000 Subject: Added comments about possible RejectedExecutionException that may occur when starting to process aSync deliveries as the broker closes its execution pools. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@486642 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/ConcurrentDeliveryManager.java | 7 ++++++- .../org/apache/qpid/server/queue/SynchronizedDeliveryManager.java | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java index dde76e5ba8..f9c8898182 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java @@ -281,7 +281,12 @@ public class ConcurrentDeliveryManager implements DeliveryManager //are we already running? if so, don't re-run if (_processing.compareAndSet(false, true)) { - executor.execute(asyncDelivery); + // Do we need this? + // This executor is created via Executors in AsyncDeliveryConfig which only returns a TPE so cast is ok. + //if (executor != null && !((ThreadPoolExecutor) executor).isShutdown()) + { + executor.execute(asyncDelivery); + } } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java index d2e53717af..ea64952bc7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -206,7 +206,12 @@ class SynchronizedDeliveryManager implements DeliveryManager //are we already running? if so, don't re-run if (_processing.compareAndSet(false, true)) { - executor.execute(new Runner()); + // Do we need this? + // This executor is created via Executors in AsyncDeliveryConfig which only returns a TPE so cast is ok. + //if (executor != null && !((ThreadPoolExecutor) executor).isShutdown()) + { + executor.execute(new Runner()); + } } } } -- cgit v1.2.1 From 842de14447a8d504d960369e5d8eeeda26d8c2cf Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 14 Dec 2006 17:25:31 +0000 Subject: QPID-190 Refactored the broker MBean classes git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@487268 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/protocol/AMQMinaProtocolSession.java | 261 +++---------- .../server/protocol/AMQProtocolSessionMBean.java | 240 ++++++++++++ .../org/apache/qpid/server/queue/AMQQueue.java | 429 +++++---------------- .../apache/qpid/server/queue/AMQQueueMBean.java | 343 ++++++++++++++++ 4 files changed, 734 insertions(+), 539 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 1aa62dbfa4..407ad236ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -40,9 +40,6 @@ import org.apache.qpid.framing.ProtocolVersionList; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.QueueRegistry; @@ -50,24 +47,12 @@ import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQStateManager; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; import javax.security.sasl.SaslServer; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Date; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; @@ -93,7 +78,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private AMQCodecFactory _codecFactory; - private ManagedAMQProtocolSession _managedObject; + private AMQProtocolSessionMBean _managedObject; private SaslServer _saslServer; @@ -102,11 +87,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private Object _lastSent; private boolean _closed; - + // maximum number of channels this session should have private long _maxNoOfChannels = 1000; /* AMQP Version for this session */ - private byte _major; private byte _minor; @@ -115,190 +99,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, 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; - //openmbean data types for representing the channel attributes - private String[] _channelAtttibuteNames = { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; - private String[] _indexNames = {_channelAtttibuteNames[0]}; - private OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; - private CompositeType _channelType = null; // represents the data type for channel data - private TabularType _channelsType = null; // Data type for list of channels type - private TabularDataSupport _channelsList = null; - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public ManagedAMQProtocolSession() throws JMException - { - super(ManagedConnection.class, ManagedConnection.TYPE); - init(); - } - - /** - * initialises the openmbean data types - */ - private void init() throws OpenDataException - { - String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? remote + hashCode() : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); - _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, - _channelAtttibuteNames, _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); - } - - 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 getMaximumNumberOfChannels() - { - return _maxNoOfChannels; - } - - public void setMaximumNumberOfChannels(Long value) - { - _maxNoOfChannels = value; - } - - public String getObjectInstanceName() - { - return _name; - } - - public void commitTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _channelMap.get(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - if (channel.isTransactional()) - { - channel.commit(); - } - } - catch(AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - public void rollbackTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _channelMap.get(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - if (channel.isTransactional()) - { - channel.rollback(); - } - } - catch(AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * Creates the list of channels in tabular form from the _channelMap. - * @return list of channels in tabular form. - * @throws OpenDataException - */ - public TabularData channels() throws OpenDataException - { - _channelsList = new TabularDataSupport(_channelsType); - - for (Map.Entry entry : _channelMap.entrySet()) - { - AMQChannel channel = entry.getValue(); - Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, - channel.getUnacknowledgedMessageMap().size()}; - - CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); - _channelsList.put(channelData); - } - - return _channelsList; - } - - public void closeChannel(int id) throws Exception - { - try - { - AMQMinaProtocolSession.this.closeChannel(id); - } - catch (AMQException ex) - { - throw new Exception(ex.toString()); - } - } - - public void closeConnection() throws Exception - { - try - { - AMQMinaProtocolSession.this.closeSession(); - } - catch (AMQException ex) - { - throw new Exception(ex.toString()); - } - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; - String name = MonitorNotification.class.getName(); - String description = "Channel count has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] {info1}; - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (channelsCount >= getMaximumNumberOfChannels()) - { - Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, - ++_notificationSequenceNumber, System.currentTimeMillis(), - "Channel count (" + channelsCount + ") has reached the threshold value"); - - _broadcaster.sendNotification(n); - } - } - - } // End of MBean class public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQCodecFactory codecFactory) @@ -322,11 +122,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _managedObject.register(); } - private ManagedAMQProtocolSession createMBean() throws AMQException + private AMQProtocolSessionMBean createMBean() throws AMQException { try { - return new ManagedAMQProtocolSession(); + return new AMQProtocolSessionMBean(this); } catch(JMException ex) { @@ -335,6 +135,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } } + public IoSession getIOSession() + { + return _minaProtocolSession; + } + public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) { return (AMQProtocolSession) minaProtocolSession.getAttachment(); @@ -495,7 +300,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _contextKey = contextKey; } - public AMQChannel getChannel(int channelId) throws AMQException + public List getChannels() + { + return new ArrayList(_channelMap.values()); + } + + public AMQChannel getChannel(int channelId) { return _channelMap.get(channelId); } @@ -503,7 +313,42 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void addChannel(AMQChannel channel) { _channelMap.put(channel.getChannelId(), channel); - _managedObject.checkForNotification(); + checkForNotification(); + } + + private void checkForNotification() + { + int channelsCount = _channelMap.size(); + if (channelsCount >= _maxNoOfChannels) + { + _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); + } + } + + public Long getMaximumNumberOfChannels() + { + return _maxNoOfChannels; + } + + public void setMaximumNumberOfChannels(Long value) + { + _maxNoOfChannels = value; + } + + public void commitTransactions(AMQChannel channel) throws AMQException + { + if (channel != null && channel.isTransactional()) + { + channel.commit(); + } + } + + public void rollbackTransactions(AMQChannel channel) throws AMQException + { + if (channel != null && channel.isTransactional()) + { + channel.rollback(); + } } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java new file mode 100644 index 0000000000..b56d22d655 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -0,0 +1,240 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.AMQChannel; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.util.Date; +import java.util.List; + +/** + * This MBean class implements the management interface. 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") +public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection +{ + private AMQMinaProtocolSession _session = null; + private String _name = null; + //openmbean data types for representing the channel attributes + private String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; + private String[] _indexNames = {_channelAtttibuteNames[0]}; + private OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; + private CompositeType _channelType = null; // represents the data type for channel data + private TabularType _channelsType = null; // Data type for list of channels type + + @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") + public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws JMException + { + super(ManagedConnection.class, ManagedConnection.TYPE); + _session = session; + init(); + } + + /** + * initialises the openmbean data types + */ + private void init() throws OpenDataException + { + String remote = getRemoteAddress(); + remote = "anonymous".equals(remote) ? remote + hashCode() : remote; + _name = jmxEncode(new StringBuffer(remote), 0).toString(); + _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, + _channelAtttibuteNames, _channelAttributeTypes); + _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); + } + + public Date getLastIoTime() + { + return new Date(_session.getIOSession().getLastIoTime()); + } + + public String getRemoteAddress() + { + return _session.getIOSession().getRemoteAddress().toString(); + } + + public Long getWrittenBytes() + { + return _session.getIOSession().getWrittenBytes(); + } + + public Long getReadBytes() + { + return _session.getIOSession().getReadBytes(); + } + + public Long getMaximumNumberOfChannels() + { + return _session.getMaximumNumberOfChannels(); + } + + public void setMaximumNumberOfChannels(Long value) + { + _session.setMaximumNumberOfChannels(value); + } + + public String getObjectInstanceName() + { + return _name; + } + + /** + * commits transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if commit fails + */ + public void commitTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + _session.commitTransactions(channel); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * rollsback the transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if rollback fails + */ + public void rollbackTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + _session.rollbackTransactions(channel); + } + 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 channels() throws OpenDataException + { + TabularDataSupport channelsList = new TabularDataSupport(_channelsType); + List list = _session.getChannels(); + + for (AMQChannel channel : list) + { + Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, + channel.getUnacknowledgedMessageMap().size()}; + + CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); + channelsList.put(channelData); + } + + return channelsList; + } + + /** + * @see AMQMinaProtocolSession#closeChannel(int) + */ + public void closeChannel(int id) throws JMException + { + AMQChannel channel = _session.getChannel(id); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + id + ") does not exist"); + } + try + { + _session.closeChannel(id); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * closes the connection. The administrator can use this management operation to close connection to free up + * resources. + * @throws JMException + */ + public void closeConnection() throws JMException + { + try + { + _session.closeSession(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String name = MonitorNotification.class.getName(); + String description = "Channel count has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[]{info1}; + } + + public void notifyClients(String notificationMsg) + { + Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, + ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); + _broadcaster.sendNotification(n); + } + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 353a2007c0..f2ef97cf9a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,15 +21,8 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -37,13 +30,7 @@ import org.apache.qpid.server.txn.TxnBuffer; import org.apache.qpid.server.txn.TxnOp; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.*; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; @@ -108,7 +95,7 @@ public class AMQQueue implements Managable, Comparable * max allowed number of messages on a queue. */ private Integer _maxMessageCount = 10000; - + /** * max queue depth(KB) for the queue */ @@ -124,322 +111,6 @@ public class AMQQueue implements Managable, Comparable return _name.compareTo(((AMQQueue) o).getName()); } - /** - * 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; - // OpenMBean data types for viewMessages method - private String[] _msgAttributeNames = {"Message Id", "Header", "Size(bytes)", "Redelivered"}; - private String[] _msgAttributeIndex = {_msgAttributeNames[0]}; - private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - // OpenMBean data types for viewMessageContent method - private CompositeType _msgContentType = null; - private String[] _msgContentAttributes = {"Message Id", "MimeType", "Encoding", "Content"}; - private OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - @MBeanConstructor("Creates an MBean exposing an AMQQueue") - public AMQQueueMBean() throws JMException - { - super(ManagedQueue.class, ManagedQueue.TYPE); - init(); - } - - /** - * initialises the openmbean data types - */ - private void init() throws OpenDataException - { - _queueName = jmxEncode(new StringBuffer(_name), 0).toString(); - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, - _msgContentAttributes, _msgContentAttributeTypes); - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = new CompositeType("Message","AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); - } - - 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 _maxMessageSize; - } - - public void setMaximumMessageSize(Long value) - { - _maxMessageSize = value; - } - - public Integer getConsumerCount() - { - return _subscribers.size(); - } - - public Integer getActiveConsumerCount() - { - return _subscribers.getWeight(); - } - - public Long getReceivedMessageCount() - { - return _totalMessagesReceived; - } - - public Integer getMaximumMessageCount() - { - return _maxMessageCount; - } - - public void setMaximumMessageCount(Integer value) - { - _maxMessageCount = value; - } - - public Long getMaximumQueueDepth() - { - return _maxQueueDepth; - } - - // Sets the queue depth, the max queue size - public void setMaximumQueueDepth(Long value) - { - _maxQueueDepth = value; - } - - /** - * returns the size of messages(KB) in the queue. - */ - public Long getQueueDepth() - { - List list = _deliveryMgr.getMessages(); - if (list.size() == 0) - { - return 0l; - } - - long queueDepth = 0; - for (AMQMessage message : list) - { - queueDepth = queueDepth + getMessageSize(message); - } - return (long)Math.round(queueDepth / 1000); - } - - /** - * returns size of message in bytes - */ - private long getMessageSize(AMQMessage msg) - { - 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) - { - // Check for threshold message count - Integer msgCount = getMessageCount(); - if (msgCount >= getMaximumMessageCount()) - { - notifyClients("Message count(" + msgCount + ") has reached or exceeded the threshold high value"); - } - - // Check for threshold message size - long messageSize = getMessageSize(msg); - if (messageSize >= _maxMessageSize) - { - notifyClients("Message size(ID=" + msg.getMessageId() + ", size=" + messageSize + " bytes) is higher than the threshold value"); - } - - // Check for threshold queue depth in bytes - long queueDepth = getQueueDepth(); - if (queueDepth >= _maxQueueDepth) - { - notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value"); - } - } - - /** - * Sends 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 message content as byte array and related attributes for the given message id. - */ - public CompositeData viewMessageContent(long msgId) throws JMException - { - List list = _deliveryMgr.getMessages(); - AMQMessage msg = null; - for (AMQMessage message : list) - { - if (message.getMessageId() == msgId) - { - msg = message; - break; - } - } - - if (msg == null) - { - throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName ); - } - // get message content - List cBodies = msg.getContentBodies(); - List msgContent = new ArrayList(); - for (ContentBody body : cBodies) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.payload.slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; - String mimeType = headerProperties.getContentType(); - String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); - Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; - - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - - /** - * Returns the header contents of the messages stored in this queue in tabular form. - */ - public TabularData viewMessages(int beginIndex, int endIndex) throws JMException - { - if ((beginIndex > endIndex) || (beginIndex < 1)) - { - throw new JMException("From Index = " + beginIndex + ", To Index = " + endIndex + - "\nFrom Index should be greater than 0 and less than To Index"); - } - - List list = _deliveryMgr.getMessages(); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - // Create the tabular list of message header contents - for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) - { - AMQMessage msg = list.get(i - 1); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)headerBody.properties; - List headerAttribsList = new ArrayList(); - headerAttribsList.add("App Id=" + headerProperties.getAppId()); - headerAttribsList.add("MimeType=" + headerProperties.getContentType()); - headerAttribsList.add("Correlation Id=" + headerProperties.getCorrelationId()); - headerAttribsList.add("Encoding=" + headerProperties.getEncoding()); - headerAttribsList.add(headerProperties.toString()); - - Object[] itemValues = {msg.getMessageId(), headerAttribsList.toArray(new String[0]), - headerBody.bodySize, msg.isRedelivered()}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); - _messageList.put(messageData); - } - - return _messageList; - } - - /** - * returns Notifications sent by this MBean. - */ - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; - String name = MonitorNotification.class.getName(); - String description = "Either Message count or Queue depth or Message size has reached threshold high 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 @@ -533,7 +204,7 @@ public class AMQQueue implements Managable, Comparable { try { - return new AMQQueueMBean(); + return new AMQQueueMBean(this); } catch (JMException ex) { @@ -566,16 +237,112 @@ public class AMQQueue implements Managable, Comparable return _autoDelete; } + /** + * @return no of messages(undelivered) on the queue. + */ public int getMessageCount() { return _deliveryMgr.getQueueMessageCount(); } + /** + * @return List of messages(undelivered) on the queue. + */ + public List getMessagesOnTheQueue() + { + return _deliveryMgr.getMessages(); + } + + /** + * @param messageId + * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. + */ + public AMQMessage getMessageOnTheQueue(long messageId) + { + List list = getMessagesOnTheQueue(); + AMQMessage msg = null; + for (AMQMessage message : list) + { + if (message.getMessageId() == messageId) + { + msg = message; + break; + } + } + + return msg; + } + + /** + * @return MBean object associated with this Queue + */ public ManagedObject getManagedObject() { return _managedObject; } + public Long getMaximumMessageSize() + { + return _maxMessageSize; + } + + public void setMaximumMessageSize(Long value) + { + _maxMessageSize = value; + } + + public Integer getConsumerCount() + { + return _subscribers.size(); + } + + public Integer getActiveConsumerCount() + { + return _subscribers.getWeight(); + } + + public Long getReceivedMessageCount() + { + return _totalMessagesReceived; + } + + public Integer getMaximumMessageCount() + { + return _maxMessageCount; + } + + public void setMaximumMessageCount(Integer value) + { + _maxMessageCount = value; + } + + public Long getMaximumQueueDepth() + { + return _maxQueueDepth; + } + + // Sets the queue depth, the max queue size + public void setMaximumQueueDepth(Long value) + { + _maxQueueDepth = value; + } + + /** + * Removes the AMQMessage from the top of the queue. + */ + public void deleteMessageFromTop() throws AMQException + { + _deliveryMgr.removeAMessageFromTop(); + } + + /** + * removes all the messages from the queue. + */ + public void clearQueue() throws AMQException + { + _deliveryMgr.clearAllMessages(); + } + public void bind(String routingKey, Exchange exchange) { _bindings.addBinding(routingKey, exchange); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java new file mode 100644 index 0000000000..54dd366d71 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -0,0 +1,343 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.mina.common.ByteBuffer; + +import javax.management.openmbean.*; +import javax.management.JMException; +import javax.management.Notification; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.OperationsException; +import javax.management.monitor.MonitorNotification; +import java.util.List; +import java.util.ArrayList; + +/** + * MBean class for AMQQueue. It implements all the management features exposed + * for an AMQQueue. + */ +@MBeanDescription("Management Interface for AMQQueue") +public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue +{ + private AMQQueue _queue = null; + private String _queueName = null; + // OpenMBean data types for viewMessages method + private String[] _msgAttributeNames = {"Message Id", "Header", "Size(bytes)", "Redelivered"}; + private String[] _msgAttributeIndex = {_msgAttributeNames[0]}; + private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + + // OpenMBean data types for viewMessageContent method + private CompositeType _msgContentType = null; + private String[] _msgContentAttributes = {"Message Id", "MimeType", "Encoding", "Content"}; + private OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + @MBeanConstructor("Creates an MBean exposing an AMQQueue") + public AMQQueueMBean(AMQQueue queue) throws JMException + { + super(ManagedQueue.class, ManagedQueue.TYPE); + _queue = queue; + _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); + init(); + } + + /** + * initialises the openmbean data types + */ + private void init() throws OpenDataException + { + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, + _msgContentAttributes, _msgContentAttributeTypes); + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); + } + + public String getObjectInstanceName() + { + return _queueName; + } + + public String getName() + { + return _queueName; + } + + public boolean isDurable() + { + return _queue.isDurable(); + } + + public String getOwner() + { + return _queue.getOwner(); + } + + public boolean isAutoDelete() + { + return _queue.isAutoDelete(); + } + + public Integer getMessageCount() + { + return _queue.getMessageCount(); + } + + public Long getMaximumMessageSize() + { + return _queue.getMaximumMessageSize(); + } + + public void setMaximumMessageSize(Long value) + { + _queue.setMaximumMessageSize(value); + } + + public Integer getConsumerCount() + { + return _queue.getConsumerCount(); + } + + public Integer getActiveConsumerCount() + { + return _queue.getActiveConsumerCount(); + } + + public Long getReceivedMessageCount() + { + return _queue.getReceivedMessageCount(); + } + + public Integer getMaximumMessageCount() + { + return _queue.getMaximumMessageCount(); + } + + public void setMaximumMessageCount(Integer value) + { + _queue.setMaximumMessageCount(value); + } + + public Long getMaximumQueueDepth() + { + return _queue.getMaximumQueueDepth(); + } + + public void setMaximumQueueDepth(Long value) + { + _queue.setMaximumQueueDepth(value); + } + + /** + * returns the size of messages(KB) in the queue. + */ + public Long getQueueDepth() + { + List list = _queue.getMessagesOnTheQueue(); + if (list.size() == 0) + { + return 0l; + } + + long queueDepth = 0; + for (AMQMessage message : list) + { + queueDepth = queueDepth + getMessageSize(message); + } + return (long) Math.round(queueDepth / 1000); + } + + /** + * returns size of message in bytes + */ + private long getMessageSize(AMQMessage msg) + { + if (msg == null) + { + return 0l; + } + + return msg.getContentHeaderBody().bodySize; + } + + /** + * Checks if there is any notification to be send to the listeners + */ + public void checkForNotification(AMQMessage msg) + { + // Check for threshold message count + Integer msgCount = getMessageCount(); + if (msgCount >= getMaximumMessageCount()) + { + notifyClients("Message count(" + msgCount + ") has reached or exceeded the threshold high value"); + } + + // Check for threshold message size + long messageSize = getMessageSize(msg); + if (messageSize >= _queue.getMaximumMessageSize()) + { + notifyClients("Message size(ID=" + msg.getMessageId() + ", size=" + messageSize + " bytes) is higher than the threshold value"); + } + + // Check for threshold queue depth in bytes + long queueDepth = getQueueDepth(); + if (queueDepth >= _queue.getMaximumQueueDepth()) + { + notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value"); + } + } + + /** + * Sends 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); + } + + /** + * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop() + */ + public void deleteMessageFromTop() throws JMException + { + try + { + _queue.deleteMessageFromTop(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * @see org.apache.qpid.server.queue.AMQQueue#clearQueue() + */ + public void clearQueue() throws JMException + { + try + { + _queue.clearQueue(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * returns message content as byte array and related attributes for the given message id. + */ + public CompositeData viewMessageContent(long msgId) throws JMException + { + AMQMessage msg = _queue.getMessageOnTheQueue(msgId); + if (msg == null) + { + throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); + } + // get message content + List cBodies = msg.getContentBodies(); + List msgContent = new ArrayList(); + for (ContentBody body : cBodies) + { + if (body.getSize() != 0) + { + ByteBuffer slice = body.payload.slice(); + for (int j = 0; j < slice.limit(); j++) + { + msgContent.add(slice.get()); + } + } + } + + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; + String mimeType = headerProperties.getContentType(); + String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; + + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + } + + /** + * Returns the header contents of the messages stored in this queue in tabular form. + */ + public TabularData viewMessages(int beginIndex, int endIndex) throws JMException + { + if ((beginIndex > endIndex) || (beginIndex < 1)) + { + throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + } + + List list = _queue.getMessagesOnTheQueue(); + TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); + + // Create the tabular list of message header contents + for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) + { + AMQMessage msg = list.get(i - 1); + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + String[] headerAttributes = headerProperties.toString().split(","); + Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + _messageList.put(messageData); + } + + return _messageList; + } + + /** + * returns Notifications sent by this MBean. + */ + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String name = MonitorNotification.class.getName(); + String description = "Either Message count or Queue depth or Message size has reached threshold high value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[]{info1}; + } + +} // End of AMQMBean class -- cgit v1.2.1 From 4b54df7a05fcf9837f2587c64afc24a6981aa6cb Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 14 Dec 2006 18:40:34 +0000 Subject: git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@487299 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQMinaProtocolSession.java | 2 +- .../apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 407ad236ea..c38f7f630b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -305,7 +305,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return new ArrayList(_channelMap.values()); } - public AMQChannel getChannel(int channelId) + public AMQChannel getChannel(int channelId) throws AMQException { return _channelMap.get(channelId); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index b56d22d655..a47d462810 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -187,13 +187,14 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void closeChannel(int id) throws JMException { - AMQChannel channel = _session.getChannel(id); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + id + ") does not exist"); - } try { + AMQChannel channel = _session.getChannel(id); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + id + ") does not exist"); + } + _session.closeChannel(id); } catch (AMQException ex) -- cgit v1.2.1 From dc3b5d32de80ec74031cc79dc32d982fd43c55ce Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 15 Dec 2006 14:12:24 +0000 Subject: QPID-183 Patch supplied by Rob Godfrey. Major changes to durable topic subscription handling. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@487562 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/DestNameExchange.java | 34 ++++- .../qpid/server/exchange/DestWildExchange.java | 45 +++++- .../org/apache/qpid/server/exchange/Exchange.java | 30 +++- .../qpid/server/exchange/HeadersExchange.java | 31 +++- .../org/apache/qpid/server/exchange/Index.java | 11 +- .../qpid/server/handler/ExchangeBoundHandler.java | 163 +++++++++++++++++++++ .../apache/qpid/server/state/AMQStateManager.java | 5 +- 7 files changed, 302 insertions(+), 17 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 6dc97f9e48..ffd0e5d8ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -197,4 +197,34 @@ public class DestNameExchange extends AbstractExchange } } } + + public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + { + final List queues = _index.get(routingKey); + return queues != null && queues.contains(queue); + } + + public boolean isBound(String routingKey) throws AMQException + { + final List queues = _index.get(routingKey); + return queues != null && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) throws AMQException + { + Map> bindings = _index.getBindingsMap(); + for (List queues : bindings.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() throws AMQException + { + return !_index.getBindingsMap().isEmpty(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index a692f9ebca..139307488e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -126,10 +126,11 @@ public class DestWildExchange extends AbstractExchange } // End of MBean class - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; assert routingKey != null; + _logger.debug("Registering queue " + queue.getName() + " with routing key " + routingKey); // 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 @@ -159,6 +160,8 @@ public class DestWildExchange extends AbstractExchange // TODO: add support for the immediate flag if (queues == null) { + _logger.warn("No queues found for routing key " + routingKey); + _logger.warn("Routing map contains: " + _routingKey2queues); //todo Check for valid topic - mritchie return; } @@ -172,7 +175,37 @@ public class DestWildExchange extends AbstractExchange } } - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + { + List queues = _routingKey2queues.get(routingKey); + return queues != null && queues.contains(queue); + } + + + public boolean isBound(String routingKey) throws AMQException + { + List queues = _routingKey2queues.get(routingKey); + return queues != null && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) throws AMQException + { + for (List queues : _routingKey2queues.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() throws AMQException + { + return !_routingKey2queues.isEmpty(); + } + + public synchronized void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException { assert queue != null; assert routingKey != null; @@ -190,6 +223,10 @@ public class DestWildExchange extends AbstractExchange throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + " with routing key " + routingKey); } + if (queues.isEmpty()) + { + _routingKey2queues.remove(queues); + } } protected ExchangeMBean createMBean() throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 787d0eddfd..824e85dc5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -47,4 +47,30 @@ public interface Exchange void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException; void route(AMQMessage message) throws AMQException; + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key + * @param routingKey + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(String routingKey, AMQQueue queue) throws AMQException; + + /** + * Determines whether a message is routing to any queue using a specific routing key + * @param routingKey + * @return + * @throws AMQException + */ + boolean isBound(String routingKey) throws AMQException; + + boolean isBound(AMQQueue queue) throws AMQException; + + /** + * Returns true if this exchange has at least one binding associated with it. + * @return + * @throws AMQException + */ + boolean hasBindings() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 3fa73aa2e2..8c4df68dea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -221,6 +221,33 @@ public class HeadersExchange extends AbstractExchange } } + public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + { + return isBound(queue); + } + + public boolean isBound(String routingKey) throws AMQException + { + return hasBindings(); + } + + public boolean isBound(AMQQueue queue) throws AMQException + { + for (Registration r : _bindings) + { + if (r.queue.equals(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() throws AMQException + { + return !_bindings.isEmpty(); + } + protected Map getHeaders(ContentHeaderBody contentHeaderFrame) { //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index fb48729c9e..485c4739bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,6 +24,7 @@ import org.apache.qpid.server.queue.AMQQueue; import java.util.List; import java.util.Map; +import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -37,7 +38,7 @@ class Index private ConcurrentMap> _index = new ConcurrentHashMap>(); - boolean add(String key, AMQQueue queue) + synchronized boolean add(String key, AMQQueue queue) { List queues = _index.get(key); if(queues == null) @@ -61,7 +62,7 @@ class Index } } - boolean remove(String key, AMQQueue queue) + synchronized boolean remove(String key, AMQQueue queue) { List queues = _index.get(key); if (queues != null) @@ -83,6 +84,6 @@ class Index Map> getBindingsMap() { - return _index; + return new HashMap>(_index); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java new file mode 100644 index 0000000000..5aaf78d6b7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -0,0 +1,163 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.ExchangeBoundBody; +import org.apache.qpid.framing.ExchangeBoundOkBody; +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; + +/** + * @author Apache Software Foundation + */ +public class ExchangeBoundHandler implements StateAwareMethodListener +{ + private static final ExchangeBoundHandler _instance = new ExchangeBoundHandler(); + + public static final int OK = 0; + + public static final int EXCHANGE_NOT_FOUND = 1; + + public static final int QUEUE_NOT_FOUND = 2; + + public static final int NO_BINDINGS = 3; + + public static final int QUEUE_NOT_BOUND = 4; + + public static final int NO_QUEUE_BOUND_WITH_RK = 5; + + public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; + + public static ExchangeBoundHandler getInstance() + { + return _instance; + } + + private ExchangeBoundHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ExchangeBoundBody body = evt.getMethod(); + + String exchangeName = body.exchange; + String queueName = body.queue; + String routingKey = body.routingKey; + if (exchangeName == null) + { + throw new AMQException("Exchange exchange must not be null"); + } + Exchange exchange = exchangeRegistry.getExchange(exchangeName); + AMQFrame response; + if (exchange == null) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), EXCHANGE_NOT_FOUND, + "Exchange " + exchangeName + " not found"); + } + else if (routingKey == null) + { + if (queueName == null) + { + if (exchange.hasBindings()) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), OK, null); + } + else + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), NO_BINDINGS, null); + } + } + else + { + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), QUEUE_NOT_FOUND, + "Queue " + queueName + " not found"); + } + else + { + if (exchange.isBound(queue)) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), OK, null); + } + else + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), QUEUE_NOT_BOUND, + "Queue " + queueName + " not bound to exchange " + + exchangeName); + } + } + } + } + else if (queueName != null) + { + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), QUEUE_NOT_FOUND, + "Queue " + queueName + " not found"); + } + else + { + if (exchange.isBound(body.routingKey, queue)) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), OK, + null); + } + else + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), + SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, + "Queue " + queueName + + " not bound with routing key " + + body.routingKey + " to exchange " + + exchangeName); + } + } + } + else + { + if (exchange.isBound(body.routingKey)) + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), OK, + null); + } + else + { + response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), + NO_QUEUE_BOUND_WITH_RK, + "No queue bound with routing key " + + body.routingKey + " to exchange " + + exchangeName); + } + } + protocolSession.writeFrame(response); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 5e88ff7f2d..4e9deeb8db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -109,6 +109,7 @@ public class AMQStateManager implements AMQMethodListener frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance()); frame2handlerMap.put(ExchangeDeclareBody.class, ExchangeDeclareHandler.getInstance()); frame2handlerMap.put(ExchangeDeleteBody.class, ExchangeDeleteHandler.getInstance()); + frame2handlerMap.put(ExchangeBoundBody.class, ExchangeBoundHandler.getInstance()); frame2handlerMap.put(BasicAckBody.class, BasicAckMethodHandler.getInstance()); frame2handlerMap.put(BasicRecoverBody.class, BasicRecoverMethodHandler.getInstance()); frame2handlerMap.put(BasicConsumeBody.class, BasicConsumeMethodHandler.getInstance()); -- cgit v1.2.1 From d1f2271a3b09d7671108027e63696524c8a1f20d Mon Sep 17 00:00:00 2001 From: Stephen Vinoski Date: Mon, 18 Dec 2006 06:36:10 +0000 Subject: remove unused imports Remove unused imports for common, broker, client, and systests as reported by Eclipse. Note that this includes imports in the Java XSL template used to generate the framing code in common. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488134 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java | 4 ---- .../main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java | 1 - .../main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java | 1 - .../apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java | 1 - .../src/main/java/org/apache/qpid/server/queue/Subscription.java | 2 -- .../java/org/apache/qpid/server/transport/ConnectorConfiguration.java | 1 - 6 files changed, 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index a4cb1f1e71..a204e176aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -20,13 +20,9 @@ */ package org.apache.qpid.server.ack; -import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.txn.TxnOp; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index dcc50a796a..4a0a6a0ee1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; public interface ExchangeRegistry extends MessageRouter diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java index 8417ada15f..87ccc60907 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -31,7 +31,6 @@ 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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index c858d25e2d..c32f5e4283 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -21,7 +21,6 @@ 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index dfc16a7c71..49f0a51bf2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.AMQException; - public interface Subscription { void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java index ca008a0bd5..ac164f0cab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -22,7 +22,6 @@ 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 -- cgit v1.2.1 From 35aee343f206afc69730dd192e59af02c84c7716 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 18 Dec 2006 10:08:09 +0000 Subject: QPID-211 : Patch supplied by Rob Godfrey - Perform null check against routing key before looking in the map git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488188 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index ffd0e5d8ae..d4069fa315 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -171,7 +171,7 @@ public class DestNameExchange extends AbstractExchange BasicPublishBody publishBody = payload.getPublishBody(); final String routingKey = publishBody.routingKey; - final List queues = _index.get(routingKey); + final List queues = (routingKey == null) ? null : _index.get(routingKey); if (queues == null || queues.isEmpty()) { String msg = "Routing key " + routingKey + " is not known to " + this; -- cgit v1.2.1 From b7ed484846d963376ad921f6c83f1b5f0410ca2a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 18 Dec 2006 14:28:18 +0000 Subject: null check added for null header properties git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488279 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueueMBean.java | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 54dd366d71..1bdf265a1b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -275,22 +275,29 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue // get message content List cBodies = msg.getContentBodies(); List msgContent = new ArrayList(); - for (ContentBody body : cBodies) + if (cBodies != null) { - if (body.getSize() != 0) + for (ContentBody body : cBodies) { - ByteBuffer slice = body.payload.slice(); - for (int j = 0; j < slice.limit(); j++) + if (body.getSize() != 0) { - msgContent.add(slice.get()); + ByteBuffer slice = body.payload.slice(); + for (int j = 0; j < slice.limit(); j++) + { + msgContent.add(slice.get()); + } } } } // Create header attributes list BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = headerProperties.getContentType(); - String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + String mimeType = null, encoding = null; + if (headerProperties != null) + { + mimeType = headerProperties.getContentType(); + encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + } Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); -- cgit v1.2.1 From d07480d43ef288fc231e8b6d41c4650af2307d22 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 18 Dec 2006 18:05:25 +0000 Subject: QPID-212 QPID-214 Patch supplied by Rob Godfrey git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488377 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQChannel.java | 11 ++++++++--- .../main/java/org/apache/qpid/server/queue/AMQMessage.java | 13 +++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index a6cb4523cf..b0fbafac56 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -397,7 +397,7 @@ public class AMQChannel long deliveryTag = entry.getKey(); String consumerTag = entry.getValue().consumerTag; AMQMessage msg = entry.getValue().message; - + msg.setRedelivered(true); session.writeFrame(msg.getDataBlock(_channelId, consumerTag, deliveryTag)); } } @@ -495,6 +495,11 @@ public class AMQChannel private void handleAcknowledgement(long deliveryTag, boolean multiple) throws AMQException { + if (_log.isDebugEnabled()) + { + _log.debug("Handling acknowledgement for channel " + _channelId + " with delivery tag " + deliveryTag + + " and multiple " + multiple); + } if (multiple) { LinkedList acked = new LinkedList(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 8b6db5b53f..12e06b31ed 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -102,7 +102,7 @@ public class AMQMessage public AMQMessage(MessageStore store, long messageId, BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, List contentBodies) throws AMQException - + { _publishBody = publishBody; _contentHeaderBody = contentHeaderBody; @@ -116,7 +116,7 @@ public class AMQMessage ContentHeaderBody contentHeaderBody, List contentBodies) throws AMQException { - this(store, store.getNewMessageId(), publishBody, contentHeaderBody, contentBodies); + this(store, store.getNewMessageId(), publishBody, contentHeaderBody, contentBodies); } protected AMQMessage(AMQMessage msg) throws AMQException @@ -211,6 +211,7 @@ public class AMQMessage return _bodyLengthReceived == _contentHeaderBody.bodySize; } + public boolean isRedelivered() { return _redelivered; @@ -236,7 +237,7 @@ public class AMQMessage return new NoConsumersException(queue, _publishBody, _contentHeaderBody, _contentBodies); } - void setRedelivered(boolean redelivered) + public void setRedelivered(boolean redelivered) { _redelivered = redelivered; } @@ -346,7 +347,7 @@ public class AMQMessage } /** - * Called to enforce the 'immediate' flag. + * 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 -- cgit v1.2.1 From 6bf41b3b90816ee3310c7e60419baa95ca51b476 Mon Sep 17 00:00:00 2001 From: Stephen Vinoski Date: Mon, 18 Dec 2006 23:09:14 +0000 Subject: clean up warnings about unused variables Remove all warnings in common, broker, client, and systests regarding unused variables, as indicated by Eclipse builds. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488450 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java | 4 ++-- .../java/org/apache/qpid/server/management/MBeanIntrospector.java | 1 - .../org/apache/qpid/server/security/auth/plain/PlainSaslServer.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 3470a5bb08..553aecc217 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -522,10 +522,10 @@ public class Main implements ProtocolVersionList */ 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 + // boolean inUse = false; + // Check if there are queue-bindings with the exchange and unregister // when there are no bindings. try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java index b8235a0808..535122efb5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -61,7 +61,6 @@ class MBeanIntrospector { */ for (Method method : interfaceClass.getMethods()) { - int argCount = method.getParameterTypes().length; String name = method.getName(); Class resultType = method.getReturnType(); MBeanAttributeInfo attributeInfo = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java index fdf655c2d9..7f51260e45 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java @@ -62,7 +62,7 @@ public class PlainSaslServer implements SaslServer } // we do not currently support authcid in any meaningful way - String authcid = new String(response, 0, authzidNullPosition, "utf8"); + // 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 -- cgit v1.2.1 From 5a914f818635425089ea0378120fa27aa6bc211b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 19 Dec 2006 10:51:39 +0000 Subject: QPID-21 Added: SelectorParser.jj - ActiveMQ selector javacc grammar used to generate SelectorParser.java server/filter - Selector Filtering code from ActiveMQ project adjusted to suite our class and package structure. server/message - Decorator classes to allow access to the JMSMessage inside the AMQMessage ConcurrentSelectorDeliveryManager.java - A new DeliveryManager that utilises PreDeliveryQueues to implement selectors AMQInvalidSelectorException.java - thrown on client and broker when the Selector text is invalid. Common: log4j.properties to remove error log4j warnings on Common tests. Modified: broker/pom.xml - to generate SelectorParser.java AMQChannel.java - Addition of argument fieldtable for filter setup. BasicConsumeMethodHandler.java - writing of InvalidSelector channel close exception. AMQMessage.java - Added decorator to get access to the enclosed JMSMessage AMQQueue.java - Enhanced 'deliverymanager' property to allow the selection of the ConcurrentSelectorDeliveryManager. Subscription.java - Enhanced interface to allow a subscription to state an 'interest' in a given message. SubscriptionFactory.java - Added method to allow passing of filter arguments. SubscriptionImpl.java - Implemented new Subscription.java methods. SubscriptionManager.java - Added ability to get a list of current subscribers. SubscriptionSet.java - augmented nextSubscriber to allow the subscriber to exert the new hasInterest feature. SynchronizedDeliveryManager.java - fixed Logging class AMQSession - Added filter extraction from consume call and pass it on to the registration. ChannelCloseMethodHandler.java - Handle the reception and correct raising of the InvalidSelector Exception AbstractJMSMessage.java - Expanded imports BlockingMethodFrameListener.java - added extra info to a debug output line. SocketTransportConnection.java - made output an info not a warn. PropertiesFileInitialContextFactory.java - updated to allow the PROVIDER_URL to specify a property file to read in for the initial values. ClusteredSubscriptionManager.java - Implementation of SubscriptionSet.java NestedSubscriptionManager.java - Implementation of SubscriptionManager.java RemoteSubscriptionImpl.java - Implementation Subscription.java AMQConstant.java - Added '322' "Invalid Selector" SubscriptionTestHelper.java - Implementation of Subscription.java Edited specs/amqp-8.0.xml to add field table to consume method. Thanks to the ActiveMQ project for writing the initial SelectorParser.jj and associated filter Expressions. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488624 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 5 +- .../qpid/server/filter/ArithmeticExpression.java | 216 ++++++++++ .../qpid/server/filter/BinaryExpression.java | 100 +++++ .../qpid/server/filter/BooleanExpression.java | 45 ++ .../qpid/server/filter/ComparisonExpression.java | 465 +++++++++++++++++++++ .../qpid/server/filter/ConstantExpression.java | 170 ++++++++ .../org/apache/qpid/server/filter/Expression.java | 42 ++ .../apache/qpid/server/filter/FilterManager.java | 37 ++ .../qpid/server/filter/FilterManagerFactory.java | 81 ++++ .../qpid/server/filter/JMSSelectorFilter.java | 79 ++++ .../apache/qpid/server/filter/LogicExpression.java | 95 +++++ .../apache/qpid/server/filter/MessageFilter.java | 30 ++ .../qpid/server/filter/PropertyExpression.java | 305 ++++++++++++++ .../qpid/server/filter/SimpleFilterManager.java | 77 ++++ .../apache/qpid/server/filter/UnaryExpression.java | 263 ++++++++++++ .../apache/qpid/server/filter/XPathExpression.java | 130 ++++++ .../qpid/server/filter/XQueryExpression.java | 56 +++ .../qpid/server/filter/XalanXPathEvaluator.java | 99 +++++ .../server/handler/BasicConsumeMethodHandler.java | 22 +- .../qpid/server/message/MessageDecorator.java | 25 ++ .../apache/qpid/server/message/jms/JMSMessage.java | 306 ++++++++++++++ .../org/apache/qpid/server/queue/AMQMessage.java | 88 +++- .../org/apache/qpid/server/queue/AMQQueue.java | 30 +- .../queue/ConcurrentSelectorDeliveryManager.java | 352 ++++++++++++++++ .../org/apache/qpid/server/queue/Subscription.java | 13 + .../qpid/server/queue/SubscriptionFactory.java | 4 + .../apache/qpid/server/queue/SubscriptionImpl.java | 65 ++- .../qpid/server/queue/SubscriptionManager.java | 3 + .../apache/qpid/server/queue/SubscriptionSet.java | 72 +++- .../server/queue/SynchronizedDeliveryManager.java | 2 +- 30 files changed, 3233 insertions(+), 44 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageDecorator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index b0fbafac56..d8485ef0f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -26,6 +26,7 @@ import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.ack.TxAck; import org.apache.qpid.server.ack.UnacknowledgedMessage; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; @@ -290,7 +291,7 @@ public class AMQChannel * @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 + public String subscribeToQueue(String tag, AMQQueue queue, AMQProtocolSession session, boolean acks, FieldTable filters) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { @@ -301,7 +302,7 @@ public class AMQChannel throw new ConsumerTagNotUniqueException(); } - queue.registerProtocolSession(session, _channelId, tag, acks); + queue.registerProtocolSession(session, _channelId, tag, acks, filters); _consumerTag2QueueMap.put(tag, queue); return tag; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java new file mode 100644 index 0000000000..0aa5739c1c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -0,0 +1,216 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + + +import org.apache.qpid.server.queue.AMQMessage; + +import javax.jms.JMSException; + +/** + * An expression which performs an operation on two expression values + * + * @version $Revision$ + */ +public abstract class ArithmeticExpression extends BinaryExpression { + + protected static final int INTEGER = 1; + protected static final int LONG = 2; + protected static final int DOUBLE = 3; + + /** + * @param left + * @param right + */ + public ArithmeticExpression(Expression left, Expression right) { + super(left, right); + } + + public static Expression createPlus(Expression left, Expression right) { + return new ArithmeticExpression(left, right) { + protected Object evaluate(Object lvalue, Object rvalue) { + if (lvalue instanceof String) { + String text = (String) lvalue; + String answer = text + rvalue; + return answer; + } + else if (lvalue instanceof Number) { + return plus((Number) lvalue, asNumber(rvalue)); + } + throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() { + return "+"; + } + }; + } + + public static Expression createMinus(Expression left, Expression right) { + return new ArithmeticExpression(left, right) { + protected Object evaluate(Object lvalue, Object rvalue) { + if (lvalue instanceof Number) { + return minus((Number) lvalue, asNumber(rvalue)); + } + throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() { + return "-"; + } + }; + } + + public static Expression createMultiply(Expression left, Expression right) { + return new ArithmeticExpression(left, right) { + + protected Object evaluate(Object lvalue, Object rvalue) { + if (lvalue instanceof Number) { + return multiply((Number) lvalue, asNumber(rvalue)); + } + throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() { + return "*"; + } + }; + } + + public static Expression createDivide(Expression left, Expression right) { + return new ArithmeticExpression(left, right) { + + protected Object evaluate(Object lvalue, Object rvalue) { + if (lvalue instanceof Number) { + return divide((Number) lvalue, asNumber(rvalue)); + } + throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() { + return "/"; + } + }; + } + + public static Expression createMod(Expression left, Expression right) { + return new ArithmeticExpression(left, right) { + + protected Object evaluate(Object lvalue, Object rvalue) { + if (lvalue instanceof Number) { + return mod((Number) lvalue, asNumber(rvalue)); + } + throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() { + return "%"; + } + }; + } + + protected Number plus(Number left, Number right) { + switch (numberType(left, right)) { + case INTEGER: + return new Integer(left.intValue() + right.intValue()); + case LONG: + return new Long(left.longValue() + right.longValue()); + default: + return new Double(left.doubleValue() + right.doubleValue()); + } + } + + protected Number minus(Number left, Number right) { + switch (numberType(left, right)) { + case INTEGER: + return new Integer(left.intValue() - right.intValue()); + case LONG: + return new Long(left.longValue() - right.longValue()); + default: + return new Double(left.doubleValue() - right.doubleValue()); + } + } + + protected Number multiply(Number left, Number right) { + switch (numberType(left, right)) { + case INTEGER: + return new Integer(left.intValue() * right.intValue()); + case LONG: + return new Long(left.longValue() * right.longValue()); + default: + return new Double(left.doubleValue() * right.doubleValue()); + } + } + + protected Number divide(Number left, Number right) { + return new Double(left.doubleValue() / right.doubleValue()); + } + + protected Number mod(Number left, Number right) { + return new Double(left.doubleValue() % right.doubleValue()); + } + + private int numberType(Number left, Number right) { + if (isDouble(left) || isDouble(right)) { + return DOUBLE; + } + else if (left instanceof Long || right instanceof Long) { + return LONG; + } + else { + return INTEGER; + } + } + + private boolean isDouble(Number n) { + return n instanceof Float || n instanceof Double; + } + + protected Number asNumber(Object value) { + if (value instanceof Number) { + return (Number) value; + } + else { + throw new RuntimeException("Cannot convert value: " + value + " into a number"); + } + } + + public Object evaluate(AMQMessage message) throws JMSException { + Object lvalue = left.evaluate(message); + if (lvalue == null) { + return null; + } + Object rvalue = right.evaluate(message); + if (rvalue == null) { + return null; + } + return evaluate(lvalue, rvalue); + } + + + /** + * @param lvalue + * @param rvalue + * @return + */ + abstract protected Object evaluate(Object lvalue, Object rvalue); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java new file mode 100644 index 0000000000..4256ab9189 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -0,0 +1,100 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + + + +/** + * An expression which performs an operation on two expression values. + * + * @version $Revision$ + */ +abstract public class BinaryExpression implements Expression { + protected Expression left; + protected Expression right; + + public BinaryExpression(Expression left, Expression right) { + this.left = left; + this.right = right; + } + + public Expression getLeft() { + return left; + } + + public Expression getRight() { + return right; + } + + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + abstract public String getExpressionSymbol(); + + /** + * @param expression + */ + public void setRight(Expression expression) { + right = expression; + } + + /** + * @param expression + */ + public void setLeft(Expression expression) { + left = expression; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java new file mode 100644 index 0000000000..b66de3fbc5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -0,0 +1,45 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import javax.jms.JMSException; + + +/** + * A BooleanExpression is an expression that always + * produces a Boolean result. + * + * @version $Revision$ + */ +public interface BooleanExpression extends Expression { + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws JMSException + */ + public boolean matches(AMQMessage message) throws JMSException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java new file mode 100644 index 0000000000..13d278cf65 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -0,0 +1,465 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import java.util.HashSet; +import java.util.List; +import java.util.regex.Pattern; + +import javax.jms.JMSException; + +/** + * A filter performing a comparison of two objects + * + * @version $Revision$ + */ +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { + + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) { + return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); + } + + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) { + return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); + } + + static final private HashSet REGEXP_CONTROL_CHARS = new HashSet(); + + static { + REGEXP_CONTROL_CHARS.add(new Character('.')); + REGEXP_CONTROL_CHARS.add(new Character('\\')); + REGEXP_CONTROL_CHARS.add(new Character('[')); + REGEXP_CONTROL_CHARS.add(new Character(']')); + REGEXP_CONTROL_CHARS.add(new Character('^')); + REGEXP_CONTROL_CHARS.add(new Character('$')); + REGEXP_CONTROL_CHARS.add(new Character('?')); + REGEXP_CONTROL_CHARS.add(new Character('*')); + REGEXP_CONTROL_CHARS.add(new Character('+')); + REGEXP_CONTROL_CHARS.add(new Character('{')); + REGEXP_CONTROL_CHARS.add(new Character('}')); + REGEXP_CONTROL_CHARS.add(new Character('|')); + REGEXP_CONTROL_CHARS.add(new Character('(')); + REGEXP_CONTROL_CHARS.add(new Character(')')); + REGEXP_CONTROL_CHARS.add(new Character(':')); + REGEXP_CONTROL_CHARS.add(new Character('&')); + REGEXP_CONTROL_CHARS.add(new Character('<')); + REGEXP_CONTROL_CHARS.add(new Character('>')); + REGEXP_CONTROL_CHARS.add(new Character('=')); + REGEXP_CONTROL_CHARS.add(new Character('!')); + } + + static class LikeExpression extends UnaryExpression implements BooleanExpression { + + Pattern likePattern; + + /** + * @param right + */ + public LikeExpression(Expression right, String like, int escape) { + super(right); + + StringBuffer regexp = new StringBuffer(like.length() * 2); + regexp.append("\\A"); // The beginning of the input + for (int i = 0; i < like.length(); i++) { + char c = like.charAt(i); + if (escape == (0xFFFF & c)) { + i++; + if (i >= like.length()) { + // nothing left to escape... + break; + } + + char t = like.charAt(i); + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & t)); + } + else if (c == '%') { + regexp.append(".*?"); // Do a non-greedy match + } + else if (c == '_') { + regexp.append("."); // match one + } + else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) { + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & c)); + } + else { + regexp.append(c); + } + } + regexp.append("\\z"); // The end of the input + + likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); + } + + /** + * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() + */ + public String getExpressionSymbol() { + return "LIKE"; + } + + /** + * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) + */ + public Object evaluate(AMQMessage message) throws JMSException { + + Object rv = this.getRight().evaluate(message); + + if (rv == null) { + return null; + } + + if (!(rv instanceof String)) { + return Boolean.FALSE; + //throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); + } + + return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; + } + + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + } + + public static BooleanExpression createLike(Expression left, String right, String escape) { + if (escape != null && escape.length() != 1) { + throw new RuntimeException("The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); + } + int c = -1; + if (escape != null) { + c = 0xFFFF & escape.charAt(0); + } + + return new LikeExpression(left, right, c); + } + + public static BooleanExpression createNotLike(Expression left, String right, String escape) { + return UnaryExpression.createNOT(createLike(left, right, escape)); + } + + public static BooleanExpression createInFilter(Expression left, List elements) { + + if( !(left instanceof PropertyExpression) ) + throw new RuntimeException("Expected a property for In expression, got: "+left); + return UnaryExpression.createInExpression((PropertyExpression)left, elements, false); + + } + + public static BooleanExpression createNotInFilter(Expression left, List elements) { + + if( !(left instanceof PropertyExpression) ) + throw new RuntimeException("Expected a property for In expression, got: "+left); + return UnaryExpression.createInExpression((PropertyExpression)left, elements, true); + + } + + public static BooleanExpression createIsNull(Expression left) { + return doCreateEqual(left, ConstantExpression.NULL); + } + + public static BooleanExpression createIsNotNull(Expression left) { + return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); + } + + public static BooleanExpression createNotEqual(Expression left, Expression right) { + return UnaryExpression.createNOT(createEqual(left, right)); + } + + public static BooleanExpression createEqual(Expression left, Expression right) { + checkEqualOperand(left); + checkEqualOperand(right); + checkEqualOperandCompatability(left, right); + return doCreateEqual(left, right); + } + + private static BooleanExpression doCreateEqual(Expression left, Expression right) { + return new ComparisonExpression(left, right) { + + public Object evaluate(AMQMessage message) throws JMSException { + Object lv = left.evaluate(message); + Object rv = right.evaluate(message); + + // Iff one of the values is null + if (lv == null ^ rv == null) { + return Boolean.FALSE; + } + if (lv == rv || lv.equals(rv)) { + return Boolean.TRUE; + } + if( lv instanceof Comparable && rv instanceof Comparable ) { + return compare((Comparable)lv, (Comparable)rv); + } + return Boolean.FALSE; + } + + protected boolean asBoolean(int answer) { + return answer == 0; + } + + public String getExpressionSymbol() { + return "="; + } + }; + } + + public static BooleanExpression createGreaterThan(final Expression left, final Expression right) { + checkLessThanOperand(left); + checkLessThanOperand(right); + return new ComparisonExpression(left, right) { + protected boolean asBoolean(int answer) { + return answer > 0; + } + + public String getExpressionSymbol() { + return ">"; + } + }; + } + + public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) { + checkLessThanOperand(left); + checkLessThanOperand(right); + return new ComparisonExpression(left, right) { + protected boolean asBoolean(int answer) { + return answer >= 0; + } + + public String getExpressionSymbol() { + return ">="; + } + }; + } + + public static BooleanExpression createLessThan(final Expression left, final Expression right) { + checkLessThanOperand(left); + checkLessThanOperand(right); + return new ComparisonExpression(left, right) { + + protected boolean asBoolean(int answer) { + return answer < 0; + } + + public String getExpressionSymbol() { + return "<"; + } + + }; + } + + public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) { + checkLessThanOperand(left); + checkLessThanOperand(right); + return new ComparisonExpression(left, right) { + + protected boolean asBoolean(int answer) { + return answer <= 0; + } + + public String getExpressionSymbol() { + return "<="; + } + }; + } + + /** + * Only Numeric expressions can be used in >, >=, < or <= expressions.s + * + * @param expr + */ + public static void checkLessThanOperand(Expression expr ) { + if( expr instanceof ConstantExpression ) { + Object value = ((ConstantExpression)expr).getValue(); + if( value instanceof Number ) + return; + + // Else it's boolean or a String.. + throw new RuntimeException("Value '"+expr+"' cannot be compared."); + } + if( expr instanceof BooleanExpression ) { + throw new RuntimeException("Value '"+expr+"' cannot be compared."); + } + } + + /** + * Validates that the expression can be used in == or <> expression. + * Cannot not be NULL TRUE or FALSE litterals. + * + * @param expr + */ + public static void checkEqualOperand(Expression expr ) { + if( expr instanceof ConstantExpression ) { + Object value = ((ConstantExpression)expr).getValue(); + if( value == null ) + throw new RuntimeException("'"+expr+"' cannot be compared."); + } + } + + /** + * + * @param left + * @param right + */ + private static void checkEqualOperandCompatability(Expression left, Expression right) { + if( left instanceof ConstantExpression && right instanceof ConstantExpression ) { + if( left instanceof BooleanExpression && !(right instanceof BooleanExpression) ) + throw new RuntimeException("'"+left+"' cannot be compared with '"+right+"'"); + } + } + + + + /** + * @param left + * @param right + */ + public ComparisonExpression(Expression left, Expression right) { + super(left, right); + } + + public Object evaluate(AMQMessage message) throws JMSException { + Comparable lv = (Comparable) left.evaluate(message); + if (lv == null) { + return null; + } + Comparable rv = (Comparable) right.evaluate(message); + if (rv == null) { + return null; + } + return compare(lv, rv); + } + + protected Boolean compare(Comparable lv, Comparable rv) { + Class lc = lv.getClass(); + Class rc = rv.getClass(); + // If the the objects are not of the same type, + // try to convert up to allow the comparison. + if (lc != rc) { + if (lc == Byte.class) { + if (rc == Short.class) { + lv = new Short(((Number) lv).shortValue()); + } + else if (rc == Integer.class) { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) { + lv = new Double(((Number) lv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } else if (lc == Short.class) { + if (rc == Integer.class) { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) { + lv = new Double(((Number) lv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } else if (lc == Integer.class) { + if (rc == Long.class) { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) { + lv = new Double(((Number) lv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } + else if (lc == Long.class) { + if (rc == Integer.class) { + rv = new Long(((Number) rv).longValue()); + } + else if (rc == Float.class) { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) { + lv = new Double(((Number) lv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } + else if (lc == Float.class) { + if (rc == Integer.class) { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Long.class) { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Double.class) { + lv = new Double(((Number) lv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } + else if (lc == Double.class) { + if (rc == Integer.class) { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Long.class) { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Float.class) { + rv = new Float(((Number) rv).doubleValue()); + } + else { + return Boolean.FALSE; + } + } + else + return Boolean.FALSE; + } + return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; + } + + protected abstract boolean asBoolean(int answer); + + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java new file mode 100644 index 0000000000..9bde712da2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -0,0 +1,170 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import java.math.BigDecimal; + +import javax.jms.JMSException; + +/** + * Represents a constant expression + * + * @version $Revision$ + */ +public class ConstantExpression implements Expression { + + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression { + public BooleanConstantExpression(Object value) { + super(value); + } + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + } + + public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); + public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); + public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); + + private Object value; + + public static ConstantExpression createFromDecimal(String text) { + + // Strip off the 'l' or 'L' if needed. + if( text.endsWith("l") || text.endsWith("L") ) + text = text.substring(0, text.length()-1); + + Number value; + try { + value = new Long(text); + } catch ( NumberFormatException e) { + // The number may be too big to fit in a long. + value = new BigDecimal(text); + } + + long l = value.longValue(); + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + value = new Integer(value.intValue()); + } + return new ConstantExpression(value); + } + + public static ConstantExpression createFromHex(String text) { + Number value = new Long(Long.parseLong(text.substring(2), 16)); + long l = value.longValue(); + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + value = new Integer(value.intValue()); + } + return new ConstantExpression(value); + } + + public static ConstantExpression createFromOctal(String text) { + Number value = new Long(Long.parseLong(text, 8)); + long l = value.longValue(); + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + value = new Integer(value.intValue()); + } + return new ConstantExpression(value); + } + + public static ConstantExpression createFloat(String text) { + Number value = new Double(text); + return new ConstantExpression(value); + } + + public ConstantExpression(Object value) { + this.value = value; + } + + public Object evaluate(AMQMessage message) throws JMSException { + return value; + } + + public Object getValue() { + return value; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + if (value == null) { + return "NULL"; + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; + } + if (value instanceof String) { + return encodeString((String) value); + } + return value.toString(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + return toString().equals(o.toString()); + + } + + + /** + * Encodes the value of string so that it looks like it would look like + * when it was provided in a selector. + * + * @param s + * @return + */ + public static String encodeString(String s) { + StringBuffer b = new StringBuffer(); + b.append('\''); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\'') { + b.append(c); + } + b.append(c); + } + b.append('\''); + return b.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java new file mode 100644 index 0000000000..a15c15fb91 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -0,0 +1,42 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import javax.jms.JMSException; + + +/** + * Represents an expression + * + * @version $Revision$ + */ +public interface Expression { + + /** + * @return the value of this expression + */ + public Object evaluate(AMQMessage message) throws JMSException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java new file mode 100644 index 0000000000..c82de9fa15 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; + +public interface FilterManager +{ + void add(MessageFilter filter); + + void remove(MessageFilter filter); + + boolean allAllow(AMQMessage msg); + + boolean hasFilters(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java new file mode 100644 index 0000000000..6ecd56586f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; + +import java.util.Iterator; + + +public class FilterManagerFactory +{ + //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); + private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); + + //fixme move to a common class so it can be refered to from client code. + private static String JMS_SELECTOR_FILTER = "x-filter-jms-selector"; + + public static FilterManager createManager(FieldTable filters) throws AMQException + { + FilterManager manager = null; + + if (filters != null) + { + + manager = new SimpleFilterManager(); + + Iterator it = filters.keySet().iterator(); + _logger.info("Processing filters:"); + while (it.hasNext()) + { + String key = (String) it.next(); + _logger.info("filter:" + key); + if (key.equals(JMS_SELECTOR_FILTER)) + { + String selector = (String) filters.get(key); + + if (selector != null && !selector.equals("")) + { + manager.add(new JMSSelectorFilter(selector)); + } + } + + } + + //If we added no filters don't bear the overhead of having an filter manager + if (!manager.hasFilters()) + { + manager = null; + } + } + else + { + _logger.info("No Filters found."); + } + + + return manager; + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java new file mode 100644 index 0000000000..4884067237 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidSelectorException; +import org.apache.log4j.Logger; + + +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; + +public class JMSSelectorFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); + + private String _selector; + private BooleanExpression _matcher; + + public JMSSelectorFilter(String selector) throws AMQException + { + _selector = selector; + _logger.info("Created JMSSelectorFilter with selector:" + _selector); + + + try + { + _matcher = new SelectorParser().parse(selector); + } + catch (InvalidSelectorException e) + { + // fixme + // Is this the correct way of throwing exception + throw new AMQInvalidSelectorException(e.getMessage()); + } + + } + + public boolean matches(AMQMessage message) + { + try + { + boolean match = _matcher.matches(message); + _logger.info(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); + return match; + } + catch (JMSException e) + { + //fixme this needs to be sorted.. it shouldn't happen + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + return false; + } + + public String getSelector() + { + return _selector; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java new file mode 100644 index 0000000000..714d8c23f5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -0,0 +1,95 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import javax.jms.JMSException; + +/** + * A filter performing a comparison of two objects + * + * @version $Revision$ + */ +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { + + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { + return new LogicExpression(lvalue, rvalue) { + + public Object evaluate(AMQMessage message) throws JMSException { + + Boolean lv = (Boolean) left.evaluate(message); + // Can we do an OR shortcut?? + if (lv !=null && lv.booleanValue()) { + return Boolean.TRUE; + } + + Boolean rv = (Boolean) right.evaluate(message); + return rv==null ? null : rv; + } + + public String getExpressionSymbol() { + return "OR"; + } + }; + } + + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { + return new LogicExpression(lvalue, rvalue) { + + public Object evaluate(AMQMessage message) throws JMSException { + + Boolean lv = (Boolean) left.evaluate(message); + + // Can we do an AND shortcut?? + if (lv == null) + return null; + if (!lv.booleanValue()) { + return Boolean.FALSE; + } + + Boolean rv = (Boolean) right.evaluate(message); + return rv == null ? null : rv; + } + + public String getExpressionSymbol() { + return "AND"; + } + }; + } + + /** + * @param left + * @param right + */ + public LogicExpression(BooleanExpression left, BooleanExpression right) { + super(left, right); + } + + abstract public Object evaluate(AMQMessage message) throws JMSException; + + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java new file mode 100644 index 0000000000..b8ca75d209 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.server.queue.AMQMessage; + +import javax.jms.JMSException; + +public interface MessageFilter +{ + boolean matches(AMQMessage message) throws JMSException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java new file mode 100644 index 0000000000..f3e9965c2e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -0,0 +1,305 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.io.IOException; +import java.util.HashMap; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; + +//import org.apache.activemq.command.ActiveMQDestination; +//import org.apache.activemq.command.Message; +//import org.apache.activemq.command.TransactionId; +//import org.apache.activemq.util.JMSExceptionSupport; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.log4j.Logger; + +/** + * Represents a property expression + * + * @version $Revision$ + */ +public class PropertyExpression implements Expression +{ + + interface SubExpression + { + public Object evaluate(AMQMessage message); + } + + interface JMSExpression + { + public abstract Object evaluate(JMSMessage message); + } + + static class SubJMSExpression implements SubExpression + { + JMSExpression _expression; + + SubJMSExpression(JMSExpression expression) + { + _expression = expression; + } + + + public Object evaluate(AMQMessage message) + { + JMSMessage msg = (JMSMessage) message.getDecodedMessage(AMQMessage.JMS_MESSAGE); + if (msg != null) + { + return _expression.evaluate(msg); + } + else + { + return null; + } + } + } + + private final static Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); + + + static final private HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); + + static + { + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSDestination(); + } + } + )); +// +// public Object evaluate(AMQMessage message) +// { +// //fixme +// +// +//// AMQDestination dest = message.getOriginalDestination(); +//// if (dest == null) +//// { +//// dest = message.getDestination(); +//// } +//// if (dest == null) +//// { +//// return null; +//// } +//// return dest.toString(); +// return ""; +// } +// }); + JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSReplyTo(); + } + }) + ); + + JMS_PROPERTY_EXPRESSIONS.put("JMSType", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSType(); + } + } + )); + + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + try + { + Integer mode = new Integer(message.getAMQMessage().isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + _logger.info("JMSDeliveryMode is :" + mode); + return mode; + } + catch (AMQException e) + { + //shouldn't happen + } + + return DeliveryMode.NON_PERSISTENT; + } + })); + + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSPriority(); + } + } + )); + + + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getAMQMessage().getMessageId(); + } + } + )); + + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSTimestamp(); + } + } + )); + + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSCorrelationID(); + } + } + )); + + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getJMSExpiration(); + } + } + )); + + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new SubJMSExpression( + new JMSExpression() + { + public Object evaluate(JMSMessage message) + { + return message.getAMQMessage().isRedelivered(); + } + } + )); + + } + + private final String name; + private final SubExpression jmsPropertyExpression; + + public PropertyExpression(String name) + { + this.name = name; + jmsPropertyExpression = (SubExpression) JMS_PROPERTY_EXPRESSIONS.get(name); + } + + public Object evaluate(AMQMessage message) throws JMSException + { +// try +// { +// if (message.isDropped()) +// { +// return null; +// } + + if (jmsPropertyExpression != null) + { + return jmsPropertyExpression.evaluate(message); + } +// try + else + { + + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + + _logger.info("Looking up property:" + name); + _logger.info("Properties are:" + _properties.getHeaders().keySet()); + + return _properties.getHeaders().get(name); + } +// catch (IOException ioe) +// { +// JMSException exception = new JMSException("Could not get property: " + name + " reason: " + ioe.getMessage()); +// exception.initCause(ioe); +// throw exception; +// } +// } +// catch (IOException e) +// { +// JMSException exception = new JMSException(e.getMessage()); +// exception.initCause(e); +// throw exception; +// } + + } + + public String getName() + { + return name; + } + + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return name; + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if (o == null || !this.getClass().equals(o.getClass())) + { + return false; + } + return name.equals(((PropertyExpression) o).name); + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java new file mode 100644 index 0000000000..dc2c2c0e6c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.server.queue.AMQMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.JMSException; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class SimpleFilterManager implements FilterManager +{ + private final Logger _logger = LoggerFactory.getLogger(SimpleFilterManager.class); + + private final ConcurrentLinkedQueue _filters; + + public SimpleFilterManager() + { + _logger.debug("Creating SimpleFilterManager"); + _filters = new ConcurrentLinkedQueue(); + } + + public void add(MessageFilter filter) + { + _filters.add(filter); + } + + public void remove(MessageFilter filter) + { + _filters.remove(filter); + } + + public boolean allAllow(AMQMessage msg) + { + for (MessageFilter filter : _filters) + { + try + { + if (!filter.matches(msg)) + { + return false; + } + } + catch (JMSException e) + { + //fixme + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + return false; + } + } + return true; + } + + public boolean hasFilters() + { + return !_filters.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java new file mode 100644 index 0000000000..49ff147411 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -0,0 +1,263 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.jms.JMSMessage; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import javax.jms.JMSException; + +/** + * An expression which performs an operation on two expression values + * + * @version $Revision$ + */ +public abstract class UnaryExpression implements Expression { + + private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); + protected Expression right; + + public static Expression createNegate(Expression left) { + return new UnaryExpression(left) { + public Object evaluate(AMQMessage message) throws JMSException { + Object rvalue = right.evaluate(message); + if (rvalue == null) { + return null; + } + if (rvalue instanceof Number) { + return negate((Number) rvalue); + } + return null; + } + + public String getExpressionSymbol() { + return "-"; + } + }; + } + + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { + + // Use a HashSet if there are many elements. + Collection t; + if( elements.size()==0 ) + t=null; + else if( elements.size() < 5 ) + t = elements; + else { + t = new HashSet(elements); + } + final Collection inList = t; + + return new BooleanUnaryExpression(right) { + public Object evaluate(AMQMessage message) throws JMSException { + + Object rvalue = right.evaluate(message); + if (rvalue == null) { + return null; + } + if( rvalue.getClass()!=String.class ) + return null; + + if( (inList!=null && inList.contains(rvalue)) ^ not ) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + + } + + public String toString() { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count=0; + for (Iterator i = inList.iterator(); i.hasNext();) { + Object o = (Object) i.next(); + if( count!=0 ) { + answer.append(", "); + } + answer.append(o); + count++; + } + + answer.append(" )"); + return answer.toString(); + } + + public String getExpressionSymbol() { + if( not ) + return "NOT IN"; + else + return "IN"; + } + }; + } + + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { + public BooleanUnaryExpression(Expression left) { + super(left); + } + + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + }; + + + public static BooleanExpression createNOT(BooleanExpression left) { + return new BooleanUnaryExpression(left) { + public Object evaluate(AMQMessage message) throws JMSException { + Boolean lvalue = (Boolean) right.evaluate(message); + if (lvalue == null) { + return null; + } + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + public String getExpressionSymbol() { + return "NOT"; + } + }; + } + + public static BooleanExpression createXPath(final String xpath) { + return new XPathExpression(xpath); + } + + public static BooleanExpression createXQuery(final String xpath) { + return new XQueryExpression(xpath); + } + + public static BooleanExpression createBooleanCast(Expression left) { + return new BooleanUnaryExpression(left) { + public Object evaluate(AMQMessage message) throws JMSException { + Object rvalue = right.evaluate(message); + if (rvalue == null) + return null; + if (!rvalue.getClass().equals(Boolean.class)) + return Boolean.FALSE; + return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + public String toString() { + return right.toString(); + } + + public String getExpressionSymbol() { + return ""; + } + }; + } + + private static Number negate(Number left) { + Class clazz = left.getClass(); + if (clazz == Integer.class) { + return new Integer(-left.intValue()); + } + else if (clazz == Long.class) { + return new Long(-left.longValue()); + } + else if (clazz == Float.class) { + return new Float(-left.floatValue()); + } + else if (clazz == Double.class) { + return new Double(-left.doubleValue()); + } + else if (clazz == BigDecimal.class) { + // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the + // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it + // as a Big decimal. But it gets Negated right away.. to here we try to covert it back + // to a Long. + BigDecimal bd = (BigDecimal)left; + bd = bd.negate(); + + if( BD_LONG_MIN_VALUE.compareTo(bd)==0 ) { + return new Long(Long.MIN_VALUE); + } + return bd; + } + else { + throw new RuntimeException("Don't know how to negate: "+left); + } + } + + public UnaryExpression(Expression left) { + this.right = left; + } + + public Expression getRight() { + return right; + } + + public void setRight(Expression expression) { + right = expression; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return "(" + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + abstract public String getExpressionSymbol(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java new file mode 100644 index 0000000000..ab952b6fea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -0,0 +1,130 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import javax.jms.JMSException; + +//import org.apache.activemq.command.Message; +//import org.apache.activemq.util.JMSExceptionSupport; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Used to evaluate an XPath Expression in a JMS selector. + */ +public final class XPathExpression implements BooleanExpression { + + private static final Log log = LogFactory.getLog(XPathExpression.class); + private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.qpid.server.filter.XPathEvaluatorClassName"; + private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName(); + + private static final Constructor EVALUATOR_CONSTRUCTOR; + + static { + String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); + Constructor m = null; + try { + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e) { + log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e); + cn = DEFAULT_EVALUATOR_CLASS_NAME; + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e2) { + log.error("Default XPath evaluator could not be loaded",e); + } + } + } finally { + EVALUATOR_CONSTRUCTOR = m; + } + } + + private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { + Class c = XPathExpression.class.getClassLoader().loadClass(cn); + if( !XPathEvaluator.class.isAssignableFrom(c) ) { + throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class); + } + return c.getConstructor(new Class[]{String.class}); + } + + private final String xpath; + private final XPathEvaluator evaluator; + + static public interface XPathEvaluator { + public boolean evaluate(AMQMessage message) throws JMSException; + } + + XPathExpression(String xpath) { + this.xpath = xpath; + this.evaluator = createEvaluator(xpath); + } + + private XPathEvaluator createEvaluator(String xpath2) { + try { + return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath}); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if( cause instanceof RuntimeException ) { + throw (RuntimeException)cause; + } + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } catch (Throwable e) { + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } + } + + public Object evaluate(AMQMessage message) throws JMSException { +// try { +//FIXME this is flow to disk work +// if( message.isDropped() ) +// return null; + return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE; +// } catch (IOException e) { +// +// JMSException exception = new JMSException(e.getMessage()); +// exception.initCause(e); +// throw exception; +// +// } + + } + + public String toString() { + return "XPATH "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws JMSException + */ + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java new file mode 100644 index 0000000000..53764cbf75 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -0,0 +1,56 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.server.queue.AMQMessage; + +import javax.jms.JMSException; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +/** + * Used to evaluate an XQuery Expression in a JMS selector. + */ +public final class XQueryExpression implements BooleanExpression { + private final String xpath; + + XQueryExpression(String xpath) { + super(); + this.xpath = xpath; + } + + public Object evaluate(AMQMessage message) throws JMSException { + return Boolean.FALSE; + } + + public String toString() { + return "XQUERY "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws JMSException + */ + public boolean matches(AMQMessage message) throws JMSException { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java new file mode 100644 index 0000000000..4b78fd18df --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -0,0 +1,99 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.io.StringReader; +import java.io.ByteArrayInputStream; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.TextMessage; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +//import org.apache.activemq.command.Message; +//import org.apache.activemq.util.ByteArrayInputStream; +import org.apache.xpath.CachedXPathAPI; +import org.apache.qpid.server.queue.AMQMessage; +import org.w3c.dom.Document; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; + +public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { + + private final String xpath; + + public XalanXPathEvaluator(String xpath) { + this.xpath = xpath; + } + + public boolean evaluate(AMQMessage m) throws JMSException { + if( m instanceof TextMessage ) { + String text = ((TextMessage)m).getText(); + return evaluate(text); + } else if ( m instanceof BytesMessage ) { + BytesMessage bm = (BytesMessage) m; + byte data[] = new byte[(int) bm.getBodyLength()]; + bm.readBytes(data); + return evaluate(data); + } + return false; + } + + private boolean evaluate(byte[] data) { + try { + + InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + + } catch (Throwable e) { + return false; + } + } + + private boolean evaluate(String text) { + try { + InputSource inputSource = new InputSource(new StringReader(text)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + // We should associated the cachedXPathAPI object with the message being evaluated + // since that should speedup subsequent xpath expressions. + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + } catch (Throwable e) { + return false; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index d4c94061a0..bf282020ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -21,10 +21,12 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidSelectorException; 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.framing.ChannelCloseBody; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -32,6 +34,7 @@ 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.queue.AMQMessage; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.log4j.Logger; @@ -68,14 +71,14 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener _tokens = new HashSet(); private AMQProtocolSession _publisher; - private final BasicPublishBody _publishBody; + private final BasicPublishBody _publishBody; private ContentHeaderBody _contentHeaderBody; @@ -83,6 +89,8 @@ public class AMQMessage * messages published with the 'immediate' flag. */ private boolean _deliveredToConsumer; + private ConcurrentHashMap _decodedMessages; + private AtomicBoolean _taken; public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody) @@ -96,7 +104,9 @@ public class AMQMessage _publishBody = publishBody; _store = messageStore; _contentBodies = new LinkedList(); + _decodedMessages = new ConcurrentHashMap(); _storeWhenComplete = storeWhenComplete; + _taken = new AtomicBoolean(false); } public AMQMessage(MessageStore store, long messageId, BasicPublishBody publishBody, @@ -107,6 +117,7 @@ public class AMQMessage _publishBody = publishBody; _contentHeaderBody = contentHeaderBody; _contentBodies = contentBodies; + _decodedMessages = new ConcurrentHashMap(); _messageId = messageId; _store = store; storeMessage(); @@ -271,7 +282,7 @@ public class AMQMessage { _store.removeMessage(_messageId); } - catch(AMQException e) + catch (AMQException e) { //to maintain consistency, we revert the count incrementReference(); @@ -292,7 +303,7 @@ public class AMQMessage public boolean checkToken(Object token) { - if(_tokens.contains(token)) + if (_tokens.contains(token)) { return true; } @@ -308,7 +319,7 @@ public class AMQMessage //if the message is not persistent or the queue is not durable //we will not need to recover the association and so do not //need to record it - if(isPersistent() && queue.isDurable()) + if (isPersistent() && queue.isDurable()) { _store.enqueueMessage(queue.getName(), _messageId); } @@ -318,7 +329,7 @@ public class AMQMessage { //only record associations where both queue and message will survive //a restart, so only need to remove association if this is the case - if(isPersistent() && queue.isDurable()) + if (isPersistent() && queue.isDurable()) { _store.dequeueMessage(queue.getName(), _messageId); } @@ -326,14 +337,14 @@ public class AMQMessage public boolean isPersistent() throws AMQException { - if(_contentHeaderBody == null) + if (_contentHeaderBody == null) { throw new AMQException("Cannot determine delivery mode of message. Content header not found."); } //todo remove literal values to a constant file such as AMQConstants in common return _contentHeaderBody.properties instanceof BasicContentHeaderProperties - &&((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + && ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; } public void setTxnBuffer(TxnBuffer buffer) @@ -352,8 +363,9 @@ public class AMQMessage * immediate delivery but has not been marked as delivered to a * consumer */ - public void checkDeliveredToConsumer() throws NoConsumersException{ - if(isImmediate() && !_deliveredToConsumer) + public void checkDeliveredToConsumer() throws NoConsumersException + { + if (isImmediate() && !_deliveredToConsumer) { throw new NoConsumersException(_publishBody, _contentHeaderBody, _contentBodies); } @@ -362,8 +374,64 @@ public class AMQMessage /** * Called when this message is delivered to a consumer. (used to * implement the 'immediate' flag functionality). + * And by selectors to determin if the message has already been sent */ - public void setDeliveredToConsumer(){ + public void setDeliveredToConsumer() + { _deliveredToConsumer = true; } + + /** + * Called selectors to determin if the message has already been sent + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return _deliveredToConsumer; + } + + + public MessageDecorator getDecodedMessage(String type) + { + MessageDecorator msgtype = null; + + if (_decodedMessages != null) + { + msgtype = _decodedMessages.get(type); + + if (msgtype == null) + { + msgtype = decorateMessage(type); + } + } + + return msgtype; + } + + private MessageDecorator decorateMessage(String type) + { + MessageDecorator msgdec = null; + + if (type.equals(JMS_MESSAGE)) + { + msgdec = new JMSMessage(this); + } + + if (msgdec != null) + { + _decodedMessages.put(type, msgdec); + } + + return msgdec; + } + + public boolean taken() + { + return _taken.getAndSet(true); + } + + public void release() + { + _taken.set(false); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index f2ef97cf9a..e64daef690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -187,16 +188,29 @@ public class AMQQueue implements Managable, Comparable _subscribers = subscribers; _subscriptionFactory = subscriptionFactory; - //fixme - Pick one. - if (Boolean.getBoolean("concurrentdeliverymanager")) + //fixme - Make this configurable via the broker config.xml + if (System.getProperties().getProperty("deliverymanager") != null) { - _logger.info("Using ConcurrentDeliveryManager"); - _deliveryMgr = new ConcurrentDeliveryManager(_subscribers, this); + if (System.getProperties().getProperty("deliverymanager").equals("ConcurrentSelectorDeliveryManager")) + { + _logger.info("Using ConcurrentSelectorDeliveryManager"); + _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); + } + else if (System.getProperties().getProperty("deliverymanager").equals("ConcurrentDeliveryManager")) + { + _logger.info("Using ConcurrentDeliveryManager"); + _deliveryMgr = new ConcurrentDeliveryManager(_subscribers, this); + } + else + { + _logger.info("Using SynchronizedDeliveryManager"); + _deliveryMgr = new SynchronizedDeliveryManager(_subscribers, this); + } } else { - _logger.info("Using SynchronizedDeliveryManager"); - _deliveryMgr = new SynchronizedDeliveryManager(_subscribers, this); + _logger.info("Using Default DeliveryManager: ConcurrentSelectorDeliveryManager"); + _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); } } @@ -348,12 +362,12 @@ public class AMQQueue implements Managable, Comparable _bindings.addBinding(routingKey, exchange); } - public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks) + public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters) 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); + Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters); _subscribers.addSubscriber(subscription); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java new file mode 100644 index 0000000000..d8bb6e1948 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -0,0 +1,352 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.configuration.Configurator; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.Executor; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicBoolean; + + +/** + * Manages delivery of messages on behalf of a queue + */ +public class ConcurrentSelectorDeliveryManager implements DeliveryManager +{ + private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class); + + @Configured(path = "advanced.compressBufferOnQueue", + defaultValue = "false") + public boolean compressBufferOnQueue; + /** + * Holds any queued messages + */ + private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); + //private int _messageCount; + /** + * Ensures that only one asynchronous task is running for this manager at + * any time. + */ + private final AtomicBoolean _processing = new AtomicBoolean(); + /** + * The subscriptions on the queue to whom messages are delivered + */ + private final SubscriptionManager _subscriptions; + + /** + * A reference to the queue we are delivering messages for. We need this to be able + * to pass the code that handles acknowledgements a handle on the queue. + */ + private final AMQQueue _queue; + + + /** + * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced + * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered + * via the async thread. + *

    + * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. + */ + private ReentrantLock _lock = new ReentrantLock(); + + + ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) + { + + //Set values from configuration + Configurator.configure(this); + + if (compressBufferOnQueue) + { + _log.warn("Compressing Buffers on queue."); + } + + _subscriptions = subscriptions; + _queue = queue; + } + + + private boolean addMessageToQueue(AMQMessage msg) + { + // Shrink the ContentBodies to their actual size to save memory. + if (compressBufferOnQueue) + { + Iterator it = msg.getContentBodies().iterator(); + while (it.hasNext()) + { + ContentBody cb = (ContentBody) it.next(); + cb.reduceBufferToFit(); + } + } + + _messages.offer(msg); + + return true; + } + + + public boolean hasQueuedMessages() + { + _lock.lock(); + try + { + return !_messages.isEmpty(); + } + finally + { + _lock.unlock(); + } + } + + public int getQueueMessageCount() + { + return getMessageCount(); + } + + /** + * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine size. + * The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. + * + * @return int the number of messages in the delivery queue. + */ + private int getMessageCount() + { + return _messages.size(); + } + + + public synchronized List getMessages() + { + return new ArrayList(_messages); + } + + public synchronized void removeAMessageFromTop() throws AMQException + { + AMQMessage msg = poll(); + if (msg != null) + { + msg.dequeue(_queue); + } + } + + public synchronized void clearAllMessages() throws AMQException + { + AMQMessage msg = poll(); + while (msg != null) + { + msg.dequeue(_queue); + msg = poll(); + } + } + + + private AMQMessage getNextMessage(Queue messages) + { + AMQMessage message = messages.peek(); + + while (message != null && message.taken()) + { + //remove the already taken message + messages.poll(); + // try the next message + message = messages.peek(); + } + return message; + } + + public void sendNextMessage(Subscription sub, Queue messageQueue, AMQQueue queue) + { + AMQMessage message = null; + try + { + message = getNextMessage(messageQueue); + + // message will be null if we have no messages in the messageQueue. + if (message == null) + { + return; + } + _log.info("Async Delivery Message:" + message + " to :" + sub); + + sub.send(message, queue); + message.setDeliveredToConsumer(); + + //remove sent message from our queue. + messageQueue.poll(); + } + catch (FailedDequeueException e) + { + message.release(); + _log.error("Unable to deliver message as dequeue failed: " + e, e); + } + } + + /** + * Only one thread should ever execute this method concurrently, but + * it can do so while other threads invoke deliver(). + */ + private void processQueue() + { + // Continue to process delivery while we haveSubscribers and messages + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + + while (hasSubscribers && hasQueuedMessages()) + { + for (Subscription sub : _subscriptions.getSubscriptions()) + { + if (!sub.isSuspended()) + { + if (sub.hasFilters()) + { + sendNextMessage(sub, sub.getPreDeliveryQueue(), _queue); + } + else + { + sendNextMessage(sub, _messages, _queue); + } + + hasSubscribers = true; + } + else + { + hasSubscribers = false; + } + } + } + } + + private AMQMessage poll() + { + return _messages.poll(); + } + + public void deliver(String name, AMQMessage msg) throws FailedDequeueException + { + _log.info("deliver :" + msg); + + //Check if we have someone to deliver the message to. + _lock.lock(); + try + { + Subscription s = _subscriptions.nextSubscriber(msg); + + if (s == null) //no-one can take the message right now. + { + _log.info("Testing Message(" + msg + ") for Queued Delivery"); + if (!msg.isImmediate()) + { + addMessageToQueue(msg); + + //release lock now message is on queue. + _lock.unlock(); + + //Pre Deliver to all subscriptions + _log.info("We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to."); + for (Subscription sub : _subscriptions.getSubscriptions()) + { + + // stop if the message gets delivered whilst PreDelivering if we have a shared queue. + if (_queue.isShared() && msg.getDeliveredToConsumer()) + { + _log.info("Stopping PreDelivery as message(" + msg + ") is already delivered."); + continue; + } + + // Only give the message to those that want them. + if (sub.hasFilters() && sub.hasInterest(msg)) + { + sub.enqueueForPreDelivery(msg); + } + } + } + } + else + { + //release lock now + _lock.unlock(); + + _log.info("Delivering Message:" + msg + " to(" + System.identityHashCode(s) + ") :" + s); + //Deliver the message + s.send(msg, _queue); + msg.setDeliveredToConsumer(); + } + } + finally + { + //ensure lock is released + if (_lock.isLocked()) + { + _lock.unlock(); + } + } + } + + Runner asyncDelivery = new Runner(); + + private class Runner implements Runnable + { + public void run() + { + boolean running = true; + while (running) + { + processQueue(); + + //Check that messages have not been added since we did our last peek(); + // Synchronize with the thread that adds to the queue. + // If the queue is still empty then we can exit + + if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) + { + running = false; + _processing.set(false); + } + } + } + } + + public void processAsync(Executor executor) + { + _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + _processing.get()); + + if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) + { + //are we already running? if so, don't re-run + if (_processing.compareAndSet(false, true)) + { + executor.execute(asyncDelivery); + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index 49f0a51bf2..523b5f06e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.server.queue; +import org.apache.qpid.AMQException; + +import java.util.Queue; + public interface Subscription { void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException; @@ -27,4 +31,13 @@ public interface Subscription boolean isSuspended(); void queueDeleted(AMQQueue queue); + + boolean hasFilters(); + + boolean hasInterest(AMQMessage msg); + + Queue getPreDeliveryQueue(); + + void enqueueForPreDelivery(AMQMessage msg); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java index 0fd44e4fbc..f464384562 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; /** * Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This @@ -32,6 +33,9 @@ import org.apache.qpid.AMQException; */ public interface SubscriptionFactory { + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters) + throws AMQException; + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 5cad28b80d..79b0593f69 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -23,12 +23,18 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.BasicDeliverBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; +import java.util.Queue; + /** * Encapsulation of a supscription to a queue. *

    @@ -48,29 +54,45 @@ public class SubscriptionImpl implements Subscription private final Object sessionKey; + private Queue _messages; + + /** * True if messages need to be acknowledged */ private final boolean _acks; + private FilterManager _filters; public static class Factory implements SubscriptionFactory { + public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters) throws AMQException + { + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters); + } + public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks); + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, null); } public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag); + return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null); } } public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, String consumerTag, boolean acks) throws AMQException + { + this(channelId, protocolSession, consumerTag, acks, null); + } + + public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, + String consumerTag, boolean acks, FieldTable filters) + throws AMQException { AMQChannel channel = protocolSession.getChannel(channelId); if (channel == null) @@ -83,6 +105,17 @@ public class SubscriptionImpl implements Subscription this.consumerTag = consumerTag; sessionKey = protocolSession.getKey(); _acks = acks; + _filters = FilterManagerFactory.createManager(filters); + + if (_filters != null) + { + _messages = new ConcurrentLinkedQueueAtomicSize(); + } + else + { + // Reference the DeliveryManager + _messages = null; + } } public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, @@ -131,7 +164,7 @@ public class SubscriptionImpl implements Subscription { // 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. @@ -178,6 +211,32 @@ public class SubscriptionImpl implements Subscription channel.queueDeleted(queue); } + public boolean hasFilters() + { + return _filters != null; + } + + public boolean hasInterest(AMQMessage msg) + { + return _filters.allAllow(msg); + } + + public Queue getPreDeliveryQueue() + { + return _messages; + } + + public void enqueueForPreDelivery(AMQMessage msg) + { + if (_messages != null) + { + _messages.offer(msg); + } + } + + + + private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) { AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), consumerTag, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java index 353b461c8d..4df88baebc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java @@ -20,12 +20,15 @@ */ package org.apache.qpid.server.queue; +import java.util.List; + /** * Abstraction of actor that will determine the subscriber to whom * a message will be sent. */ public interface SubscriptionManager { + public List getSubscriptions(); public boolean hasActiveSubscribers(); public Subscription nextSubscriber(AMQMessage msg); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index 7cc3f5f719..a4afe18e4d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -21,6 +21,8 @@ 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; @@ -58,6 +60,7 @@ class SubscriptionSet implements WeightedSubscriptionManager /** * Remove the subscription, returning it if it was found + * * @param subscription * @return null if no match was found */ @@ -90,7 +93,7 @@ class SubscriptionSet implements WeightedSubscriptionManager /** * 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 @@ -105,31 +108,58 @@ class SubscriptionSet implements WeightedSubscriptionManager return null; } - try { - final Subscription result = nextSubscriber(); - if (result == null) { + try + { + final Subscription result = nextSubscriberImpl(msg); + if (result == null) + { _currentSubscriber = 0; - return nextSubscriber(); - } else { + return nextSubscriberImpl(msg); + } + else + { return result; } - } catch (IndexOutOfBoundsException e) { + } + catch (IndexOutOfBoundsException e) + { _currentSubscriber = 0; - return nextSubscriber(); + return nextSubscriber(msg); } } - private Subscription nextSubscriber() + private Subscription nextSubscriberImpl(AMQMessage msg) { final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); - while (iterator.hasNext()) { + while (iterator.hasNext()) + { Subscription subscription = iterator.next(); ++_currentSubscriber; subscriberScanned(); - if (!subscription.isSuspended()) { - return subscription; + + if (!subscription.isSuspended()) + { + if (!subscription.hasFilters()) + { + return subscription; + } + else + { + if (subscription.hasInterest(msg)) + { + // if the queue is not empty then this client is ready to receive a message. + //FIXME the queue could be full of sent messages. + // Either need to clean all PDQs after sending a message + // OR have a clean up thread that runs the PDQs expunging the messages. + if (subscription.getPreDeliveryQueue().isEmpty()) + { + return subscription; + } + } + } } } + return null; } @@ -145,11 +175,19 @@ class SubscriptionSet implements WeightedSubscriptionManager return _subscriptions.isEmpty(); } + public List getSubscriptions() + { + return _subscriptions; + } + public boolean hasActiveSubscribers() { for (Subscription s : _subscriptions) { - if (!s.isSuspended()) return true; + if (!s.isSuspended()) + { + return true; + } } return false; } @@ -159,7 +197,10 @@ class SubscriptionSet implements WeightedSubscriptionManager int count = 0; for (Subscription s : _subscriptions) { - if (!s.isSuspended()) count++; + if (!s.isSuspended()) + { + count++; + } } return count; } @@ -177,7 +218,8 @@ class SubscriptionSet implements WeightedSubscriptionManager } } - int size() { + int size() + { return _subscriptions.size(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java index ea64952bc7..49b0111b67 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ class SynchronizedDeliveryManager implements DeliveryManager { - private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); + private static final Logger _log = Logger.getLogger(SynchronizedDeliveryManager.class); /** * Holds any queued messages -- cgit v1.2.1 From 7b6cf0020bfb48906f563ca3d1088c7b6983ec67 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 19 Dec 2006 15:09:50 +0000 Subject: QPID-188 Adding unit tests for Java broker JMX functionality git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488701 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index c38f7f630b..e623d23a79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -412,6 +412,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { channel.close(this); } + _channelMap.clear(); } /** -- cgit v1.2.1 From 31ebe383026bc208da66614a8537f52d8f3ed87c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 19 Dec 2006 16:07:12 +0000 Subject: QPID-216 BasicConsumeMethodHandler.java - Pulled the nolocal param from the method body and passed down channel to subscription. SubscriptionFactory.java / AMQQueue.java/AMQChannel.java - passed the nolocal parameter through to the Subscription ConnectionStartOkMethodHandler.java - Saved the client properties so the client identifier can be used in comparison with the publisher id to implement no_local AMQMinaProtocolSession.java - added _clientProperties to store the sent client properties. AMQProtocolSession.java - interface changes to get/set ClientProperties ConcurrentSelectorDeliveryManager.java - only need to do hasInterset as this will take care of the hasFilters optimisation check. SubscriptionImpl.java - Added code to do comparison of client ids to determin insterest in a given message. SubscriptionSet.java - tidied up code to use hasInterest as this is where the nolocal is implemented. ConnectionStartMethodHandler.java - Moved literal values to a ClientProperties.java enumeration and a QpidProperties.java values. QpidConnectionMetaData.java - updated to get values from QpidProperties.java MockProtocolSession.java - null implementation of new get/set methods git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488712 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 8 ++- .../server/handler/BasicConsumeMethodHandler.java | 7 ++- .../handler/ConnectionStartOkMethodHandler.java | 9 ++- .../server/protocol/AMQMinaProtocolSession.java | 66 ++++++++++++++-------- .../qpid/server/protocol/AMQProtocolSession.java | 6 ++ .../org/apache/qpid/server/queue/AMQQueue.java | 11 +++- .../queue/ConcurrentSelectorDeliveryManager.java | 2 +- .../qpid/server/queue/SubscriptionFactory.java | 10 ++-- .../apache/qpid/server/queue/SubscriptionImpl.java | 39 ++++++++----- .../apache/qpid/server/queue/SubscriptionSet.java | 22 +++----- 10 files changed, 112 insertions(+), 68 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index d8485ef0f2..117231b36e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -286,12 +286,14 @@ public class AMQChannel * @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 + * @param noLocal * @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, FieldTable filters) throws AMQException, ConsumerTagNotUniqueException + public String subscribeToQueue(String tag, AMQQueue queue, AMQProtocolSession session, boolean acks, + FieldTable filters, boolean noLocal) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { @@ -302,7 +304,7 @@ public class AMQChannel throw new ConsumerTagNotUniqueException(); } - queue.registerProtocolSession(session, _channelId, tag, acks, filters); + queue.registerProtocolSession(session, _channelId, tag, acks, filters,noLocal); _consumerTag2QueueMap.put(tag, queue); return tag; } @@ -499,7 +501,7 @@ public class AMQChannel if (_log.isDebugEnabled()) { _log.debug("Handling acknowledgement for channel " + _channelId + " with delivery tag " + deliveryTag + - " and multiple " + multiple); + " and multiple " + multiple); } if (multiple) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index bf282020ee..1e57c714ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -77,7 +77,8 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener evt = new AMQMethodEvent(frame.channel, - (AMQMethodBody)frame.bodyFrame); + (AMQMethodBody) frame.bodyFrame); try { boolean wasAnyoneInterested = false; @@ -266,7 +272,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content header frame received: " + frame); } - getChannel(frame.channel).publishContentHeader((ContentHeaderBody)frame.bodyFrame); + getChannel(frame.channel).publishContentHeader((ContentHeaderBody) frame.bodyFrame); } private void contentBodyReceived(AMQFrame frame) throws AMQException @@ -275,7 +281,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } - getChannel(frame.channel).publishContentBody((ContentBody)frame.bodyFrame); + getChannel(frame.channel).publishContentBody((ContentBody) frame.bodyFrame); } /** @@ -355,6 +361,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, * 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 @@ -381,6 +388,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, /** * In our current implementation this is used by the clustering code. + * * @param channelId */ public void removeChannel(int channelId) @@ -390,11 +398,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, /** * Initialise heartbeats on the session. + * * @param delay delay in seconds (not ms) */ public void initHeartbeats(int delay) { - if(delay > 0) + if (delay > 0) { _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); @@ -404,6 +413,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, /** * 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 @@ -421,7 +431,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, */ public void closeSession() throws AMQException { - if(!_closed) + if (!_closed) { _closed = true; closeAllChannels(); @@ -463,11 +473,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, // information is used by SASL primary. if (address instanceof InetSocketAddress) { - return ((InetSocketAddress)address).getHostName(); + return ((InetSocketAddress) address).getHostName(); } else if (address instanceof VmPipeAddress) { - return "vmpipe:" + ((VmPipeAddress)address).getPort(); + return "vmpipe:" + ((VmPipeAddress) address).getPort(); } else { @@ -484,22 +494,32 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _saslServer = saslServer; } - + + public FieldTable getClientProperties() + { + return _clientProperties; + } + + public void setClientProperties(FieldTable clientProperties) + { + _clientProperties = clientProperties; + } + /** * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index acaf6b0d9b..03d0c50dac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.AMQException; @@ -122,4 +123,9 @@ public interface AMQProtocolSession * @param saslServer */ void setSaslServer(SaslServer saslServer); + + + FieldTable getClientProperties(); + + void setClientProperties(FieldTable clientProperties); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index e64daef690..561b719b2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -96,7 +96,7 @@ public class AMQQueue implements Managable, Comparable * max allowed number of messages on a queue. */ private Integer _maxMessageCount = 10000; - + /** * max queue depth(KB) for the queue */ @@ -362,12 +362,17 @@ public class AMQQueue implements Managable, Comparable _bindings.addBinding(routingKey, exchange); } - public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters) + public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters) throws AMQException + { + registerProtocolSession(ps, channel, consumerTag, acks, filters, false); + } + + public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters, boolean noLocal) 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, filters); + Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal); _subscribers.addSubscriber(subscription); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index d8bb6e1948..8bdadcb493 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -281,7 +281,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } // Only give the message to those that want them. - if (sub.hasFilters() && sub.hasInterest(msg)) + if (sub.hasInterest(msg)) { sub.enqueueForPreDelivery(msg); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java index f464384562..2bb77dc649 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -33,12 +33,10 @@ import org.apache.qpid.framing.FieldTable; */ public interface SubscriptionFactory { - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters) - throws AMQException; + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, + FieldTable filters, boolean noLocal) throws AMQException; - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) - throws AMQException; - Subscription createSubscription(int channel, AMQProtocolSession protocolSession,String consumerTag) - throws AMQException; + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) + throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 79b0593f69..fc00754cda 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; +import org.apache.qpid.common.ClientProperties; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; @@ -56,6 +57,7 @@ public class SubscriptionImpl implements Subscription private Queue _messages; + private final boolean _noLocal; /** * True if messages need to be acknowledged @@ -65,21 +67,15 @@ public class SubscriptionImpl implements Subscription public static class Factory implements SubscriptionFactory { - public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters) throws AMQException + public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters); - } - - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) - throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, null); + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal); } public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null); + return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false); } } @@ -87,11 +83,11 @@ public class SubscriptionImpl implements Subscription String consumerTag, boolean acks) throws AMQException { - this(channelId, protocolSession, consumerTag, acks, null); + this(channelId, protocolSession, consumerTag, acks, null, false); } public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - String consumerTag, boolean acks, FieldTable filters) + String consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException { AMQChannel channel = protocolSession.getChannel(channelId); @@ -105,6 +101,8 @@ public class SubscriptionImpl implements Subscription this.consumerTag = consumerTag; sessionKey = protocolSession.getKey(); _acks = acks; + _noLocal = noLocal; + _filters = FilterManagerFactory.createManager(filters); if (_filters != null) @@ -218,7 +216,22 @@ public class SubscriptionImpl implements Subscription public boolean hasInterest(AMQMessage msg) { - return _filters.allAllow(msg); + if (_noLocal) + { + return !(protocolSession.getClientProperties().get(ClientProperties.instance.toString()).equals( + msg.getPublisher().getClientProperties().get(ClientProperties.instance.toString()))); + } + else + { + if (_filters != null) + { + return _filters.allAllow(msg); + } + else + { + return true; + } + } } public Queue getPreDeliveryQueue() @@ -235,8 +248,6 @@ public class SubscriptionImpl implements Subscription } - - private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) { AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), consumerTag, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index a4afe18e4d..91e720ea54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -139,22 +139,15 @@ class SubscriptionSet implements WeightedSubscriptionManager if (!subscription.isSuspended()) { - if (!subscription.hasFilters()) + if (subscription.hasInterest(msg)) { - return subscription; - } - else - { - if (subscription.hasInterest(msg)) + // if the queue is not empty then this client is ready to receive a message. + //FIXME the queue could be full of sent messages. + // Either need to clean all PDQs after sending a message + // OR have a clean up thread that runs the PDQs expunging the messages. + if (!subscription.hasFilters() || subscription.getPreDeliveryQueue().isEmpty()) { - // if the queue is not empty then this client is ready to receive a message. - //FIXME the queue could be full of sent messages. - // Either need to clean all PDQs after sending a message - // OR have a clean up thread that runs the PDQs expunging the messages. - if (subscription.getPreDeliveryQueue().isEmpty()) - { - return subscription; - } + return subscription; } } } @@ -208,6 +201,7 @@ class SubscriptionSet implements WeightedSubscriptionManager /** * 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) -- cgit v1.2.1 From 914c431e3ab17c7c5ddbae1e9a9ec528da8259b3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 19 Dec 2006 16:09:39 +0000 Subject: Maven output clean up. Mainly removed exception stack traces from expected exceptions. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488713 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/util/CircularBuffer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java index 4767844abe..b58d551226 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java @@ -20,10 +20,15 @@ */ package org.apache.qpid.server.util; +import org.apache.log4j.Logger; + import java.util.Iterator; public class CircularBuffer implements Iterable { + + private static final Logger _logger = Logger.getLogger(CircularBuffer.class); + private final Object[] _log; private int _size; private int _index; @@ -102,7 +107,7 @@ public class CircularBuffer implements Iterable { for(Object o : this) { - System.out.println(o); + _logger.info(o); } } @@ -120,7 +125,7 @@ public class CircularBuffer implements Iterable for(String s : items) { buffer.add(s); - System.out.println(buffer); + _logger.info(buffer); } } } -- cgit v1.2.1 From 83dfcd846205e21f90639d23078b718bfbbe2dc4 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 19 Dec 2006 17:02:19 +0000 Subject: QPID-222 ensured that the TXBuffer of a message is set to null when re queuing. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@488726 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 117231b36e..3081181c80 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -304,7 +304,7 @@ public class AMQChannel throw new ConsumerTagNotUniqueException(); } - queue.registerProtocolSession(session, _channelId, tag, acks, filters,noLocal); + queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal); _consumerTag2QueueMap.put(tag, queue); return tag; } @@ -382,6 +382,8 @@ public class AMQChannel { if (unacked.queue != null) { + unacked.message.setTxnBuffer(null); + unacked.queue.deliver(unacked.message); } } -- cgit v1.2.1 From 5649d301fd375ef2bc755f089a42a0207e35e869 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 20 Dec 2006 12:46:20 +0000 Subject: QPID-21 outstanding issues: Fixed an issue where a consumer with no_local set would not have its filters applied to messages. Fixed problem where new consumers would start with an empty PDQ rather than checking the existing queue of messages for messages of interest. AMQQueue.java - Added code check exisiting queue data for messages for the new subscriber with a filter. DeliveryManager.java - added populatePreDeliveryQueue SynchronizedDeliveryManager.java/ConcurrentDeliveryManager.java - implemented new DeliveryManager.java interface SubscriptionImpl.java - fixed issue with no_local subscribers had their filters ignored. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@489070 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 9 ++ .../server/queue/ConcurrentDeliveryManager.java | 6 +- .../queue/ConcurrentSelectorDeliveryManager.java | 48 ++++++++--- .../apache/qpid/server/queue/DeliveryManager.java | 2 + .../apache/qpid/server/queue/SubscriptionImpl.java | 95 ++++++++++++++++------ .../server/queue/SynchronizedDeliveryManager.java | 6 +- 6 files changed, 126 insertions(+), 40 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 561b719b2e..101a2833a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -373,6 +373,15 @@ public class AMQQueue implements Managable, Comparable 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, filters, noLocal); + + if(subscription.hasFilters()) + { + if (_deliveryMgr.hasQueuedMessages()) + { + _deliveryMgr.populatePreDeliveryQueue(subscription); + } + } + _subscribers.addSubscriber(subscription); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java index f9c8898182..022d3b9635 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java @@ -198,6 +198,11 @@ public class ConcurrentDeliveryManager implements DeliveryManager return new ArrayList(_messages); } + public void populatePreDeliveryQueue(Subscription subscription) + { + //no-op . This DM has no PreDeliveryQueues + } + public synchronized void removeAMessageFromTop() throws AMQException { AMQMessage msg = poll(); @@ -312,7 +317,6 @@ public class ConcurrentDeliveryManager implements DeliveryManager else { s.send(msg, _queue); - msg.setDeliveredToConsumer(); } } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 8bdadcb493..f99f2d78b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -148,6 +148,25 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return new ArrayList(_messages); } + public void populatePreDeliveryQueue(Subscription subscription) + { + if (_log.isTraceEnabled()) + { + _log.trace("Populating PreDeliveryQueue for Subscription(" + System.identityHashCode(subscription) + ")"); + } + + Iterator currentQueue = _messages.iterator(); + + while (currentQueue.hasNext()) + { + AMQMessage message = currentQueue.next(); + if (subscription.hasInterest(message)) + { + subscription.enqueueForPreDelivery(message); + } + } + } + public synchronized void removeAMessageFromTop() throws AMQException { AMQMessage msg = poll(); @@ -197,7 +216,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _log.info("Async Delivery Message:" + message + " to :" + sub); sub.send(message, queue); - message.setDeliveredToConsumer(); //remove sent message from our queue. messageQueue.poll(); @@ -220,6 +238,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager while (hasSubscribers && hasQueuedMessages()) { + hasSubscribers = false; + for (Subscription sub : _subscriptions.getSubscriptions()) { if (!sub.isSuspended()) @@ -232,13 +252,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { sendNextMessage(sub, _messages, _queue); } - + hasSubscribers = true; } - else - { - hasSubscribers = false; - } } } } @@ -250,7 +266,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void deliver(String name, AMQMessage msg) throws FailedDequeueException { - _log.info("deliver :" + msg); + _log.info(id() + "deliver :" + System.identityHashCode(msg)); //Check if we have someone to deliver the message to. _lock.lock(); @@ -260,7 +276,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (s == null) //no-one can take the message right now. { - _log.info("Testing Message(" + msg + ") for Queued Delivery"); + _log.info(id() + "Testing Message(" + System.identityHashCode(msg) + ") for Queued Delivery"); if (!msg.isImmediate()) { addMessageToQueue(msg); @@ -269,20 +285,21 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.unlock(); //Pre Deliver to all subscriptions - _log.info("We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to."); + _log.info(id() + "We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to."); for (Subscription sub : _subscriptions.getSubscriptions()) { // stop if the message gets delivered whilst PreDelivering if we have a shared queue. if (_queue.isShared() && msg.getDeliveredToConsumer()) { - _log.info("Stopping PreDelivery as message(" + msg + ") is already delivered."); + _log.info(id() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + ") is already delivered."); continue; } // Only give the message to those that want them. if (sub.hasInterest(msg)) { + _log.info(id() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); sub.enqueueForPreDelivery(msg); } } @@ -293,10 +310,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //release lock now _lock.unlock(); - _log.info("Delivering Message:" + msg + " to(" + System.identityHashCode(s) + ") :" + s); + _log.info(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + System.identityHashCode(s) + ") :" + s); //Deliver the message s.send(msg, _queue); - msg.setDeliveredToConsumer(); } } finally @@ -309,6 +325,14 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + //fixme remove + private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")"; + + private String id() + { + return id; + } + Runner asyncDelivery = new Runner(); private class Runner implements Runnable diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index dadf86c1d8..cac499587f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -73,4 +73,6 @@ interface DeliveryManager void clearAllMessages() throws AMQException; List getMessages(); + + void populatePreDeliveryQueue(Subscription subscription); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index fc00754cda..f4e7482396 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -160,32 +160,39 @@ public class SubscriptionImpl implements Subscription { 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) + try { - long deliveryTag = channel.getNextDeliveryTag(); + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - if (_acks) + // 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) { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + queue.dequeue(msg); } + synchronized(channel) + { + long deliveryTag = channel.getNextDeliveryTag(); - ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); - AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); + if (_acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } - protocolSession.writeFrame(frame); + ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); + AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); + + protocolSession.writeFrame(frame); + } + } + finally + { + msg.setDeliveredToConsumer(); } } else @@ -218,19 +225,55 @@ public class SubscriptionImpl implements Subscription { if (_noLocal) { - return !(protocolSession.getClientProperties().get(ClientProperties.instance.toString()).equals( - msg.getPublisher().getClientProperties().get(ClientProperties.instance.toString()))); + // We don't want local messages so check to see if message is one we sent + if (protocolSession.getClientProperties().get(ClientProperties.instance.toString()).equals( + msg.getPublisher().getClientProperties().get(ClientProperties.instance.toString()))) + { + if (_logger.isTraceEnabled()) + { + _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + + System.identityHashCode(msg) + ")"); + } + return false; + } + else // if not then filter the message. + { + if (_logger.isTraceEnabled()) + { + _logger.trace("(" + System.identityHashCode(this) + ") local message(" + System.identityHashCode(msg) + + ") but not ours so filtering"); + } + return checkFilters(msg); + } } else { - if (_filters != null) + if (_logger.isTraceEnabled()) { - return _filters.allAllow(msg); + _logger.trace("(" + System.identityHashCode(this) + ") checking filters for message (" + System.identityHashCode(msg)); } - else + return checkFilters(msg); + } + } + + private boolean checkFilters(AMQMessage msg) + { + if (_filters != null) + { + if (_logger.isTraceEnabled()) { - return true; + _logger.trace("(" + System.identityHashCode(this) + ") has filters."); } + return _filters.allAllow(msg); + } + else + { + if (_logger.isTraceEnabled()) + { + _logger.trace("(" + System.identityHashCode(this) + ") has no filters"); + } + + return true; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java index 49b0111b67..c967ea2cde 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -122,6 +122,11 @@ class SynchronizedDeliveryManager implements DeliveryManager return new ArrayList(_messages); } + public void populatePreDeliveryQueue(Subscription subscription) + { + //no-op . This DM has no PreDeliveryQueues + } + public synchronized void removeAMessageFromTop() throws AMQException { AMQMessage msg = poll(); @@ -243,7 +248,6 @@ class SynchronizedDeliveryManager implements DeliveryManager else { s.send(msg, _queue); - msg.setDeliveredToConsumer(); } } } -- cgit v1.2.1 From 845d61c8a2f1fe68d4bb2f20756c2c6180027b45 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 20 Dec 2006 14:54:01 +0000 Subject: QPID-101 Initial Implementation of Queue Browsing by Robert Godfrey and Martin Ritchie AMQChannel.java - record messages browsed so not to discard them on ack. FilterManagerFactory.java - Added a NoConsumerFilter ConcurrentSelectorDeliveryManager.java - Update to send browsers messages without taking the message from other consumers Subscription.java - Added autoClose and isBrowser methods SubscriptionTestHelper.java / RemoteSubscriptionImpl.java / SubscriptionImpl.java - implemented new interface methods Added NoConsumerFilter.java Patches from Rob Godfrey for client implmentation AMQSession.java - Added AUTO_CLOSE and NO_CONSUME properties to arguments FieldTable for consume method. BasicMessageConsumer.java - updates to correctly close consumer when an BasicCancel is received from the broker. AMQProtocolSession.java - method to allow cancellation of the client AMQStateManager.java - added handler for BasicCancelOkMethodHandler.java Added new AMQQueueBrowser.java BasicCancelOkMethodHandler.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@489106 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 29 +++- .../qpid/server/filter/FilterManagerFactory.java | 9 +- .../qpid/server/filter/NoConsumerFilter.java | 48 +++++++ .../queue/ConcurrentSelectorDeliveryManager.java | 48 ++++--- .../org/apache/qpid/server/queue/Subscription.java | 5 + .../apache/qpid/server/queue/SubscriptionImpl.java | 153 +++++++++++++++++---- 6 files changed, 243 insertions(+), 49 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 3081181c80..c5b45659cf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -46,6 +46,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.Set; +import java.util.HashSet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -110,6 +112,7 @@ public class AMQChannel private TxAck ackOp; private final List _returns = new LinkedList(); + private Set _browsedAcks = new HashSet(); public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) throws AMQException @@ -555,7 +558,14 @@ public class AMQChannel for (UnacknowledgedMessage msg : acked) { - msg.discard(); + if (!_browsedAcks.contains(deliveryTag)) + { + msg.discard(); + } + else + { + _browsedAcks.remove(deliveryTag); + } } } @@ -572,7 +582,16 @@ public class AMQChannel _log.trace("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); } - msg.discard(); + + if (!_browsedAcks.contains(deliveryTag)) + { + msg.discard(); + } + else + { + _browsedAcks.remove(deliveryTag); + } + if (_log.isTraceEnabled()) { _log.trace("Received non-multiple ack for messaging with delivery tag " + deliveryTag); @@ -693,6 +712,12 @@ public class AMQChannel _returns.clear(); } + public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, String consumerTag, AMQQueue queue) + { + _browsedAcks.add(deliveryTag); + addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } + //we use this wrapper to ensure we are always using the correct //map instance (its not final unfortunately) private class AckMap implements UnacknowledgedMessageMap diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index 6ecd56586f..49f99132ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; //import org.slf4j.Logger; //import org.slf4j.LoggerFactory; @@ -34,7 +35,6 @@ public class FilterManagerFactory private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); //fixme move to a common class so it can be refered to from client code. - private static String JMS_SELECTOR_FILTER = "x-filter-jms-selector"; public static FilterManager createManager(FieldTable filters) throws AMQException { @@ -51,7 +51,7 @@ public class FilterManagerFactory { String key = (String) it.next(); _logger.info("filter:" + key); - if (key.equals(JMS_SELECTOR_FILTER)) + if (key.equals(AMQPFilterTypes.JMS_SELECTOR.getValue())) { String selector = (String) filters.get(key); @@ -61,6 +61,11 @@ public class FilterManagerFactory } } + if (key.equals(AMQPFilterTypes.NO_CONSUME.getValue())) + { + manager.add(new NoConsumerFilter()); + } + } //If we added no filters don't bear the overhead of having an filter manager diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java new file mode 100644 index 0000000000..283d324ff6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidSelectorException; +import org.apache.log4j.Logger; + + +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; + +public class NoConsumerFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(NoConsumerFilter.class); + + + public NoConsumerFilter() throws AMQException + { + _logger.info("Created NoConsumerFilter"); + } + + public boolean matches(AMQMessage message) + { + return true; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index f99f2d78b7..2100734ada 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -164,7 +164,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { subscription.enqueueForPreDelivery(message); } - } + } } public synchronized void removeAMessageFromTop() throws AMQException @@ -187,11 +187,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } - private AMQMessage getNextMessage(Queue messages) + private AMQMessage getNextMessage(Queue messages, Subscription sub) { AMQMessage message = messages.peek(); - while (message != null && message.taken()) + while (message != null && (sub.isBrowser() || message.taken())) { //remove the already taken message messages.poll(); @@ -201,12 +201,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return message; } - public void sendNextMessage(Subscription sub, Queue messageQueue, AMQQueue queue) + public void sendNextMessage(Subscription sub, Queue messageQueue) { AMQMessage message = null; try { - message = getNextMessage(messageQueue); + message = getNextMessage(messageQueue, sub); // message will be null if we have no messages in the messageQueue. if (message == null) @@ -215,7 +215,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } _log.info("Async Delivery Message:" + message + " to :" + sub); - sub.send(message, queue); + sub.send(message, _queue); //remove sent message from our queue. messageQueue.poll(); @@ -244,21 +244,33 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (!sub.isSuspended()) { - if (sub.hasFilters()) - { - sendNextMessage(sub, sub.getPreDeliveryQueue(), _queue); - } - else - { - sendNextMessage(sub, _messages, _queue); - } - + sendNextMessage(sub); + hasSubscribers = true; } } } } + private void sendNextMessage(Subscription sub) + { + if (sub.hasFilters()) + { + sendNextMessage(sub, sub.getPreDeliveryQueue()); + if (sub.isAutoClose()) + { + if (sub.getPreDeliveryQueue().isEmpty()) + { + sub.close(); + } + } + } + else + { + sendNextMessage(sub, _messages); + } + } + private AMQMessage poll() { return _messages.poll(); @@ -359,9 +371,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void processAsync(Executor executor) { - _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get()); + _log.info("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + _processing.get()); if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index 523b5f06e9..a5672f2b19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -40,4 +40,9 @@ public interface Subscription void enqueueForPreDelivery(AMQMessage msg); + boolean isAutoClose(); + + void close(); + + boolean isBrowser(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index f4e7482396..4272541298 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -24,11 +24,13 @@ import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.BasicDeliverBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.BasicCancelOkBody; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; @@ -64,6 +66,9 @@ public class SubscriptionImpl implements Subscription */ private final boolean _acks; private FilterManager _filters; + private final boolean _isBrowser; + private final Boolean _autoClose; + private boolean _closed = false; public static class Factory implements SubscriptionFactory { @@ -105,9 +110,48 @@ public class SubscriptionImpl implements Subscription _filters = FilterManagerFactory.createManager(filters); + + if (_filters != null) + { + Object isBrowser = filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); + if (isBrowser != null) + { + _isBrowser = (Boolean) isBrowser; + } + else + { + _isBrowser = false; + } + } + else + { + _isBrowser = false; + } + + + if (_filters != null) + { + Object autoClose = filters.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); + if (autoClose != null) + { + _autoClose = (Boolean) autoClose; + } + else + { + _autoClose = false; + } + } + else + { + _autoClose = false; + } + + if (_filters != null) { _messages = new ConcurrentLinkedQueueAtomicSize(); + + } else { @@ -116,6 +160,7 @@ public class SubscriptionImpl implements Subscription } } + public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, String consumerTag) throws AMQException @@ -160,44 +205,78 @@ public class SubscriptionImpl implements Subscription { if (msg != null) { - try + if (_isBrowser) + { + sendToBrowser(msg, queue); + } + else { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. + sendToConsumer(msg, queue); + } + } + else + { + _logger.error("Attempt to send Null message", new NullPointerException()); + } + } - // 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. + private void sendToBrowser(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + { + // We don't decrement the reference here as we don't want to consume the message + // but we do want to send it to the client. - // 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(); + synchronized(channel) + { + long deliveryTag = channel.getNextDeliveryTag(); + + // We don't need to add the message to the unacknowledgedMap as we don't need to know if the client + // received the message. If it is lost in transit that is not important. + if (_acks) + { + channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); + } + ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); + AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); - if (_acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - } + protocolSession.writeFrame(frame); + } + } - ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); - AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); + private void sendToConsumer(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + { + try + { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - protocolSession.writeFrame(frame); - } + // 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); } - finally + synchronized(channel) { - msg.setDeliveredToConsumer(); + long deliveryTag = channel.getNextDeliveryTag(); + + if (_acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } + + ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); + AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); + + protocolSession.writeFrame(frame); } } - else + finally { - _logger.error("Attempt to send Null message", new NullPointerException()); + msg.setDeliveredToConsumer(); } } @@ -290,6 +369,26 @@ public class SubscriptionImpl implements Subscription } } + public boolean isAutoClose() + { + return _autoClose; + } + + public void close() + { + if (!_closed) + { + _logger.info("Closing autoclose subscription:" + this); + protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), consumerTag)); + _closed = true; + } + } + + public boolean isBrowser() + { + return _isBrowser; + } + private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) { -- cgit v1.2.1 From 63c42a711f8882b79b979507ed152cfba76bdeb1 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 21 Dec 2006 11:32:58 +0000 Subject: QPID-188 Unit test for AMQProtocolSession mbean updated and closeChannel() method removed from mbean because it didn't seem to be a required feature for management console. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@489330 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/protocol/AMQMinaProtocolSession.java | 7 +++++- .../qpid/server/protocol/AMQProtocolSession.java | 2 +- .../server/protocol/AMQProtocolSessionMBean.java | 29 ++++++---------------- .../qpid/server/protocol/ManagedConnection.java | 9 ------- 4 files changed, 15 insertions(+), 32 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 6ba78ba722..7a9dfbc67c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -316,8 +316,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _channelMap.get(channelId); } - public void addChannel(AMQChannel channel) + public void addChannel(AMQChannel channel) throws AMQException { + if (_closed) + { + throw new AMQException("Session is closed"); + } + _channelMap.put(channel.getChannelId(), channel); checkForNotification(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 03d0c50dac..a75627d240 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -70,7 +70,7 @@ public interface AMQProtocolSession * @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); + void addChannel(AMQChannel channel) throws AMQException; /** * Close a specific channel. This will remove any resources used by the channel, including: diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index a47d462810..d57f9b9be1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -18,6 +18,9 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -182,27 +185,6 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed return channelsList; } - /** - * @see AMQMinaProtocolSession#closeChannel(int) - */ - public void closeChannel(int id) throws JMException - { - try - { - AMQChannel channel = _session.getChannel(id); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + id + ") does not exist"); - } - - _session.closeChannel(id); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - /** * closes the connection. The administrator can use this management operation to close connection to free up * resources. @@ -210,6 +192,11 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void closeConnection() throws JMException { + + final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, AMQConstant.REPLY_SUCCESS.getCode(), + "Broker Management Console has closing the connection.", 0, 0); + _session.writeFrame(response); + try { _session.closeSession(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 2f3102b048..1a7b7e9e96 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -113,15 +113,6 @@ public interface ManagedConnection impact= MBeanOperationInfo.ACTION) void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - /** - * Unsubscribes the consumers and unregisters the channel from managed objects. - */ - @MBeanOperation(name="closeChannel", - description="Closes the channel with given channel Id and connected consumers will be unsubscribed", - impact= MBeanOperationInfo.ACTION) - void closeChannel(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) - throws Exception; - /** * Closes all the related channels and unregisters this connection from managed objects. */ -- cgit v1.2.1 From 32d79a6e99ad773e8a7b49efa12e06c028e7d2f4 Mon Sep 17 00:00:00 2001 From: Kim van der Riet Date: Fri, 22 Dec 2006 17:00:28 +0000 Subject: AMQP version using new generator - Part 1. In these changes, all places where version-specific info is required, it has been hard-wired to major=8, minor=0. The next phase of changes will connect the version info to that obtained from ProtocolInitiation for the current session. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@489691 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/RequiredDeliveryException.java | 6 +- .../server/handler/BasicCancelMethodHandler.java | 7 +- .../server/handler/BasicConsumeMethodHandler.java | 31 ++++++-- .../server/handler/BasicPublishMethodHandler.java | 10 ++- .../qpid/server/handler/BasicQosHandler.java | 5 +- .../qpid/server/handler/ChannelCloseHandler.java | 5 +- .../qpid/server/handler/ChannelFlowHandler.java | 10 ++- .../qpid/server/handler/ChannelOpenHandler.java | 5 +- .../handler/ConnectionCloseMethodHandler.java | 5 +- .../handler/ConnectionOpenMethodHandler.java | 7 +- .../handler/ConnectionSecureOkMethodHandler.java | 34 +++++++-- .../handler/ConnectionStartOkMethodHandler.java | 17 ++++- .../qpid/server/handler/ExchangeBoundHandler.java | 85 +++++++++++++++------- .../server/handler/ExchangeDeclareHandler.java | 5 +- .../qpid/server/handler/ExchangeDeleteHandler.java | 5 +- .../qpid/server/handler/QueueBindHandler.java | 5 +- .../qpid/server/handler/QueueDeclareHandler.java | 9 ++- .../qpid/server/handler/QueueDeleteHandler.java | 7 +- .../qpid/server/handler/TxCommitHandler.java | 5 +- .../qpid/server/handler/TxRollbackHandler.java | 5 +- .../qpid/server/handler/TxSelectHandler.java | 5 +- .../server/protocol/AMQMinaProtocolSession.java | 13 +++- .../server/protocol/AMQPFastProtocolHandler.java | 13 +++- .../server/protocol/AMQProtocolSessionMBean.java | 12 ++- .../org/apache/qpid/server/queue/AMQMessage.java | 14 +++- .../apache/qpid/server/queue/SubscriptionImpl.java | 22 +++++- 26 files changed, 274 insertions(+), 73 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index 87691ccaa3..5e463646f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -81,7 +81,11 @@ public abstract class RequiredDeliveryException extends AMQException public CompositeAMQDataBlock getReturnMessage(int channel) { - BasicReturnBody returnBody = new BasicReturnBody(); + // AMQP version change: All generated *Body classes are now version-aware. + // Shortcut: hardwire version to 0-8 (major=8, minor=0) for now. + // TODO: Connect the version to that returned by the ProtocolInitiation + // for this session. + BasicReturnBody returnBody = new BasicReturnBody((byte)8, (byte)0); returnBody.exchange = _publishBody.exchange; returnBody.replyCode = getReplyCode(); returnBody.replyText = _message; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index 673556cbec..198d2c1f3d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -54,7 +54,12 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener AMQProtocolSession session, AMQMethodEvent evt) throws AMQException { session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); - session.writeFrame(new AMQFrame(evt.getChannelId(), new BasicQosOkBody())); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + session.writeFrame(new AMQFrame(evt.getChannelId(), new BasicQosOkBody((byte)8, (byte)0))); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index 0efe12b137..d26f84d17e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -55,7 +55,10 @@ public class ChannelCloseHandler implements StateAwareMethodListener evt) throws AMQException { + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + byte major = (byte)8; + byte minor = (byte)0; + ExchangeBoundBody body = evt.getMethod(); String exchangeName = body.exchange; @@ -77,8 +82,11 @@ public class ExchangeBoundHandler implements StateAwareMethodListener } if (!body.nowait) { - final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId()); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); protocolSession.writeFrame(response); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index b7004de2a9..83f98de2d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -102,7 +102,14 @@ public class QueueDeclareHandler implements StateAwareMethodListener try{ AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); channel.commit(); - protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId())); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); channel.processReturns(protocolSession); }catch(AMQException e){ throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 475f6ecacf..588dc026d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -51,7 +51,10 @@ public class TxRollbackHandler implements StateAwareMethodListener AMQMethodEvent evt) throws AMQException { protocolSession.getChannel(evt.getChannelId()).setTransactional(true); - protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId())); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 7a9dfbc67c..9ff6b96690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -165,8 +165,17 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _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()); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, + (byte)8, (byte)0, // AMQP version (major, minor) + locales.getBytes(), // locales + mechanisms.getBytes(), // mechanisms + null, // serverProperties + (short)8, // versionMajor + (short)0 // versionMinor + ); _minaProtocolSession.write(response); } catch (AMQException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 18980f440b..2e9590277b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -168,11 +168,20 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco } else if(throwable instanceof IOException) { - _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); + _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); } else { - protocolSession.write(ConnectionCloseBody.createAMQFrame(0, 200, throwable.getMessage(), 0, 0)); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + protocolSession.write(ConnectionCloseBody.createAMQFrame(0, + (byte)8, (byte)0, // AMQP version (major, minor) + 0, // classId + 0, // methodId + 200, // replyCode + throwable.getMessage() // replyText + )); _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); protocolSession.close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index d57f9b9be1..0ceadcb30b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -193,8 +193,16 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public void closeConnection() throws JMException { - final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, AMQConstant.REPLY_SUCCESS.getCode(), - "Broker Management Console has closing the connection.", 0, 0); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, + (byte)8, (byte)0, // AMQP version (major, minor) + 0, // classId + 0, // methodId + AMQConstant.REPLY_SUCCESS.getCode(), // replyCode + "Broker Management Console has closing the connection." // replyText + ); _session.writeFrame(response); try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index b27cd807c0..afe4ea95b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -157,10 +157,20 @@ public class AMQMessage public CompositeAMQDataBlock getDataBlock(int channel, String consumerTag, long deliveryTag) { + AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; - allFrames[0] = BasicDeliverBody.createAMQFrame(channel, consumerTag, deliveryTag, _redelivered, - getExchangeName(), getRoutingKey()); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + allFrames[0] = BasicDeliverBody.createAMQFrame(channel, + (byte)8, (byte)0, // AMQP version (major, minor) + consumerTag, // consumerTag + deliveryTag, // deliveryTag + getExchangeName(), // exchange + _redelivered, // redelivered + getRoutingKey() // routingKey + ); allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); for (int i = 2; i < allFrames.length; i++) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 4272541298..78310e8eb3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -379,7 +379,13 @@ public class SubscriptionImpl implements Subscription if (!_closed) { _logger.info("Closing autoclose subscription:" + this); - protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), consumerTag)); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), + (byte)8, (byte)0, // AMQP version (major, minor) + consumerTag // consumerTag + )); _closed = true; } } @@ -392,9 +398,17 @@ public class SubscriptionImpl implements Subscription private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) { - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), consumerTag, - deliveryTag, false, exchange, - routingKey); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), + (byte)8, (byte)0, // AMQP version (major, minor) + consumerTag, // consumerTag + deliveryTag, // deliveryTag + exchange, // exchange + false, // redelivered + routingKey // routingKey + ); ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? deliverFrame.writePayload(buf); buf.flip(); -- cgit v1.2.1 From 9cad5792c8fa0203114d63a1851b0a9181c967f5 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 22 Dec 2006 20:32:43 +0000 Subject: QPID-229 : Patch supplied by Rob Godfrey - Change implementation of FieldTable git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@489748 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/HeadersBinding.java | 143 ++++++++++++++++----- .../qpid/server/exchange/HeadersExchange.java | 42 +++--- 2 files changed, 132 insertions(+), 53 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index b058211288..1c63a5571e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -21,12 +21,11 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQTypedValue; -import java.util.Collections; -import java.util.Map; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * Defines binding and matching based on a set of headers. @@ -35,11 +34,53 @@ 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 final FieldTable _mappings = new FieldTable(); + private final Set required = new HashSet(); + private final Map matches = new HashMap(); private boolean matchAny; + private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor + { + private Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor + { + Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if(required.contains(propertyName)) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + + /** * 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 @@ -47,33 +88,50 @@ class HeadersBinding * define a required match of value. * @param mappings the defined mappings this binding should use */ - HeadersBinding(Map mappings) + + HeadersBinding(FieldTable mappings) { - //noinspection unchecked - this(mappings == null ? new HashSet() : mappings.entrySet()); - _mappings.putAll(mappings); + Enumeration propertyNames = mappings.getPropertyNames(); + while(propertyNames.hasMoreElements()) + { + String propName = (String) propertyNames.nextElement(); + _mappings.put(propName, mappings.getObject(propName)); + } + initMappings(); } - private HeadersBinding(Set entries) + private void initMappings() { - for (Map.Entry e : entries) + + _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() { - if (isSpecial(e.getKey())) - { - processSpecial((String) e.getKey(), e.getValue()); - } - else if (e.getValue() == null || e.getValue().equals("")) + + public boolean processElement(String propertyName, AMQTypedValue value) { - required.add(e.getKey()); + if (isSpecial(propertyName)) + { + processSpecial(propertyName, value.getValue()); + } + else if (value.getValue() == null || value.getValue().equals("")) + { + required.add(propertyName); + } + else + { + matches.put(propertyName,value.getValue()); + } + + return true; } - else + + public Object getResult() { - matches.add(e); + return null; } - } + }); } - protected Map getMappings() + protected FieldTable getMappings() { return _mappings; } @@ -84,7 +142,7 @@ class HeadersBinding * @return true if the headers define any required keys and match any required * values */ - public boolean matches(Map headers) + public boolean matches(FieldTable headers) { if(headers == null) { @@ -96,18 +154,37 @@ class HeadersBinding } } - private boolean and(Map headers) + private boolean and(FieldTable headers) { - //need to match all the defined mapping rules: - return headers.keySet().containsAll(required) - && headers.entrySet().containsAll(matches); + if(headers.keys().containsAll(required)) + { + for(Map.Entry e : matches.entrySet()) + { + if(!e.getValue().equals(headers.getObject(e.getKey()))) + { + return false; + } + } + return true; + } + else + { + return false; + } } - private boolean or(Map headers) + + private boolean or(final FieldTable headers) { - //only need to match one mapping rule: - return !Collections.disjoint(headers.keySet(), required) - || !Collections.disjoint(headers.entrySet(), matches); + if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) + { + return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) + || (required.isEmpty() && matches.isEmpty()); + } + else + { + return true; + } } private void processSpecial(String key, Object value) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 8c4df68dea..229502d2a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -22,10 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; +import org.apache.qpid.framing.*; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -34,10 +31,7 @@ import org.apache.qpid.server.registry.ApplicationRegistry; import javax.management.JMException; import javax.management.openmbean.*; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -119,16 +113,24 @@ public class HeadersExchange extends AbstractExchange String queueName = registration.queue.getName(); HeadersBinding headers = registration.binding; - Map headerMappings = headers.getMappings(); - List mappingList = new ArrayList(); + FieldTable headerMappings = headers.getMappings(); + final List mappingList = new ArrayList(); - for (Map.Entry en : headerMappings.entrySet()) + headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() { - String key = en.getKey().toString(); - String value = en.getValue().toString(); - mappingList.add(key + "=" + value); - } + public boolean processElement(String propertyName, AMQTypedValue value) + { + mappingList.add(propertyName + "=" + value.getValue()); + return true; + } + + public Object getResult() + { + return mappingList; + } + }); + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); @@ -155,7 +157,7 @@ public class HeadersExchange extends AbstractExchange } String[] bindings = binding.split(","); - FieldTable fieldTable = FieldTableFactory.newFieldTable(); + FieldTable bindingMap = new FieldTable(); for (int i = 0; i < bindings.length; i++) { String[] keyAndValue = bindings[i].split("="); @@ -163,10 +165,10 @@ public class HeadersExchange extends AbstractExchange { throw new JMException("Format for headers binding should be \"=,=\" "); } - fieldTable.put(keyAndValue[0], keyAndValue[1]); + bindingMap.setString(keyAndValue[0], keyAndValue[1]); } - _bindings.add(new Registration(new HeadersBinding(fieldTable), queue)); + _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); } } // End of MBean class @@ -185,7 +187,7 @@ public class HeadersExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { - Map headers = getHeaders(payload.getContentHeaderBody()); + FieldTable headers = getHeaders(payload.getContentHeaderBody()); if (_logger.isDebugEnabled()) { _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); @@ -248,7 +250,7 @@ public class HeadersExchange extends AbstractExchange return !_bindings.isEmpty(); } - protected Map getHeaders(ContentHeaderBody contentHeaderFrame) + protected FieldTable 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. -- cgit v1.2.1 From e2cd3536444cb5d9c840075725723f7d569612d7 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 28 Dec 2006 12:02:26 +0000 Subject: MBean created as a separate class git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@490708 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 192 +++++++++++++++++++++ .../src/main/java/org/apache/qpid/server/Main.java | 176 +------------------ 2 files changed, 201 insertions(+), 167 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java new file mode 100644 index 0000000000..509f57be7f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -0,0 +1,192 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedBroker; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.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.server.registry.IApplicationRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.AMQException; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + +/** + * This MBean 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") +public class AMQBrokerManagerMBean 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") + public AMQBrokerManagerMBean() throws JMException + { + 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, durable, autoDelete, 0); + _exchangeRegistry.registerExchange(exchange); + } + else + { + throw new JMException("The exchange \"" + exchangeName + "\" already exists."); + } + } + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in creating exchange " + exchangeName); + } + } + + /** + * Unregisters the exchange from registry. + * + * @param exchangeName + * @throws JMException + */ + public void unregisterExchange(String exchangeName) throws JMException + { + // TODO + // Check if the exchange is in use. + // boolean inUse = false; + // Check if there are queue-bindings with the exchange and unregister + // when there are no bindings. + try + { + _exchangeRegistry.unregisterExchange(exchangeName, false); + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); + } + } + + /** + * 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 createNewQueue(String queueName, boolean durable, String owner, boolean autoDelete) + throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(queueName); + if (queue != null) + { + throw new JMException("The queue \"" + queueName + "\" already exists."); + } + + try + { + queue = new AMQQueue(queueName, durable, owner, autoDelete, _queueRegistry); + if (queue.isDurable() && !queue.isAutoDelete()) + { + _messageStore.createQueue(queue); + } + _queueRegistry.registerQueue(queue); + } + catch (AMQException ex) + { + throw new MBeanException(ex,"Error in creating queue " + queueName); + } + } + + /** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 553aecc217..ffd25de0b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -40,29 +40,16 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.ProtocolVersionList; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedBroker; +import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; -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.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.url.URLSyntaxException; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; import java.io.File; import java.io.IOException; import java.net.InetAddress; @@ -75,7 +62,7 @@ import java.util.StringTokenizer; * Main entry point for AMQPD. * */ -public class Main implements ProtocolVersionList +public class Main implements ProtocolVersionList, Managable { private static final Logger _logger = Logger.getLogger(Main.class); @@ -83,6 +70,8 @@ public class Main implements ProtocolVersionList private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + private AMQBrokerManagerMBean _mbean = null; + protected static class InitException extends Exception { InitException(String msg) @@ -445,7 +434,8 @@ public class Main implements ProtocolVersionList { try { - new AMQBrokerManager().register(); + _mbean = new AMQBrokerManagerMBean(); + _mbean.register(); } catch (JMException ex) { @@ -453,156 +443,8 @@ public class Main implements ProtocolVersionList } } - /** - * 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 + public ManagedObject getManagedObject() { - 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 JMException - { - 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, durable, autoDelete, 0); - _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 - { - // TODO - // Check if the exchange is in use. - // boolean inUse = false; - // Check if there are queue-bindings with the exchange 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 createNewQueue(String queueName, boolean durable, String owner, boolean autoDelete) - throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(queueName); - if (queue != null) - { - throw new JMException("The queue \"" + queueName + "\" already exists."); - } - - 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()); - } - } - - /** - * 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 + return _mbean; + } } -- cgit v1.2.1 From 13ecd6a0d3293d3f9233dc2353db4fc30c350501 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 29 Dec 2006 22:12:44 +0000 Subject: Reduced logging level to debug to avoid performance sapping output git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@491120 13f79535-47bb-0310-9956-ffa450edef68 --- .../queue/ConcurrentSelectorDeliveryManager.java | 48 +++++++++++++++++----- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 2100734ada..b58807c651 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -213,7 +213,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { return; } - _log.info("Async Delivery Message:" + message + " to :" + sub); + if (_log.isDebugEnabled()) + { + _log.debug("Async Delivery Message:" + message + " to :" + sub); + } sub.send(message, _queue); @@ -278,7 +281,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void deliver(String name, AMQMessage msg) throws FailedDequeueException { - _log.info(id() + "deliver :" + System.identityHashCode(msg)); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "deliver :" + System.identityHashCode(msg)); + } //Check if we have someone to deliver the message to. _lock.lock(); @@ -288,7 +294,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (s == null) //no-one can take the message right now. { - _log.info(id() + "Testing Message(" + System.identityHashCode(msg) + ") for Queued Delivery"); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "Testing Message(" + System.identityHashCode(msg) + ") for Queued Delivery"); + } if (!msg.isImmediate()) { addMessageToQueue(msg); @@ -297,21 +306,33 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.unlock(); //Pre Deliver to all subscriptions - _log.info(id() + "We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to."); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "We have " + _subscriptions.getSubscriptions().size() + + " subscribers to give the message to."); + } for (Subscription sub : _subscriptions.getSubscriptions()) { // stop if the message gets delivered whilst PreDelivering if we have a shared queue. if (_queue.isShared() && msg.getDeliveredToConsumer()) { - _log.info(id() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + ") is already delivered."); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + + ") is already delivered."); + } continue; } // Only give the message to those that want them. if (sub.hasInterest(msg)) { - _log.info(id() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "Queuing message(" + System.identityHashCode(msg) + + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); + } sub.enqueueForPreDelivery(msg); } } @@ -322,7 +343,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //release lock now _lock.unlock(); - _log.info(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + System.identityHashCode(s) + ") :" + s); + if (_log.isDebugEnabled()) + { + _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + + System.identityHashCode(s) + ") :" + s); + } //Deliver the message s.send(msg, _queue); } @@ -371,9 +396,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void processAsync(Executor executor) { - _log.info("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get()); + if (_log.isDebugEnabled()) + { + _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + _processing.get()); + } if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) { -- cgit v1.2.1 From f96388bb6a6c9e94e7366bc2dd4da5a60f916671 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 1 Jan 2007 23:02:01 +0000 Subject: QPID-233 : Patch from Rob Godfrey - fix to lock.unlock() bug git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@491673 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index b58807c651..f09e8213b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -355,7 +355,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager finally { //ensure lock is released - if (_lock.isLocked()) + if (_lock.isHeldByCurrentThread()) { _lock.unlock(); } -- cgit v1.2.1 From 363a0a519d9997fc1e07f0732b2dd09b162d807d Mon Sep 17 00:00:00 2001 From: Kim van der Riet Date: Thu, 4 Jan 2007 21:30:39 +0000 Subject: Fixed C++ client sending protocol version 0-0 over the wire. Minor fixes and tidy-up in related code. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@492756 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQMinaProtocolSession.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 9ff6b96690..831117d2c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -165,17 +165,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _minor = pi.protocolMinor; String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); String locales = "en_US"; - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. + // Interfacing with generated code - be aware of possible changes to parameter order as versions change. AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, - (byte)8, (byte)0, // AMQP version (major, minor) + _major, _minor, // AMQP version (major, minor) locales.getBytes(), // locales mechanisms.getBytes(), // mechanisms null, // serverProperties - (short)8, // versionMajor - (short)0 // versionMinor - ); + (short)_major, // versionMajor + (short)_minor); // versionMinor _minaProtocolSession.write(response); } catch (AMQException e) -- cgit v1.2.1 From c2e8c9c9318334f1fd3073abab8a0a764552cbd3 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Sun, 7 Jan 2007 23:11:53 +0000 Subject: QPID-32: new model for holding and processing message in memory to support new persistent stores git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@493872 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 544 ++++------------- .../qpid/server/RequiredDeliveryException.java | 79 +-- .../java/org/apache/qpid/server/ack/TxAck.java | 41 +- .../qpid/server/ack/UnacknowledgedMessage.java | 13 +- .../qpid/server/ack/UnacknowledgedMessageMap.java | 52 +- .../server/ack/UnacknowledgedMessageMapImpl.java | 165 +++++- .../server/exchange/DefaultExchangeRegistry.java | 5 +- .../qpid/server/exchange/DestNameExchange.java | 5 +- .../qpid/server/exchange/DestWildExchange.java | 2 +- .../org/apache/qpid/server/exchange/Exchange.java | 2 +- .../qpid/server/exchange/HeadersExchange.java | 10 +- .../apache/qpid/server/exchange/MessageRouter.java | 3 +- .../qpid/server/filter/ArithmeticExpression.java | 7 +- .../qpid/server/filter/BooleanExpression.java | 8 +- .../qpid/server/filter/ComparisonExpression.java | 12 +- .../qpid/server/filter/ConstantExpression.java | 115 ++-- .../org/apache/qpid/server/filter/Expression.java | 6 +- .../qpid/server/filter/JMSSelectorFilter.java | 2 +- .../apache/qpid/server/filter/LogicExpression.java | 9 +- .../qpid/server/filter/NoConsumerFilter.java | 12 +- .../qpid/server/filter/PropertyExpression.java | 6 +- .../apache/qpid/server/filter/UnaryExpression.java | 12 +- .../apache/qpid/server/filter/XPathExpression.java | 8 +- .../qpid/server/filter/XQueryExpression.java | 6 +- .../qpid/server/filter/XalanXPathEvaluator.java | 32 +- .../qpid/server/handler/TxCommitHandler.java | 9 +- .../qpid/server/handler/TxSelectHandler.java | 2 +- .../apache/qpid/server/message/jms/JMSMessage.java | 3 +- .../server/protocol/AMQMinaProtocolSession.java | 15 +- .../org/apache/qpid/server/queue/AMQMessage.java | 644 ++++++++++++++------- .../apache/qpid/server/queue/AMQMessageHandle.java | 77 +++ .../org/apache/qpid/server/queue/AMQQueue.java | 102 +--- .../apache/qpid/server/queue/AMQQueueMBean.java | 91 ++- .../server/queue/ConcurrentDeliveryManager.java | 63 +- .../queue/ConcurrentSelectorDeliveryManager.java | 29 +- .../apache/qpid/server/queue/DeliveryManager.java | 11 +- .../qpid/server/queue/InMemoryMessageHandle.java | 133 +++++ .../org/apache/qpid/server/queue/ManagedQueue.java | 11 +- .../qpid/server/queue/MessageHandleFactory.java | 46 ++ .../apache/qpid/server/queue/MessageMetaData.java | 70 +++ .../qpid/server/queue/NoConsumersException.java | 21 +- .../org/apache/qpid/server/queue/Subscription.java | 10 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 39 +- .../apache/qpid/server/queue/SubscriptionSet.java | 2 +- .../server/queue/SynchronizedDeliveryManager.java | 23 +- .../qpid/server/queue/TransientMessageData.java | 118 ++++ .../server/queue/WeakReferenceMessageHandle.java | 190 ++++++ .../qpid/server/store/MemoryMessageStore.java | 100 ++-- .../org/apache/qpid/server/store/MessageStore.java | 35 +- .../org/apache/qpid/server/store/StoreContext.java | 42 ++ .../qpid/server/txn/CleanupMessageOperation.java | 91 +++ .../qpid/server/txn/DeliverMessageOperation.java | 74 +++ .../qpid/server/txn/LocalTransactionalContext.java | 148 +++++ .../qpid/server/txn/NonTransactionalContext.java | 208 +++++++ .../qpid/server/txn/StoreMessageOperation.java | 58 ++ .../qpid/server/txn/TransactionalContext.java | 48 ++ .../java/org/apache/qpid/server/txn/TxnBuffer.java | 62 +- .../java/org/apache/qpid/server/txn/TxnOp.java | 13 +- 58 files changed, 2562 insertions(+), 1182 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index c5b45659cf..999eb9f651 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -22,32 +22,27 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.ack.TxAck; import org.apache.qpid.server.ack.UnacknowledgedMessage; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.exchange.MessageRouter; +import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.LocalTransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.server.txn.TxnOp; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.Set; -import java.util.HashSet; + +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -59,7 +54,7 @@ public class AMQChannel private final int _channelId; - private boolean _transactional; + //private boolean _transactional; private long _prefetch_HighWaterMark; @@ -97,21 +92,24 @@ public class AMQChannel private final MessageStore _messageStore; - private final Object _unacknowledgedMessageMapLock = new Object(); - - private Map _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); - - private long _lastDeliveryTag; + private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); private final AtomicBoolean _suspended = new AtomicBoolean(false); private final MessageRouter _exchanges; - private final TxnBuffer _txnBuffer; + private TransactionalContext _txnContext; + + /** + * A context used by the message store enabling it to track context for a given channel even across + * thread boundaries + */ + private final StoreContext _storeContext = new StoreContext(); + + private final List _returnMessages = new LinkedList(); - private TxAck ackOp; + private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); - private final List _returns = new LinkedList(); private Set _browsedAcks = new HashSet(); public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) @@ -122,22 +120,29 @@ public class AMQChannel _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; _messageStore = messageStore; _exchanges = exchanges; - _txnBuffer = new TxnBuffer(_messageStore); + // by default the session is non-transactional + _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } - public int getChannelId() + /** + * Sets this channel to be part of a local transaction + */ + public void setLocalTransactional() { - return _channelId; + _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, new TxnBuffer(), _returnMessages); } public boolean isTransactional() { - return _transactional; + // this does not look great but there should only be one "non-transactional" + // transactional context, while there could be several transactional ones in + // theory + return !(_txnContext instanceof NonTransactionalContext); } - public void setTransactional(boolean transactional) + public int getChannelId() { - _transactional = transactional; + return _channelId; } public long getPrefetchCount() @@ -173,7 +178,9 @@ public class AMQChannel public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException { - _currentMessage = new AMQMessage(_messageStore, publishBody); + _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), publishBody, + _txnContext); + // TODO: used in clustering only I think (RG) _currentMessage.setPublisher(publisher); } @@ -182,92 +189,60 @@ public class AMQChannel { if (_currentMessage == null) { - throw new AMQException("Received content header without previously receiving a BasicDeliver frame"); + throw new AMQException("Received content header without previously receiving a BasicPublish frame"); } else { _currentMessage.setContentHeaderBody(contentHeaderBody); - // check and route if header says body length is zero + routeCurrentMessage(); + _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); + + // check and deliver if header says body length is zero if (contentHeaderBody.bodySize == 0) { - routeCurrentMessage(); + _currentMessage = null; } } } - public void publishContentBody(ContentBody contentBody) + public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException { if (_currentMessage == null) { throw new AMQException("Received content body without previously receiving a JmsPublishBody"); } - if (_currentMessage.getContentHeaderBody() == null) + + // returns true iff the message was delivered (i.e. if all data was + // received + try { - throw new AMQException("Received content body without previously receiving a content header"); + if (_currentMessage.addContentBodyFrame(_storeContext, contentBody)) + { + // callback to allow the context to do any post message processing + // primary use is to allow message return processing in the non-tx case + _txnContext.messageProcessed(protocolSession); + _currentMessage = null; + } } - - _currentMessage.addContentBodyFrame(contentBody); - if (_currentMessage.isAllContentReceived()) + catch (AMQException e) { - routeCurrentMessage(); + // 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 { - if (_transactional) + try { - //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; - } + _exchanges.routeContent(_currentMessage); } - else + catch (NoRouteException e) { - try - { - _exchanges.routeContent(_currentMessage); - //following check implements the functionality - //required by the 'immediate' flag: - _currentMessage.checkDeliveredToConsumer(); - } - finally - { - _currentMessage.decrementReference(); - _currentMessage = null; - } + _returnMessages.add(e); } } @@ -329,13 +304,7 @@ public class AMQChannel */ public void close(AMQProtocolSession session) throws AMQException { - if (_transactional) - { - synchronized(_txnBuffer) - { - _txnBuffer.rollback();//releases messages - } - } + _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); } @@ -353,41 +322,32 @@ public class AMQChannel /** * Add a message to the channel-based list of unacknowledged messages * - * @param message - * @param deliveryTag - * @param queue + * @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) { - synchronized(_unacknowledgedMessageMapLock) - { - _unacknowledgedMessageMap.put(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); - _lastDeliveryTag = deliveryTag; - checkSuspension(); - } + _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 - Map currentList; - synchronized(_unacknowledgedMessageMapLock) - { - currentList = _unacknowledgedMessageMap; - _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); - } + Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - for (UnacknowledgedMessage unacked : currentList.values()) + for (UnacknowledgedMessage unacked : messagesToBeDelivered) { if (unacked.queue != null) { - unacked.message.setTxnBuffer(null); - - unacked.queue.deliver(unacked.message); + _txnContext.deliver(unacked.message, unacked.queue); } } } @@ -395,53 +355,62 @@ public class AMQChannel /** * Called to resend all outstanding unacknowledged messages to this same channel. */ - public void resend(AMQProtocolSession session) + public void resend(final AMQProtocolSession session) throws AMQException { - //messages go to this channel - synchronized(_unacknowledgedMessageMapLock) + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - for (Map.Entry entry : _unacknowledgedMessageMap.entrySet()) + public boolean callback(UnacknowledgedMessage message) throws AMQException { - long deliveryTag = entry.getKey(); - String consumerTag = entry.getValue().consumerTag; - AMQMessage msg = entry.getValue().message; + long deliveryTag = message.deliveryTag; + String consumerTag = message.consumerTag; + AMQMessage msg = message.message; msg.setRedelivered(true); - session.writeFrame(msg.getDataBlock(_channelId, consumerTag, deliveryTag)); + 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 sine we may get an ack for a delivery tag that was generated from the + * actually removing the item since we may get an ack for a delivery tag that was generated from the * deleted queue. * - * @param 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(AMQQueue queue) + public void queueDeleted(final AMQQueue queue) throws AMQException { - synchronized(_unacknowledgedMessageMapLock) + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - for (Map.Entry unacked : _unacknowledgedMessageMap.entrySet()) + public boolean callback(UnacknowledgedMessage message) throws AMQException { - final UnacknowledgedMessage unackedMsg = unacked.getValue(); - // we can compare the reference safely in this case - if (unackedMsg.queue == queue) + if (message.queue == queue) { - unackedMsg.queue = null; try { - unackedMsg.message.decrementReference(); + message.discard(_storeContext); + message.queue = null; } catch (AMQException e) { - _log.error("Error decrementing ref count on message " + unackedMsg.message.getMessageId() + ": " + + _log.error("Error decrementing ref count on message " + message.message.getMessageId() + ": " + e, e); } } + return false; } - } + + public void visitComplete() + { + } + }); } /** @@ -454,150 +423,7 @@ public class AMQChannel */ public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { - if (_transactional) - { - //check that the tag exists to give early failure - if (!multiple || deliveryTag > 0) - { - checkAck(deliveryTag); - } - //we use a single txn op for all acks and update this op - //as new acks come in. If this is the first ack in the txn - //we will need to create and enlist the op. - if (ackOp == null) - { - ackOp = new TxAck(new AckMap()); - _txnBuffer.enlist(ackOp); - } - //update the op to include this ack request - if (multiple && deliveryTag == 0) - { - synchronized(_unacknowledgedMessageMapLock) - { - //if have signalled to ack all, that refers only - //to all at this time - ackOp.update(_lastDeliveryTag, multiple); - } - } - else - { - ackOp.update(deliveryTag, multiple); - } - } - else - { - handleAcknowledgement(deliveryTag, multiple); - } - } - - private void checkAck(long deliveryTag) throws AMQException - { - synchronized(_unacknowledgedMessageMapLock) - { - if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - } - - private void handleAcknowledgement(long deliveryTag, boolean multiple) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Handling acknowledgement for channel " + _channelId + " with delivery tag " + deliveryTag + - " and multiple " + multiple); - } - if (multiple) - { - LinkedList acked = new LinkedList(); - synchronized(_unacknowledgedMessageMapLock) - { - if (deliveryTag == 0) - { - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, tells the server to acknowledge all outstanding mesages. - _log.trace("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + _unacknowledgedMessageMap.size()); - acked = new LinkedList(_unacknowledgedMessageMap.values()); - _unacknowledgedMessageMap.clear(); - } - else - { - if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - Iterator> i = _unacknowledgedMessageMap.entrySet().iterator(); - - while (i.hasNext()) - { - - Map.Entry unacked = i.next(); - - if (unacked.getKey() > deliveryTag) - { - //This should not occur now. - throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + " When deliveryTag is:" + deliveryTag + "ES:" + _unacknowledgedMessageMap.entrySet().toString()); - } - - i.remove(); - - acked.add(unacked.getValue()); - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - }// synchronized - - if (_log.isTraceEnabled()) - { - _log.trace("Received multiple ack for delivery tag " + deliveryTag + ". Removing " + - acked.size() + " items."); - } - - for (UnacknowledgedMessage msg : acked) - { - if (!_browsedAcks.contains(deliveryTag)) - { - msg.discard(); - } - else - { - _browsedAcks.remove(deliveryTag); - } - } - - } - else - { - UnacknowledgedMessage msg; - synchronized(_unacknowledgedMessageMapLock) - { - msg = _unacknowledgedMessageMap.remove(deliveryTag); - } - - if (msg == null) - { - _log.trace("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); - } - - if (!_browsedAcks.contains(deliveryTag)) - { - msg.discard(); - } - else - { - _browsedAcks.remove(deliveryTag); - } - - if (_log.isTraceEnabled()) - { - _log.trace("Received non-multiple ack for messaging with delivery tag " + deliveryTag); - } - } - + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); checkSuspension(); } @@ -606,19 +432,22 @@ public class AMQChannel * * @return the map of unacknowledged messages */ - public Map getUnacknowledgedMessageMap() + public UnacknowledgedMessageMap getUnacknowledgedMessageMap() { return _unacknowledgedMessageMap; } + public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, String consumerTag, AMQQueue queue) + { + _browsedAcks.add(deliveryTag); + addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } + private void checkSuspension() { boolean suspend; - //noinspection SynchronizeOnNonFinalField - synchronized(_unacknowledgedMessageMapLock) - { - suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; - } + suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; + setSuspended(suspend); } @@ -628,11 +457,8 @@ public class AMQChannel if (isSuspended && !suspended) { - synchronized(_unacknowledgedMessageMapLock) - { - // Continue being suspended if we are above the _prefetch_LowWaterMark - suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; - } + // Continue being suspended if we are above the _prefetch_LowWaterMark + suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; } boolean wasSuspended = _suspended.getAndSet(suspended); @@ -661,33 +487,18 @@ public class AMQChannel public void commit() throws AMQException { - if (ackOp != null) - { - ackOp.consolidate(); - if (ackOp.checkPersistent()) - { - _txnBuffer.containsPersistentChanges(); - } - ackOp = null;//already enlisted, after commit will reset regardless of outcome - } - - _txnBuffer.commit(); - //TODO: may need to return 'immediate' messages at this point + _txnContext.commit(); } public void rollback() throws AMQException { - //need to protect rollback and close from each other... - synchronized(_txnBuffer) - { - _txnBuffer.rollback(); - } + _txnContext.rollback(); } public String toString() { StringBuilder sb = new StringBuilder(30); - sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(_transactional); + sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(isTransactional()); sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); sb.append("/").append(_prefetch_HighWaterMark); return sb.toString(); @@ -703,121 +514,18 @@ public class AMQChannel return _defaultQueue; } - public void processReturns(AMQProtocolSession session) + public StoreContext getStoreContext() { - for (AMQDataBlock block : _returns) - { - session.writeFrame(block); - } - _returns.clear(); - } - - public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, String consumerTag, AMQQueue queue) - { - _browsedAcks.add(deliveryTag); - addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + return _storeContext; } - //we use this wrapper to ensure we are always using the correct - //map instance (its not final unfortunately) - private class AckMap implements UnacknowledgedMessageMap + public void processReturns(AMQProtocolSession session) throws AMQException { - public void collect(long deliveryTag, boolean multiple, List msgs) - { - impl().collect(deliveryTag, multiple, msgs); - } - - public void remove(List msgs) - { - impl().remove(msgs); - } - - private UnacknowledgedMessageMap impl() - { - return new UnacknowledgedMessageMapImpl(_unacknowledgedMessageMapLock, _unacknowledgedMessageMap); - } - } - - private class Store implements TxnOp - { - //just use this to do a store of the message during the - //prepare phase. Any enqueueing etc is done by TxnOps enlisted - //by the queues themselves. - private final AMQMessage _msg; - - Store(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - _msg.storeMessage(); - //the routers reference can now be released - _msg.decrementReference(); - } - - public void undoPrepare() - { - } - - public void commit() - { - } - - public void rollback() + for (RequiredDeliveryException bouncedMessage : _returnMessages) { + AMQMessage message = bouncedMessage.getAMQMessage(); + message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), bouncedMessage.getMessage()); } + _returnMessages.clear(); } - - private class Cleanup implements TxnOp - { - private final AMQMessage _msg; - - Cleanup(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - } - - public void undoPrepare() - { - //don't need to do anything here, if the store's txn failed - //when processing prepare then the message was not stored - //or enqueued on any queues and can be discarded - } - - public void commit() - { - //The routers reference can now be released. This is done - //here to ensure that it happens after the queues that - //enqueue it have incremented their counts (which as a - //memory only operation is done in the commit phase). - try - { - _msg.decrementReference(); - } - catch (AMQException e) - { - _log.error("On commiting transaction, failed to cleanup unused message: " + e, e); - } - try - { - _msg.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - //TODO: store this for delivery after the commit-ok - _returns.add(e.getReturnMessage(_channelId)); - } - } - - public void rollback() - { - } - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index 5e463646f9..b85e3603b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,17 +20,9 @@ */ package org.apache.qpid.server; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.CompositeAMQDataBlock; -import org.apache.qpid.framing.BasicReturnBody; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; -import java.util.List; - /** * Signals that a required delivery could not be made. This could be bacuse of * the immediate flag being set and the queue having no consumers, or the mandatory @@ -38,79 +30,24 @@ import java.util.List; */ public abstract class RequiredDeliveryException extends AMQException { - private final String _message; - private final BasicPublishBody _publishBody; - private final ContentHeaderBody _contentHeaderBody; - private final List _contentBodies; + private final AMQMessage _amqMessage; public RequiredDeliveryException(String message, AMQMessage payload) { super(message); - _message = message; - _publishBody = payload.getPublishBody(); - _contentHeaderBody = payload.getContentHeaderBody(); - _contentBodies = payload.getContentBodies(); + _amqMessage = payload; + payload.incrementReference(); } - public RequiredDeliveryException(String message, - BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) + public AMQMessage getAMQMessage() { - super(message); - _message = message; - _publishBody = publishBody; - _contentHeaderBody = contentHeaderBody; - _contentBodies = contentBodies; - } - - public BasicPublishBody getPublishBody() - { - return _publishBody; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public List getContentBodies() - { - return _contentBodies; - } - - public CompositeAMQDataBlock getReturnMessage(int channel) - { - // AMQP version change: All generated *Body classes are now version-aware. - // Shortcut: hardwire version to 0-8 (major=8, minor=0) for now. - // TODO: Connect the version to that returned by the ProtocolInitiation - // for this session. - BasicReturnBody returnBody = new BasicReturnBody((byte)8, (byte)0); - returnBody.exchange = _publishBody.exchange; - returnBody.replyCode = getReplyCode(); - returnBody.replyText = _message; - returnBody.routingKey = _publishBody.routingKey; - - AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; - - AMQFrame returnFrame = new AMQFrame(); - returnFrame.bodyFrame = returnBody; - returnFrame.channel = channel; - - allFrames[0] = returnFrame; - allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 2; i < allFrames.length; i++) - { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); - } - - return new CompositeAMQDataBlock(allFrames); + return _amqMessage; } public int getErrorCode() { return getReplyCode(); - } + } public abstract int getReplyCode(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index a204e176aa..c0a631080e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,13 +22,14 @@ package org.apache.qpid.server.ack; import org.apache.qpid.AMQException; import org.apache.qpid.server.txn.TxnOp; +import org.apache.qpid.server.store.StoreContext; import java.util.LinkedList; import java.util.List; /** * A TxnOp implementation for handling accumulated acks - */ + */ public class TxAck implements TxnOp { private final UnacknowledgedMessageMap _map; @@ -44,14 +45,14 @@ public class TxAck implements TxnOp public void update(long deliveryTag, boolean multiple) { - if(!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) + else if (deliveryTag > _deliveryTag) { //have simply moved the last acked message on a //bit @@ -63,7 +64,7 @@ public class TxAck implements TxnOp public void consolidate() { //lookup all the unacked messages that have been acked in this transaction - if(_multiple) + if (_multiple) { //get all the unacked messages for the accumulated //multiple acks @@ -71,22 +72,22 @@ public class TxAck implements TxnOp } //get any unacked messages for individual acks outside the //range covered by multiple acks - for(long tag : _individual) + for (long tag : _individual) { if(_deliveryTag < tag) { - _map.collect(tag, false, _unacked); + _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) + for (UnacknowledgedMessage msg : _unacked) { - if(msg.message.isPersistent()) + if (msg.message.isPersistent()) { return true; } @@ -94,34 +95,34 @@ public class TxAck implements TxnOp return false; } - public void prepare() throws AMQException + public void prepare(StoreContext storeContext) throws AMQException { //make persistent changes, i.e. dequeue and decrementReference - for(UnacknowledgedMessage msg : _unacked) + for (UnacknowledgedMessage msg : _unacked) { - msg.discard(); + msg.discard(storeContext); } } - + public void undoPrepare() { //decrementReference is annoyingly untransactional (due to //in memory counter) so if we failed in prepare for full //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for(UnacknowledgedMessage msg : _unacked) + //in memory (persistent changes will be rolled back by store) + for (UnacknowledgedMessage msg : _unacked) { msg.message.incrementReference(); - } + } } - public void commit() + public void commit(StoreContext storeContext) { //remove the unacked messages from the channels map _map.remove(_unacked); } - public void rollback() + public void rollback(StoreContext storeContext) { } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index 0eff5a3cca..26f41e19af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,6 +23,7 @@ package org.apache.qpid.server.ack; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; public class UnacknowledgedMessage { @@ -30,7 +31,7 @@ public class UnacknowledgedMessage public final String consumerTag; public final long deliveryTag; public AMQQueue queue; - + public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, String consumerTag, long deliveryTag) { this.queue = queue; @@ -39,13 +40,13 @@ public class UnacknowledgedMessage this.deliveryTag = deliveryTag; } - public void discard() throws AMQException + public void discard(StoreContext storeContext) throws AMQException { if (queue != null) { - message.dequeue(queue); + message.dequeue(storeContext, queue); } - message.decrementReference(); + message.decrementReference(storeContext); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index b0bbe224e3..b7a75d5b71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,11 +20,55 @@ */ package org.apache.qpid.server.ack; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TransactionalContext; + +import java.util.Collection; import java.util.List; +import java.util.Set; public interface UnacknowledgedMessageMap { - public void collect(long deliveryTag, boolean multiple, List msgs); - public void remove(List msgs); + 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(); + + UnacknowledgedMessage get(long deliveryTag); + + /** + * Get the set of delivery tags that are outstanding. + * @return a set of delivery tags + */ + Set getDeliveryTags(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index eda3233e56..1f4333549a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,19 +20,34 @@ */ package org.apache.qpid.server.ack; -import java.util.List; -import java.util.Map; +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; + private final Object _lock = new Object(); + private Map _map; - public UnacknowledgedMessageMapImpl(Object lock, 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) { @@ -47,28 +62,151 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } + public boolean contains(long deliveryTag) throws AMQException + { + synchronized (_lock) + { + return _map.containsKey(deliveryTag); + } + } + public void remove(List msgs) { - synchronized(_lock) + 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); + } + visitor.visitComplete(); + } + } + + 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) + public UnacknowledgedMessage get(long key) { - synchronized(_lock) + synchronized (_lock) { return _map.get(key); } } + public Set getDeliveryTags() + { + synchronized (_lock) + { + return _map.keySet(); + } + } + private void collect(long key, List msgs) { - synchronized(_lock) + synchronized (_lock) { for(Map.Entry entry : _map.entrySet()) { @@ -76,9 +214,8 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap if (entry.getKey() == key) { break; - } + } } } } } - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index eb9d1acb59..99c08ad200 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,10 +20,10 @@ */ 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 org.apache.log4j.Logger; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -84,8 +84,9 @@ public class DefaultExchangeRegistry implements ExchangeRegistry final String exchange = payload.getPublishBody().exchange; final Exchange exch = _exchangeMap.get(exchange); // there is a small window of opportunity for the exchange to be deleted in between - // the JmsPublish being received (where the exchange is validated) and the final + // 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"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index d4069fa315..7b28161263 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -168,8 +168,7 @@ public class DestNameExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { - BasicPublishBody publishBody = payload.getPublishBody(); - + final BasicPublishBody publishBody = payload.getPublishBody(); final String routingKey = publishBody.routingKey; final List queues = (routingKey == null) ? null : _index.get(routingKey); if (queues == null || queues.isEmpty()) @@ -193,7 +192,7 @@ public class DestNameExchange extends AbstractExchange for (AMQQueue q : queues) { - q.deliver(payload); + payload.enqueue(q); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 139307488e..c341f30ab6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -171,7 +171,7 @@ public class DestWildExchange extends AbstractExchange // TODO: modify code generator to add clone() method then clone the deliver body // without this addition we have a race condition - we will be modifying the body // before the encoder has encoded the body for delivery - q.deliver(payload); + payload.enqueue(q); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 824e85dc5c..8ef5f0ab29 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -22,8 +22,8 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; public interface Exchange { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 229502d2a6..dcb64e2d30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -145,7 +145,7 @@ public class HeadersExchange extends AbstractExchange * =,=,... * @param queueName * @param binding - * @throws JMException + * @throws javax.management.JMException */ public void createNewBinding(String queueName, String binding) throws JMException { @@ -192,7 +192,7 @@ public class HeadersExchange extends AbstractExchange { _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); } - boolean delivered = false; + boolean routed = false; for (Registration e : _bindings) { if (e.binding.matches(headers)) @@ -202,11 +202,11 @@ public class HeadersExchange extends AbstractExchange _logger.debug("Exchange " + getName() + ": delivering message with headers " + headers + " to " + e.queue.getName()); } - e.queue.deliver(payload); - delivered = true; + payload.enqueue(e.queue); + routed = true; } } - if (!delivered) + if (!routed) { String msg = "Exchange " + getName() + ": message not routable."; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java index 70b80f65da..7508e80f7f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.exchange; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; /** * Separated out from the ExchangeRegistry interface to allow components @@ -33,6 +33,7 @@ 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/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index 0aa5739c1c..c536f77dde 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; import javax.jms.JMSException; @@ -58,7 +59,8 @@ public abstract class ArithmeticExpression extends BinaryExpression { throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "+"; } }; @@ -193,7 +195,8 @@ public abstract class ArithmeticExpression extends BinaryExpression { } } - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException + { Object lvalue = left.evaluate(message); if (lvalue == null) { return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index b66de3fbc5..de71e95049 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import javax.jms.JMSException; @@ -33,13 +34,14 @@ import javax.jms.JMSException; * * @version $Revision$ */ -public interface BooleanExpression extends Expression { - +public interface BooleanExpression extends Expression +{ + /** * @param message * @return true if the expression evaluates to Boolean.TRUE. * @throws JMSException */ - public boolean matches(AMQMessage message) throws JMSException; + public boolean matches(AMQMessage message) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 13d278cf65..07391098ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import java.util.HashSet; import java.util.List; @@ -123,7 +124,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B /** * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) */ - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Object rv = this.getRight().evaluate(message); @@ -139,7 +140,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; } - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } @@ -199,7 +200,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B private static BooleanExpression doCreateEqual(Expression left, Expression right) { return new ComparisonExpression(left, right) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Object lv = left.evaluate(message); Object rv = right.evaluate(message); @@ -340,7 +341,8 @@ public abstract class ComparisonExpression extends BinaryExpression implements B super(left, right); } - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException + { Comparable lv = (Comparable) left.evaluate(message); if (lv == null) { return null; @@ -457,7 +459,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B protected abstract boolean asBoolean(int answer); - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 9bde712da2..2cd305d4b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import java.math.BigDecimal; @@ -29,19 +30,24 @@ import javax.jms.JMSException; /** * Represents a constant expression - * + * * @version $Revision$ */ -public class ConstantExpression implements Expression { +public class ConstantExpression implements Expression +{ - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression { - public BooleanConstantExpression(Object value) { + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression + { + public BooleanConstantExpression(Object value) + { super(value); } - public boolean matches(AMQMessage message) throws JMSException { + + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; - } + return object != null && object == Boolean.TRUE; + } } public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); @@ -50,73 +56,92 @@ public class ConstantExpression implements Expression { private Object value; - public static ConstantExpression createFromDecimal(String text) { - - // Strip off the 'l' or 'L' if needed. - if( text.endsWith("l") || text.endsWith("L") ) - text = text.substring(0, text.length()-1); - - Number value; - try { - value = new Long(text); - } catch ( NumberFormatException e) { - // The number may be too big to fit in a long. - value = new BigDecimal(text); - } - + public static ConstantExpression createFromDecimal(String text) + { + + // Strip off the 'l' or 'L' if needed. + if (text.endsWith("l") || text.endsWith("L")) + { + text = text.substring(0, text.length() - 1); + } + + Number value; + try + { + value = new Long(text); + } + catch (NumberFormatException e) + { + // The number may be too big to fit in a long. + value = new BigDecimal(text); + } + long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + { value = new Integer(value.intValue()); } return new ConstantExpression(value); } - public static ConstantExpression createFromHex(String text) { + public static ConstantExpression createFromHex(String text) + { Number value = new Long(Long.parseLong(text.substring(2), 16)); long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + { value = new Integer(value.intValue()); } return new ConstantExpression(value); } - public static ConstantExpression createFromOctal(String text) { + public static ConstantExpression createFromOctal(String text) + { Number value = new Long(Long.parseLong(text, 8)); long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) { + if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + { value = new Integer(value.intValue()); } return new ConstantExpression(value); } - public static ConstantExpression createFloat(String text) { + public static ConstantExpression createFloat(String text) + { Number value = new Double(text); return new ConstantExpression(value); } - public ConstantExpression(Object value) { + public ConstantExpression(Object value) + { this.value = value; } - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException + { return value; } - public Object getValue() { + public Object getValue() + { return value; - } + } /** * @see java.lang.Object#toString() */ - public String toString() { - if (value == null) { + public String toString() + { + if (value == null) + { return "NULL"; } - if (value instanceof Boolean) { + if (value instanceof Boolean) + { return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; } - if (value instanceof String) { + if (value instanceof String) + { return encodeString((String) value); } return value.toString(); @@ -127,7 +152,8 @@ public class ConstantExpression implements Expression { * * @see java.lang.Object#hashCode() */ - public int hashCode() { + public int hashCode() + { return toString().hashCode(); } @@ -136,9 +162,11 @@ public class ConstantExpression implements Expression { * * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object o) { + public boolean equals(Object o) + { - if (o == null || !this.getClass().equals(o.getClass())) { + if (o == null || !this.getClass().equals(o.getClass())) + { return false; } return toString().equals(o.toString()); @@ -153,12 +181,15 @@ public class ConstantExpression implements Expression { * @param s * @return */ - public static String encodeString(String s) { + public static String encodeString(String s) + { StringBuffer b = new StringBuffer(); b.append('\''); - for (int i = 0; i < s.length(); i++) { + for (int i = 0; i < s.length(); i++) + { char c = s.charAt(i); - if (c == '\'') { + if (c == '\'') + { b.append(c); } b.append(c); @@ -166,5 +197,5 @@ public class ConstantExpression implements Expression { b.append('\''); return b.toString(); } - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index a15c15fb91..3b5debd3ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import javax.jms.JMSException; @@ -32,11 +33,12 @@ import javax.jms.JMSException; * * @version $Revision$ */ -public interface Expression { +public interface Expression +{ /** * @return the value of this expression */ - public Object evaluate(AMQMessage message) throws JMSException; + public Object evaluate(AMQMessage message) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 4884067237..5f505fbeba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -64,7 +64,7 @@ public class JMSSelectorFilter implements MessageFilter _logger.info(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); return match; } - catch (JMSException e) + catch (AMQException e) { //fixme this needs to be sorted.. it shouldn't happen e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index 714d8c23f5..e6ad98cb8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import javax.jms.JMSException; @@ -35,7 +36,7 @@ public abstract class LogicExpression extends BinaryExpression implements Boolea public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { return new LogicExpression(lvalue, rvalue) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Boolean lv = (Boolean) left.evaluate(message); // Can we do an OR shortcut?? @@ -56,7 +57,7 @@ public abstract class LogicExpression extends BinaryExpression implements Boolea public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { return new LogicExpression(lvalue, rvalue) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Boolean lv = (Boolean) left.evaluate(message); @@ -85,9 +86,9 @@ public abstract class LogicExpression extends BinaryExpression implements Boolea super(left, right); } - abstract public Object evaluate(AMQMessage message) throws JMSException; + abstract public Object evaluate(AMQMessage message) throws AMQException; - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java index 283d324ff6..47ca930d12 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -20,15 +20,9 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.filter.jms.selector.SelectorParser; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidSelectorException; import org.apache.log4j.Logger; - - -import javax.jms.InvalidSelectorException; -import javax.jms.JMSException; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; public class NoConsumerFilter implements MessageFilter { @@ -36,7 +30,7 @@ public class NoConsumerFilter implements MessageFilter public NoConsumerFilter() throws AMQException - { + { _logger.info("Created NoConsumerFilter"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index f3e9965c2e..7d6a98df84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -47,7 +47,7 @@ public class PropertyExpression implements Expression interface SubExpression { - public Object evaluate(AMQMessage message); + public Object evaluate(AMQMessage message) throws AMQException; } interface JMSExpression @@ -65,7 +65,7 @@ public class PropertyExpression implements Expression } - public Object evaluate(AMQMessage message) + public Object evaluate(AMQMessage message) throws AMQException { JMSMessage msg = (JMSMessage) message.getDecodedMessage(AMQMessage.JMS_MESSAGE); if (msg != null) @@ -226,7 +226,7 @@ public class PropertyExpression implements Expression jmsPropertyExpression = (SubExpression) JMS_PROPERTY_EXPRESSIONS.get(name); } - public Object evaluate(AMQMessage message) throws JMSException + public Object evaluate(AMQMessage message) throws AMQException { // try // { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 49ff147411..abc56f04d0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.qpid.AMQException; import java.math.BigDecimal; import java.util.Collection; @@ -43,7 +44,8 @@ public abstract class UnaryExpression implements Expression { public static Expression createNegate(Expression left) { return new UnaryExpression(left) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException + { Object rvalue = right.evaluate(message); if (rvalue == null) { return null; @@ -74,7 +76,7 @@ public abstract class UnaryExpression implements Expression { final Collection inList = t; return new BooleanUnaryExpression(right) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Object rvalue = right.evaluate(message); if (rvalue == null) { @@ -126,7 +128,7 @@ public abstract class UnaryExpression implements Expression { super(left); } - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } @@ -135,7 +137,7 @@ public abstract class UnaryExpression implements Expression { public static BooleanExpression createNOT(BooleanExpression left) { return new BooleanUnaryExpression(left) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Boolean lvalue = (Boolean) right.evaluate(message); if (lvalue == null) { return null; @@ -159,7 +161,7 @@ public abstract class UnaryExpression implements Expression { public static BooleanExpression createBooleanCast(Expression left) { return new BooleanUnaryExpression(left) { - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { Object rvalue = right.evaluate(message); if (rvalue == null) return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index ab952b6fea..85402e0781 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -31,6 +31,7 @@ import javax.jms.JMSException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; /** * Used to evaluate an XPath Expression in a JMS selector. @@ -75,7 +76,7 @@ public final class XPathExpression implements BooleanExpression { private final XPathEvaluator evaluator; static public interface XPathEvaluator { - public boolean evaluate(AMQMessage message) throws JMSException; + public boolean evaluate(AMQMessage message) throws AMQException; } XPathExpression(String xpath) { @@ -97,7 +98,7 @@ public final class XPathExpression implements BooleanExpression { } } - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { // try { //FIXME this is flow to disk work // if( message.isDropped() ) @@ -122,7 +123,8 @@ public final class XPathExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws JMSException */ - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index 53764cbf75..da8a61650a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -18,6 +18,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; import javax.jms.JMSException; // @@ -35,7 +36,7 @@ public final class XQueryExpression implements BooleanExpression { this.xpath = xpath; } - public Object evaluate(AMQMessage message) throws JMSException { + public Object evaluate(AMQMessage message) throws AMQException { return Boolean.FALSE; } @@ -48,7 +49,8 @@ public final class XQueryExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws JMSException */ - public boolean matches(AMQMessage message) throws JMSException { + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index 4b78fd18df..f74e0cedec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -34,6 +34,7 @@ import javax.xml.parsers.DocumentBuilderFactory; //import org.apache.activemq.util.ByteArrayInputStream; import org.apache.xpath.CachedXPathAPI; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; import org.w3c.dom.Document; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; @@ -46,17 +47,26 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { this.xpath = xpath; } - public boolean evaluate(AMQMessage m) throws JMSException { - if( m instanceof TextMessage ) { - String text = ((TextMessage)m).getText(); - return evaluate(text); - } else if ( m instanceof BytesMessage ) { - BytesMessage bm = (BytesMessage) m; - byte data[] = new byte[(int) bm.getBodyLength()]; - bm.readBytes(data); - return evaluate(data); - } - return false; + public boolean evaluate(AMQMessage m) throws AMQException + { + try + { + + if( m instanceof TextMessage ) { + String text = ((TextMessage)m).getText(); + return evaluate(text); + } else if ( m instanceof BytesMessage ) { + BytesMessage bm = (BytesMessage) m; + byte data[] = new byte[(int) bm.getBodyLength()]; + bm.readBytes(data); + return evaluate(data); + } + return false; + } + catch (JMSException e) + { + throw new AMQException("Error evaluting message: " + e, e); + } } private boolean evaluate(byte[] data) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java index 7fcad5bbf3..c67b86af09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -49,15 +49,18 @@ public class TxCommitHandler implements StateAwareMethodListener AMQMethodEvent evt) throws AMQException { - try{ + try + { AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); channel.commit(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); - channel.processReturns(protocolSession); - }catch(AMQException e){ + channel.processReturns(protocolSession); + } + catch(AMQException e) + { throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java index 7df3825d8a..f4738ff01b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -47,7 +47,7 @@ public class TxSelectHandler implements StateAwareMethodListener ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, AMQMethodEvent evt) throws AMQException { - protocolSession.getChannel(evt.getChannelId()).setTransactional(true); + protocolSession.getChannel(evt.getChannelId()).setLocalTransactional(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java index 72e241ea0a..376f88cbf1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java @@ -24,6 +24,7 @@ import org.apache.qpid.server.message.MessageDecorator; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.AMQException; import javax.jms.Message; import javax.jms.JMSException; @@ -37,7 +38,7 @@ public class JMSMessage implements MessageDecorator private AMQMessage _message; private BasicContentHeaderProperties _properties; - public JMSMessage(AMQMessage message) + public JMSMessage(AMQMessage message) throws AMQException { _message = message; ContentHeaderBody contentHeader = message.getContentHeaderBody(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 831117d2c6..08668f0f6a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -40,7 +40,6 @@ import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -201,17 +200,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } else { - try - { - contentFrameReceived(frame); - } - catch (RequiredDeliveryException e) - { - //need to return the message: - _logger.info("Returning message to " + this + " channel " + frame.channel - + ": " + e.getMessage()); - writeFrame(e.getReturnMessage(frame.channel)); - } + contentFrameReceived(frame); } } } @@ -287,7 +276,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } - getChannel(frame.channel).publishContentBody((ContentBody) frame.bodyFrame); + getChannel(frame.channel).publishContentBody((ContentBody)frame.bodyFrame, this); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index afe4ea95b9..f30667690f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -21,19 +21,17 @@ 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.TxnBuffer; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.message.MessageDecorator; import org.apache.qpid.server.message.jms.JMSMessage; -import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; -import java.util.ArrayList; -import java.util.List; -import java.util.LinkedList; -import java.util.Set; -import java.util.HashSet; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.ConcurrentHashMap; @@ -43,45 +41,28 @@ import java.util.concurrent.ConcurrentHashMap; */ public class AMQMessage { + private static final Logger _log = Logger.getLogger(AMQMessage.class); + public static final String JMS_MESSAGE = "jms.message"; + /** + * Used in clustering + */ private final Set _tokens = new HashSet(); + /** + * Only use in clustering - should ideally be removed? + */ private AMQProtocolSession _publisher; - private final BasicPublishBody _publishBody; - - private ContentHeaderBody _contentHeaderBody; - - private List _contentBodies; - - private boolean _redelivered; - private final long _messageId; private final AtomicInteger _referenceCount = new AtomicInteger(1); - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; + private AMQMessageHandle _messageHandle; - /** - * The message store in which this message is contained. - */ - private transient final MessageStore _store; - - /** - * For non transactional publishes, a message can be stored as - * soon as it is complete. For transactional messages it doesnt - * need to be stored until the transaction is committed. - */ - private boolean _storeWhenComplete; - - /** - * TxnBuffer for transactionally published messages - */ - private TxnBuffer _txnBuffer; + // TODO: ideally this should be able to go into the transient message date - check this! (RG) + private TransactionalContext _txnContext; /** * Flag to indicate whether message has been delivered to a @@ -89,178 +70,245 @@ public class AMQMessage * messages published with the 'immediate' flag. */ private boolean _deliveredToConsumer; + private ConcurrentHashMap _decodedMessages; - private AtomicBoolean _taken; + private AtomicBoolean _taken = new AtomicBoolean(false); + private TransientMessageData _transientMessageData = new TransientMessageData(); - public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody) + /** + * 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 { - this(messageStore, publishBody, true); - } + private int _channel; - public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody, boolean storeWhenComplete) - { - _messageId = messageStore.getNewMessageId(); - _publishBody = publishBody; - _store = messageStore; - _contentBodies = new LinkedList(); - _decodedMessages = new ConcurrentHashMap(); - _storeWhenComplete = storeWhenComplete; - _taken = new AtomicBoolean(false); - } + private int _index = -1; - public AMQMessage(MessageStore store, long messageId, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, List contentBodies) - throws AMQException + private BodyFrameIterator(int channel) + { + _channel = channel; + } - { - _publishBody = publishBody; - _contentHeaderBody = contentHeaderBody; - _contentBodies = contentBodies; - _decodedMessages = new ConcurrentHashMap(); - _messageId = messageId; - _store = store; - storeMessage(); - } + public boolean hasNext() + { + try + { + return _index < _messageHandle.getBodyCount(_messageId) - 1; + } + catch (AMQException e) + { + _log.error("Unable to get body count: " + e, e); + return false; + } + } - public AMQMessage(MessageStore store, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, List contentBodies) - throws AMQException - { - this(store, store.getNewMessageId(), publishBody, contentHeaderBody, contentBodies); - } + 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); + } - protected AMQMessage(AMQMessage msg) throws AMQException - { - this(msg._store, msg._messageId, msg._publishBody, msg._contentHeaderBody, msg._contentBodies); - } + } - public void storeMessage() throws AMQException - { - if (isPersistent()) + public void remove() { - _store.put(this); + throw new UnsupportedOperationException(); } } - public CompositeAMQDataBlock getDataBlock(ByteBuffer encodedDeliverBody, int channel) + private class BodyContentIterator implements Iterator { - AMQFrame[] allFrames = new AMQFrame[1 + _contentBodies.size()]; - allFrames[0] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 1; i < allFrames.length; i++) + private int _index = -1; + + public boolean hasNext() { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 1)); + try + { + return _index < _messageHandle.getBodyCount(_messageId) - 1; + } + catch (AMQException e) + { + _log.error("Error getting body count: " + e, e); + return false; + } } - return new CompositeAMQDataBlock(encodedDeliverBody, allFrames); - } - public CompositeAMQDataBlock getDataBlock(int channel, String consumerTag, long deliveryTag) - { - - AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; + public ContentBody next() + { + try + { + return _messageHandle.getContentBody(_messageId, ++_index); + } + catch (AMQException e) + { + throw new RuntimeException("Error getting content body: " + e, e); + } + } - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - allFrames[0] = BasicDeliverBody.createAMQFrame(channel, - (byte)8, (byte)0, // AMQP version (major, minor) - consumerTag, // consumerTag - deliveryTag, // deliveryTag - getExchangeName(), // exchange - _redelivered, // redelivered - getRoutingKey() // routingKey - ); - allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 2; i < allFrames.length; i++) + public void remove() { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); + throw new UnsupportedOperationException(); } - return new CompositeAMQDataBlock(allFrames); } - public List getPayload() + public AMQMessage(long messageId, BasicPublishBody publishBody, + TransactionalContext txnContext) { - List payload = new ArrayList(2 + _contentBodies.size()); - payload.add(_publishBody); - payload.add(_contentHeaderBody); - payload.addAll(_contentBodies); - return payload; + _messageId = messageId; + _txnContext = txnContext; + _transientMessageData.setPublishBody(publishBody); + _decodedMessages = new ConcurrentHashMap(); + _taken = new AtomicBoolean(false); + if (_log.isDebugEnabled()) + { + _log.debug("Message created with id " + messageId); + } } - public BasicPublishBody getPublishBody() + /** + * Used when recovering, i.e. when the message store is creating references to messages. + * In that case, the normal enqueue/routingComplete is not done since the recovery process + * is responsible for routing the messages to queues. + * @param messageId + * @param store + * @param factory + * @throws AMQException + */ + public AMQMessage(long messageId, MessageStore store, MessageHandleFactory factory) throws AMQException { - return _publishBody; + _messageId = messageId; + _messageHandle = factory.createMessageHandle(messageId, store, true); + _transientMessageData = null; } - public ContentHeaderBody getContentHeaderBody() + /** + * Used in testing only. This allows the passing of the content header immediately + * on construction. + * @param messageId + * @param publishBody + * @param txnContext + * @param contentHeader + */ + public AMQMessage(long messageId, BasicPublishBody publishBody, + TransactionalContext txnContext, ContentHeaderBody contentHeader) throws AMQException { - return _contentHeaderBody; + this(messageId, publishBody, txnContext); + setContentHeaderBody(contentHeader); } - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException - { - _contentHeaderBody = contentHeaderBody; - if (_storeWhenComplete && isAllContentReceived()) + /** + * Used in testing only. This allows the passing of the content header and some body fragments on + * construction. + * @param messageId + * @param publishBody + * @param txnContext + * @param contentHeader + * @param destinationQueues + * @param contentBodies + * @throws AMQException + */ + public AMQMessage(long messageId, BasicPublishBody publishBody, + TransactionalContext txnContext, + ContentHeaderBody contentHeader, List destinationQueues, + List contentBodies, MessageStore messageStore, StoreContext storeContext, + MessageHandleFactory messageHandleFactory) throws AMQException + { + this(messageId, publishBody, txnContext, contentHeader); + _transientMessageData.setDestinationQueues(destinationQueues); + routingComplete(messageStore, storeContext, messageHandleFactory); + for (ContentBody cb : contentBodies) { - storeMessage(); + addContentBodyFrame(storeContext, cb); } } - public List getContentBodies() + protected AMQMessage(AMQMessage msg) throws AMQException { - return _contentBodies; + _messageId = msg._messageId; + _messageHandle = msg._messageHandle; + _txnContext = msg._txnContext; + _deliveredToConsumer = msg._deliveredToConsumer; + _transientMessageData = msg._transientMessageData; } - public void setContentBodies(List contentBodies) + public Iterator getBodyFrameIterator(int channel) { - _contentBodies = contentBodies; + return new BodyFrameIterator(channel); } - public void addContentBodyFrame(ContentBody contentBody) throws AMQException + public Iterator getContentBodyIterator() { - _contentBodies.add(contentBody); - _bodyLengthReceived += contentBody.getSize(); - if (_storeWhenComplete && isAllContentReceived()) - { - storeMessage(); - } + return new BodyContentIterator(); } - public boolean isAllContentReceived() + public ContentHeaderBody getContentHeaderBody() throws AMQException { - return _bodyLengthReceived == _contentHeaderBody.bodySize; + if (_transientMessageData != null) + { + return _transientMessageData.getContentHeaderBody(); + } + else + { + return _messageHandle.getContentHeaderBody(_messageId); + } } - - public boolean isRedelivered() + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + throws AMQException { - return _redelivered; + _transientMessageData.setContentHeaderBody(contentHeaderBody); } - String getExchangeName() + public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) throws AMQException { - return _publishBody.exchange; - } + final boolean persistent = isPersistent(); + _messageHandle = factory.createMessageHandle(_messageId, store, persistent); + if (persistent) + { + _txnContext.beginTranIfNecessary(); + } - String getRoutingKey() - { - return _publishBody.routingKey; - } + // enqueuing the messages ensure that if required the destinations are recorded to a + // persistent store + for (AMQQueue q : _transientMessageData.getDestinationQueues()) + { + _messageHandle.enqueue(storeContext, _messageId, q); + } - boolean isImmediate() - { - return _publishBody.immediate; + if (_transientMessageData.getContentHeaderBody().bodySize == 0) + { + deliver(storeContext); + } } - NoConsumersException getNoConsumersException(String queue) + public boolean addContentBodyFrame(StoreContext storeContext, ContentBody contentBody) throws AMQException { - return new NoConsumersException(queue, _publishBody, _contentHeaderBody, _contentBodies); + _transientMessageData.addBodyLength(contentBody.getSize()); + _messageHandle.addContentBodyFrame(storeContext, _messageId, contentBody); + if (isAllContentReceived()) + { + deliver(storeContext); + return true; + } + else + { + return false; + } } - public void setRedelivered(boolean redelivered) + public boolean isAllContentReceived() throws AMQException { - _redelivered = redelivered; + return _transientMessageData.isAllContentReceived(); } public long getMessageId() @@ -274,13 +322,20 @@ public class AMQMessage 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 + public void decrementReference(StoreContext storeContext) 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 @@ -290,7 +345,16 @@ public class AMQMessage { try { - _store.removeMessage(_messageId); + if (_log.isDebugEnabled()) + { + _log.debug("Ref count on message " + _messageId + " is zero; removing message"); + } + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + if (_messageHandle != null) + { + _messageHandle.removeMessage(storeContext, _messageId); + } } catch (AMQException e) { @@ -299,6 +363,17 @@ public class AMQMessage 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) @@ -311,6 +386,60 @@ public class AMQMessage return _publisher; } + /** + * Called selectors to determin if the message has already been sent + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return _deliveredToConsumer; + } + + + public MessageDecorator getDecodedMessage(String type) throws AMQException + { + MessageDecorator msgtype = null; + + if (_decodedMessages != null) + { + msgtype = _decodedMessages.get(type); + + if (msgtype == null) + { + msgtype = decorateMessage(type); + } + } + + return msgtype; + } + + private MessageDecorator decorateMessage(String type) throws AMQException + { + MessageDecorator msgdec = null; + + if (type.equals(JMS_MESSAGE)) + { + msgdec = new JMSMessage(this); + } + + if (msgdec != null) + { + _decodedMessages.put(type, msgdec); + } + + return msgdec; + } + + public boolean taken() + { + return _taken.getAndSet(true); + } + + public void release() + { + _taken.set(false); + } + public boolean checkToken(Object token) { if (_tokens.contains(token)) @@ -324,124 +453,215 @@ public class AMQMessage } } + /** + * 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 { - //if the message is not persistent or the queue is not durable - //we will not need to recover the association and so do not - //need to record it - if (isPersistent() && queue.isDurable()) - { - _store.enqueueMessage(queue.getName(), _messageId); - } + _transientMessageData.addDestinationQueue(queue); } - public void dequeue(AMQQueue queue) throws AMQException + public void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException { - //only record associations where both queue and message will survive - //a restart, so only need to remove association if this is the case - if (isPersistent() && queue.isDurable()) - { - _store.dequeueMessage(queue.getName(), _messageId); - } + _messageHandle.dequeue(storeContext, _messageId, queue); } public boolean isPersistent() throws AMQException { - if (_contentHeaderBody == null) + if (_transientMessageData != null) { - throw new AMQException("Cannot determine delivery mode of message. Content header not found."); + return _transientMessageData.isPersistent(); } + else + { + return _messageHandle.isPersistent(_messageId); + } + } - //todo remove literal values to a constant file such as AMQConstants in common - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties - && ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + /** + * 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 void setTxnBuffer(TxnBuffer buffer) + public BasicPublishBody getPublishBody() throws AMQException { - _txnBuffer = buffer; + BasicPublishBody pb; + if (_transientMessageData != null) + { + pb = _transientMessageData.getPublishBody(); + } + else + { + pb = _messageHandle.getPublishBody(_messageId); + } + return pb; } - public TxnBuffer getTxnBuffer() + public boolean isRedelivered() { - return _txnBuffer; + return _messageHandle.isRedelivered(); } - /** - * 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 + public void setRedelivered(boolean redelivered) { - if (isImmediate() && !_deliveredToConsumer) - { - throw new NoConsumersException(_publishBody, _contentHeaderBody, _contentBodies); - } + _messageHandle.setRedelivered(redelivered); } /** * Called when this message is delivered to a consumer. (used to * implement the 'immediate' flag functionality). - * And by selectors to determin if the message has already been sent */ public void setDeliveredToConsumer() { _deliveredToConsumer = true; } - /** - * Called selectors to determin if the message has already been sent - * @return _deliveredToConsumer - */ - public boolean getDeliveredToConsumer() + private void deliver(StoreContext storeContext) throws AMQException { - return _deliveredToConsumer; - } - + // we get a reference to the destination queues now so that we can clear the + // transient message data as quickly as possible + List destinationQueues = _transientMessageData.getDestinationQueues(); + try + { + // first we allow the handle to know that the message has been fully received. This is useful if it is + // maintaining any calculated values based on content chunks + _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, _transientMessageData.getPublishBody(), + _transientMessageData.getContentHeaderBody()); - public MessageDecorator getDecodedMessage(String type) - { - MessageDecorator msgtype = 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()); - if (_decodedMessages != null) - { - msgtype = _decodedMessages.get(type); + _transientMessageData = null; - if (msgtype == null) + for (AMQQueue q : destinationQueues) { - msgtype = decorateMessage(type); + _txnContext.deliver(this, q); } } - - return msgtype; + finally + { + destinationQueues.clear(); + decrementReference(storeContext); + } } - private MessageDecorator decorateMessage(String type) + public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, String consumerTag) + throws AMQException { - MessageDecorator msgdec = null; + ByteBuffer deliver = createEncodedDeliverFrame(channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); - if (type.equals(JMS_MESSAGE)) + 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()) { - msgdec = new JMSMessage(this); + 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); } - if (msgdec != null) + // + // Now start writing out the other content bodies + // + while (bodyFrameIterator.hasNext()) { - _decodedMessages.put(type, msgdec); + protocolSession.writeFrame(bodyFrameIterator.next()); } - return msgdec; } - public boolean taken() + private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, String consumerTag) + throws AMQException { - return _taken.getAndSet(true); + BasicPublishBody pb = getPublishBody(); + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, (byte) 8, (byte) 0, consumerTag, + deliveryTag, pb.exchange, _messageHandle.isRedelivered(), + pb.routingKey); + ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? + deliverFrame.writePayload(buf); + buf.flip(); + return buf; } - public void release() + private ByteBuffer createEncodedReturnFrame(int channelId, int replyCode, String replyText) throws AMQException { - _taken.set(false); + AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, (byte) 8, (byte) 0, getPublishBody().exchange, + replyCode, replyText, + getPublishBody().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()); + } + } + + public String toString() + { + return "Message: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + + _taken; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java new file mode 100644 index 0000000000..ef5d460b9b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +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(long messageId) throws AMQException; + + /** + * @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(StoreContext storeContext, long messageId, ContentBody contentBody) throws AMQException; + + BasicPublishBody getPublishBody(long messageId) throws AMQException; + + boolean isRedelivered(); + + void setRedelivered(boolean redelivered); + + boolean isPersistent(long messageId) throws AMQException; + + void setPublishAndContentHeaderBody(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException; + + void removeMessage(StoreContext storeContext, long messageId) throws AMQException; + + void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException; + + void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException; +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 101a2833a0..6f1018e753 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,8 +27,7 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.server.txn.TxnOp; +import org.apache.qpid.server.store.StoreContext; import javax.management.JMException; import java.text.MessageFormat; @@ -344,17 +343,17 @@ public class AMQQueue implements Managable, Comparable /** * Removes the AMQMessage from the top of the queue. */ - public void deleteMessageFromTop() throws AMQException + public void deleteMessageFromTop(StoreContext storeContext) throws AMQException { - _deliveryMgr.removeAMessageFromTop(); + _deliveryMgr.removeAMessageFromTop(storeContext); } /** * removes all the messages from the queue. */ - public void clearQueue() throws AMQException + public void clearQueue(StoreContext storeContext) throws AMQException { - _deliveryMgr.clearAllMessages(); + _deliveryMgr.clearAllMessages(storeContext); } public void bind(String routingKey, Exchange exchange) @@ -378,7 +377,7 @@ public class AMQQueue implements Managable, Comparable { if (_deliveryMgr.hasQueuedMessages()) { - _deliveryMgr.populatePreDeliveryQueue(subscription); + _deliveryMgr.populatePreDeliveryQueue(subscription); } } @@ -443,30 +442,9 @@ public class AMQQueue implements Managable, Comparable delete(); } - public void deliver(AMQMessage msg) throws AMQException + public void process(StoreContext storeContext, AMQMessage msg) throws AMQException { - TxnBuffer buffer = msg.getTxnBuffer(); - if (buffer == null) - { - //non-transactional - record(msg); - process(msg); - } - else - { - buffer.enlist(new Deliver(msg)); - } - } - - private void record(AMQMessage msg) throws AMQException - { - msg.enqueue(this); - msg.incrementReference(); - } - - private void process(AMQMessage msg) throws FailedDequeueException - { - _deliveryMgr.deliver(getName(), msg); + _deliveryMgr.deliver(storeContext, getName(), msg); try { msg.checkDeliveredToConsumer(); @@ -476,16 +454,16 @@ public class AMQQueue implements Managable, Comparable { // as this message will be returned, it should be removed // from the queue: - dequeue(msg); + dequeue(storeContext, msg); } } - void dequeue(AMQMessage msg) throws FailedDequeueException + void dequeue(StoreContext storeContext, AMQMessage msg) throws FailedDequeueException { try { - msg.dequeue(this); - msg.decrementReference(); + msg.dequeue(storeContext, this); + msg.decrementReference(storeContext); } catch (MessageCleanupException e) { @@ -511,10 +489,17 @@ public class AMQQueue implements Managable, Comparable return _subscribers; } - protected void updateReceivedMessageCount(AMQMessage msg) + protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException { _totalMessagesReceived++; - _managedObject.checkForNotification(msg); + try + { + _managedObject.checkForNotification(msg); + } + catch (JMException e) + { + throw new AMQException("Unable to get notification from manage queue: " + e, e); + } } public boolean equals(Object o) @@ -550,45 +535,4 @@ public class AMQQueue implements Managable, Comparable _logger.debug(MessageFormat.format(msg, args)); } } - - private class Deliver implements TxnOp - { - private final AMQMessage _msg; - - Deliver(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - //do the persistent part of the record() - _msg.enqueue(AMQQueue.this); - } - - public void undoPrepare() - { - } - - public void commit() - { - //do the memeory part of the record() - _msg.incrementReference(); - //then process the message - try - { - process(_msg); - } - catch (FailedDequeueException e) - { - //TODO: is there anything else we can do here? I think not... - _logger.error("Error during commit of a queue delivery: " + e, e); - } - } - - public void rollback() - { - } - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 1bdf265a1b..77bbdf7b4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -20,6 +20,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -35,6 +36,7 @@ import javax.management.OperationsException; import javax.management.monitor.MonitorNotification; import java.util.List; import java.util.ArrayList; +import java.util.Iterator; /** * MBean class for AMQQueue. It implements all the management features exposed @@ -43,6 +45,12 @@ import java.util.ArrayList; @MBeanDescription("Management Interface for AMQQueue") public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue { + /** + * Since the MBean is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + private StoreContext _storeContext = new StoreContext(); + private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method @@ -165,7 +173,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue /** * returns the size of messages(KB) in the queue. */ - public Long getQueueDepth() + public Long getQueueDepth() throws JMException { List list = _queue.getMessagesOnTheQueue(); if (list.size() == 0) @@ -174,9 +182,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue } long queueDepth = 0; - for (AMQMessage message : list) + try { - queueDepth = queueDepth + getMessageSize(message); + for (AMQMessage message : list) + { + queueDepth = queueDepth + getMessageSize(message); + } + } + catch (AMQException e) + { + throw new JMException("Unable to get message size: " + e); } return (long) Math.round(queueDepth / 1000); } @@ -184,7 +199,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue /** * returns size of message in bytes */ - private long getMessageSize(AMQMessage msg) + private long getMessageSize(AMQMessage msg) throws AMQException { if (msg == null) { @@ -197,7 +212,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue /** * Checks if there is any notification to be send to the listeners */ - public void checkForNotification(AMQMessage msg) + public void checkForNotification(AMQMessage msg) throws AMQException, JMException { // Check for threshold message count Integer msgCount = getMessageCount(); @@ -233,13 +248,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue } /** - * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop() + * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop */ public void deleteMessageFromTop() throws JMException { try { - _queue.deleteMessageFromTop(); + _queue.deleteMessageFromTop(_storeContext); } catch (AMQException ex) { @@ -248,13 +263,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue } /** - * @see org.apache.qpid.server.queue.AMQQueue#clearQueue() + * @see org.apache.qpid.server.queue.AMQQueue#clearQueue */ public void clearQueue() throws JMException { try { - _queue.clearQueue(); + _queue.clearQueue(_storeContext); } catch (AMQException ex) { @@ -273,11 +288,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } // get message content - List cBodies = msg.getContentBodies(); + Iterator cBodies = msg.getContentBodyIterator(); List msgContent = new ArrayList(); - if (cBodies != null) + while (cBodies.hasNext()) { - for (ContentBody body : cBodies) + ContentBody body = cBodies.next(); + if (body.getSize() != 0) { if (body.getSize() != 0) { @@ -290,17 +306,23 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue } } - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) + try { - mimeType = headerProperties.getContentType(); - encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; + String mimeType = null, encoding = null; + if (headerProperties != null) + { + mimeType = headerProperties.getContentType(); + encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + } + Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + } + catch (AMQException e) + { + throw new JMException("Error creating header attributes list: " + e); } - Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; - - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); } /** @@ -317,17 +339,24 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue List list = _queue.getMessagesOnTheQueue(); TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - // Create the tabular list of message header contents - for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) + try { - AMQMessage msg = list.get(i - 1); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; - String[] headerAttributes = headerProperties.toString().split(","); - Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); - _messageList.put(messageData); + // Create the tabular list of message header contents + for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) + { + AMQMessage msg = list.get(i - 1); + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + String[] headerAttributes = headerProperties.toString().split(","); + Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + _messageList.put(messageData); + } + } + catch (AMQException e) + { + throw new JMException("Error creating message contents: " + e); } return _messageList; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java index 022d3b9635..a2898ccdce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,18 +22,17 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.ContentBody; import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Queue; import java.util.concurrent.Executor; -import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; /** @@ -46,16 +45,19 @@ public class ConcurrentDeliveryManager implements DeliveryManager @Configured(path = "advanced.compressBufferOnQueue", defaultValue = "false") public boolean compressBufferOnQueue; + /** * Holds any queued messages */ private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); + //private int _messageCount; /** * Ensures that only one asynchronous task is running for this manager at * any time. */ private final AtomicBoolean _processing = new AtomicBoolean(); + /** * The subscriptions on the queue to whom messages are delivered */ @@ -67,7 +69,6 @@ public class ConcurrentDeliveryManager implements DeliveryManager */ private final AMQQueue _queue; - /** * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered @@ -77,7 +78,6 @@ public class ConcurrentDeliveryManager implements DeliveryManager */ private ReentrantLock _lock = new ReentrantLock(); - ConcurrentDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -101,14 +101,13 @@ public class ConcurrentDeliveryManager implements DeliveryManager return hasQueuedMessages(); } - /** * @param msg to enqueue * @return true if we are queue this message */ - private boolean enqueue(AMQMessage msg) + private boolean enqueue(AMQMessage msg) throws AMQException { - if (msg.isImmediate()) + if (msg.getPublishBody().immediate) { return false; } @@ -133,9 +132,9 @@ public class ConcurrentDeliveryManager implements DeliveryManager } } - private void startQueueing(AMQMessage msg) + private void startQueueing(AMQMessage msg) throws AMQException { - if (!msg.isImmediate()) + if (!msg.getPublishBody().immediate) { addMessageToQueue(msg); } @@ -143,7 +142,10 @@ public class ConcurrentDeliveryManager implements DeliveryManager private boolean addMessageToQueue(AMQMessage msg) { - // Shrink the ContentBodies to their actual size to save memory. + // Shrink the ContentBodies to their actual size to save memory. + /* TODO need to reimplement this - probably not in this class though + * for obvious reasons + if (compressBufferOnQueue) { Iterator it = msg.getContentBodies().iterator(); @@ -153,16 +155,14 @@ public class ConcurrentDeliveryManager implements DeliveryManager cb.reduceBufferToFit(); } } - + */ _messages.offer(msg); return true; } - public boolean hasQueuedMessages() { - _lock.lock(); try { @@ -172,8 +172,6 @@ public class ConcurrentDeliveryManager implements DeliveryManager { _lock.unlock(); } - - } public int getQueueMessageCount() @@ -203,21 +201,21 @@ public class ConcurrentDeliveryManager implements DeliveryManager //no-op . This DM has no PreDeliveryQueues } - public synchronized void removeAMessageFromTop() throws AMQException + public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); if (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); } } - public synchronized void clearAllMessages() throws AMQException + public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); while (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); msg = poll(); } } @@ -226,7 +224,7 @@ public class ConcurrentDeliveryManager implements DeliveryManager * Only one thread should ever execute this method concurrently, but * it can do so while other threads invoke deliver(). */ - private void processQueue() + private void processQueue() throws AMQException { try { @@ -296,7 +294,7 @@ public class ConcurrentDeliveryManager implements DeliveryManager } } - public void deliver(String name, AMQMessage msg) throws FailedDequeueException + public void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException { // first check whether we are queueing, and enqueue if we are if (!enqueue(msg)) @@ -308,7 +306,7 @@ public class ConcurrentDeliveryManager implements DeliveryManager Subscription s = _subscriptions.nextSubscriber(msg); if (s == null) { - if (!msg.isImmediate()) + if (!msg.getPublishBody().immediate) { // no subscribers yet so enter 'queueing' mode and queue this message startQueueing(msg); @@ -333,7 +331,18 @@ public class ConcurrentDeliveryManager implements DeliveryManager boolean running = true; while (running) { - processQueue(); + try + { + processQueue(); + } + catch (AMQException e) + { + _log.error("Error processing queue: " + e, e); + _log.error("Delivery manager terminating."); + running = false; + _processing.set(false); + break; + } //Check that messages have not been added since we did our last peek(); // Synchronize with the thread that adds to the queue. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index f09e8213b1..8f0c3a5ec7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -26,6 +26,7 @@ import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.store.StoreContext; import java.util.ArrayList; import java.util.Iterator; @@ -99,10 +100,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // Shrink the ContentBodies to their actual size to save memory. if (compressBufferOnQueue) { - Iterator it = msg.getContentBodies().iterator(); + Iterator it = msg.getContentBodyIterator(); while (it.hasNext()) { - ContentBody cb = (ContentBody) it.next(); + ContentBody cb = it.next(); cb.reduceBufferToFit(); } } @@ -167,21 +168,21 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - public synchronized void removeAMessageFromTop() throws AMQException + public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); if (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); } } - public synchronized void clearAllMessages() throws AMQException + public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); while (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); msg = poll(); } } @@ -223,7 +224,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //remove sent message from our queue. messageQueue.poll(); } - catch (FailedDequeueException e) + catch (AMQException e) { message.release(); _log.error("Unable to deliver message as dequeue failed: " + e, e); @@ -279,11 +280,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return _messages.poll(); } - public void deliver(String name, AMQMessage msg) throws FailedDequeueException + public void deliver(StoreContext context, String name, AMQMessage msg) throws AMQException { if (_log.isDebugEnabled()) { - _log.debug(id() + "deliver :" + System.identityHashCode(msg)); + _log.debug(id() + "deliver :" + msg); } //Check if we have someone to deliver the message to. @@ -296,9 +297,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Testing Message(" + System.identityHashCode(msg) + ") for Queued Delivery"); + _log.debug(id() + "Testing Message(" + msg + ") for Queued Delivery"); } - if (!msg.isImmediate()) + if (!msg.getPublishBody().immediate) { addMessageToQueue(msg); @@ -308,7 +309,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //Pre Deliver to all subscriptions if (_log.isDebugEnabled()) { - _log.debug(id() + "We have " + _subscriptions.getSubscriptions().size() + + _log.debug(id() + "We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to."); } for (Subscription sub : _subscriptions.getSubscriptions()) @@ -330,7 +331,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Queuing message(" + System.identityHashCode(msg) + + _log.debug(id() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); } sub.enqueueForPreDelivery(msg); @@ -345,7 +346,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (_log.isDebugEnabled()) { - _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + + _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + System.identityHashCode(s) + ") :" + s); } //Deliver the message diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index cac499587f..82d8f9538f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; import java.util.concurrent.Executor; import java.util.List; @@ -66,11 +67,11 @@ interface DeliveryManager * @param msg the message to deliver * @throws org.apache.qpid.server.queue.FailedDequeueException if the message could not be dequeued */ - void deliver(String name, AMQMessage msg) throws FailedDequeueException; + void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException; - void removeAMessageFromTop() throws AMQException; + void removeAMessageFromTop(StoreContext storeContext) throws AMQException; - void clearAllMessages() throws AMQException; + void clearAllMessages(StoreContext storeContext) throws AMQException; List getMessages(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java new file mode 100644 index 0000000000..e2758ce6cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -0,0 +1,133 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +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(long messageId) + { + 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(StoreContext storeContext, long messageId, ContentBody contentBody) + throws AMQException + { + _contentBodies.add(contentBody); + } + + public BasicPublishBody getPublishBody(long messageId) throws AMQException + { + return _publishBody; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + + public void setRedelivered(boolean redelivered) + { + _redelivered = 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(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + _publishBody = publishBody; + _contentHeaderBody = contentHeaderBody; + } + + public void removeMessage(StoreContext storeContext, long messageId) throws AMQException + { + // NO OP + } + + public void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + { + // NO OP + } + + public void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + { + // NO OP + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index de5d0f55a7..c36cc6bd7b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,11 +23,12 @@ 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 javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; import java.io.IOException; /** @@ -70,7 +71,7 @@ public interface ManagedQueue * @throws IOException */ @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue") - Long getQueueDepth() throws IOException; + Long getQueueDepth() throws IOException, JMException; /** * Returns the total number of active subscribers to the queue. @@ -184,7 +185,7 @@ public interface ManagedQueue description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, @MBeanOperationParameter(name="to index", description="to index")int toIndex) - throws IOException, JMException; + throws IOException, JMException, AMQException; @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java new file mode 100644 index 0000000000..a7ada2c1f8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java new file mode 100644 index 0000000000..deed18c188 --- /dev/null +++ b/qpid/java/broker/src/main/java/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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java index 2d37b806f6..2049189e0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -20,13 +20,8 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.protocol.AMQConstant; - -import java.util.List; +import org.apache.qpid.server.RequiredDeliveryException; /** * Signals that no consumers exist for a message at a given point in time. @@ -35,19 +30,9 @@ import java.util.List; */ public class NoConsumersException extends RequiredDeliveryException { - public NoConsumersException(String queue, - BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) - { - super("Immediate delivery to " + queue + " is not possible.", publishBody, contentHeaderBody, contentBodies); - } - - public NoConsumersException(BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) + public NoConsumersException(AMQMessage message) { - super("Immediate delivery is not possible.", publishBody, contentHeaderBody, contentBodies); + super("Immediate delivery is not possible.", message); } public int getReplyCode() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index a5672f2b19..2dab551e07 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,11 +26,11 @@ import java.util.Queue; public interface Subscription { - void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException; + void send(AMQMessage msg, AMQQueue queue) throws AMQException; boolean isSuspended(); - void queueDeleted(AMQQueue queue); + void queueDeleted(AMQQueue queue) throws AMQException; boolean hasFilters(); @@ -44,5 +44,5 @@ public interface Subscription void close(); - boolean isBrowser(); + boolean isBrowser(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 78310e8eb3..0dc1f3b0c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,18 +23,18 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.common.ClientProperties; import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicCancelOkBody; import org.apache.qpid.framing.BasicDeliverBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.BasicCancelOkBody; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import java.util.Queue; @@ -201,7 +201,7 @@ public class SubscriptionImpl implements Subscription * @param queue * @throws AMQException */ - public void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + public void send(AMQMessage msg, AMQQueue queue) throws AMQException { if (msg != null) { @@ -211,7 +211,7 @@ public class SubscriptionImpl implements Subscription } else { - sendToConsumer(msg, queue); + sendToConsumer(channel.getStoreContext(), msg, queue); } } else @@ -220,7 +220,7 @@ public class SubscriptionImpl implements Subscription } } - private void sendToBrowser(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + private void sendToBrowser(AMQMessage msg, AMQQueue queue) throws AMQException { // We don't decrement the reference here as we don't want to consume the message // but we do want to send it to the client. @@ -235,14 +235,12 @@ public class SubscriptionImpl implements Subscription { channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); } - ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); - AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); - - protocolSession.writeFrame(frame); + msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); } } - private void sendToConsumer(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + private void sendToConsumer(StoreContext storeContext, AMQMessage msg, AMQQueue queue) + throws AMQException { try { @@ -257,7 +255,11 @@ public class SubscriptionImpl implements Subscription // the message is unacked, it will be lost. if (!_acks) { - queue.dequeue(msg); + if (_logger.isDebugEnabled()) + { + _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); + } + queue.dequeue(storeContext, msg); } synchronized(channel) { @@ -268,10 +270,7 @@ public class SubscriptionImpl implements Subscription channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); } - ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); - AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); - - protocolSession.writeFrame(frame); + msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); } } finally @@ -290,7 +289,7 @@ public class SubscriptionImpl implements Subscription * * @param queue */ - public void queueDeleted(AMQQueue queue) + public void queueDeleted(AMQQueue queue) throws AMQException { channel.queueDeleted(queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index 91e720ea54..8272202571 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -204,7 +204,7 @@ class SubscriptionSet implements WeightedSubscriptionManager * * @param queue */ - public void queueDeleted(AMQQueue queue) + public void queueDeleted(AMQQueue queue) throws AMQException { for (Subscription s : _subscriptions) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java index c967ea2cde..f290452058 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; import org.apache.log4j.Logger; import java.util.LinkedList; @@ -41,11 +42,13 @@ class SynchronizedDeliveryManager implements DeliveryManager * 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 */ @@ -70,9 +73,9 @@ class SynchronizedDeliveryManager implements DeliveryManager _queue = queue; } - private synchronized boolean enqueue(AMQMessage msg) + private synchronized boolean enqueue(AMQMessage msg) throws AMQException { - if (msg.isImmediate()) + if (msg.getPublishBody().immediate) { return false; } @@ -90,7 +93,7 @@ class SynchronizedDeliveryManager implements DeliveryManager } } - private synchronized void startQueueing(AMQMessage msg) + private synchronized void startQueueing(AMQMessage msg) throws AMQException { _queueing = true; enqueue(msg); @@ -127,21 +130,21 @@ class SynchronizedDeliveryManager implements DeliveryManager //no-op . This DM has no PreDeliveryQueues } - public synchronized void removeAMessageFromTop() throws AMQException + public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); if (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); } } - public synchronized void clearAllMessages() throws AMQException + public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); while (msg != null) { - msg.dequeue(_queue); + msg.dequeue(storeContext, _queue); msg = poll(); } } @@ -231,7 +234,7 @@ class SynchronizedDeliveryManager implements DeliveryManager * @throws NoConsumersException if there are no active subscribers to deliver * the message to */ - public void deliver(String name, AMQMessage msg) throws FailedDequeueException + public void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException { // first check whether we are queueing, and enqueue if we are if (!enqueue(msg)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java new file mode 100644 index 0000000000..0c50dc5207 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -0,0 +1,118 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.LinkedList; + +/** + * Contains data that is only used in AMQMessage transiently, e.g. while the content + * body fragments are arriving. + * + * Having this data stored in a separate class means that the AMQMessage class avoids + * the small overhead of numerous guaranteed-null references. + * + * @author Apache Software Foundation + */ +public class TransientMessageData +{ + /** + * Stored temporarily until the header has been received at which point it is used when + * constructing the handle + */ + private 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; + + /** + * 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(); + + public BasicPublishBody getPublishBody() + { + return _publishBody; + } + + public void setPublishBody(BasicPublishBody publishBody) + { + _publishBody = publishBody; + } + + public List getDestinationQueues() + { + return _destinationQueues; + } + + public void setDestinationQueues(List destinationQueues) + { + _destinationQueues = destinationQueues; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public long getBodyLengthReceived() + { + return _bodyLengthReceived; + } + + public void addBodyLength(int value) + { + _bodyLengthReceived += value; + } + + public boolean isAllContentReceived() throws AMQException + { + return _bodyLengthReceived == _contentHeaderBody.bodySize; + } + + public void addDestinationQueue(AMQQueue queue) + { + _destinationQueues.add(queue); + } + + public boolean isPersistent() + { + //todo remove literal values to a constant file such as AMQConstants in common + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java new file mode 100644 index 0000000000..2fb2bdd2e3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -0,0 +1,190 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +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 org.apache.qpid.server.store.StoreContext; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class WeakReferenceMessageHandle implements AMQMessageHandle +{ + private WeakReference _contentHeaderBody; + + private WeakReference _publishBody; + + private List> _contentBodies; + + private boolean _redelivered; + + private final MessageStore _messageStore; + + public WeakReferenceMessageHandle(MessageStore messageStore) + { + _messageStore = messageStore; + } + + public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException + { + ContentHeaderBody chb = (_contentHeaderBody != null?_contentHeaderBody.get():null); + 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(long messageId) throws AMQException + { + if (_contentBodies == null) + { + MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + int chunkCount = mmd.getContentChunkCount(); + _contentBodies = new ArrayList>(chunkCount); + for (int i = 0; i < chunkCount; i++) + { + _contentBodies.add(new WeakReference(null)); + } + } + 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; + } + + /** + * Content bodies are set before the publish and header frames + * @param storeContext + * @param messageId + * @param contentBody + * @throws AMQException + */ + public void addContentBodyFrame(StoreContext storeContext, long messageId, ContentBody contentBody) throws AMQException + { + if (_contentBodies == null) + { + _contentBodies = new LinkedList>(); + } + _contentBodies.add(new WeakReference(contentBody)); + _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody); + } + + public BasicPublishBody getPublishBody(long messageId) throws AMQException + { + BasicPublishBody bpb = (_publishBody != null?_publishBody.get():null); + 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 void setRedelivered(boolean redelivered) + { + _redelivered = 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(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + // if there are no content bodies the list will be null so we must + // create en empty list here + if (contentHeaderBody.bodySize == 0) + { + _contentBodies = new LinkedList>(); + } + _messageStore.storeMessageMetaData(storeContext, messageId, new MessageMetaData(publishBody, contentHeaderBody, + _contentBodies.size())); + _publishBody = new WeakReference(publishBody); + _contentHeaderBody = new WeakReference(contentHeaderBody); + } + + public void removeMessage(StoreContext storeContext, long messageId) throws AMQException + { + _messageStore.removeMessage(storeContext, messageId); + } + + public void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + { + _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); + } + + public void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + { + _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 328aed81d9..edf2386314 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,10 +23,12 @@ package org.apache.qpid.server.store; import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.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; @@ -43,21 +45,25 @@ public class MemoryMessageStore implements MessageStore private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity"; - protected ConcurrentMap _messageMap; + 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 table"); - _messageMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); + _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 table"); - _messageMap = new ConcurrentHashMap(hashtableCapacity); + _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 @@ -67,70 +73,71 @@ public class MemoryMessageStore implements MessageStore public void close() throws Exception { - if (_messageMap != null) + if (_metaDataMap != null) { - _messageMap.clear(); - _messageMap = null; + _metaDataMap.clear(); + _metaDataMap = null; + } + if (_contentBodyMap != null) + { + _contentBodyMap.clear(); + _contentBodyMap = null; } } - public void put(AMQMessage msg) - { - _messageMap.put(msg.getMessageId(), msg); - } - - public void removeMessage(long messageId) + public void removeMessage(StoreContext context, long messageId) { if (_log.isDebugEnabled()) { _log.debug("Removing message with id " + messageId); } - _messageMap.remove(messageId); + _metaDataMap.remove(messageId); + _contentBodyMap.remove(messageId); } public void createQueue(AMQQueue queue) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } public void removeQueue(String name) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public void enqueueMessage(String name, long messageId) throws AMQException + public void enqueueMessage(StoreContext context, String name, long messageId) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public void dequeueMessage(String name, long messageId) throws AMQException + public void dequeueMessage(StoreContext context, String name, long messageId) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public void beginTran() throws AMQException + public void beginTran(StoreContext context) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public void commitTran() throws AMQException + public void commitTran(StoreContext context) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public void abortTran() throws AMQException + public void abortTran(StoreContext context) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + // Not required to do anything } - public boolean inTran() + public boolean inTran(StoreContext context) { return false; } public List createQueues() throws AMQException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public long getNewMessageId() @@ -138,8 +145,33 @@ public class MemoryMessageStore implements MessageStore return _messageId.getAndIncrement(); } - public AMQMessage getMessage(long messageId) + public void storeContentBodyChunk(StoreContext context, 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(StoreContext context, 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 { - return _messageMap.get(messageId); + List bodyList = _contentBodyMap.get(messageId); + return bodyList.get(index); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 8ee1d09862..973c661c06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,8 +22,9 @@ package org.apache.qpid.server.store; import org.apache.commons.configuration.Configuration; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.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; @@ -37,34 +38,33 @@ public interface MessageStore * @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 + * @throws Exception if close fails */ void close() throws Exception; - void put(AMQMessage msg) throws AMQException; - - void removeMessage(long messageId) throws AMQException; + void removeMessage(StoreContext storeContext, 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 enqueueMessage(StoreContext context, String name, long messageId) throws AMQException; - void dequeueMessage(String name, long messageId) throws AMQException; + void dequeueMessage(StoreContext context, String name, long messageId) throws AMQException; - void beginTran() throws AMQException; + void beginTran(StoreContext context) throws AMQException; - void commitTran() throws AMQException; + void commitTran(StoreContext context) throws AMQException; - void abortTran() throws AMQException; + void abortTran(StoreContext context) throws AMQException; - boolean inTran(); + boolean inTran(StoreContext context); /** * Recreate all queues that were persisted, including re-enqueuing of existing messages @@ -78,6 +78,13 @@ public interface MessageStore * @return a message id */ long getNewMessageId(); -} + void storeContentBodyChunk(StoreContext context, long messageId, int index, ContentBody contentBody) throws AMQException; + void storeMessageMetaData(StoreContext context, long messageId, MessageMetaData messageMetaData) throws AMQException; + + MessageMetaData getMessageMetaData(long messageId) throws AMQException; + + ContentBody getContentBodyChunk(long messageId, int index) throws AMQException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java new file mode 100644 index 0000000000..55e5067852 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +/** + * A context that the store can use to associate with a transactional context. For example, it could store + * some kind of txn id. + * + * @author Apache Software Foundation + */ +public class StoreContext +{ + private Object _payload; + + public Object getPayload() + { + return _payload; + } + + public void setPayload(Object payload) + { + _payload = payload; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java new file mode 100644 index 0000000000..6d5d3c42f3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 org.apache.qpid.server.store.StoreContext; + +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(StoreContext context) 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(StoreContext context) + { + //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(context); + } + 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(StoreContext context) + { + // NO OP + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java new file mode 100644 index 0000000000..3934943665 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java @@ -0,0 +1,74 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.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; +import org.apache.qpid.server.store.StoreContext; + +/** + * @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(StoreContext context) throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit(StoreContext context) + { + //do the memeory part of the record() + _msg.incrementReference(); + //then process the message + try + { + _queue.process(context, _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(StoreContext storeContext) + { + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java new file mode 100644 index 0000000000..ff6abdd58b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -0,0 +1,148 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +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 final StoreContext _storeContext; + + private boolean _inTran = false; + + public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, + TxnBuffer txnBuffer, List returnMessages) + { + _messageStore = messageStore; + _storeContext = storeContext; + _txnBuffer = txnBuffer; + _returnMessages = returnMessages; + _txnBuffer.enlist(new StoreMessageOperation(messageStore)); + } + + public void rollback() throws AMQException + { + _txnBuffer.rollback(_storeContext); + } + + public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + { + // A publication will result in the enlisting of several + // TxnOps. The first is an op that will store the message. + // Following that (and ordering is important), an op will + // be added for every queue onto which the message is + // enqueued. 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 messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + // Not required in this transactional context + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(_storeContext); + _inTran = true; + } + } + + public void commit() throws AMQException + { + if (_ackOp != null) + { + _ackOp.consolidate(); + //already enlisted, after commit will reset regardless of outcome + _ackOp = null; + } + + _txnBuffer.commit(_storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java new file mode 100644 index 0000000000..f09d811b50 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -0,0 +1,208 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.protocol.AMQProtocolSession; +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 org.apache.qpid.server.store.StoreContext; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * @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 Set _browsedAcks; + + private final MessageStore _messageStore; + + private StoreContext _storeContext; + + /** + * Whether we are in a transaction + */ + private boolean _inTran; + + public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, + List returnMessages, Set browsedAcks) + { + _channel = channel; + _storeContext = storeContext; + _returnMessages = returnMessages; + _messageStore = messageStore; + _browsedAcks = browsedAcks; + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(_storeContext); + _inTran = true; + } + } + + public void commit() throws AMQException + { + // Does not apply to this context + } + + public void rollback() throws AMQException + { + // Does not apply to this context + } + + public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + { + try + { + message.incrementReference(); + queue.process(_storeContext, 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 + { + if (!_browsedAcks.contains(deliveryTag)) + { + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + message.message.getMessageId()); + } + message.discard(_storeContext); + } + else + { + _browsedAcks.remove(deliveryTag); + } + 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) + { + if (!_browsedAcks.contains(deliveryTag)) + { + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + msg.message.getMessageId()); + } + msg.discard(_storeContext); + } + else + { + _browsedAcks.remove(deliveryTag); + } + } + } + } + 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(_storeContext); + if (_log.isDebugEnabled()) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + + msg.message.getMessageId()); + } + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + if (persistent) + { + _messageStore.commitTran(_storeContext); + _inTran = false; + } + } + + public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + _channel.processReturns(protocolSession); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java new file mode 100644 index 0000000000..0e4d6c2030 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** + * A transactional operation to store messages in an underlying persistent store. When this operation + * commits it will do everything to ensure that all messages are safely committed to persistent + * storage. + */ +public class StoreMessageOperation implements TxnOp +{ + private final MessageStore _messsageStore; + + public StoreMessageOperation(MessageStore messageStore) + { + _messsageStore = messageStore; + } + + public void prepare(StoreContext context) throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit(StoreContext context) throws AMQException + { + _messsageStore.commitTran(context); + } + + public void rollback(StoreContext context) throws AMQException + { + _messsageStore.abortTran(context); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java new file mode 100644 index 0000000000..bba4b98de4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.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; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +/** + * @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; + + void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java index 402065d5e1..069caf0ae1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,91 +22,63 @@ package org.apache.qpid.server.txn; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; import java.util.ArrayList; import java.util.List; /** * Holds a list of TxnOp instance representing transactional - * operations. + * 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() + public TxnBuffer() { - _containsPersistentChanges = true; } - public void commit() throws AMQException + public void commit(StoreContext context) throws AMQException { - if (_containsPersistentChanges) + if (prepare(context)) { - _log.debug("Begin Transaction."); - _store.beginTran(); - if(prepare()) + for (TxnOp op : _ops) { - _log.debug("Transaction Succeeded"); - _store.commitTran(); - for (TxnOp op : _ops) - { - op.commit(); - } + op.commit(context); } - else - { - _log.debug("Transaction Failed"); - _store.abortTran(); - } - }else{ - if(prepare()) - { - for (TxnOp op : _ops) - { - op.commit(); - } - } } _ops.clear(); } - private boolean prepare() - { + private boolean prepare(StoreContext context) + { for (int i = 0; i < _ops.size(); i++) { TxnOp op = _ops.get(i); try { - op.prepare(); + op.prepare(context); } - catch(Exception e) + 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 + public void rollback(StoreContext context) throws AMQException { for (TxnOp op : _ops) { - op.rollback(); + op.rollback(context); } _ops.clear(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java index e863bab73e..919c078cf0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,6 +21,7 @@ package org.apache.qpid.server.txn; import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; /** * This provides the abstraction of an individual operation within a @@ -29,14 +30,14 @@ import org.apache.qpid.AMQException; public interface TxnOp { /** - * Do the part of the operation that updates persistent state + * Do the part of the operation that updates persistent state */ - public void prepare() throws AMQException; + public void prepare(StoreContext context) throws AMQException; /** * Complete the operation started by prepare. Can now update in * memory state or make netork transfers. */ - public void commit(); + public void commit(StoreContext context) throws AMQException; /** * This is not the same as rollback. Unfortunately the use of an * in memory reference count as a locking mechanism and a test for @@ -50,5 +51,5 @@ public interface TxnOp /** * Rolls back the operation. */ - public void rollback(); + public void rollback(StoreContext context) throws AMQException; } -- cgit v1.2.1 From 2f297ac87909ed98c9d7dbb6dc725c294799d32f Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 8 Jan 2007 17:02:26 +0000 Subject: QPID-255 : Patch Supplied by Rob Godfrey - Change to use bespoke AMQShortString rather than converting to String git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494121 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 13 +++---- .../java/org/apache/qpid/server/AMQChannel.java | 23 ++++++------ .../qpid/server/ack/UnacknowledgedMessage.java | 5 +-- .../server/ack/UnacknowledgedMessageMapImpl.java | 3 +- .../configuration/VirtualHostConfiguration.java | 3 +- .../qpid/server/exchange/AbstractExchange.java | 11 +++--- .../server/exchange/DefaultExchangeFactory.java | 12 ++++--- .../server/exchange/DefaultExchangeRegistry.java | 9 ++--- .../qpid/server/exchange/DestNameExchange.java | 29 +++++++-------- .../qpid/server/exchange/DestWildExchange.java | 27 +++++++------- .../org/apache/qpid/server/exchange/Exchange.java | 15 ++++---- .../qpid/server/exchange/ExchangeFactory.java | 3 +- .../qpid/server/exchange/ExchangeRegistry.java | 5 +-- .../qpid/server/exchange/HeadersBinding.java | 9 ++--- .../qpid/server/exchange/HeadersExchange.java | 12 +++---- .../org/apache/qpid/server/exchange/Index.java | 15 ++++---- .../qpid/server/filter/FilterManagerFactory.java | 29 +++++++-------- .../qpid/server/filter/PropertyExpression.java | 2 +- .../server/handler/BasicConsumeMethodHandler.java | 11 +++--- .../server/handler/BasicPublishMethodHandler.java | 9 +++-- .../handler/ConnectionOpenMethodHandler.java | 7 ++-- .../handler/ConnectionStartOkMethodHandler.java | 2 +- .../qpid/server/handler/ExchangeBoundHandler.java | 23 ++++++------ .../qpid/server/handler/QueueDeclareHandler.java | 10 +++--- .../qpid/server/handler/QueueDeleteHandler.java | 2 +- .../apache/qpid/server/message/jms/JMSMessage.java | 42 +++++++++++----------- .../server/protocol/AMQMinaProtocolSession.java | 17 +++------ .../server/protocol/AMQPFastProtocolHandler.java | 2 +- .../qpid/server/protocol/AMQProtocolSession.java | 5 +-- .../server/protocol/AMQProtocolSessionMBean.java | 5 ++- .../qpid/server/protocol/ExchangeInitialiser.java | 3 +- .../org/apache/qpid/server/queue/AMQMessage.java | 8 ++--- .../org/apache/qpid/server/queue/AMQQueue.java | 33 ++++++++--------- .../apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../server/queue/ConcurrentDeliveryManager.java | 3 +- .../queue/ConcurrentSelectorDeliveryManager.java | 3 +- .../qpid/server/queue/DefaultQueueRegistry.java | 7 ++-- .../apache/qpid/server/queue/DeliveryManager.java | 3 +- .../apache/qpid/server/queue/ExchangeBindings.java | 9 ++--- .../apache/qpid/server/queue/QueueRegistry.java | 5 +-- .../qpid/server/queue/SubscriptionFactory.java | 5 +-- .../apache/qpid/server/queue/SubscriptionImpl.java | 23 ++++++------ .../server/queue/SynchronizedDeliveryManager.java | 3 +- .../server/queue/WeakReferenceMessageHandle.java | 4 +-- .../security/auth/AuthenticationManager.java | 2 ++ .../security/auth/NullAuthenticationManager.java | 1 + .../security/auth/SASLAuthenticationManager.java | 1 + .../security/auth/amqplain/AmqPlainSaslServer.java | 4 +-- 48 files changed, 246 insertions(+), 233 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 509f57be7f..d7326b4c64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import javax.management.JMException; import javax.management.MBeanException; @@ -81,10 +82,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { synchronized (_exchangeRegistry) { - Exchange exchange = _exchangeRegistry.getExchange(exchangeName); + Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); if (exchange == null) { - exchange = _exchangeFactory.createExchange(exchangeName, type, durable, autoDelete, 0); + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, autoDelete, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -114,7 +115,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr // when there are no bindings. try { - _exchangeRegistry.unregisterExchange(exchangeName, false); + _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); } catch (AMQException ex) { @@ -135,7 +136,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr public void createNewQueue(String queueName, boolean durable, String owner, boolean autoDelete) throws JMException { - AMQQueue queue = _queueRegistry.getQueue(queueName); + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue != null) { throw new JMException("The queue \"" + queueName + "\" already exists."); @@ -143,7 +144,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { - queue = new AMQQueue(queueName, durable, owner, autoDelete, _queueRegistry); + queue = new AMQQueue(new AMQShortString(queueName), durable, new AMQShortString(owner), autoDelete, _queueRegistry); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); @@ -164,7 +165,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr */ public void deleteQueue(String queueName) throws JMException { - AMQQueue queue = _queueRegistry.getQueue(queueName); + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue == null) { throw new JMException("The Queue " + queueName + " is not a registerd queue."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 999eb9f651..799b085fb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -22,10 +22,7 @@ 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.framing.FieldTable; +import org.apache.qpid.framing.*; import org.apache.qpid.server.ack.UnacknowledgedMessage; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; @@ -88,7 +85,7 @@ public class AMQChannel /** * Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */ - private final Map _consumerTag2QueueMap = new TreeMap(); + private final Map _consumerTag2QueueMap = new HashMap(); private final MessageStore _messageStore; @@ -270,12 +267,12 @@ public class AMQChannel * @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, + public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, FieldTable filters, boolean noLocal) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { - tag = "sgen_" + getNextConsumerTag(); + tag = new AMQShortString("sgen_" + getNextConsumerTag()); } if (_consumerTag2QueueMap.containsKey(tag)) { @@ -288,7 +285,7 @@ public class AMQChannel } - public void unsubscribeConsumer(AMQProtocolSession session, String consumerTag) throws AMQException + public void unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException { AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); if (q != null) @@ -312,7 +309,7 @@ public class AMQChannel private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException { _log.info("Unsubscribing all consumers on channel " + toString()); - for (Map.Entry me : _consumerTag2QueueMap.entrySet()) + for (Map.Entry me : _consumerTag2QueueMap.entrySet()) { me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); } @@ -327,7 +324,7 @@ public class AMQChannel * the delivery tag) * @param queue the queue from which the message was delivered */ - public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, String consumerTag, AMQQueue queue) + public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) { _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); checkSuspension(); @@ -362,7 +359,7 @@ public class AMQChannel public boolean callback(UnacknowledgedMessage message) throws AMQException { long deliveryTag = message.deliveryTag; - String consumerTag = message.consumerTag; + AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; msg.setRedelivered(true); msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); @@ -437,7 +434,7 @@ public class AMQChannel return _unacknowledgedMessageMap; } - public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, String consumerTag, AMQQueue queue) + public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) { _browsedAcks.add(deliveryTag); addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); @@ -524,7 +521,7 @@ public class AMQChannel for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); - message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), bouncedMessage.getMessage()); + message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index 26f41e19af..ac390718c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.ack; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.StoreContext; @@ -28,11 +29,11 @@ import org.apache.qpid.server.store.StoreContext; public class UnacknowledgedMessage { public final AMQMessage message; - public final String consumerTag; + public final AMQShortString consumerTag; public final long deliveryTag; public AMQQueue queue; - public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, String consumerTag, long deliveryTag) + public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, AMQShortString consumerTag, long deliveryTag) { this.queue = queue; this.message = message; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 1f4333549a..0677494134 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -24,6 +24,7 @@ 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 org.apache.qpid.framing.AMQShortString; import java.util.*; @@ -180,7 +181,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap for (Map.Entry entry : _map.entrySet()) { long deliveryTag = entry.getKey(); - String consumerTag = entry.getValue().consumerTag; + AMQShortString consumerTag = entry.getValue().consumerTag; AMQMessage msg = entry.getValue().message; msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 9ecbf3d31a..7e807304c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -29,6 +29,7 @@ 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.qpid.framing.AMQShortString; import org.apache.log4j.Logger; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; @@ -157,7 +158,7 @@ public class VirtualHostConfiguration private void bind(AMQBindingURL binding) throws AMQException, ConfigurationException { - String queueName = binding.getQueueName(); + AMQShortString queueName = binding.getQueueName(); // This will occur if the URL is a Topic if (queueName == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index d5ca567308..94c792c358 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -31,7 +32,7 @@ import javax.management.ObjectName; public abstract class AbstractExchange implements Exchange, Managable { - private String _name; + private AMQShortString _name; protected boolean _durable; protected String _exchangeType; @@ -58,12 +59,12 @@ public abstract class AbstractExchange implements Exchange, Managable public String getObjectInstanceName() { - return _name; + return _name.toString(); } public String getName() { - return _name; + return _name.toString(); } public String getExchangeType() @@ -95,7 +96,7 @@ public abstract class AbstractExchange implements Exchange, Managable } // End of MBean class - public String getName() + public AMQShortString getName() { return _name; } @@ -107,7 +108,7 @@ public abstract class AbstractExchange implements Exchange, Managable */ protected abstract ExchangeMBean createMBean() throws AMQException; - public void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException + public void initialise(AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException { _name = name; _durable = durable; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 0c73e0f9f0..222cd2aef2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; import java.util.HashMap; import java.util.Map; @@ -30,16 +32,16 @@ public class DefaultExchangeFactory implements ExchangeFactory { private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); - private Map> _exchangeClassMap = new HashMap>(); + 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); + _exchangeClassMap.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestNameExchange.class); + _exchangeClassMap.put(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestWildExchange.class); + _exchangeClassMap.put(ExchangeDefaults.HEADERS_EXCHANGE_CLASS, org.apache.qpid.server.exchange.HeadersExchange.class); } - public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, + public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 99c08ad200..cadcd22001 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; @@ -35,7 +36,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry /** * Maps from exchange name to exchange instance */ - private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); + private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); public DefaultExchangeRegistry(ExchangeFactory exchangeFactory) { @@ -55,7 +56,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry _exchangeMap.put(exchange.getName(), exchange); } - public void unregisterExchange(String name, boolean inUse) throws AMQException + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); @@ -69,7 +70,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry } } - public Exchange getExchange(String name) + public Exchange getExchange(AMQShortString name) { return _exchangeMap.get(name); } @@ -81,7 +82,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry */ public void routeContent(AMQMessage payload) throws AMQException { - final String exchange = payload.getPublishBody().exchange; + final AMQShortString 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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 7b28161263..dc65297615 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -24,6 +24,7 @@ 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.framing.AMQShortString; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -83,21 +84,21 @@ public class DestNameExchange extends AbstractExchange public TabularData bindings() throws OpenDataException { - Map> bindings = _index.getBindingsMap(); + Map> bindings = _index.getBindingsMap(); _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Map.Entry> entry : bindings.entrySet()) + for (Map.Entry> entry : bindings.entrySet()) { - String key = entry.getKey(); + AMQShortString key = entry.getKey(); List queueList = new ArrayList(); List queues = entry.getValue(); for (AMQQueue q : queues) { - queueList.add(q.getName()); + queueList.add(q.getName().toString()); } - Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -107,7 +108,7 @@ public class DestNameExchange extends AbstractExchange public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); @@ -115,8 +116,8 @@ public class DestNameExchange extends AbstractExchange try { - registerQueue(binding, queue, null); - queue.bind(binding, DestNameExchange.this); + registerQueue(new AMQShortString(binding), queue, null); + queue.bind(new AMQShortString(binding), DestNameExchange.this); } catch (AMQException ex) { @@ -140,7 +141,7 @@ public class DestNameExchange extends AbstractExchange } } - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; assert routingKey != null; @@ -154,7 +155,7 @@ public class DestNameExchange extends AbstractExchange } } - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException { assert queue != null; assert routingKey != null; @@ -169,7 +170,7 @@ public class DestNameExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { final BasicPublishBody publishBody = payload.getPublishBody(); - final String routingKey = publishBody.routingKey; + final AMQShortString routingKey = publishBody.routingKey; final List queues = (routingKey == null) ? null : _index.get(routingKey); if (queues == null || queues.isEmpty()) { @@ -197,13 +198,13 @@ public class DestNameExchange extends AbstractExchange } } - public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { final List queues = _index.get(routingKey); return queues != null && queues.contains(queue); } - public boolean isBound(String routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) throws AMQException { final List queues = _index.get(routingKey); return queues != null && !queues.isEmpty(); @@ -211,7 +212,7 @@ public class DestNameExchange extends AbstractExchange public boolean isBound(AMQQueue queue) throws AMQException { - Map> bindings = _index.getBindingsMap(); + Map> bindings = _index.getBindingsMap(); for (List queues : bindings.values()) { if (queues.contains(queue)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index c341f30ab6..179dc0e9ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -24,6 +24,7 @@ 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.framing.AMQShortString; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -43,7 +44,7 @@ public class DestWildExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(DestWildExchange.class); - private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); + private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); /** * DestWildExchangeMBean class implements the management interface for the @@ -87,18 +88,18 @@ public class DestWildExchange extends AbstractExchange public TabularData bindings() throws OpenDataException { _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Map.Entry> entry : _routingKey2queues.entrySet()) + for (Map.Entry> entry : _routingKey2queues.entrySet()) { - String key = entry.getKey(); + AMQShortString key = entry.getKey(); List queueList = new ArrayList(); List queues = entry.getValue(); for (AMQQueue q : queues) { - queueList.add(q.getName()); + queueList.add(q.getName().toString()); } - Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -108,14 +109,14 @@ public class DestWildExchange extends AbstractExchange public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(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); + registerQueue(new AMQShortString(binding), queue, null); + queue.bind(new AMQShortString(binding), DestWildExchange.this); } catch (AMQException ex) { @@ -126,7 +127,7 @@ public class DestWildExchange extends AbstractExchange } // End of MBean class - public synchronized void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; assert routingKey != null; @@ -154,7 +155,7 @@ public class DestWildExchange extends AbstractExchange { BasicPublishBody publishBody = payload.getPublishBody(); - final String routingKey = publishBody.routingKey; + final AMQShortString 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 @@ -175,14 +176,14 @@ public class DestWildExchange extends AbstractExchange } } - public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { List queues = _routingKey2queues.get(routingKey); return queues != null && queues.contains(queue); } - public boolean isBound(String routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) throws AMQException { List queues = _routingKey2queues.get(routingKey); return queues != null && !queues.isEmpty(); @@ -205,7 +206,7 @@ public class DestWildExchange extends AbstractExchange return !_routingKey2queues.isEmpty(); } - public synchronized void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + public synchronized void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException { assert queue != null; assert routingKey != null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 8ef5f0ab29..7ba9ddd5a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -22,14 +22,15 @@ 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.framing.AMQShortString; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; public interface Exchange { - String getName(); + AMQShortString getName(); - void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + void initialise(AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; boolean isDurable(); @@ -42,9 +43,9 @@ public interface Exchange void close() throws AMQException; - void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException; + void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException; + void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException; void route(AMQMessage message) throws AMQException; @@ -55,7 +56,7 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(String routingKey, AMQQueue queue) throws AMQException; + boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException; /** * Determines whether a message is routing to any queue using a specific routing key @@ -63,7 +64,7 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(String routingKey) throws AMQException; + boolean isBound(AMQShortString routingKey) throws AMQException; boolean isBound(AMQQueue queue) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index 37ba883bc3..e07fd0b8fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -21,11 +21,12 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; public interface ExchangeFactory { - Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, + Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index 4a0a6a0ee1..efcb963f8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; public interface ExchangeRegistry extends MessageRouter @@ -34,7 +35,7 @@ public interface ExchangeRegistry extends MessageRouter * @throws ExchangeInUseException when the exchange cannot be deleted because it is in use * @throws AMQException */ - void unregisterExchange(String name, boolean inUse) throws ExchangeInUseException, AMQException; + void unregisterExchange(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; - Exchange getExchange(String name); + Exchange getExchange(AMQShortString name); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index 1c63a5571e..cf10f219aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -34,7 +34,7 @@ class HeadersBinding { private static final Logger _logger = Logger.getLogger(HeadersBinding.class); - private final FieldTable _mappings = new FieldTable(); + private final FieldTable _mappings; private final Set required = new HashSet(); private final Map matches = new HashMap(); private boolean matchAny; @@ -91,12 +91,7 @@ class HeadersBinding HeadersBinding(FieldTable mappings) { - Enumeration propertyNames = mappings.getPropertyNames(); - while(propertyNames.hasMoreElements()) - { - String propName = (String) propertyNames.nextElement(); - _mappings.put(propName, mappings.getObject(propName)); - } + _mappings = mappings; initMappings(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index dcb64e2d30..e681cb4c47 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -110,7 +110,7 @@ public class HeadersExchange extends AbstractExchange for (Iterator itr = _bindings.iterator(); itr.hasNext();) { Registration registration = itr.next(); - String queueName = registration.queue.getName(); + String queueName = registration.queue.getName().toString(); HeadersBinding headers = registration.binding; FieldTable headerMappings = headers.getMappings(); @@ -149,7 +149,7 @@ public class HeadersExchange extends AbstractExchange */ public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { @@ -173,13 +173,13 @@ public class HeadersExchange extends AbstractExchange } // End of MBean class - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); _bindings.add(new Registration(new HeadersBinding(args), queue)); } - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException { _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); _bindings.remove(new Registration(null, queue)); @@ -223,12 +223,12 @@ public class HeadersExchange extends AbstractExchange } } - public boolean isBound(String routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { return isBound(queue); } - public boolean isBound(String routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) throws AMQException { return hasBindings(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index 485c4739bd..8527a68862 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.framing.AMQShortString; import java.util.List; import java.util.Map; @@ -35,10 +36,10 @@ import java.util.concurrent.CopyOnWriteArrayList; */ class Index { - private ConcurrentMap> _index - = new ConcurrentHashMap>(); + private ConcurrentMap> _index + = new ConcurrentHashMap>(); - synchronized boolean add(String key, AMQQueue queue) + synchronized boolean add(AMQShortString key, AMQQueue queue) { List queues = _index.get(key); if(queues == null) @@ -62,7 +63,7 @@ class Index } } - synchronized boolean remove(String key, AMQQueue queue) + synchronized boolean remove(AMQShortString key, AMQQueue queue) { List queues = _index.get(key); if (queues != null) @@ -77,13 +78,13 @@ class Index return false; } - List get(String key) + List get(AMQShortString key) { return _index.get(key); } - Map> getBindingsMap() + Map> getBindingsMap() { - return new HashMap>(_index); + return new HashMap>(_index); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index 49f99132ef..5c784983cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -45,29 +45,24 @@ public class FilterManagerFactory manager = new SimpleFilterManager(); - Iterator it = filters.keySet().iterator(); - _logger.info("Processing filters:"); - while (it.hasNext()) + if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) { - String key = (String) it.next(); - _logger.info("filter:" + key); - if (key.equals(AMQPFilterTypes.JMS_SELECTOR.getValue())) - { - String selector = (String) filters.get(key); - - if (selector != null && !selector.equals("")) - { - manager.add(new JMSSelectorFilter(selector)); - } - } + String selector = filters.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - if (key.equals(AMQPFilterTypes.NO_CONSUME.getValue())) + if (selector != null && !selector.equals("")) { - manager.add(new NoConsumerFilter()); + manager.add(new JMSSelectorFilter(selector)); } } + if (filters.containsKey(AMQPFilterTypes.NO_CONSUME.getValue())) + { + manager.add(new NoConsumerFilter()); + } + + + //If we added no filters don't bear the overhead of having an filter manager if (!manager.hasFilters()) { @@ -76,7 +71,7 @@ public class FilterManagerFactory } else { - _logger.info("No Filters found."); + _logger.debug("No Filters found."); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 7d6a98df84..934bca991d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -248,7 +248,7 @@ public class PropertyExpression implements Expression _logger.info("Looking up property:" + name); _logger.info("Properties are:" + _properties.getHeaders().keySet()); - return _properties.getHeaders().get(name); + return _properties.getHeaders().getObject(name); } // catch (IOException ioe) // { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index d3aece9818..0cb1d8bee8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -23,10 +23,7 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidSelectorException; 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.framing.ChannelCloseBody; +import org.apache.qpid.framing.*; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -77,7 +74,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); + + private static final AMQShortString UNKNOWN_EXCHANGE_NAME = new AMQShortString("Unknown exchange name"); public static BasicPublishMethodHandler getInstance() { @@ -55,7 +59,8 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener evt) throws AMQException { ConnectionOpenBody body = evt.getMethod(); - String contextKey = body.virtualHost; + AMQShortString 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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 9f24100df1..7cf1236d2f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -73,7 +73,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< SaslServer ss = null; try { - ss = authMgr.createSaslServer(body.mechanism, protocolSession.getLocalFQDN()); + ss = authMgr.createSaslServer(String.valueOf(body.mechanism), protocolSession.getLocalFQDN()); protocolSession.setSaslServer(ss); AuthenticationResult authResult = authMgr.authenticate(ss, body.response); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java index 30e8990b54..0b216c4da1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -21,6 +21,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ExchangeBoundBody; import org.apache.qpid.framing.ExchangeBoundOkBody; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQMethodEvent; @@ -71,9 +72,9 @@ public class ExchangeBoundHandler implements StateAwareMethodListener _channelMap = new HashMap(); @@ -291,12 +282,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _minaProtocolSession.write(frame); } - public String getContextKey() + public AMQShortString getContextKey() { return _contextKey; } - public void setContextKey(String contextKey) + public void setContextKey(AMQShortString contextKey) { _contextKey = contextKey; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 2e9590277b..f4f443b162 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -180,7 +180,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco 0, // classId 0, // methodId 200, // replyCode - throwable.getMessage() // replyText + new AMQShortString(throwable.getMessage()) // replyText )); _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); protocolSession.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index a75627d240..ee01dd9f5b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.AMQException; @@ -48,14 +49,14 @@ public interface AMQProtocolSession * in the AMQ protocol specification (RFC 6). * @return the context key */ - String getContextKey(); + AMQShortString 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); + void setContextKey(AMQShortString contextKey); /** * Get the channel for this session associated with the specified id. A channel diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 0ceadcb30b..08045e1c41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -21,6 +21,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -58,6 +59,8 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed private OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; private CompositeType _channelType = null; // represents the data type for channel data private TabularType _channelsType = null; // Data type for list of channels type + private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSING_THE_CONNECTION = + new AMQShortString("Broker Management Console has closing the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws JMException @@ -201,7 +204,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed 0, // classId 0, // methodId AMQConstant.REPLY_SUCCESS.getCode(), // replyCode - "Broker Management Console has closing the connection." // replyText + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSING_THE_CONNECTION // replyText ); _session.writeFrame(response); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java index d3ec70456f..d4881aefaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -34,7 +35,7 @@ public class ExchangeInitialiser } private void define(ExchangeRegistry r, ExchangeFactory f, - String name, String type) throws AMQException + AMQShortString name, AMQShortString type) throws AMQException { r.registerExchange(f.createExchange(name, type, true, false, 0)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index f30667690f..05b4f5ec2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -562,7 +562,7 @@ public class AMQMessage } } - public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, String consumerTag) + public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { ByteBuffer deliver = createEncodedDeliverFrame(channelId, deliveryTag, consumerTag); @@ -598,7 +598,7 @@ public class AMQMessage } - private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, String consumerTag) + private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { BasicPublishBody pb = getPublishBody(); @@ -611,7 +611,7 @@ public class AMQMessage return buf; } - private ByteBuffer createEncodedReturnFrame(int channelId, int replyCode, String replyText) throws AMQException + private ByteBuffer createEncodedReturnFrame(int channelId, int replyCode, AMQShortString replyText) throws AMQException { AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, (byte) 8, (byte) 0, getPublishBody().exchange, replyCode, replyText, @@ -622,7 +622,7 @@ public class AMQMessage return buf; } - public void writeReturn(AMQProtocolSession protocolSession, int channelId, int replyCode, String replyText) + public void writeReturn(AMQProtocolSession protocolSession, int channelId, int replyCode, AMQShortString replyText) throws AMQException { ByteBuffer returnFrame = createEncodedReturnFrame(channelId, replyCode, replyText); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 6f1018e753..ea09654988 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -42,12 +43,12 @@ public class AMQQueue implements Managable, Comparable { private static final Logger _logger = Logger.getLogger(AMQQueue.class); - private final String _name; + private final AMQShortString _name; /** * null means shared */ - private final String _owner; + private final AMQShortString _owner; private final boolean _durable; @@ -111,7 +112,7 @@ public class AMQQueue implements Managable, Comparable return _name.compareTo(((AMQQueue) o).getName()); } - public AMQQueue(String name, boolean durable, String owner, + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry) throws AMQException { @@ -119,7 +120,7 @@ public class AMQQueue implements Managable, Comparable AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionImpl.Factory()); } - public AMQQueue(String name, boolean durable, String owner, + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, SubscriptionFactory subscriptionFactory) throws AMQException { @@ -127,7 +128,7 @@ public class AMQQueue implements Managable, Comparable AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscriptionFactory); } - public AMQQueue(String name, boolean durable, String owner, + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery, SubscriptionFactory subscriptionFactory) throws AMQException @@ -136,7 +137,7 @@ public class AMQQueue implements Managable, Comparable this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), subscriptionFactory); } - public AMQQueue(String name, boolean durable, String owner, + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery) throws AMQException { @@ -145,7 +146,7 @@ public class AMQQueue implements Managable, Comparable new SubscriptionImpl.Factory()); } - protected AMQQueue(String name, boolean durable, String owner, + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) throws AMQException @@ -154,7 +155,7 @@ public class AMQQueue implements Managable, Comparable AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, subscriptionFactory); } - protected AMQQueue(String name, boolean durable, String owner, + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, SubscriptionSet subscribers) throws AMQException @@ -163,7 +164,7 @@ public class AMQQueue implements Managable, Comparable AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); } - protected AMQQueue(String name, boolean durable, String owner, + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) throws AMQException @@ -225,7 +226,7 @@ public class AMQQueue implements Managable, Comparable } } - public String getName() + public AMQShortString getName() { return _name; } @@ -240,7 +241,7 @@ public class AMQQueue implements Managable, Comparable return _durable; } - public String getOwner() + public AMQShortString getOwner() { return _owner; } @@ -356,17 +357,17 @@ public class AMQQueue implements Managable, Comparable _deliveryMgr.clearAllMessages(storeContext); } - public void bind(String routingKey, Exchange exchange) + public void bind(AMQShortString routingKey, Exchange exchange) { _bindings.addBinding(routingKey, exchange); } - public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters) throws AMQException + public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, FieldTable filters) throws AMQException { registerProtocolSession(ps, channel, consumerTag, acks, filters, false); } - public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks, FieldTable filters, boolean noLocal) + public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException { debug("Registering protocol session {0} with channel {1} and consumer tag {2} with {3}", ps, channel, consumerTag, this); @@ -384,7 +385,7 @@ public class AMQQueue implements Managable, Comparable _subscribers.addSubscriber(subscription); } - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, String consumerTag) throws AMQException + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException { debug("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, this); @@ -475,7 +476,7 @@ public class AMQQueue implements Managable, Comparable } catch (AMQException e) { - throw new FailedDequeueException(_name, e); + throw new FailedDequeueException(_name.toString(), e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 77bbdf7b4b..fb4a8e06bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -112,7 +112,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue public String getOwner() { - return _queue.getOwner(); + return String.valueOf(_queue.getOwner()); } public boolean isAutoDelete() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java index a2898ccdce..1a44e86f1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.configuration.Configured; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.store.StoreContext; @@ -294,7 +295,7 @@ public class ConcurrentDeliveryManager implements DeliveryManager } } - public void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException + public void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg) throws FailedDequeueException, AMQException { // first check whether we are queueing, and enqueue if we are if (!enqueue(msg)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 8f0c3a5ec7..91c49a4cf9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -25,6 +25,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.store.StoreContext; @@ -280,7 +281,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return _messages.poll(); } - public void deliver(StoreContext context, String name, AMQMessage msg) throws AMQException + public void deliver(StoreContext context, AMQShortString name, AMQMessage msg) throws AMQException { if (_log.isDebugEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index 3b73072e30..8ab26def74 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -21,13 +21,14 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; public class DefaultQueueRegistry implements QueueRegistry { - private ConcurrentMap _queueMap = new ConcurrentHashMap(); + private ConcurrentMap _queueMap = new ConcurrentHashMap(); public DefaultQueueRegistry() { @@ -38,12 +39,12 @@ public class DefaultQueueRegistry implements QueueRegistry _queueMap.put(queue.getName(), queue); } - public void unregisterQueue(String name) throws AMQException + public void unregisterQueue(AMQShortString name) throws AMQException { _queueMap.remove(name); } - public AMQQueue getQueue(String name) + public AMQQueue getQueue(AMQShortString name) { return _queueMap.get(name); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 82d8f9538f..d3d235f07f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.store.StoreContext; import java.util.concurrent.Executor; @@ -67,7 +68,7 @@ interface DeliveryManager * @param msg the message to deliver * @throws org.apache.qpid.server.queue.FailedDequeueException if the message could not be dequeued */ - void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException; + void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg) throws FailedDequeueException, AMQException; void removeAMessageFromTop(StoreContext storeContext) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index 684e312fa3..2f742952c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import java.util.List; import java.util.HashSet; @@ -37,9 +38,9 @@ class ExchangeBindings static class ExchangeBinding { private final Exchange exchange; - private final String routingKey; + private final AMQShortString routingKey; - ExchangeBinding(String routingKey, Exchange exchange) + ExchangeBinding(AMQShortString routingKey, Exchange exchange) { this.routingKey = routingKey; this.exchange = exchange; @@ -55,7 +56,7 @@ class ExchangeBindings return exchange; } - public String getRoutingKey() + public AMQShortString getRoutingKey() { return routingKey; } @@ -87,7 +88,7 @@ class ExchangeBindings * are being tracked by the instance has been bound to the exchange * @param exchange the exchange bound to */ - void addBinding(String routingKey, Exchange exchange) + void addBinding(AMQShortString routingKey, Exchange exchange) { _bindings.add(new ExchangeBinding(routingKey, exchange)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index c83f17b98c..bfbaf27c84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -21,13 +21,14 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; public interface QueueRegistry { void registerQueue(AMQQueue queue) throws AMQException; - void unregisterQueue(String name) throws AMQException; + void unregisterQueue(AMQShortString name) throws AMQException; - AMQQueue getQueue(String name); + AMQQueue getQueue(AMQShortString name); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java index 2bb77dc649..6cc55f2818 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortString; /** * Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This @@ -33,10 +34,10 @@ import org.apache.qpid.framing.FieldTable; */ public interface SubscriptionFactory { - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException; - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 0dc1f3b0c1..0afe17c6ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -25,10 +25,7 @@ import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicCancelOkBody; -import org.apache.qpid.framing.BasicDeliverBody; -import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.*; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; @@ -53,7 +50,7 @@ public class SubscriptionImpl implements Subscription public final AMQProtocolSession protocolSession; - public final String consumerTag; + public final AMQShortString consumerTag; private final Object sessionKey; @@ -72,12 +69,12 @@ public class SubscriptionImpl implements Subscription public static class Factory implements SubscriptionFactory { - public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException + public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException { return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal); } - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) + public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) throws AMQException { return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false); @@ -85,14 +82,14 @@ public class SubscriptionImpl implements Subscription } public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - String consumerTag, boolean acks) + AMQShortString consumerTag, boolean acks) throws AMQException { this(channelId, protocolSession, consumerTag, acks, null, false); } public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - String consumerTag, boolean acks, FieldTable filters, boolean noLocal) + AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException { AMQChannel channel = protocolSession.getChannel(channelId); @@ -162,7 +159,7 @@ public class SubscriptionImpl implements Subscription public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, - String consumerTag) + AMQShortString consumerTag) throws AMQException { this(channel, protocolSession, consumerTag, false); @@ -304,8 +301,8 @@ public class SubscriptionImpl implements Subscription if (_noLocal) { // We don't want local messages so check to see if message is one we sent - if (protocolSession.getClientProperties().get(ClientProperties.instance.toString()).equals( - msg.getPublisher().getClientProperties().get(ClientProperties.instance.toString()))) + if (protocolSession.getClientProperties().getObject(ClientProperties.instance.toString()).equals( + msg.getPublisher().getClientProperties().getObject(ClientProperties.instance.toString()))) { if (_logger.isTraceEnabled()) { @@ -395,7 +392,7 @@ public class SubscriptionImpl implements Subscription } - private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) + private ByteBuffer createEncodedDeliverFrame(long deliveryTag, AMQShortString routingKey, AMQShortString exchange) { // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java index f290452058..02fe86a083 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.store.StoreContext; import org.apache.log4j.Logger; @@ -234,7 +235,7 @@ class SynchronizedDeliveryManager implements DeliveryManager * @throws NoConsumersException if there are no active subscribers to deliver * the message to */ - public void deliver(StoreContext storeContext, String name, AMQMessage msg) throws FailedDequeueException, AMQException + public void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg) throws FailedDequeueException, AMQException { // first check whether we are queueing, and enqueue if we are if (!enqueue(msg)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 2fb2bdd2e3..446cf5ec2c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -180,11 +180,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle public void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException { - _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); + _messageStore.enqueueMessage(storeContext, queue.getName().toString(), messageId); } public void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException { - _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); + _messageStore.dequeueMessage(storeContext, queue.getName().toString(), messageId); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java index 9f4addd7ee..6cee2ee452 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.security.auth; +import org.apache.qpid.framing.AMQShortString; + import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java index 14cce86715..5c21dd4de4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.security.auth; import org.apache.qpid.server.security.auth.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.framing.AMQShortString; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java index 21eb80c69d..e96bd68cad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java @@ -24,6 +24,7 @@ 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 org.apache.qpid.framing.AMQShortString; import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java index c364ca1d8d..a943003bd3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java @@ -56,13 +56,13 @@ public class AmqPlainSaslServer implements SaslServer try { final FieldTable ft = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.get("LOGIN"); + String username = (String) ft.getString("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"); + String pwd = (String) ft.getString("PASSWORD"); passwordCb.setPassword(pwd.toCharArray()); AuthorizeCallback authzCb = new AuthorizeCallback(username, username); Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; -- cgit v1.2.1 From 293fb66a4c83f6be1a887e3e4050141c5c40d59b Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 9 Jan 2007 23:36:50 +0000 Subject: QPID-269 : (Patch supplied by Rob Godfrey) Add getType() to Exchange git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494652 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/exchange/DestNameExchange.java | 6 ++++++ .../main/java/org/apache/qpid/server/exchange/DestWildExchange.java | 6 ++++++ .../src/main/java/org/apache/qpid/server/exchange/Exchange.java | 1 + .../main/java/org/apache/qpid/server/exchange/HeadersExchange.java | 6 ++++++ 4 files changed, 19 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index dc65297615..fcd6e8fdad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; @@ -141,6 +142,11 @@ public class DestNameExchange extends AbstractExchange } } + public AMQShortString getType() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 179dc0e9ef..d1b35451b5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; @@ -127,6 +128,11 @@ public class DestWildExchange extends AbstractExchange } // End of MBean class + public AMQShortString getType() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + public synchronized void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 7ba9ddd5a8..366dcb11b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -29,6 +29,7 @@ import org.apache.qpid.server.queue.AMQMessage; public interface Exchange { AMQShortString getName(); + AMQShortString getType(); void initialise(AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index e681cb4c47..93933cd88d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.*; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; @@ -173,6 +174,11 @@ public class HeadersExchange extends AbstractExchange } // End of MBean class + public AMQShortString getType() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); -- cgit v1.2.1 From d21feec9fb0b72ccf363051094c48d771c4ba6f4 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 10 Jan 2007 00:11:27 +0000 Subject: QPID-271 : (Patch supplied by Rob Godfrey) Implement fanout exchange git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494658 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/exchange/DefaultExchangeFactory.java | 8 +- .../qpid/server/exchange/FanoutExchange.java | 206 +++++++++++++++++++++ .../qpid/server/protocol/ExchangeInitialiser.java | 1 + 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 222cd2aef2..77f9819048 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -22,6 +22,9 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -39,6 +42,8 @@ public class DefaultExchangeFactory implements ExchangeFactory _exchangeClassMap.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestNameExchange.class); _exchangeClassMap.put(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestWildExchange.class); _exchangeClassMap.put(ExchangeDefaults.HEADERS_EXCHANGE_CLASS, org.apache.qpid.server.exchange.HeadersExchange.class); + _exchangeClassMap.put(ExchangeDefaults.FANOUT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.FanoutExchange.class); + } public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, @@ -48,7 +53,8 @@ public class DefaultExchangeFactory implements ExchangeFactory Class exchClass = _exchangeClassMap.get(type); if (exchClass == null) { - throw new AMQException(_logger, "Unknown exchange type: " + type); + + throw new AMQUnknownExchangeType("Unknown exchange type: " + type); } try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java new file mode 100644 index 0000000000..2e7457e4a6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -0,0 +1,206 @@ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.MBeanConstructor; +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.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; + +import javax.management.openmbean.*; +import javax.management.JMException; +import javax.management.MBeanException; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class FanoutExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Fanout Exchange") + private final class FanoutExchangeMBean extends ExchangeMBean + { + // open mbean data types for representing exchange bindings + private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; + private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; + 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 FanoutExchangeMBean() throws JMException + { + super(); + _exchangeType = "fanout"; + init(); + } + + /** + * initialises the OpenType objects. + */ + private void init() throws OpenDataException + { + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + + public TabularData bindings() throws OpenDataException + { + + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (AMQQueue queue : _queues) + { + String queueName = queue.getName().toString(); + + + + Object[] bindingItemValues = {queueName, new String[] {queueName}}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + registerQueue(new AMQShortString(binding), queue, null); + queue.bind(new AMQShortString(binding), FanoutExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + }// End of MBean class + + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new FanoutExchange.FanoutExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public AMQShortString getType() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (_queues.contains(queue)) + { + _logger.debug("Queue " + queue + " is already registered"); + } + else + { + _queues.add(queue); + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); + } + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + { + assert queue != null; + assert routingKey != null; + + if (!_queues.remove(queue)) + { + throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + + ". "); + } + } + + public void route(AMQMessage payload) throws AMQException + { + final BasicPublishBody publishBody = payload.getPublishBody(); + final AMQShortString routingKey = publishBody.routingKey; + if (_queues == null || _queues.isEmpty()) + { + String msg = "No queues bound 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); + } + } + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + { + return _queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) throws AMQException + { + + return _queues != null && !_queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) throws AMQException + { + + + return _queues.contains(queue); + } + + public boolean hasBindings() throws AMQException + { + return !_queues.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java index d4881aefaf..e1fac55d3b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -32,6 +32,7 @@ public class ExchangeInitialiser 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); + define(registry, factory, ExchangeDefaults.FANOUT_EXCHANGE_NAME, ExchangeDefaults.FANOUT_EXCHANGE_CLASS); } private void define(ExchangeRegistry r, ExchangeFactory f, -- cgit v1.2.1 From 8dc53a78a3888e1fe23c6ff84d653c6e4e23e3e4 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 10 Jan 2007 08:31:42 +0000 Subject: QPID-273 : (Patch supplied by Rob Godfrey) Remove unnecessary Map creation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494765 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/filter/PropertyExpression.java | 272 +++++++++++---------- .../org/apache/qpid/server/queue/AMQMessage.java | 88 +++---- 2 files changed, 174 insertions(+), 186 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 934bca991d..ba7000f822 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -26,6 +26,7 @@ import java.util.HashMap; import javax.jms.DeliveryMode; import javax.jms.JMSException; +import javax.jms.Message; //import org.apache.activemq.command.ActiveMQDestination; //import org.apache.activemq.command.Message; @@ -45,225 +46,232 @@ import org.apache.log4j.Logger; public class PropertyExpression implements Expression { - interface SubExpression - { - public Object evaluate(AMQMessage message) throws AMQException; - } - - interface JMSExpression - { - public abstract Object evaluate(JMSMessage message); - } - - static class SubJMSExpression implements SubExpression - { - JMSExpression _expression; - - SubJMSExpression(JMSExpression expression) - { - _expression = expression; - } - public Object evaluate(AMQMessage message) throws AMQException - { - JMSMessage msg = (JMSMessage) message.getDecodedMessage(AMQMessage.JMS_MESSAGE); - if (msg != null) - { - return _expression.evaluate(msg); - } - else - { - return null; - } - } - } - private final static Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - static final private HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); + static final private HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); static { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSDestination(); + //TODO + return null; } } - )); -// -// public Object evaluate(AMQMessage message) -// { -// //fixme -// -// -//// AMQDestination dest = message.getOriginalDestination(); -//// if (dest == null) -//// { -//// dest = message.getDestination(); -//// } -//// if (dest == null) -//// { -//// return null; -//// } -//// return dest.toString(); -// return ""; -// } -// }); - JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new SubJMSExpression( - new JMSExpression() - { - public Object evaluate(JMSMessage message) + ); + JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() + { + public Object evaluate(AMQMessage message) { - return message.getJMSReplyTo(); + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getReplyTo(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } - }) - ); - JMS_PROPERTY_EXPRESSIONS.put("JMSType", new SubJMSExpression( - new JMSExpression() + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSType", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSType(); + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getType(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } } - )); + ); - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { try { - Integer mode = new Integer(message.getAMQMessage().isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - _logger.info("JMSDeliveryMode is :" + mode); + int mode = message.isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; + if(_logger.isDebugEnabled()) + { + _logger.debug("JMSDeliveryMode is :" + mode); + } return mode; } catch (AMQException e) { - //shouldn't happen + _logger.warn(e); } return DeliveryMode.NON_PERSISTENT; } - })); + }); - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSPriority(); + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return (int) _properties.getPriority(); + } + catch (AMQException e) + { + _logger.warn(e); + } + return Message.DEFAULT_PRIORITY; } } - )); + ); - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getAMQMessage().getMessageId(); + + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getMessageId(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } } - )); + ); - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSTimestamp(); + + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getTimestamp(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } } - )); + ); - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSCorrelationID(); + + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getCorrelationId(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } } - )); + ); - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getJMSExpiration(); + + try + { + BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + return _properties.getExpiration(); + } + catch (AMQException e) + { + _logger.warn(e); + return null; + } + } - } - )); + }); - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new SubJMSExpression( - new JMSExpression() + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", + new Expression() { - public Object evaluate(JMSMessage message) + public Object evaluate(AMQMessage message) { - return message.getAMQMessage().isRedelivered(); + return message.isRedelivered(); } } - )); + ); } private final String name; - private final SubExpression jmsPropertyExpression; + private final Expression jmsPropertyExpression; public PropertyExpression(String name) { this.name = name; - jmsPropertyExpression = (SubExpression) JMS_PROPERTY_EXPRESSIONS.get(name); + jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); } public Object evaluate(AMQMessage message) throws AMQException { -// try -// { -// if (message.isDropped()) -// { -// return null; -// } if (jmsPropertyExpression != null) { return jmsPropertyExpression.evaluate(message); } -// try + else { BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; - _logger.info("Looking up property:" + name); - _logger.info("Properties are:" + _properties.getHeaders().keySet()); + if(_logger.isDebugEnabled()) + { + _logger.debug("Looking up property:" + name); + _logger.debug("Properties are:" + _properties.getHeaders().keySet()); + } return _properties.getHeaders().getObject(name); } -// catch (IOException ioe) -// { -// JMSException exception = new JMSException("Could not get property: " + name + " reason: " + ioe.getMessage()); -// exception.initCause(ioe); -// throw exception; -// } -// } -// catch (IOException e) -// { -// JMSException exception = new JMSException(e.getMessage()); -// exception.initCause(e); -// throw exception; -// } - } public String getName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 05b4f5ec2b..b56523f904 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -48,7 +48,7 @@ public class AMQMessage /** * Used in clustering */ - private final Set _tokens = new HashSet(); + private Set _tokens; /** * Only use in clustering - should ideally be removed? @@ -71,7 +71,6 @@ public class AMQMessage */ private boolean _deliveredToConsumer; - private ConcurrentHashMap _decodedMessages; private AtomicBoolean _taken = new AtomicBoolean(false); private TransientMessageData _transientMessageData = new TransientMessageData(); @@ -167,7 +166,7 @@ public class AMQMessage _messageId = messageId; _txnContext = txnContext; _transientMessageData.setPublishBody(publishBody); - _decodedMessages = new ConcurrentHashMap(); + _taken = new AtomicBoolean(false); if (_log.isDebugEnabled()) { @@ -396,39 +395,6 @@ public class AMQMessage } - public MessageDecorator getDecodedMessage(String type) throws AMQException - { - MessageDecorator msgtype = null; - - if (_decodedMessages != null) - { - msgtype = _decodedMessages.get(type); - - if (msgtype == null) - { - msgtype = decorateMessage(type); - } - } - - return msgtype; - } - - private MessageDecorator decorateMessage(String type) throws AMQException - { - MessageDecorator msgdec = null; - - if (type.equals(JMS_MESSAGE)) - { - msgdec = new JMSMessage(this); - } - - if (msgdec != null) - { - _decodedMessages.put(type, msgdec); - } - - return msgdec; - } public boolean taken() { @@ -442,6 +408,12 @@ public class AMQMessage public boolean checkToken(Object token) { + + if(_tokens==null) + { + _tokens = new HashSet(); + } + if (_tokens.contains(token)) { return true; @@ -569,33 +541,41 @@ public class AMQMessage 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()) + final int bodyCount = _messageHandle.getBodyCount(_messageId); + if(bodyCount == 0) { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); protocolSession.writeFrame(compositeBlock); } else { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, - new AMQDataBlock[]{contentHeader}); + + + // + // 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. + // + ContentBody cb = _messageHandle.getContentBody(_messageId, 0); + + AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); protocolSession.writeFrame(compositeBlock); - } - // - // Now start writing out the other content bodies - // - while (bodyFrameIterator.hasNext()) - { - protocolSession.writeFrame(bodyFrameIterator.next()); + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = _messageHandle.getContentBody(_messageId, i); + protocolSession.writeFrame(ContentBody.createAMQFrame(channelId, cb)); + } + + } + } private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, AMQShortString consumerTag) -- cgit v1.2.1 From d989614d675abf5d970e0aff420fb3db79ace159 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 10 Jan 2007 08:52:41 +0000 Subject: QPID-275 : (Patch supplied by Rob Godfrey) Fixes to allow broker to pass more of the Python tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494769 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/handler/BasicConsumeMethodHandler.java | 99 ++++++++++++++-------- .../server/handler/ExchangeDeclareHandler.java | 33 +++++++- .../qpid/server/handler/QueueDeclareHandler.java | 41 ++++++--- .../qpid/server/handler/QueueDeleteHandler.java | 35 ++++++-- .../server/protocol/AMQMinaProtocolSession.java | 21 +++-- .../org/apache/qpid/server/queue/AMQQueue.java | 11 +++ .../apache/qpid/server/queue/ExchangeBindings.java | 2 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 6 +- 8 files changed, 180 insertions(+), 68 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 0cb1d8bee8..cee6ef7c98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -71,49 +71,78 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { @@ -79,14 +82,30 @@ public class QueueDeleteHandler implements StateAwareMethodListener Date: Thu, 11 Jan 2007 09:39:40 +0000 Subject: QPID-32 : Add persistence to work with ShortStrings git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495169 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../java/org/apache/qpid/server/handler/QueueDeleteHandler.java | 2 +- .../org/apache/qpid/server/queue/WeakReferenceMessageHandle.java | 4 ++-- .../java/org/apache/qpid/server/store/MemoryMessageStore.java | 7 ++++--- .../src/main/java/org/apache/qpid/server/store/MessageStore.java | 7 ++++--- .../org/apache/qpid/server/txn/LocalTransactionalContext.java | 9 ++++++++- 6 files changed, 20 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index d7326b4c64..6f93a14469 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -174,7 +174,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.removeQueue(queueName); + _messageStore.removeQueue(new AMQShortString(queueName)); } catch (AMQException ex) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index bbe1464bdc..7a0edf2f06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -98,7 +98,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener Date: Thu, 11 Jan 2007 17:35:49 +0000 Subject: QPID-32: transaction fixes git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495304 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 15 +++- .../qpid/server/handler/BasicAckMethodHandler.java | 13 ++- .../server/handler/BasicPublishMethodHandler.java | 14 +++- .../qpid/server/handler/TxCommitHandler.java | 11 ++- .../org/apache/qpid/server/queue/AMQMessage.java | 22 +++-- .../qpid/server/txn/DeliverMessageOperation.java | 2 +- .../qpid/server/txn/LocalTransactionalContext.java | 97 ++++++++++++++++++++-- .../qpid/server/txn/NonTransactionalContext.java | 6 ++ .../qpid/server/txn/TransactionalContext.java | 3 + 9 files changed, 154 insertions(+), 29 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 799b085fb2..470789bb1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -37,7 +37,6 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.txn.TxnBuffer; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -126,7 +125,7 @@ public class AMQChannel */ public void setLocalTransactional() { - _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, new TxnBuffer(), _returnMessages); + _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); } public boolean isTransactional() @@ -190,6 +189,10 @@ public class AMQChannel } else { + if (_log.isDebugEnabled()) + { + _log.debug("Content header received on channel " + _channelId); + } _currentMessage.setContentHeaderBody(contentHeaderBody); routeCurrentMessage(); _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); @@ -212,6 +215,10 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received + if (_log.isDebugEnabled()) + { + _log.debug("Content body received on channel " + _channelId); + } try { if (_currentMessage.addContentBodyFrame(_storeContext, contentBody)) @@ -484,6 +491,10 @@ public class AMQChannel public void commit() throws AMQException { + if (!isTransactional()) + { + throw new AMQException("Fatal error: commit called on non-transactional channel"); + } _txnContext.commit(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index b2b7a21296..f7644f3bad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -29,9 +29,12 @@ 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; +import org.apache.log4j.Logger; public class BasicAckMethodHandler implements StateAwareMethodListener -{ +{ + private static final Logger _log = Logger.getLogger(BasicAckMethodHandler.class); + private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); public static BasicAckMethodHandler getInstance() @@ -47,6 +50,10 @@ public class BasicAckMethodHandler implements StateAwareMethodListener evt) throws AMQException { + if (_log.isDebugEnabled()) + { + _log.debug("Ack received on channel " + evt.getChannelId()); + } BasicAckBody body = evt.getMethod(); final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); // this method throws an AMQException if the delivery tag is not known diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 181409c255..9c25759cd3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,11 +34,14 @@ 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 BasicPublishMethodHandler implements StateAwareMethodListener { + private static final Logger _log = Logger.getLogger(BasicPublishMethodHandler.class); + private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); - + private static final AMQShortString UNKNOWN_EXCHANGE_NAME = new AMQShortString("Unknown exchange name"); public static BasicPublishMethodHandler getInstance() @@ -56,6 +59,11 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener { + private static final Logger _log = Logger.getLogger(TxCommitHandler.class); + private static TxCommitHandler _instance = new TxCommitHandler(); public static TxCommitHandler getInstance() @@ -51,6 +54,10 @@ public class TxCommitHandler implements StateAwareMethodListener try { + if (_log.isDebugEnabled()) + { + _log.debug("Commit received on channel " + evt.getChannelId()); + } AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); channel.commit(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index b56523f904..c55d24d507 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.queue; +import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.*; @@ -27,14 +28,13 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.message.MessageDecorator; -import org.apache.qpid.server.message.jms.JMSMessage; -import org.apache.log4j.Logger; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; /** * Combines the information that make up a deliverable message into a more manageable form. @@ -166,7 +166,7 @@ public class AMQMessage _messageId = messageId; _txnContext = txnContext; _transientMessageData.setPublishBody(publishBody); - + _taken = new AtomicBoolean(false); if (_log.isDebugEnabled()) { @@ -468,7 +468,7 @@ public class AMQMessage if (pb.immediate && !_deliveredToConsumer) { throw new NoConsumersException(this); - } + } } public BasicPublishBody getPublishBody() throws AMQException @@ -509,6 +509,10 @@ public class AMQMessage // we get a reference to the destination queues now so that we can clear the // transient message data as quickly as possible List destinationQueues = _transientMessageData.getDestinationQueues(); + if (_log.isDebugEnabled()) + { + _log.debug("Delivering message " + _messageId); + } try { // first we allow the handle to know that the message has been fully received. This is useful if it is @@ -555,7 +559,7 @@ public class AMQMessage // // 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. - // + // ContentBody cb = _messageHandle.getContentBody(_messageId, 0); AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java index 3934943665..4dff514ff4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java @@ -52,7 +52,7 @@ public class DeliverMessageOperation implements TxnOp { } - public void commit(StoreContext context) + public void commit(StoreContext context) throws AMQException { //do the memeory part of the record() _msg.incrementReference(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index f430a44ba0..d87554524f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -17,16 +17,18 @@ */ package org.apache.qpid.server.txn; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.ack.TxAck; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; +import java.util.LinkedList; import java.util.List; /** @@ -34,7 +36,11 @@ import java.util.List; */ public class LocalTransactionalContext implements TransactionalContext { - private final TxnBuffer _txnBuffer; + private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); + + private final TxnBuffer _txnBuffer = new TxnBuffer(); + + private final List _postCommitDeliveryList = new LinkedList(); /** * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are @@ -50,14 +56,34 @@ public class LocalTransactionalContext implements TransactionalContext private boolean _inTran = false; + private boolean _messageDelivered = false; + + private static class DeliveryDetails + { + public AMQMessage message; + public AMQQueue queue; + + + public DeliveryDetails(AMQMessage message, AMQQueue queue) + { + this.message = message; + this.queue = queue; + } + } + public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, - TxnBuffer txnBuffer, List returnMessages) + List returnMessages) { _messageStore = messageStore; _storeContext = storeContext; - _txnBuffer = txnBuffer; _returnMessages = returnMessages; - _txnBuffer.enlist(new StoreMessageOperation(messageStore)); + //_txnBuffer.enlist(new StoreMessageOperation(messageStore)); + } + + + public StoreContext getStoreContext() + { + return _storeContext; } public void rollback() throws AMQException @@ -73,9 +99,19 @@ public class LocalTransactionalContext implements TransactionalContext // 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)); + message.incrementReference(); + _postCommitDeliveryList.add(new DeliveryDetails(message, queue)); + _messageDelivered = true; + /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); + if (_log.isDebugEnabled()) + { + _log.debug("Incrementing ref count on message and enlisting cleanup operation - id " + + message.getMessageId()); + } + message.incrementReference(); + _messageDelivered = true; _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); + */ } private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException @@ -129,6 +165,10 @@ public class LocalTransactionalContext implements TransactionalContext { if (!_inTran) { + if (_log.isDebugEnabled()) + { + _log.debug("Starting transaction on message store"); + } _messageStore.beginTran(_storeContext); _inTran = true; } @@ -136,6 +176,10 @@ public class LocalTransactionalContext implements TransactionalContext public void commit() throws AMQException { + if (_log.isDebugEnabled()) + { + _log.debug("Committing transactional context"); + } if (_ackOp != null) { _ackOp.consolidate(); @@ -143,13 +187,48 @@ public class LocalTransactionalContext implements TransactionalContext _ackOp = null; } + if (_messageDelivered) + { + _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); + } try { _txnBuffer.commit(_storeContext); } finally { - _inTran = false; + _messageDelivered = false; + _inTran = _messageStore.inTran(_storeContext); } + + try + { + postCommitDelivery(); + } + catch (AMQException e) + { + // OK so what do we do now...? + _log.error("Failed to deliver messages following txn commit: " + e, e); + } + } + + private void postCommitDelivery() throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Performing post commit delivery"); + } + try + { + for (DeliveryDetails dd : _postCommitDeliveryList) + { + dd.queue.process(_storeContext, dd.message); + } + } + finally + { + _postCommitDeliveryList.clear(); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index f09d811b50..f3e6c69cc5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -72,6 +72,12 @@ public class NonTransactionalContext implements TransactionalContext _browsedAcks = browsedAcks; } + + public StoreContext getStoreContext() + { + return _storeContext; + } + public void beginTranIfNecessary() throws AMQException { if (!_inTran) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index bba4b98de4..e241ed4874 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -25,6 +25,7 @@ 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.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; /** * @author Robert Greig (robert.j.greig@jpmorgan.com) @@ -45,4 +46,6 @@ public interface TransactionalContext void messageFullyReceived(boolean persistent) throws AMQException; void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; + + StoreContext getStoreContext(); } -- cgit v1.2.1 From 066d8bd639e7fb9da25e0361d3c35e7bcc85cda2 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 11 Jan 2007 18:00:19 +0000 Subject: QPID-32 Fix for non-persistent message sending git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495314 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index d87554524f..2adedea8e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -187,7 +187,7 @@ public class LocalTransactionalContext implements TransactionalContext _ackOp = null; } - if (_messageDelivered) + if (_messageDelivered && _inTran) { _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); } -- cgit v1.2.1 From fdf1089ef7e8edec7a07e57596764540285e8ddf Mon Sep 17 00:00:00 2001 From: Kim van der Riet Date: Thu, 11 Jan 2007 21:26:17 +0000 Subject: Refactor to create a common AMQMethodEvent object. Also created a common AMQProtocolWriter interface for writing frames. These are required for common request and response handlers to be introduced in 0-9. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495380 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicAckMethodHandler.java | 2 +- .../server/handler/BasicCancelMethodHandler.java | 2 +- .../server/handler/BasicConsumeMethodHandler.java | 2 +- .../server/handler/BasicPublishMethodHandler.java | 2 +- .../qpid/server/handler/BasicQosHandler.java | 2 +- .../server/handler/BasicRecoverMethodHandler.java | 2 +- .../qpid/server/handler/ChannelCloseHandler.java | 2 +- .../qpid/server/handler/ChannelCloseOkHandler.java | 2 +- .../qpid/server/handler/ChannelFlowHandler.java | 2 +- .../qpid/server/handler/ChannelOpenHandler.java | 2 +- .../handler/ConnectionCloseMethodHandler.java | 2 +- .../handler/ConnectionCloseOkMethodHandler.java | 2 +- .../handler/ConnectionOpenMethodHandler.java | 2 +- .../handler/ConnectionSecureOkMethodHandler.java | 2 +- .../handler/ConnectionStartOkMethodHandler.java | 2 +- .../handler/ConnectionTuneOkMethodHandler.java | 2 +- .../qpid/server/handler/ExchangeBoundHandler.java | 2 +- .../server/handler/ExchangeDeclareHandler.java | 2 +- .../qpid/server/handler/ExchangeDeleteHandler.java | 2 +- .../qpid/server/handler/QueueBindHandler.java | 2 +- .../qpid/server/handler/QueueDeclareHandler.java | 2 +- .../qpid/server/handler/QueueDeleteHandler.java | 2 +- .../qpid/server/handler/TxCommitHandler.java | 2 +- .../qpid/server/handler/TxRollbackHandler.java | 2 +- .../qpid/server/handler/TxSelectHandler.java | 2 +- .../qpid/server/protocol/AMQMethodEvent.java | 65 ---------------------- .../qpid/server/protocol/AMQMethodListener.java | 1 + .../server/protocol/AMQMinaProtocolSession.java | 1 + .../qpid/server/protocol/AMQProtocolSession.java | 9 +-- .../apache/qpid/server/state/AMQStateManager.java | 2 +- .../server/state/StateAwareMethodListener.java | 2 +- 31 files changed, 31 insertions(+), 99 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index f7644f3bad..e12dd4a9db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -22,8 +22,8 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicAckBody; +import org.apache.qpid.protocol.AMQMethodEvent; 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index 198d2c1f3d..a23a29941f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index cee6ef7c98..e078b0cdee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -27,7 +27,7 @@ import org.apache.qpid.framing.*; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 9c25759cd3..25cc981693 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -29,7 +29,7 @@ import org.apache.qpid.framing.AMQShortString; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java index 379ce3d072..60f6458b8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.AMQException; public class BasicQosHandler implements StateAwareMethodListener diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index 85e802d10d..0e37871439 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -25,7 +25,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.framing.BasicRecoverBody; import org.apache.qpid.AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index d26f84d17e..a24ecd9b01 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -26,7 +26,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java index fd6714de3a..81a5371829 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -23,7 +23,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java index 27833ac250..d92a4eed6a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -26,7 +26,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ChannelFlowBody; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index 43d2cae8e4..6ea9dfa595 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java index d000e3b590..0fe25a1c89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java index cc9277593b..bcdd86d2ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -23,7 +23,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index c00fe858fa..b16de88851 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -26,7 +26,7 @@ import org.apache.qpid.framing.ConnectionOpenBody; import org.apache.qpid.framing.ConnectionOpenOkBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQState; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index ea93a357d1..d33874b727 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -24,7 +24,7 @@ import org.apache.qpid.AMQException; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 7cf1236d2f..6cb384f081 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java index f0b4e0a515..960643325a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -24,7 +24,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQState; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java index 0b216c4da1..596e6bf332 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -24,7 +24,7 @@ import org.apache.qpid.framing.ExchangeBoundOkBody; import org.apache.qpid.framing.AMQShortString; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index 4053364778..f6897227aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -32,7 +32,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java index 153a9de4c4..2faba57e04 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -26,7 +26,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java index b7fc786981..45180d0cb6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -28,7 +28,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 7a73fbb18a..c2bec68b89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -29,7 +29,7 @@ import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.*; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index 7a0edf2f06..3f6d752f74 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -26,7 +26,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.framing.QueueDeleteBody; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java index 14dc01656b..68b0c584eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -25,7 +25,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 588dc026d4..7dd1f9579b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -24,7 +24,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java index f4738ff01b..7d66fa9d5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -24,7 +24,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java deleted file mode 100644 index 3d12828900..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.framing.AMQMethodBody; - -/** - * An event that is passed to AMQMethodListeners describing a particular method. - * It supplies the: - *
    • channel id
    • - *
    • protocol method
    • - * to listeners. This means that listeners do not need to be stateful. - * - * In the StateAwareMethodListener, other useful objects such as the protocol session - * are made available. - * - */ -public class AMQMethodEvent -{ - private final M _method; - - private final int _channelId; - - public AMQMethodEvent(int channelId, M method) - { - _channelId = channelId; - _method = method; - } - - public M getMethod() - { - return _method; - } - - public int getChannelId() - { - return _channelId; - } - - public String toString() - { - StringBuilder buf = new StringBuilder("Method event: "); - buf.append("\nChannel id: ").append(_channelId); - buf.append("\nMethod: ").append(_method); - return buf.toString(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java index d2062d3c17..6596da1f8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.framing.AMQMethodBody; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 596631b3a8..415b7a3c68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -28,6 +28,7 @@ import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index ee01dd9f5b..934d1ccff8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -23,13 +23,14 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQProtocolWriter; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.AMQException; import javax.security.sasl.SaslServer; -public interface AMQProtocolSession +public interface AMQProtocolSession extends AMQProtocolWriter { /** * Called when a protocol data block is received @@ -38,12 +39,6 @@ public interface AMQProtocolSession */ 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). diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 4e9deeb8db..fb78b0d8b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -24,7 +24,7 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQMethodListener; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java index 7d58f242e5..56323258b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -21,7 +21,7 @@ package org.apache.qpid.server.state; import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.exchange.ExchangeRegistry; -- cgit v1.2.1 From d1abe24b52a1550d56049d05db10371927f741e6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 12 Jan 2007 01:03:21 +0000 Subject: QPID-146 QPID-112 QPID-278 Summary Reworked a lot of the distribution work done by the build system. This ended up with me creating a reduced client distribution (hope that is ok Steve) Each module now has has a distribution directory (except common it may need a tests build later) This will build the individual components in to a distribution binary only, binary with tests and source. To build the binary with tests in the distribution directory use profile tests so $mvn -Ptests In all cases the dependencies have been reduced and correctly assigned to the correct scope. There were a couple of cases where a runtime dependency of one of our dependencies didn't make it in to the distributions so they were added explicitly. This should be looked at again. Specifics Broker: Three new assembly files are located in the distribution/src directory (broker-bin taking heavily from distribution - bin) these generate the three distributions. SimpleFilterManager.java removed slf4j reference broker/test directory removed as it was left over from the ant system Client: Added intelij files to ignore list. client/dist deleted as it was left over from the ant system client/distribution as for the broker three assemblies matching the three distributions Renamed log4j.properties to client.log4j to prevent issues when it is packaged into the jar. Removed old_test ping and requestreply1 as they have been moved to perftests Moved broker back to a test dependency. This required modifying AMQSession.java to remove reference to ExchangeBoundHandler.java Common: Added more common dependencies from broker and client here. Distribution: Reduced the assemblies to only build the full project binary, binary with tests and source. Perftests: Added building of perftests distribution so this can be bundled separately. Resources: Moved Resources from distribution project to root level this allows them to be easily incorporated in all projects. Systests: as with perftests now builds a separate distribution that can be used on an existing installation. renamed log4j.properties to systests.log4j to prevent logging problems. As systests is a module having the code under the test folder isn't accurate as it is the main code. Test code here should be testing the tests :D !! git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495455 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/filter/SimpleFilterManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index dc2c2c0e6c..9065551697 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -21,15 +21,14 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.log4j.Logger; import javax.jms.JMSException; import java.util.concurrent.ConcurrentLinkedQueue; public class SimpleFilterManager implements FilterManager { - private final Logger _logger = LoggerFactory.getLogger(SimpleFilterManager.class); + private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); private final ConcurrentLinkedQueue _filters; -- cgit v1.2.1 From e1219f264e198ae99a1e5f514ae467deefd29ace Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 12 Jan 2007 01:23:43 +0000 Subject: QPID-276 Update to AMQChannel to remove race condition over UnacknowledgedMessageMap git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495460 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 24 ++++++++++++++-------- .../qpid/server/ack/UnacknowledgedMessageMap.java | 3 +++ .../server/ack/UnacknowledgedMessageMapImpl.java | 13 ++++++++---- .../server/protocol/AMQPFastProtocolHandler.java | 1 + 4 files changed, 29 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 470789bb1a..0497d4bb8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -275,7 +275,7 @@ public class AMQChannel * @throws AMQException if something goes wrong */ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { @@ -326,20 +326,24 @@ public class AMQChannel /** * Add a message to the channel-based list of unacknowledged messages * - * @param message the message that was delivered + * @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 + * the delivery tag) + * @param queue the queue from which the message was delivered */ public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) { - _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); - checkSuspension(); + synchronized (_unacknowledgedMessageMap.getLock()) + { + _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 @@ -427,8 +431,11 @@ public class AMQChannel */ public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); - checkSuspension(); + synchronized (_unacknowledgedMessageMap.getLock()) + { + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); + checkSuspension(); + } } /** @@ -450,6 +457,7 @@ public class AMQChannel private void checkSuspension() { boolean suspend; + suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; setSuspended(suspend); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index b7a75d5b71..ef58ba01a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -43,6 +43,8 @@ public interface UnacknowledgedMessageMap void visit(Visitor visitor) throws AMQException; + Object getLock(); + void add(long deliveryTag, UnacknowledgedMessage message); void collect(long deliveryTag, boolean multiple, List msgs); @@ -67,6 +69,7 @@ public interface UnacknowledgedMessageMap /** * Get the set of delivery tags that are outstanding. + * * @return a set of delivery tags */ Set getDeliveryTags(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 0677494134..a21e4cfff6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -75,7 +75,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { synchronized (_lock) { - for(UnacknowledgedMessage msg : msgs) + for (UnacknowledgedMessage msg : msgs) { _map.remove(msg.deliveryTag); } @@ -95,7 +95,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap synchronized (_lock) { Collection currentEntries = _map.values(); - for (UnacknowledgedMessage msg: currentEntries) + for (UnacknowledgedMessage msg : currentEntries) { visitor.callback(msg); } @@ -103,9 +103,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } + public Object getLock() + { + return _lock; + } + public void add(long deliveryTag, UnacknowledgedMessage message) { - synchronized( _lock) + synchronized (_lock) { _map.put(deliveryTag, message); _lastDeliveryTag = deliveryTag; @@ -209,7 +214,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { synchronized (_lock) { - for(Map.Entry entry : _map.entrySet()) + for (Map.Entry entry : _map.entrySet()) { msgs.add(entry.getValue()); if (entry.getKey() == key) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index f4f443b162..10e23caac3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -134,6 +134,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco { _logger.info("Protocol Session closed"); final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + //fixme -- this can be null amqProtocolSession.closeSession(); } -- cgit v1.2.1 From 0c34a623ee48024182030a7a0dc552dbf17bfea0 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 12 Jan 2007 15:05:32 +0000 Subject: QPID-32 : Persistence Optimisation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495595 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/txn/LocalTransactionalContext.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 2adedea8e0..d750ee7f72 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -135,6 +135,7 @@ public class LocalTransactionalContext implements TransactionalContext //we will need to create and enlist the op. if (_ackOp == null) { + beginTranIfNecessary(); _ackOp = new TxAck(unacknowledgedMessageMap); _txnBuffer.enlist(_ackOp); } @@ -182,6 +183,8 @@ public class LocalTransactionalContext implements TransactionalContext } if (_ackOp != null) { + + _messageDelivered = true; _ackOp.consolidate(); //already enlisted, after commit will reset regardless of outcome _ackOp = null; -- cgit v1.2.1 From 9225300532f0cbe1cf82ad8d97b752cbef344a03 Mon Sep 17 00:00:00 2001 From: Kim van der Riet Date: Fri, 12 Jan 2007 22:02:11 +0000 Subject: Created common AMQMethodListener class, allowing the Request and Response managers to use a common interface to dispatch events to both the client and servers. Refactoring of bothe the client and broker AMQStateManagers and AMQProtocolSession classes was performed. The refactoring has run aground in the clustering, however, and this still needs to be resolved. As the cluster tests are currently disabled (by whom, I'm not sure), this does not disrupt the overall test result. JIRAs will be opened for this issue. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495754 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/protocol/AMQMethodListener.java | 56 ---------------------- .../server/protocol/AMQMinaProtocolSession.java | 20 ++++++-- .../apache/qpid/server/state/AMQStateManager.java | 24 +++++----- 3 files changed, 28 insertions(+), 72 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java deleted file mode 100644 index 6596da1f8f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQMethodEvent; -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/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 415b7a3c68..fa43b8809d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -29,6 +29,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; @@ -99,10 +100,19 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, AMQCodecFactory codecFactory) throws AMQException { - this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); + _stateManager = new AMQStateManager(queueRegistry, exchangeRegistry, this); + _minaProtocolSession = session; + session.setAttachment(this); + + _queueRegistry = queueRegistry; + _exchangeRegistry = exchangeRegistry; + _codecFactory = codecFactory; + _managedObject = createMBean(); + _managedObject.register(); +// this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } - public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, + public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQCodecFactory codecFactory, AMQStateManager stateManager) throws AMQException { @@ -208,13 +218,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, (AMQMethodBody) frame.bodyFrame); try { - boolean wasAnyoneInterested = _stateManager.methodReceived(evt, this, _queueRegistry, _exchangeRegistry); + boolean wasAnyoneInterested = _stateManager.methodReceived(evt); if(!_frameListeners.isEmpty()) { for (AMQMethodListener listener : _frameListeners) { - wasAnyoneInterested = listener.methodReceived(evt, this, _queueRegistry, _exchangeRegistry) || + wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; } } @@ -233,7 +243,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _logger.error("Closing connection due to: " + e.getMessage()); writeFrame(e.getCloseFrame(frame.channel)); } - catch (AMQException e) + catch (Exception e) { _stateManager.error(e); for (AMQMethodListener listener : _frameListeners) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index fb78b0d8b7..70e530699e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -25,7 +25,7 @@ import org.apache.qpid.framing.*; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.handler.*; import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQMethodListener; +import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.log4j.Logger; @@ -43,7 +43,9 @@ import java.util.concurrent.CopyOnWriteArraySet; public class AMQStateManager implements AMQMethodListener { private static final Logger _logger = Logger.getLogger(AMQStateManager.class); - + private final QueueRegistry _queueRegistry; + private final ExchangeRegistry _exchangeRegistry; + private final AMQProtocolSession _protocolSession; /** * The current state */ @@ -58,13 +60,16 @@ public class AMQStateManager implements AMQMethodListener private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - public AMQStateManager() + public AMQStateManager(QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession) { - this(AMQState.CONNECTION_NOT_STARTED, true); + this(AMQState.CONNECTION_NOT_STARTED, true, queueRegistry, exchangeRegistry, protocolSession); } - protected AMQStateManager(AMQState initial, boolean register) + protected AMQStateManager(AMQState initial, boolean register, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession) { + _queueRegistry = queueRegistry; + _exchangeRegistry = exchangeRegistry; + _protocolSession = protocolSession; _currentState = initial; if (register) { @@ -149,7 +154,7 @@ public class AMQStateManager implements AMQMethodListener } } - public void error(AMQException e) + public void error(Exception e) { _logger.error("State manager received error notification: " + e, e); for (StateListener l : _stateListeners) @@ -158,15 +163,12 @@ public class AMQStateManager implements AMQMethodListener } } - public boolean methodReceived(AMQMethodEvent evt, - AMQProtocolSession protocolSession, - QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry) throws AMQException + public boolean methodReceived(AMQMethodEvent evt) throws AMQException { StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod()); if (handler != null) { - handler.methodReceived(this, queueRegistry, exchangeRegistry, protocolSession, evt); + handler.methodReceived(this, _queueRegistry, _exchangeRegistry, _protocolSession, evt); return true; } return false; -- cgit v1.2.1 From 1a2327b98e6d5b2a65a12b70a9abc3f5ceb0f113 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 15 Jan 2007 16:10:59 +0000 Subject: QPID-295 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496384 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/AMQQueueMBean.java | 34 +++++++++++++++------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index fb4a8e06bf..012b3600ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -54,16 +54,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method - private String[] _msgAttributeNames = {"Message Id", "Header", "Size(bytes)", "Redelivered"}; - private String[] _msgAttributeIndex = {_msgAttributeNames[0]}; - private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + private final static String[] _msgAttributeNames = {"AMQ MessageId", "Header", "Size(bytes)", "Redelivered"}; + private static String[] _msgAttributeIndex = {_msgAttributeNames[0]}; + private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. // OpenMBean data types for viewMessageContent method - private CompositeType _msgContentType = null; - private String[] _msgContentAttributes = {"Message Id", "MimeType", "Encoding", "Content"}; - private OpenType[] _msgContentAttributeTypes = new OpenType[4]; + private static CompositeType _msgContentType = null; + private final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"}; + private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException @@ -71,13 +71,25 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); - init(); + } + + static + { + try + { + init(); + } + catch(JMException ex) + { + // It should never occur + System.out.println(ex.getMessage()); + } } /** * initialises the openmbean data types */ - private void init() throws OpenDataException + private static void init() throws OpenDataException { _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType @@ -376,4 +388,4 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue return new MBeanNotificationInfo[]{info1}; } -} // End of AMQMBean class +} // End of AMQQueueMBean class -- cgit v1.2.1 From 9fc53037c7b4d32b3f0f9270b5ea50899d60133d Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 16 Jan 2007 10:51:04 +0000 Subject: QPID-299 Messages not being correctly requeued when transacted session closed git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496658 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 0497d4bb8f..10f039779c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -311,6 +311,7 @@ public class AMQChannel _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); + _txnContext.commit(); } private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException -- cgit v1.2.1 From d3afeb37f22fc356d5cda3861a85c8f949a9c051 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 19 Jan 2007 10:35:21 +0000 Subject: QPID-275 : Patch supplied by Rob Godfrey - Add support for get / purge / qos size / default exchanges and some other small fixes highlighted by the python tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497770 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 83 ++++- .../qpid/server/ack/UnacknowledgedMessageMap.java | 2 + .../server/ack/UnacknowledgedMessageMapImpl.java | 28 +- .../server/exchange/DefaultExchangeRegistry.java | 24 +- .../qpid/server/exchange/ExchangeRegistry.java | 2 + .../server/handler/BasicConsumeMethodHandler.java | 44 +-- .../server/handler/BasicPublishMethodHandler.java | 17 +- .../qpid/server/handler/BasicQosHandler.java | 2 + .../server/handler/BasicRecoverMethodHandler.java | 4 +- .../handler/ConnectionOpenMethodHandler.java | 11 +- .../server/handler/ExchangeDeclareHandler.java | 4 +- .../qpid/server/handler/QueueDeclareHandler.java | 22 +- .../qpid/server/handler/QueueDeleteHandler.java | 10 +- .../qpid/server/handler/TxRollbackHandler.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 55 ++- .../qpid/server/protocol/AMQProtocolSession.java | 2 + .../qpid/server/protocol/ExchangeInitialiser.java | 2 + .../org/apache/qpid/server/queue/AMQMessage.java | 82 ++++- .../org/apache/qpid/server/queue/AMQQueue.java | 139 ++++++-- .../server/queue/ConcurrentDeliveryManager.java | 367 --------------------- .../queue/ConcurrentSelectorDeliveryManager.java | 77 ++++- .../apache/qpid/server/queue/DeliveryManager.java | 6 +- .../org/apache/qpid/server/queue/Subscription.java | 2 + .../apache/qpid/server/queue/SubscriptionImpl.java | 59 +++- .../apache/qpid/server/queue/SubscriptionSet.java | 2 +- .../server/queue/SynchronizedDeliveryManager.java | 268 --------------- .../apache/qpid/server/state/AMQStateManager.java | 19 ++ 27 files changed, 552 insertions(+), 783 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 10f039779c..2529ddc064 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -37,6 +37,7 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.mina.common.ByteBuffer; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -56,6 +57,8 @@ public class AMQChannel private long _prefetch_LowWaterMark; + private long _prefetchSize; + /** * 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 @@ -108,6 +111,8 @@ public class AMQChannel private Set _browsedAcks = new HashSet(); + + public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) throws AMQException { @@ -151,6 +156,17 @@ public class AMQChannel _prefetch_HighWaterMark = prefetchCount; } + public long getPrefetchSize() + { + return _prefetchSize; + } + + + public void setPrefetchSize(long prefetchSize) + { + _prefetchSize = prefetchSize; + } + public long getPrefetchLowMarkCount() { return _prefetch_LowWaterMark; @@ -213,14 +229,15 @@ public class AMQChannel 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 if (_log.isDebugEnabled()) { _log.debug("Content body received on channel " + _channelId); } try { + + // returns true iff the message was delivered (i.e. if all data was + // received if (_currentMessage.addContentBodyFrame(_storeContext, contentBody)) { // callback to allow the context to do any post message processing @@ -269,13 +286,14 @@ public class AMQChannel * @param queue the queue to subscribe to * @param session the protocol session of the subscriber * @param noLocal + * @param exclusive * @return the consumer tag. This is returned to the subscriber and used in * subsequent unsubscribe requests * @throws ConsumerTagNotUniqueException if the tag is not unique * @throws AMQException if something goes wrong */ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { @@ -286,7 +304,7 @@ public class AMQChannel throw new ConsumerTagNotUniqueException(); } - queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal); + queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive); _consumerTag2QueueMap.put(tag, queue); return tag; } @@ -364,8 +382,10 @@ public class AMQChannel /** * Called to resend all outstanding unacknowledged messages to this same channel. */ - public void resend(final AMQProtocolSession session) throws AMQException + public void resend(final AMQProtocolSession session, final boolean requeue) throws AMQException { + final List msgToRequeue = new LinkedList(); + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { public boolean callback(UnacknowledgedMessage message) throws AMQException @@ -374,7 +394,20 @@ public class AMQChannel AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; msg.setRedelivered(true); - msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); + if((consumerTag != null) && _consumerTag2QueueMap.containsKey(consumerTag)) + { + msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); + } + else + { + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (message.queue != null && (consumerTag == null || requeue)) + { + msgToRequeue.add(message); + } + } // false means continue processing return false; } @@ -383,6 +416,12 @@ public class AMQChannel { } }); + + for(UnacknowledgedMessage message : msgToRequeue) + { + _txnContext.deliver(message.message, message.queue); + _unacknowledgedMessageMap.remove(message.deliveryTag); + } } /** @@ -459,8 +498,9 @@ public class AMQChannel { boolean suspend; - suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; - + suspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark) + || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); + setSuspended(suspend); } @@ -545,4 +585,31 @@ public class AMQChannel } _returnMessages.clear(); } + + + public boolean wouldSuspend(AMQMessage msg) + { + if (isSuspended()) + { + return true; + } + else + { + boolean willSuspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() + 1 > _prefetch_HighWaterMark); + if(!willSuspend) + { + final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); + + willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < msg.getSize() + unackedSize); + } + + + if(willSuspend) + { + setSuspended(true); + } + return willSuspend; + } + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index ef58ba01a3..7ea22a447f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -73,5 +73,7 @@ public interface UnacknowledgedMessageMap * @return a set of delivery tags */ Set getDeliveryTags(); + + public long getUnacknowledgeBytes(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index a21e4cfff6..e50d239d57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -32,6 +32,8 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { private final Object _lock = new Object(); + private long _unackedSize; + private Map _map; private long _lastDeliveryTag; @@ -77,7 +79,8 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { for (UnacknowledgedMessage msg : msgs) { - _map.remove(msg.deliveryTag); + remove(msg.deliveryTag); + } } } @@ -86,7 +89,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { synchronized (_lock) { - return _map.remove(deliveryTag); + + UnacknowledgedMessage message = _map.remove(deliveryTag); + if(message != null) + { + _unackedSize -= message.message.getSize(); + } + + return message; } } @@ -113,6 +123,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap synchronized (_lock) { _map.put(deliveryTag, message); + _unackedSize += message.message.getSize(); _lastDeliveryTag = deliveryTag; } } @@ -123,6 +134,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { Collection currentEntries = _map.values(); _map = new LinkedHashMap(_prefetchLimit); + _unackedSize = 0l; return currentEntries; } } @@ -149,6 +161,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap synchronized (_lock) { _map.clear(); + _unackedSize = 0l; } } @@ -169,6 +182,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } it.remove(); + _unackedSize -= unacked.getValue().message.getSize(); destination.add(unacked.getValue()); if (unacked.getKey() == deliveryTag) @@ -189,7 +203,10 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap AMQShortString consumerTag = entry.getValue().consumerTag; AMQMessage msg = entry.getValue().message; - msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); + if(consumerTag != null) + { + msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); + } } } } @@ -224,4 +241,9 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } } + + public long getUnacknowledgeBytes() + { + return _unackedSize; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index cadcd22001..374772bc4a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -38,6 +38,8 @@ public class DefaultExchangeRegistry implements ExchangeRegistry */ private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); + private Exchange _defaultExchange; + public DefaultExchangeRegistry(ExchangeFactory exchangeFactory) { //create 'standard' exchanges: @@ -53,9 +55,18 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) { + if(_defaultExchange == null) + { + setDefaultExchange(exchange); + } _exchangeMap.put(exchange.getName(), exchange); } + public void setDefaultExchange(Exchange exchange) + { + _defaultExchange = exchange; + } + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument @@ -72,7 +83,16 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public Exchange getExchange(AMQShortString name) { - return _exchangeMap.get(name); + + if(name == null || name.length() == 0) + { + return _defaultExchange; + } + else + { + return _exchangeMap.get(name); + } + } /** @@ -83,7 +103,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void routeContent(AMQMessage payload) throws AMQException { final AMQShortString exchange = payload.getPublishBody().exchange; - final Exchange exch = _exchangeMap.get(exchange); + final Exchange exch = getExchange(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) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index efcb963f8b..24884d20d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -38,4 +38,6 @@ public interface ExchangeRegistry extends MessageRouter void unregisterExchange(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; Exchange getExchange(AMQShortString name); + + void setDefaultExchange(Exchange exchange); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index e078b0cdee..721001b454 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidSelectorException; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.*; import org.apache.qpid.server.AMQChannel; @@ -66,6 +68,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener AMQProtocolSession session, AMQMethodEvent evt) throws AMQException { session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); + session.getChannel(evt.getChannelId()).setPrefetchSize(evt.getMethod().prefetchSize); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index 0e37871439..f3e0cc3a63 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -52,6 +52,8 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener evt) throws AMQException { ConnectionOpenBody body = evt.getMethod(); - AMQShortString 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) + if (protocolSession.getContextKey() == null) { - contextKey = generateClientID(); + protocolSession.setContextKey(generateClientID()); } - protocolSession.setContextKey(contextKey); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, (byte)8, (byte)0, // AMQP version (major, minor) - contextKey); // knownHosts + body.virtualHost); // knownHosts stateManager.changeState(AMQState.CONNECTION_OPEN); protocolSession.writeFrame(response); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index f6897227aa..84e9a4e3f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -76,7 +76,7 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener @@ -84,15 +85,12 @@ public class QueueDeleteHandler implements StateAwareMethodListener 1) + { + if(isExclusive()) + { + decrementSubscriberCount(); + throw EXISTING_EXCLUSIVE; + } + else if(exclusive) + { + decrementSubscriberCount(); + throw EXISTING_SUBSCRIPTION; + } + + } + else if(exclusive) + { + setExclusive(true); + } + 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, filters, noLocal); @@ -385,6 +409,28 @@ public class AMQQueue implements Managable, Comparable _subscribers.addSubscriber(subscription); } + + private boolean isExclusive() + { + return _isExclusive.get(); + } + + private void setExclusive(boolean exclusive) + { + _isExclusive.set(exclusive); + } + + private int incrementSubscriberCount() + { + return _subscriberCount.incrementAndGet(); + } + + private int decrementSubscriberCount() + { + return _subscriberCount.decrementAndGet(); + } + + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException { debug("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, @@ -400,6 +446,10 @@ public class AMQQueue implements Managable, Comparable " and protocol session key " + ps.getKey() + " not registered with queue " + this); } + setExclusive(false); + decrementSubscriberCount(); + + // if we are eligible for auto deletion, unregister from the queue registry if (_autoDelete && _subscribers.isEmpty()) { @@ -454,6 +504,23 @@ public class AMQQueue implements Managable, Comparable delete(); } + public void processGet(StoreContext storeContext, AMQMessage msg) throws AMQException + { + _deliveryMgr.deliver(storeContext, getName(), msg); + try + { + msg.checkDeliveredToConsumer(); + updateReceivedMessageCount(msg); + } + catch (NoConsumersException e) + { + // as this message will be returned, it should be removed + // from the queue: + dequeue(storeContext, msg); + } + } + + public void process(StoreContext storeContext, AMQMessage msg) throws AMQException { _deliveryMgr.deliver(storeContext, getName(), msg); @@ -547,4 +614,12 @@ public class AMQQueue implements Managable, Comparable _logger.debug(MessageFormat.format(msg, args)); } } + + public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException + { + return _deliveryMgr.performGet(session, channel, acks); + } + + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java deleted file mode 100644 index 1a44e86f1a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQShortString; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; - -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; - - -/** - * Manages delivery of messages on behalf of a queue - */ -public class ConcurrentDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); - - @Configured(path = "advanced.compressBufferOnQueue", - defaultValue = "false") - public boolean compressBufferOnQueue; - - /** - * Holds any queued messages - */ - private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); - - //private int _messageCount; - /** - * Ensures that only one asynchronous task is running for this manager at - * any time. - */ - private final AtomicBoolean _processing = new AtomicBoolean(); - - /** - * The subscriptions on the queue to whom messages are delivered - */ - private final SubscriptionManager _subscriptions; - - /** - * A reference to the queue we are delivering messages for. We need this to be able - * to pass the code that handles acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - /** - * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced - * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered - * via the async thread. - *

      - * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. - */ - private ReentrantLock _lock = new ReentrantLock(); - - ConcurrentDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - - //Set values from configuration - Configurator.configure(this); - - if (compressBufferOnQueue) - { - _log.info("Compressing Buffers on queue."); - } - - _subscriptions = subscriptions; - _queue = queue; - } - - /** - * @return boolean if we are queueing - */ - private boolean queueing() - { - return hasQueuedMessages(); - } - - /** - * @param msg to enqueue - * @return true if we are queue this message - */ - private boolean enqueue(AMQMessage msg) throws AMQException - { - if (msg.getPublishBody().immediate) - { - return false; - } - else - { - _lock.lock(); - try - { - if (queueing()) - { - return addMessageToQueue(msg); - } - else - { - return false; - } - } - finally - { - _lock.unlock(); - } - } - } - - private void startQueueing(AMQMessage msg) throws AMQException - { - if (!msg.getPublishBody().immediate) - { - addMessageToQueue(msg); - } - } - - private boolean addMessageToQueue(AMQMessage msg) - { - // Shrink the ContentBodies to their actual size to save memory. - /* TODO need to reimplement this - probably not in this class though - * for obvious reasons - - if (compressBufferOnQueue) - { - Iterator it = msg.getContentBodies().iterator(); - while (it.hasNext()) - { - ContentBody cb = (ContentBody) it.next(); - cb.reduceBufferToFit(); - } - } - */ - _messages.offer(msg); - - return true; - } - - public boolean hasQueuedMessages() - { - _lock.lock(); - try - { - return !_messages.isEmpty(); - } - finally - { - _lock.unlock(); - } - } - - public int getQueueMessageCount() - { - return getMessageCount(); - } - - /** - * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine size. - * The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. - * - * @return int the number of messages in the delivery queue. - */ - private int getMessageCount() - { - return _messages.size(); - } - - - public synchronized List getMessages() - { - return new ArrayList(_messages); - } - - public void populatePreDeliveryQueue(Subscription subscription) - { - //no-op . This DM has no PreDeliveryQueues - } - - public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException - { - AMQMessage msg = poll(); - if (msg != null) - { - msg.dequeue(storeContext, _queue); - } - } - - public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException - { - AMQMessage msg = poll(); - while (msg != null) - { - msg.dequeue(storeContext, _queue); - msg = poll(); - } - } - - /** - * Only one thread should ever execute this method concurrently, but - * it can do so while other threads invoke deliver(). - */ - private void processQueue() throws AMQException - { - try - { - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - AMQMessage message = peek(); - - //While we have messages to send and subscribers to send them to. - while (message != null && hasSubscribers) - { - // _log.debug("Have messages(" + _messages.size() + ") and subscribers"); - Subscription next = _subscriptions.nextSubscriber(message); - //FIXME Is there still not the chance that this subscribe could be suspended between here and the send? - - //We don't synchronize access to subscribers so need to re-check - if (next != null) - { - next.send(message, _queue); - poll(); - message = peek(); - } - else - { - hasSubscribers = false; - } - } - } - catch (FailedDequeueException e) - { - _log.error("Unable to deliver message as dequeue failed: " + e, e); - } - finally - { - _log.debug("End of processQueue: (" + getQueueMessageCount() + ")" + " subscribers:" + _subscriptions.hasActiveSubscribers()); - } - } - - private AMQMessage peek() - { - return _messages.peek(); - } - - private AMQMessage poll() - { - return _messages.poll(); - } - - Runner asyncDelivery = new Runner(); - - public void processAsync(Executor executor) - { - _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get()); - - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - // Do we need this? - // This executor is created via Executors in AsyncDeliveryConfig which only returns a TPE so cast is ok. - //if (executor != null && !((ThreadPoolExecutor) executor).isShutdown()) - { - executor.execute(asyncDelivery); - } - } - } - } - - public void deliver(StoreContext storeContext, AMQShortString 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 - _lock.lock(); - try - { - 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); - } - } - finally - { - _lock.unlock(); - } - } - } - - private class Runner implements Runnable - { - public void run() - { - boolean running = true; - while (running) - { - try - { - processQueue(); - } - catch (AMQException e) - { - _log.error("Error processing queue: " + e, e); - _log.error("Delivery manager terminating."); - running = false; - _processing.set(false); - break; - } - - //Check that messages have not been added since we did our last peek(); - // Synchronize with the thread that adds to the queue. - // If the queue is still empty then we can exit - _lock.lock(); - try - { - if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) - { - running = false; - _processing.set(false); - } - } - finally - { - _lock.unlock(); - } - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 91c49a4cf9..ba4d0bf4ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -28,6 +28,8 @@ import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; import java.util.ArrayList; import java.util.Iterator; @@ -52,6 +54,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager * Holds any queued messages */ private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); + + private final ReentrantLock _messageAccessLock = new ReentrantLock(); + //private int _messageCount; /** * Ensures that only one asynchronous task is running for this manager at @@ -169,6 +174,56 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException + { + AMQMessage msg = getNextMessage(); + if(msg == null) + { + return false; + } + else + { + + try + { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + if (!acks) + { + if (_log.isDebugEnabled()) + { + _log.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); + } + _queue.dequeue(channel.getStoreContext(), msg); + } + synchronized(channel) + { + long deliveryTag = channel.getNextDeliveryTag(); + + if (acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, null, _queue); + } + + msg.writeGetOk(protocolSession, channel.getChannelId(), deliveryTag, _queue.getMessageCount()); + } + } + finally + { + msg.setDeliveredToConsumer(); + } + return true; + + } + } + public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); @@ -178,22 +233,35 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException + public synchronized long clearAllMessages(StoreContext storeContext) throws AMQException { + long count = 0; AMQMessage msg = poll(); while (msg != null) { msg.dequeue(storeContext, _queue); + count++; msg = poll(); } + return count; + } + + public synchronized AMQMessage getNextMessage() throws AMQException + { + return getNextMessage(_messages); } - private AMQMessage getNextMessage(Queue messages, Subscription sub) + private AMQMessage getNextMessage(Queue messages) + { + return getNextMessage(messages, false); + } + + private AMQMessage getNextMessage(Queue messages, boolean browsing) { AMQMessage message = messages.peek(); - while (message != null && (sub.isBrowser() || message.taken())) + while (message != null && (browsing || message.taken())) { //remove the already taken message messages.poll(); @@ -208,7 +276,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager AMQMessage message = null; try { - message = getNextMessage(messageQueue, sub); + message = getNextMessage(messageQueue, sub.isBrowser()); // message will be null if we have no messages in the messageQueue. if (message == null) @@ -287,6 +355,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _log.debug(id() + "deliver :" + msg); } + msg.release(); //Check if we have someone to deliver the message to. _lock.lock(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index d3d235f07f..6954be8473 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; import java.util.concurrent.Executor; import java.util.List; @@ -72,9 +74,11 @@ interface DeliveryManager void removeAMessageFromTop(StoreContext storeContext) throws AMQException; - void clearAllMessages(StoreContext storeContext) throws AMQException; + long clearAllMessages(StoreContext storeContext) throws AMQException; List getMessages(); void populatePreDeliveryQueue(Subscription subscription); + + boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index 2dab551e07..5277069d33 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -45,4 +45,6 @@ public interface Subscription void close(); boolean isBrowser(); + + boolean wouldSuspend(AMQMessage msg); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index e2356faaf5..e120752959 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -66,6 +66,7 @@ public class SubscriptionImpl implements Subscription private final boolean _isBrowser; private final Boolean _autoClose; private boolean _closed = false; + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); public static class Factory implements SubscriptionFactory { @@ -300,37 +301,54 @@ public class SubscriptionImpl implements Subscription { if (_noLocal) { + boolean isLocal; // We don't want local messages so check to see if message is one we sent - Object localInstance = protocolSession.getClientProperties().getObject(ClientProperties.instance.toString()); - Object msgInstance = msg.getPublisher().getClientProperties().getObject(ClientProperties.instance.toString()); + Object localInstance; + Object msgInstance; - if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) + if((protocolSession.getClientProperties() != null) && + (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { - if (_logger.isTraceEnabled()) + if((msg.getPublisher().getClientProperties() != null) && + (msgInstance = msg.getPublisher().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { - _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + - System.identityHashCode(msg) + ")"); + if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) + { + if (_logger.isTraceEnabled()) + { + _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + + System.identityHashCode(msg) + ")"); + } + return false; + } } - return false; } - else // if not then filter the message. + else { - if (_logger.isTraceEnabled()) + localInstance = protocolSession.getClientIdentifier(); + msgInstance = msg.getPublisher().getClientIdentifier(); + if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) { - _logger.trace("(" + System.identityHashCode(this) + ") local message(" + System.identityHashCode(msg) + - ") but not ours so filtering"); + if (_logger.isTraceEnabled()) + { + _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + + System.identityHashCode(msg) + ")"); + } + return false; } - return checkFilters(msg); + } + + } - else + + + if (_logger.isTraceEnabled()) { - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + System.identityHashCode(this) + ") checking filters for message (" + System.identityHashCode(msg)); - } - return checkFilters(msg); + _logger.trace("(" + System.identityHashCode(this) + ") checking filters for message (" + System.identityHashCode(msg)); } + return checkFilters(msg); + } private boolean checkFilters(AMQMessage msg) @@ -393,6 +411,11 @@ public class SubscriptionImpl implements Subscription return _isBrowser; } + public boolean wouldSuspend(AMQMessage msg) + { + return channel.wouldSuspend(msg); + } + private ByteBuffer createEncodedDeliverFrame(long deliveryTag, AMQShortString routingKey, AMQShortString exchange) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index 8272202571..e7c90fb201 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -137,7 +137,7 @@ class SubscriptionSet implements WeightedSubscriptionManager ++_currentSubscriber; subscriberScanned(); - if (!subscription.isSuspended()) + if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) { if (subscription.hasInterest(msg)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java deleted file mode 100644 index 02fe86a083..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.store.StoreContext; -import org.apache.log4j.Logger; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Manages delivery of messages on behalf of a queue - */ -class SynchronizedDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(SynchronizedDeliveryManager.class); - - /** - * Holds any queued messages - */ - private final Queue _messages = new LinkedList(); - - /** - * Ensures that only one asynchronous task is running for this manager at - * any time. - */ - private final AtomicBoolean _processing = new AtomicBoolean(); - - /** - * The subscriptions on the queue to whom messages are delivered - */ - private final SubscriptionManager _subscriptions; - - /** - * An indication of the mode we are in. If this is true then messages are - * being queued up in _messages for asynchronous delivery. If it is false - * then messages can be delivered directly as they come in. - */ - private volatile boolean _queueing; - - /** - * A reference to the queue we are delivering messages for. We need this to be able - * to pass the code that handles acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - SynchronizedDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - _subscriptions = subscriptions; - _queue = queue; - } - - private synchronized boolean enqueue(AMQMessage msg) throws AMQException - { - if (msg.getPublishBody().immediate) - { - return false; - } - else - { - if (_queueing) - { - _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 - */ - public synchronized boolean hasQueuedMessages() - { - boolean empty = _messages.isEmpty(); - if (empty) - { - _queueing = false; - } - return !empty; - } - - public synchronized int getQueueMessageCount() - { - return _messages.size(); - } - - public synchronized List getMessages() - { - return new ArrayList(_messages); - } - - public void populatePreDeliveryQueue(Subscription subscription) - { - //no-op . This DM has no PreDeliveryQueues - } - - public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException - { - AMQMessage msg = poll(); - if (msg != null) - { - msg.dequeue(storeContext, _queue); - } - } - - public synchronized void clearAllMessages(StoreContext storeContext) throws AMQException - { - AMQMessage msg = poll(); - while (msg != null) - { - msg.dequeue(storeContext, _queue); - msg = poll(); - } - } - - /** - * Only one thread should ever execute this method concurrently, but - * it can do so while other threads invoke deliver(). - */ - private void processQueue() - { - try - { - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - while (hasQueuedMessages() && hasSubscribers) - { - Subscription next = _subscriptions.nextSubscriber(peek()); - //We don't synchronize access to subscribers so need to re-check - if (next != null) - { - try - { - next.send(poll(), _queue); - } - catch (AMQException e) - { - _log.error("Unable to deliver message: " + e, e); - } - } - else - { - hasSubscribers = false; - } - } - } - finally - { - _processing.set(false); - } - } - - private synchronized AMQMessage peek() - { - return _messages.peek(); - } - - private synchronized AMQMessage poll() - { - return _messages.poll(); - } - - /** - * Requests that the delivery manager start processing the queue asynchronously - * if there is work that can be done (i.e. there are messages queued up and - * subscribers that can receive them. - *

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

      - * - * @param executor the executor on which the delivery should take place - */ - public void processAsync(Executor executor) - { - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - // Do we need this? - // This executor is created via Executors in AsyncDeliveryConfig which only returns a TPE so cast is ok. - //if (executor != null && !((ThreadPoolExecutor) executor).isShutdown()) - { - executor.execute(new Runner()); - } - } - } - } - - /** - * Handles message delivery. The delivery manager is always in one of two modes; - * it is either queueing messages for asynchronous delivery or delivering - * directly. - * - * @param name the name of the entity on whose behalf we are delivering the message - * @param msg the message to deliver - * @throws NoConsumersException if there are no active subscribers to deliver - * the message to - */ - public void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg) throws FailedDequeueException, AMQException - { - // first check whether we are queueing, and enqueue if we are - if (!enqueue(msg)) - { - synchronized(this) - { - // not queueing so deliver message to 'next' subscriber - Subscription s = _subscriptions.nextSubscriber(msg); - if (s == null) - { - // no subscribers yet so enter 'queueing' mode and queue this message - startQueueing(msg); - } - else - { - s.send(msg, _queue); - } - } - } - - } - - private class Runner implements Runnable - { - public void run() - { - processQueue(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 70e530699e..81ce704026 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -21,6 +21,8 @@ package org.apache.qpid.server.state; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.*; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.handler.*; @@ -28,6 +30,7 @@ import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.AMQChannel; import org.apache.log4j.Logger; import java.util.HashMap; @@ -118,12 +121,14 @@ public class AMQStateManager implements AMQMethodListener frame2handlerMap.put(BasicAckBody.class, BasicAckMethodHandler.getInstance()); frame2handlerMap.put(BasicRecoverBody.class, BasicRecoverMethodHandler.getInstance()); frame2handlerMap.put(BasicConsumeBody.class, BasicConsumeMethodHandler.getInstance()); + frame2handlerMap.put(BasicGetBody.class, BasicGetMethodHandler.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(QueuePurgeBody.class, QueuePurgeHandler.getInstance()); frame2handlerMap.put(ChannelFlowBody.class, ChannelFlowHandler.getInstance()); frame2handlerMap.put(TxSelectBody.class, TxSelectHandler.getInstance()); frame2handlerMap.put(TxCommitBody.class, TxCommitHandler.getInstance()); @@ -168,12 +173,26 @@ public class AMQStateManager implements AMQMethodListener StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod()); if (handler != null) { + + checkChannel(evt, _protocolSession); + handler.methodReceived(this, _queueRegistry, _exchangeRegistry, _protocolSession, evt); return true; } return false; } + private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) + throws AMQException + { + if(evt.getChannelId() != 0 + && !(evt.getMethod() instanceof ChannelOpenBody) + && protocolSession.getChannel(evt.getChannelId()) == null) + { + throw evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR.getCode(),"No such channel: " + evt.getChannelId()); + } + } + protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, B frame) throws IllegalStateTransitionException -- cgit v1.2.1 From 0420b0021e02254d161f027529b80991060d3cc8 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 22 Jan 2007 10:26:03 +0000 Subject: QPID-275 : Patch supplied by Rob Godfrey - Add support for get / purge / qos size / default exchanges and some other small fixes highlighted by the python tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498574 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicGetMethodHandler.java | 77 ++++++++++++++++++++ .../qpid/server/handler/QueuePurgeHandler.java | 81 ++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java new file mode 100644 index 0000000000..1eb3152973 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -0,0 +1,77 @@ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.*; +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.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ConsumerTagNotUniqueException; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidSelectorException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession session, + AMQMethodEvent evt) throws AMQException + { + BasicGetBody 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 + "'"); + if(body.queue!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND.getCode(), + "No such queue, '" + body.queue + "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED.getCode(), + "No queue name provided, no default queue defined."); + } + } + else + { + if(!queue.performGet(session, channel, !body.noAck)) + { + + + // TODO - set clusterId + session.writeFrame(BasicGetEmptyBody.createAMQFrame(channelId, (byte) 8, (byte) 0, null)); + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java new file mode 100644 index 0000000000..ad63d36351 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -0,0 +1,81 @@ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; +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.protocol.AMQMethodEvent; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, AMQProtocolSession session, AMQMethodEvent evt) throws AMQException + { + QueuePurgeBody body = evt.getMethod(); + AMQQueue queue; + if(body.queue == null) + { + queue = session.getChannel(evt.getChannelId()).getDefaultQueue(); + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED.getCode(),"No queue specified."); + } + + } + } + else + { + queue = queues.getQueue(body.queue); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(404, "Queue " + body.queue + " does not exist."); + } + } + else + { + long purged = queue.clearQueue(session.getChannel(evt.getChannelId()).getStoreContext()); + + + if(!body.nowait) + { + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + session.writeFrame(QueuePurgeOkBody.createAMQFrame(evt.getChannelId(), + (byte)8, (byte)0, // AMQP version (major, minor) + purged)); // messageCount + } + } + } +} -- cgit v1.2.1 From 1ee7712d55033e1ec39929b9c48dd1e399b9e52a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 22 Jan 2007 16:16:51 +0000 Subject: modified the mbean and mbean test for any failure in creating TabularData(for channels) git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498670 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 08045e1c41..df494915a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -178,7 +178,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed for (AMQChannel channel : list) { Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, channel.getUnacknowledgedMessageMap().size()}; CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); -- cgit v1.2.1 From c23332e9a0ad5fd751824616367d3a4ca5c0b0e2 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 23 Jan 2007 14:58:56 +0000 Subject: QPID-314 : Patch supplied by Rob Godfrey - treat non-durable exclusive queues as auto-delete git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499041 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 19df23b103..b62fe22b89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -148,6 +148,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener Date: Wed, 24 Jan 2007 15:41:48 +0000 Subject: QPID-50 : Patch supplied by Rob Godfrey - Virtual Host implementation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499446 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 46 +++-- .../src/main/java/org/apache/qpid/server/Main.java | 25 +-- .../qpid/server/configuration/Configurator.java | 19 +- .../configuration/VirtualHostConfiguration.java | 21 ++- .../qpid/server/exchange/AbstractExchange.java | 39 ++++- .../server/exchange/DefaultExchangeFactory.java | 7 +- .../qpid/server/exchange/DestNameExchange.java | 2 +- .../qpid/server/exchange/DestWildExchange.java | 3 +- .../org/apache/qpid/server/exchange/Exchange.java | 3 +- .../qpid/server/exchange/FanoutExchange.java | 4 +- .../qpid/server/exchange/HeadersExchange.java | 2 +- .../qpid/server/handler/BasicAckMethodHandler.java | 7 +- .../server/handler/BasicCancelMethodHandler.java | 7 +- .../server/handler/BasicConsumeMethodHandler.java | 11 +- .../qpid/server/handler/BasicGetMethodHandler.java | 11 +- .../server/handler/BasicPublishMethodHandler.java | 15 +- .../qpid/server/handler/BasicQosHandler.java | 5 +- .../server/handler/BasicRecoverMethodHandler.java | 13 +- .../qpid/server/handler/ChannelCloseHandler.java | 10 +- .../qpid/server/handler/ChannelCloseOkHandler.java | 5 +- .../qpid/server/handler/ChannelFlowHandler.java | 9 +- .../qpid/server/handler/ChannelOpenHandler.java | 19 +- .../handler/ConnectionCloseMethodHandler.java | 11 +- .../handler/ConnectionCloseOkMethodHandler.java | 7 +- .../handler/ConnectionOpenMethodHandler.java | 45 +++-- .../handler/ConnectionSecureOkMethodHandler.java | 17 +- .../handler/ConnectionStartOkMethodHandler.java | 19 +- .../handler/ConnectionTuneOkMethodHandler.java | 7 +- .../qpid/server/handler/ExchangeBoundHandler.java | 14 +- .../server/handler/ExchangeDeclareHandler.java | 15 +- .../qpid/server/handler/ExchangeDeleteHandler.java | 11 +- .../qpid/server/handler/QueueBindHandler.java | 15 +- .../qpid/server/handler/QueueDeclareHandler.java | 63 +++++-- .../qpid/server/handler/QueueDeleteHandler.java | 19 +- .../qpid/server/handler/QueuePurgeHandler.java | 9 +- .../qpid/server/handler/TxCommitHandler.java | 12 +- .../qpid/server/handler/TxRollbackHandler.java | 13 +- .../qpid/server/handler/TxSelectHandler.java | 11 +- .../server/management/DefaultManagedObject.java | 10 +- .../server/protocol/AMQMinaProtocolSession.java | 53 ++++-- .../server/protocol/AMQPFastProtocolHandler.java | 31 +--- .../qpid/server/protocol/AMQPProtocolProvider.java | 3 +- .../qpid/server/protocol/AMQProtocolSession.java | 17 ++ .../server/protocol/AMQProtocolSessionMBean.java | 6 + .../org/apache/qpid/server/queue/AMQQueue.java | 107 ++++++------ .../apache/qpid/server/queue/AMQQueueMBean.java | 22 ++- .../qpid/server/queue/DefaultQueueRegistry.java | 11 +- .../apache/qpid/server/queue/QueueRegistry.java | 3 + .../qpid/server/registry/ApplicationRegistry.java | 32 ++-- .../ConfigurationFileApplicationRegistry.java | 66 +++---- .../qpid/server/registry/IApplicationRegistry.java | 18 +- .../apache/qpid/server/state/AMQStateManager.java | 27 ++- .../server/state/StateAwareMethodListener.java | 5 +- .../qpid/server/store/MemoryMessageStore.java | 3 +- .../org/apache/qpid/server/store/MessageStore.java | 5 +- .../qpid/server/util/NullApplicationRegistry.java | 48 +++-- .../server/virtualhost/ManagedVirtualHost.java | 51 ++++++ .../qpid/server/virtualhost/VirtualHost.java | 193 +++++++++++++++++++++ .../server/virtualhost/VirtualHostRegistry.java | 52 ++++++ 59 files changed, 911 insertions(+), 423 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 6f93a14469..2e6293081d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -30,6 +30,7 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -50,20 +51,28 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final ExchangeFactory _exchangeFactory; private final MessageStore _messageStore; + private final VirtualHost.VirtualHostMBean _virtualHostMBean; + @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean() throws JMException + public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { super(ManagedBroker.class, ManagedBroker.TYPE); - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - _queueRegistry = appRegistry.getQueueRegistry(); - _exchangeRegistry = appRegistry.getExchangeRegistry(); - _exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); - _messageStore = ApplicationRegistry.getInstance().getMessageStore(); + + _virtualHostMBean = virtualHostMBean; + VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); + + + + + _queueRegistry = virtualHost.getQueueRegistry(); + _exchangeRegistry = virtualHost.getExchangeRegistry(); + _messageStore = virtualHost.getMessageStore(); + _exchangeFactory = virtualHost.getExchangeFactory(); } public String getObjectInstanceName() { - return this.getClass().getName(); + return _virtualHostMBean.getVirtualHost().getName(); } /** @@ -144,7 +153,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { - queue = new AMQQueue(new AMQShortString(queueName), durable, new AMQShortString(owner), autoDelete, _queueRegistry); + queue = new AMQQueue(new AMQShortString(queueName), durable, new AMQShortString(owner), autoDelete, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); @@ -157,6 +166,11 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } } + private VirtualHost getVirtualHost() + { + return _virtualHostMBean.getVirtualHost(); + } + /** * Deletes the queue from queue registry and persistant storage. * @@ -183,11 +197,17 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } } - public ObjectName getObjectName() throws MalformedObjectNameException + public ManagedObject getParentObject() { - StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); - objectName.append(":type=").append(getType()); - - return new ObjectName(objectName.toString()); + return _virtualHostMBean; } + +// public ObjectName getObjectName() throws MalformedObjectNameException +// { +// StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); +// objectName.append(".").append(getVirtualHost().getName()); +// objectName.append(":type=").append(getType()); +// +// return new ObjectName(objectName.toString()); +// } } // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index ffd25de0b4..c45d1ad2c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -62,7 +62,7 @@ import java.util.StringTokenizer; * Main entry point for AMQPD. * */ -public class Main implements ProtocolVersionList, Managable +public class Main implements ProtocolVersionList { private static final Logger _logger = Logger.getLogger(Main.class); @@ -70,7 +70,8 @@ public class Main implements ProtocolVersionList, Managable private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - private AMQBrokerManagerMBean _mbean = null; + + private static Main _instance; protected static class InitException extends Exception { @@ -265,7 +266,6 @@ public class Main implements ProtocolVersionList, Managable } bind(port, connectorConfig); - createAndRegisterBrokerMBean(); } protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException @@ -368,7 +368,7 @@ public class Main implements ProtocolVersionList, Managable public static void main(String[] args) { - new Main(args); + _instance = new Main(args); } private byte[] parseIP(String address) throws Exception @@ -430,21 +430,4 @@ public class Main implements ProtocolVersionList, Managable } } - private void createAndRegisterBrokerMBean() throws AMQException - { - try - { - _mbean = new AMQBrokerManagerMBean(); - _mbean.register(); - } - catch (JMException ex) - { - throw new AMQException("Exception occured in creating AMQBrokerManager MBean"); - } - } - - public ManagedObject getManagedObject() - { - return _mbean; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java index 5e3ac03ba7..379da94aa3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java @@ -37,14 +37,15 @@ 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 + * Configure a given instance using the supplied configuration. Note that superclasses are not * currently configured but this could easily be added if required. * @param instance the instance to configure + * @param config the configuration to use to configure the object */ - public static void configure(Object instance) + public static void configure(Object instance, Configuration config) { - final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); for (Field f : instance.getClass().getDeclaredFields()) { @@ -56,6 +57,18 @@ public class Configurator } } + + + /** + * 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) + { + configure(instance, ApplicationRegistry.getInstance().getConfiguration()); + } + private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) { Class fieldClass = f.getType(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 7e807304c8..361a21b284 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -28,6 +28,7 @@ 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.server.virtualhost.VirtualHost; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.log4j.Logger; @@ -113,6 +114,7 @@ public class VirtualHostConfiguration } _logger.info("VirtualHost:'" + prop + "'"); + String virtualHost = prop.toString(); prop = _config.getProperty(path + "." + XML_BIND); if (prop instanceof Collection) @@ -121,16 +123,16 @@ public class VirtualHostConfiguration _logger.debug("Number of Bindings: " + bindings); for (int dest = 0; dest < bindings; dest++) { - loadBinding(path, dest); + loadBinding(virtualHost, path, dest); } } else { - loadBinding(path, -1); + loadBinding(virtualHost,path, -1); } } - private void loadBinding(String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException + private void loadBinding(String virtualHost, String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException { String path = rootpath + "." + XML_BIND; if (index != -1) @@ -146,7 +148,7 @@ public class VirtualHostConfiguration try { - bind(binding); + bind(virtualHost, binding); } catch (AMQException amqe) { @@ -155,7 +157,7 @@ public class VirtualHostConfiguration } } - private void bind(AMQBindingURL binding) throws AMQException, ConfigurationException + private void bind(String virtualHostName, AMQBindingURL binding) throws AMQException, ConfigurationException { AMQShortString queueName = binding.getQueueName(); @@ -169,9 +171,10 @@ public class VirtualHostConfiguration } //Get references to Broker Registries - QueueRegistry queueRegistry = ApplicationRegistry.getInstance().getQueueRegistry(); - MessageStore messageStore = ApplicationRegistry.getInstance().getMessageStore(); - ExchangeRegistry exchangeRegistry = ApplicationRegistry.getInstance().getExchangeRegistry(); + VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore messageStore = virtualHost.getMessageStore(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); synchronized (queueRegistry) { @@ -184,7 +187,7 @@ public class VirtualHostConfiguration 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); + false /* Therefore autodelete makes no sence */, virtualHost); if (queue.isDurable()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 94c792c358..caafb83568 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -25,6 +25,10 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; @@ -34,10 +38,14 @@ public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; + + protected boolean _durable; protected String _exchangeType; protected int _ticket; + private VirtualHost _virtualHost; + protected ExchangeMBean _exchangeMbean; /** @@ -57,6 +65,11 @@ public abstract class AbstractExchange implements Exchange, Managable super(ManagedExchange.class, ManagedExchange.TYPE); } + public ManagedObject getParentObject() + { + return _virtualHost.getManagedObject(); + } + public String getObjectInstanceName() { return _name.toString(); @@ -87,13 +100,17 @@ public abstract class AbstractExchange implements Exchange, Managable return _autoDelete; } - public ObjectName getObjectName() throws MalformedObjectNameException +// public ObjectName getObjectName() throws MalformedObjectNameException +// { +// String objNameString = super.getObjectName().toString(); +// objNameString = objNameString + ",VirtualHost="+ _virtualHost.getName() +",ExchangeType=" + _exchangeType; +// return new ObjectName(objNameString); +// } + + protected ManagedObjectRegistry getManagedObjectRegistry() { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + _exchangeType; - return new ObjectName(objNameString); + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); } - } // End of MBean class public AMQShortString getName() @@ -108,8 +125,9 @@ public abstract class AbstractExchange implements Exchange, Managable */ protected abstract ExchangeMBean createMBean() throws AMQException; - public void initialise(AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException { + _virtualHost = host; _name = name; _durable = durable; _autoDelete = autoDelete; @@ -151,4 +169,13 @@ public abstract class AbstractExchange implements Exchange, Managable return _exchangeMbean; } + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public QueueRegistry getQueueRegistry() + { + return getVirtualHost().getQueueRegistry(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 77f9819048..d77f1b6c5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -24,6 +24,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -36,9 +37,11 @@ public class DefaultExchangeFactory implements ExchangeFactory private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); private Map> _exchangeClassMap = new HashMap>(); + private final VirtualHost _host; - public DefaultExchangeFactory() + public DefaultExchangeFactory(VirtualHost host) { + _host = host; _exchangeClassMap.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestNameExchange.class); _exchangeClassMap.put(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestWildExchange.class); _exchangeClassMap.put(ExchangeDefaults.HEADERS_EXCHANGE_CLASS, org.apache.qpid.server.exchange.HeadersExchange.class); @@ -59,7 +62,7 @@ public class DefaultExchangeFactory implements ExchangeFactory try { Exchange e = exchClass.newInstance(); - e.initialise(exchange, durable, ticket, autoDelete); + e.initialise(_host, exchange, durable, ticket, autoDelete); return e; } catch (InstantiationException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index fcd6e8fdad..8862bd5104 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -109,7 +109,7 @@ public class DestNameExchange extends AbstractExchange public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index d1b35451b5..c38b9fe9b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import javax.management.MBeanException; @@ -110,7 +111,7 @@ public class DestWildExchange extends AbstractExchange public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 366dcb11b3..c012a1c1c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -25,13 +25,14 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; public interface Exchange { AMQShortString getName(); AMQShortString getType(); - void initialise(AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; boolean isDurable(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 2e7457e4a6..82039c345f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -44,7 +44,7 @@ public class FanoutExchange extends AbstractExchange private TabularType _bindinglistDataType = null; private TabularDataSupport _bindingList = null; - @MBeanConstructor("Creates an MBean for AMQ direct exchange") + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") public FanoutExchangeMBean() throws JMException { super(); @@ -86,7 +86,7 @@ public class FanoutExchange extends AbstractExchange public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 93933cd88d..3a49ff586b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -150,7 +150,7 @@ public class HeadersExchange extends AbstractExchange */ public void createNewBinding(String queueName, String binding) throws JMException { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(new AMQShortString(queueName)); + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index e12dd4a9db..b2b1b0a716 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -29,6 +29,7 @@ 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; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.log4j.Logger; public class BasicAckMethodHandler implements StateAwareMethodListener @@ -46,10 +47,10 @@ public class BasicAckMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession protocolSession = stateManager.getProtocolSession(); + if (_log.isDebugEnabled()) { _log.debug("Ack received on channel " + evt.getChannelId()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index a23a29941f..2bbb696e90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -30,6 +30,7 @@ import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.AMQException; public class BasicCancelMethodHandler implements StateAwareMethodListener @@ -45,10 +46,10 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession protocolSession = stateManager.getProtocolSession(); + final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); final BasicCancelBody body = evt.getMethod(); channel.unsubscribeConsumer(protocolSession, body.consumerTag); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 721001b454..bc695431c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -28,6 +28,8 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.*; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ConsumerTagNotUniqueException; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -53,14 +55,15 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + BasicConsumeBody body = evt.getMethod(); final int channelId = evt.getChannelId(); AMQChannel channel = session.getChannel(channelId); + VirtualHost vHost = session.getVirtualHost(); if (channel == null) { _log.error("Channel " + channelId + " not found"); @@ -69,7 +72,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + BasicGetBody body = evt.getMethod(); final int channelId = evt.getChannelId(); + VirtualHost vHost = session.getVirtualHost(); AMQChannel channel = session.getChannel(channelId); if (channel == null) @@ -46,7 +49,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + final BasicPublishBody body = evt.getMethod(); if (_log.isDebugEnabled()) @@ -70,7 +72,8 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener return _instance; } - public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, - AMQProtocolSession session, AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); session.getChannel(evt.getChannelId()).setPrefetchSize(evt.getMethod().prefetchSize); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index f3e0cc3a63..a247ee33ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -27,6 +27,7 @@ import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.framing.BasicRecoverBody; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; @@ -42,18 +43,18 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { - _logger.debug("Recover received on protocol session " + protocolSession + " and channel " + evt.getChannelId()); - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + evt.getChannelId()); + AMQChannel channel = session.getChannel(evt.getChannelId()); if (channel == null) { throw new AMQException("Unknown channel " + evt.getChannelId()); } BasicRecoverBody body = evt.getMethod(); - channel.resend(protocolSession, body.requeue); + channel.resend(session, body.requeue); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index a24ecd9b01..d46a4f6424 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -31,6 +31,7 @@ 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.virtualhost.VirtualHostRegistry; public class ChannelCloseHandler implements StateAwareMethodListener { @@ -47,18 +48,17 @@ public class ChannelCloseHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); 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()); + session.closeChannel(evt.getChannelId()); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame response = ChannelCloseOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - protocolSession.writeFrame(response); + session.writeFrame(response); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java index 81a5371829..be11d5e939 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -28,6 +28,7 @@ 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.virtualhost.VirtualHostRegistry; import org.apache.log4j.Logger; public class ChannelCloseOkHandler implements StateAwareMethodListener @@ -45,9 +46,7 @@ public class ChannelCloseOkHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { _logger.info("Received channel-close-ok for channel-id " + evt.getChannelId()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java index d92a4eed6a..62f7ed4b78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -48,13 +48,12 @@ public class ChannelFlowHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); ChannelFlowBody body = evt.getMethod(); - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + AMQChannel channel = session.getChannel(evt.getChannelId()); channel.setSuspended(!body.active); _logger.debug("Channel.Flow for channel " + evt.getChannelId() + ", active=" + body.active); @@ -64,6 +63,6 @@ public class ChannelFlowHandler implements StateAwareMethodListener evt) throws AMQException - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - final AMQChannel channel = new AMQChannel(evt.getChannelId(), registry.getMessageStore(), - exchangeRegistry); - protocolSession.addChannel(channel); + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + + final AMQChannel channel = new AMQChannel(evt.getChannelId(), virtualHost.getMessageStore(), + virtualHost.getExchangeRegistry()); + session.addChannel(channel); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame response = ChannelOpenOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - protocolSession.writeFrame(response); + session.writeFrame(response); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java index 0fe25a1c89..8bc849d5cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -47,16 +47,15 @@ public class ConnectionCloseMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); final ConnectionCloseBody body = evt.getMethod(); _logger.info("ConnectionClose received with reply code/reply text " + body.replyCode + "/" + - body.replyText + " for " + protocolSession); + body.replyText + " for " + session); try { - protocolSession.closeSession(); + session.closeSession(); } catch (Exception e) { @@ -66,6 +65,6 @@ public class ConnectionCloseMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); //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(); + session.closeSession(); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 8056ff9adb..88717c446b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -27,11 +27,13 @@ import org.apache.qpid.framing.ConnectionOpenOkBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; 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; +import org.apache.qpid.server.virtualhost.VirtualHost; public class ConnectionOpenMethodHandler implements StateAwareMethodListener { @@ -51,28 +53,39 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); ConnectionOpenBody body = evt.getMethod(); - + String virtualHostName = String.valueOf(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 (protocolSession.getContextKey() == null) + VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); + + if(virtualHost == null) { - protocolSession.setContextKey(generateClientID()); + throw body.getConnectionException(AMQConstant.NOT_FOUND.getCode(), "Unknown virtual host: " + virtualHostName); } + else + { + session.setVirtualHost( virtualHost ); + - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, - (byte)8, (byte)0, // AMQP version (major, minor) - body.virtualHost); // knownHosts - stateManager.changeState(AMQState.CONNECTION_OPEN); - protocolSession.writeFrame(response); + + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts + if (session.getContextKey() == null) + { + session.setContextKey(generateClientID()); + } + + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, + (byte)8, (byte)0, // AMQP version (major, minor) + body.virtualHost); + stateManager.changeState(AMQState.CONNECTION_OPEN); + session.writeFrame(response); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index d33874b727..11cbaade30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -54,14 +54,13 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener { } - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); ConnectionSecureOkBody body = evt.getMethod(); AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); - SaslServer ss = protocolSession.getSaslServer(); + SaslServer ss = session.getSaslServer(); if (ss == null) { throw new AMQException("No SASL context set up in session"); @@ -84,8 +83,8 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionCloseBody.getMethod((byte)8, (byte)0), // methodId AMQConstant.NOT_ALLOWED.getCode(), // replyCode AMQConstant.NOT_ALLOWED.getName()); // replyText - protocolSession.writeFrame(close); - disposeSaslServer(protocolSession); + session.writeFrame(close); + disposeSaslServer(session); break; case SUCCESS: _logger.info("Connected as: " + ss.getAuthorizationID()); @@ -101,8 +100,8 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener Integer.MAX_VALUE, // channelMax ConnectionStartOkMethodHandler.getConfiguredFrameSize(), // frameMax HeartbeatConfig.getInstance().getDelay()); // heartbeat - protocolSession.writeFrame(tune); - disposeSaslServer(protocolSession); + session.writeFrame(tune); + disposeSaslServer(session); break; case CONTINUE: stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); @@ -112,7 +111,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, (byte)8, (byte)0, // AMQP version (major, minor) authResult.challenge); // challenge - protocolSession.writeFrame(challenge); + session.writeFrame(challenge); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 6cb384f081..b45a017166 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -60,10 +60,9 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< { } - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); final ConnectionStartOkBody body = evt.getMethod(); _logger.info("SASL Mechanism selected: " + body.mechanism); _logger.info("Locale selected: " + body.locale); @@ -73,15 +72,15 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< SaslServer ss = null; try { - ss = authMgr.createSaslServer(String.valueOf(body.mechanism), protocolSession.getLocalFQDN()); - protocolSession.setSaslServer(ss); + ss = authMgr.createSaslServer(String.valueOf(body.mechanism), session.getLocalFQDN()); + session.setSaslServer(ss); AuthenticationResult authResult = authMgr.authenticate(ss, body.response); //save clientProperties - if (protocolSession.getClientProperties() == null) + if (session.getClientProperties() == null) { - protocolSession.setClientProperties(body.clientProperties); + session.setClientProperties(body.clientProperties); } switch (authResult.status) @@ -100,7 +99,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< Integer.MAX_VALUE, // channelMax getConfiguredFrameSize(), // frameMax HeartbeatConfig.getInstance().getDelay()); // heartbeat - protocolSession.writeFrame(tune); + session.writeFrame(tune); break; case CONTINUE: stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); @@ -110,12 +109,12 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, (byte)8, (byte)0, // AMQP version (major, minor) authResult.challenge); // challenge - protocolSession.writeFrame(challenge); + session.writeFrame(challenge); } } catch (SaslException e) { - disposeSaslServer(protocolSession); + disposeSaslServer(session); throw new AMQException("SASL error: " + e, e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java index 960643325a..020e93b7d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -42,16 +42,15 @@ public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); ConnectionTuneOkBody body = evt.getMethod(); if (_logger.isDebugEnabled()) { _logger.debug(body); } stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); - protocolSession.initHeartbeats(body.heartbeat); + session.initHeartbeats(body.heartbeat); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java index 596e6bf332..30da1398b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -30,6 +30,7 @@ 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.virtualhost.VirtualHost; /** * @author Apache Software Foundation @@ -61,10 +62,12 @@ public class ExchangeBoundHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. byte major = (byte)8; @@ -79,7 +82,7 @@ public class ExchangeBoundHandler implements StateAwareMethodListener { @@ -50,17 +51,19 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + final ExchangeDeclareBody body = evt.getMethod(); if (_logger.isDebugEnabled()) { @@ -106,7 +109,7 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener { @@ -45,10 +46,12 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeDeleteBody body = evt.getMethod(); try { @@ -57,7 +60,7 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener { @@ -50,15 +51,19 @@ public class QueueBindHandler implements StateAwareMethodListener { } - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + final QueueBindBody body = evt.getMethod(); final AMQQueue queue; if (body.queue == null) { - queue = protocolSession.getChannel(evt.getChannelId()).getDefaultQueue(); + queue = session.getChannel(evt.getChannelId()).getDefaultQueue(); if (queue == null) { throw new AMQException("No default queue defined on channel and queue was null"); @@ -94,7 +99,7 @@ public class QueueBindHandler implements StateAwareMethodListener // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - protocolSession.writeFrame(response); + session.writeFrame(response); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index b62fe22b89..fdf98bb49e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.configuration.Configured; @@ -37,7 +36,7 @@ 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 org.apache.qpid.server.virtualhost.VirtualHost; import java.text.MessageFormat; import java.util.concurrent.atomic.AtomicInteger; @@ -58,18 +57,21 @@ public class QueueDeclareHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + QueueDeclareBody body = evt.getMethod(); // if we aren't given a queue name, we create one which we return to the client @@ -94,10 +96,10 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -47,7 +43,6 @@ public class QueueDeleteHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + QueueDeleteBody body = evt.getMethod(); AMQQueue queue; if(body.queue == null) @@ -71,7 +70,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + QueuePurgeBody body = evt.getMethod(); AMQQueue queue; if(body.queue == null) @@ -52,7 +57,7 @@ public class QueuePurgeHandler implements StateAwareMethodListener { } - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); try { @@ -58,13 +58,13 @@ public class TxCommitHandler implements StateAwareMethodListener { _log.debug("Commit received on channel " + evt.getChannelId()); } - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + AMQChannel channel = session.getChannel(evt.getChannelId()); channel.commit(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); - channel.processReturns(protocolSession); + session.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + channel.processReturns(session); } catch(AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index d71c93a6c6..31a28d2275 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -30,6 +30,7 @@ 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; +import org.apache.qpid.server.virtualhost.VirtualHost; public class TxRollbackHandler implements StateAwareMethodListener { @@ -44,20 +45,20 @@ public class TxRollbackHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { + AMQProtocolSession session = stateManager.getProtocolSession(); + try{ - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + AMQChannel channel = session.getChannel(evt.getChannelId()); channel.rollback(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - protocolSession.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + session.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); //Now resend all the unacknowledged messages back to the original subscribers. //(Must be done after the TxnRollback-ok response). - channel.resend(protocolSession, false); + channel.resend(session, false); }catch(AMQException e){ throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java index 7d66fa9d5c..30b70869f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -29,6 +29,7 @@ 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.virtualhost.VirtualHost; public class TxSelectHandler implements StateAwareMethodListener { @@ -43,14 +44,14 @@ public class TxSelectHandler implements StateAwareMethodListener { } - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { - protocolSession.getChannel(evt.getChannelId()).setLocalTransactional(); + AMQProtocolSession session = stateManager.getProtocolSession(); + + session.getChannel(evt.getChannelId()).setLocalTransactional(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + session.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 311eb8add9..46bac52e78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -67,7 +67,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana { try { - ApplicationRegistry.getInstance().getManagedObjectRegistry().registerObject(this); + getManagedObjectRegistry().registerObject(this); } catch (JMException e) { @@ -75,11 +75,16 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana } } + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + public void unregister() throws AMQException { try { - ApplicationRegistry.getInstance().getManagedObjectRegistry().unregisterObject(this); + getManagedObjectRegistry().unregisterObject(this); } catch (JMException e) { @@ -91,6 +96,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana { return getObjectInstanceName() + "[" + getType() + "]"; } + /** * Created the ObjectName as per the JMX Specs diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index ed74263596..9ca11abb56 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -35,10 +35,10 @@ import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQStateManager; @@ -51,6 +51,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.CopyOnWriteArrayList; public class AMQMinaProtocolSession implements AMQProtocolSession, ProtocolVersionList, @@ -65,16 +66,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private AMQShortString _contextKey; + private VirtualHost _virtualHost; + 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 AMQProtocolSessionMBean _managedObject; @@ -93,6 +92,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private byte _major; private byte _minor; private FieldTable _clientProperties; + private final List _taskList = new CopyOnWriteArrayList(); + public ManagedObject getManagedObject() { @@ -100,23 +101,23 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } - public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) throws AMQException { - _stateManager = new AMQStateManager(queueRegistry, exchangeRegistry, this); + _stateManager = new AMQStateManager(virtualHostRegistry, this); _minaProtocolSession = session; session.setAttachment(this); - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; + + _codecFactory = codecFactory; _managedObject = createMBean(); _managedObject.register(); // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } - public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, AMQStateManager stateManager) throws AMQException { @@ -124,8 +125,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _minaProtocolSession = session; session.setAttachment(this); - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; + _codecFactory = codecFactory; _managedObject = createMBean(); _managedObject.register(); @@ -461,6 +461,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _managedObject.unregister(); } + for(Task task : _taskList) + { + task.doTask(this); + } } } @@ -556,4 +560,27 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { return _minaProtocolSession.getRemoteAddress(); } + + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 10e23caac3..474714680b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -53,41 +53,26 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco { 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; + private final IApplicationRegistry _applicationRegistry; - /** - * 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"); + this(ApplicationRegistry.getInstance(applicationRegistryInstance)); } - public AMQPFastProtocolHandler(QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry) + public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) { - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; + _applicationRegistry = applicationRegistry; _logger.debug("AMQPFastProtocolHandler created"); } protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) { - this(handler._queueRegistry, handler._exchangeRegistry); + this(handler._applicationRegistry); } public void sessionCreated(IoSession protocolSession) throws Exception @@ -95,7 +80,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco SessionUtil.initialize(protocolSession); final AMQCodecFactory codecFactory = new AMQCodecFactory(true); - createSession(protocolSession, _queueRegistry, _exchangeRegistry, codecFactory); + createSession(protocolSession, _applicationRegistry, codecFactory); _logger.info("Protocol session created"); final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); @@ -120,9 +105,9 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco /** * Separated into its own, protected, method to allow easier reuse */ - protected void createSession(IoSession session, QueueRegistry queues, ExchangeRegistry exchanges, AMQCodecFactory codec) throws AMQException + protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException { - new AMQMinaProtocolSession(session, queues, exchanges, codec); + new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); } public void sessionOpened(IoSession protocolSession) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java index ff1316f704..07c153bfe8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java @@ -42,8 +42,7 @@ public class AMQPProtocolProvider public AMQPProtocolProvider() { IApplicationRegistry registry = ApplicationRegistry.getInstance(); - _handler = new AMQPFastProtocolHandler(registry.getQueueRegistry(), - registry.getExchangeRegistry()); + _handler = new AMQPFastProtocolHandler(registry); } public AMQPFastProtocolHandler getHandler() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index a1249723ee..ee7e46eba4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.protocol.AMQProtocolWriter; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.AMQException; import javax.security.sasl.SaslServer; @@ -32,6 +33,13 @@ import javax.security.sasl.SaslServer; public interface AMQProtocolSession extends AMQProtocolWriter { + + + public static interface Task + { + public void doTask(AMQProtocolSession session) throws AMQException; + } + /** * Called when a protocol data block is received * @param message the data block that has been received @@ -126,4 +134,13 @@ public interface AMQProtocolSession extends AMQProtocolWriter void setClientProperties(FieldTable clientProperties); Object getClientIdentifier(); + + VirtualHost getVirtualHost(); + + void setVirtualHost(VirtualHost virtualHost); + + void addSessionCloseTask(Task task); + + void removeSessionCloseTask(Task task); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index df494915a3..b5fec39626 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; import javax.management.JMException; import javax.management.MBeanException; @@ -93,6 +94,11 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed return _session.getIOSession().getRemoteAddress().toString(); } + public ManagedObject getParentObject() + { + return _session.getVirtualHost().getManagedObject(); + } + public Long getWrittenBytes() { return _session.getIOSession().getWrittenBytes(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 18b3adc635..709dd28ad5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -30,11 +30,14 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import java.text.MessageFormat; import java.util.List; +import java.util.ArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean; @@ -45,6 +48,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class AMQQueue implements Managable, Comparable { + public static final class ExistingExclusiveSubscription extends AMQException { @@ -95,17 +99,18 @@ public class AMQQueue implements Managable, Comparable private final AtomicBoolean _isExclusive = new AtomicBoolean(); + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + + + private List _deleteTaskList = new CopyOnWriteArrayList(); + /** * 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. @@ -119,6 +124,9 @@ public class AMQQueue implements Managable, Comparable private final AMQQueueMBean _managedObject; + private final VirtualHost _virtualHost; + + /** * max allowed size(KB) of a single message */ @@ -145,59 +153,26 @@ public class AMQQueue implements Managable, Comparable } public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionImpl.Factory()); - } - - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, SubscriptionFactory subscriptionFactory) + boolean autoDelete, VirtualHost virtualHost) throws AMQException { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscriptionFactory); + this(name, durable, owner, autoDelete, virtualHost, + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionSet(), new SubscriptionImpl.Factory()); } - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery, - SubscriptionFactory subscriptionFactory) - throws AMQException - { - - this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), subscriptionFactory); - } - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery) - throws AMQException - { - - this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), - new SubscriptionImpl.Factory()); - } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, - SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, subscriptionFactory); - } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, + boolean autoDelete, VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException { - this(name, durable, owner, autoDelete, queueRegistry, + this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, QueueRegistry queueRegistry, + boolean autoDelete, VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) throws AMQException { @@ -205,18 +180,20 @@ public class AMQQueue implements Managable, Comparable { throw new IllegalArgumentException("Queue name must not be null"); } - if (queueRegistry == null) + if (virtualHost == null) { - throw new IllegalArgumentException("Queue registry must not be null"); + throw new IllegalArgumentException("Virtual Host must not be null"); } _name = name; _durable = durable; _owner = owner; _autoDelete = autoDelete; - _queueRegistry = queueRegistry; + _virtualHost = virtualHost; _asyncDelivery = asyncDelivery; + _managedObject = createMBean(); _managedObject.register(); + _subscribers = subscribers; _subscriptionFactory = subscriptionFactory; _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); @@ -492,10 +469,18 @@ public class AMQQueue implements Managable, Comparable public void delete() throws AMQException { - _subscribers.queueDeleted(this); - _bindings.deregister(); - _queueRegistry.unregisterQueue(_name); - _managedObject.unregister(); + if(!_deleted.getAndSet(true)) + { + _subscribers.queueDeleted(this); + _bindings.deregister(); + _virtualHost.getQueueRegistry().unregisterQueue(_name); + _managedObject.unregister(); + for(Task task : _deleteTaskList) + { + task.doTask(this); + } + _deleteTaskList.clear(); + } } protected void autodelete() throws AMQException @@ -620,6 +605,24 @@ public class AMQQueue implements Managable, Comparable return _deliveryMgr.performGet(session, channel, acks); } - + public QueueRegistry getQueueRegistry() + { + return _virtualHost.getQueueRegistry(); + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public static interface Task + { + public void doTask(AMQQueue queue) throws AMQException; + } + + public void addQueueDeleteTask(Task task) + { + _deleteTaskList.add(task); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 012b3600ca..ab67012b19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -20,7 +20,9 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.Main; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -28,11 +30,7 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.mina.common.ByteBuffer; import javax.management.openmbean.*; -import javax.management.JMException; -import javax.management.Notification; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.OperationsException; +import javax.management.*; import javax.management.monitor.MonitorNotification; import java.util.List; import java.util.ArrayList; @@ -73,6 +71,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } + + public ManagedObject getParentObject() + { + return _queue.getVirtualHost().getManagedObject(); + } + static { try @@ -373,6 +377,14 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue return _messageList; } +// +// public ObjectName getObjectName() throws MalformedObjectNameException +// { +// String objNameString = super.getObjectName().toString(); +// +// return new ObjectName(objNameString); +// } + /** * returns Notifications sent by this MBean. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index 8ab26def74..084612ca41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.framing.AMQShortString; import java.util.concurrent.ConcurrentMap; @@ -30,8 +31,16 @@ public class DefaultQueueRegistry implements QueueRegistry { private ConcurrentMap _queueMap = new ConcurrentHashMap(); - public DefaultQueueRegistry() + private final VirtualHost _virtualHost; + + public DefaultQueueRegistry(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public VirtualHost getVirtualHost() { + return _virtualHost; } public void registerQueue(AMQQueue queue) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index bfbaf27c84..c5f235f1b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -21,11 +21,14 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.framing.AMQShortString; public interface QueueRegistry { + VirtualHost getVirtualHost(); + void registerQueue(AMQQueue queue) throws AMQException; void unregisterQueue(AMQShortString name) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 48331843e5..0630d4f39f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -23,6 +23,7 @@ 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 org.apache.qpid.server.virtualhost.VirtualHost; import java.util.HashMap; import java.util.Iterator; @@ -38,7 +39,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { private static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); - private static Map _instanceMap = new HashMap(); + private static Map _instanceMap = new HashMap(); private final Map, Object> _configuredObjects = new HashMap, Object>(); @@ -62,20 +63,13 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { synchronized (ApplicationRegistry.class) { - Iterator keyIterator = _instanceMap.keySet().iterator(); + Iterator keyIterator = _instanceMap.values().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(); - } - } + IApplicationRegistry instance = keyIterator.next(); + + instance.close(); } } } @@ -118,7 +112,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { try { - ((IApplicationRegistry) _instanceMap.get(instanceID)).getMessageStore().close(); + _instanceMap.get(instanceID).close(); } catch (Exception e) { @@ -143,7 +137,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public static IApplicationRegistry getInstance(int instanceID) { - IApplicationRegistry instance = (IApplicationRegistry) _instanceMap.get(instanceID); + IApplicationRegistry instance = _instanceMap.get(instanceID); if (instance == null) { @@ -168,6 +162,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + public void close() throws Exception + { + for(VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) + { + virtualHost.close(); + } + } + public Configuration getConfiguration() { return _configuration; @@ -193,6 +195,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return instance; } + + public static void setDefaultApplicationRegistry(String clazz) { _APPLICATION_REGISTRY = clazz; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 1eb490d6fb..790421b497 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -38,22 +38,26 @@ 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 org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.mina.common.ByteBuffer; import java.io.File; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; private ManagedObjectRegistry _managedObjectRegistry; private AuthenticationManager _authenticationManager; - private MessageStore _messageStore; + private VirtualHostRegistry _virtualHostRegistry; + + + private final Map _virtualHosts = new ConcurrentHashMap(); + public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { @@ -91,11 +95,19 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { initialiseManagedObjectRegistry(); - _queueRegistry = new DefaultQueueRegistry(); - _exchangeFactory = new DefaultExchangeFactory(); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _virtualHostRegistry = new VirtualHostRegistry(); _authenticationManager = new SASLAuthenticationManager(); - initialiseMessageStore(); + + initialiseVirtualHosts(); + } + + private void initialiseVirtualHosts() throws Exception + { + for(String name : getVirtualHostNames()) + { + + _virtualHostRegistry.registerVirtualHost(new VirtualHost(name,getConfiguration().subset("virtualhosts.virtualhost."+name))); + } } private void initialiseManagedObjectRegistry() @@ -111,34 +123,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - 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() + public VirtualHostRegistry getVirtualHostRegistry() { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; + return _virtualHostRegistry; } public ManagedObjectRegistry getManagedObjectRegistry() @@ -151,8 +139,8 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry return _authenticationManager; } - public MessageStore getMessageStore() + public Collection getVirtualHostNames() { - return _messageStore; - } + return getConfiguration().getList("virtualhosts.virtualhost.name"); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index cd664f9a4b..703aed69d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -26,8 +26,12 @@ 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.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.commons.configuration.Configuration; +import java.util.Collection; + public interface IApplicationRegistry { /** @@ -35,7 +39,9 @@ public interface IApplicationRegistry * 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; + void initialise() throws Exception; + + void close() throws Exception; /** * This gets access to a "configured object". A configured object has fields populated from a the configuration @@ -54,15 +60,11 @@ public interface IApplicationRegistry */ Configuration getConfiguration(); - QueueRegistry getQueueRegistry(); - - ExchangeRegistry getExchangeRegistry(); - - ExchangeFactory getExchangeFactory(); - ManagedObjectRegistry getManagedObjectRegistry(); AuthenticationManager getAuthenticationManager(); - MessageStore getMessageStore(); + Collection getVirtualHostNames(); + + VirtualHostRegistry getVirtualHostRegistry(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 81ce704026..7b8ba1d9cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -31,6 +31,7 @@ import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.log4j.Logger; import java.util.HashMap; @@ -46,8 +47,8 @@ import java.util.concurrent.CopyOnWriteArraySet; public class AMQStateManager implements AMQMethodListener { private static final Logger _logger = Logger.getLogger(AMQStateManager.class); - private final QueueRegistry _queueRegistry; - private final ExchangeRegistry _exchangeRegistry; + + private final VirtualHostRegistry _virtualHostRegistry; private final AMQProtocolSession _protocolSession; /** * The current state @@ -63,15 +64,15 @@ public class AMQStateManager implements AMQMethodListener private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - public AMQStateManager(QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession) + + public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) { - this(AMQState.CONNECTION_NOT_STARTED, true, queueRegistry, exchangeRegistry, protocolSession); + this(AMQState.CONNECTION_NOT_STARTED, true, virtualHostRegistry, protocolSession); } - protected AMQStateManager(AMQState initial, boolean register, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession) + protected AMQStateManager(AMQState initial, boolean register, VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) { - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; + _virtualHostRegistry = virtualHostRegistry; _protocolSession = protocolSession; _currentState = initial; if (register) @@ -176,7 +177,7 @@ public class AMQStateManager implements AMQMethodListener checkChannel(evt, _protocolSession); - handler.methodReceived(this, _queueRegistry, _exchangeRegistry, _protocolSession, evt); + handler.methodReceived(this, evt); return true; } return false; @@ -241,4 +242,14 @@ public class AMQStateManager implements AMQMethodListener { _stateListeners.remove(listener); } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java index 56323258b7..99d5d7fe88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -25,6 +25,7 @@ import org.apache.qpid.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.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.framing.AMQMethodBody; /** @@ -34,7 +35,5 @@ import org.apache.qpid.framing.AMQMethodBody; */ public interface StateAwareMethodListener { - void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException; + void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 98a4c3f6e7..eaaffa2dce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -28,6 +28,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; import java.util.List; @@ -67,7 +68,7 @@ public class MemoryMessageStore implements MessageStore _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); } - public void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception + public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception { configure(base, config); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index c9c7045402..8daad0e5e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -27,6 +27,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.List; @@ -35,13 +36,13 @@ 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 virtualHost the virtual host using by this store * @param base the base element identifier from which all configuration items are relative. For example, if the base * element is "store", the all elements used by concrete classes will be "store.foo" etc. * @param config the apache commons configuration object * @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; + void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 2e77f33363..e9a3a3d048 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -33,24 +33,23 @@ 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.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.MapConfiguration; import java.util.HashMap; +import java.util.Collection; +import java.util.Collections; +import java.util.Arrays; public class NullApplicationRegistry extends ApplicationRegistry { - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - private ManagedObjectRegistry _managedObjectRegistry; private AuthenticationManager _authenticationManager; - private MessageStore _messageStore; + private VirtualHostRegistry _virtualHostRegistry; public NullApplicationRegistry() @@ -60,15 +59,16 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { + _configuration.addProperty("store.class","org.apache.qpid.server.store.MemoryMessageStore"); + _managedObjectRegistry = new NoopManagedObjectRegistry(); - _queueRegistry = new DefaultQueueRegistry(); - _exchangeFactory = new DefaultExchangeFactory(); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _virtualHostRegistry = new VirtualHostRegistry(); + VirtualHost dummyHost = new VirtualHost("test",getConfiguration()); + _virtualHostRegistry.registerVirtualHost(dummyHost); _authenticationManager = new NullAuthenticationManager(); - _messageStore = new MemoryMessageStore(); - ((MemoryMessageStore)_messageStore).configure(); _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes + } public Configuration getConfiguration() @@ -76,20 +76,6 @@ public class NullApplicationRegistry extends ApplicationRegistry return _configuration; } - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } public ManagedObjectRegistry getManagedObjectRegistry() { @@ -101,9 +87,15 @@ public class NullApplicationRegistry extends ApplicationRegistry return _authenticationManager; } - public MessageStore getMessageStore() + public Collection getVirtualHostNames() + { + String[] hosts = {"test"}; + return Arrays.asList( hosts ); + } + + public VirtualHostRegistry getVirtualHostRegistry() { - return _messageStore; + return _virtualHostRegistry; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java new file mode 100644 index 0000000000..2c888caac1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.queue.ManagedQueue; +import org.apache.qpid.server.exchange.ManagedExchange; + +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. + * @version 0.1 + */ +public interface ManagedVirtualHost +{ + static final String TYPE = "VirtualHost"; + + /** + * Returns the name of the managed virtualHost. + * @return the name of the exchange. + * @throws java.io.IOException + */ + @MBeanAttribute(name="Name", description= TYPE + " Name") + String getName() throws IOException; + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java new file mode 100644 index 0000000000..15bad19e58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -0,0 +1,193 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.exchange.*; +import org.apache.qpid.server.management.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; + +import javax.management.NotCompliantMBeanException; + +public class VirtualHost +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + + /** + * Abstract MBean class. This has some of the methods implemented from + * management intrerface for exchanges. Any implementaion of an + * Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + + + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + _virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + + initialiseMessageStore(hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(this, "store", config); + } + + + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public void close() throws Exception + { + if(_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java new file mode 100644 index 0000000000..25f67c1cf3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.util.Map; +import java.util.Collection; +import java.util.Collections; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + + +public class VirtualHostRegistry +{ + private final Map _registry = new ConcurrentHashMap(); + + public synchronized void registerVirtualHost(VirtualHost host) throws Exception + { + if(_registry.containsKey(host.getName())) + { + throw new Exception("Virtual Host with name " + host.getName() + " already registered."); + } + _registry.put(host.getName(),host); + } + + public VirtualHost getVirtualHost(String name) + { + return _registry.get(name); + } + + public Collection getVirtualHosts() + { + return new ArrayList(_registry.values()); + } +} -- cgit v1.2.1 From 35dabdb9069e9b4ccb1aefc2874e90275f9976e0 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 24 Jan 2007 16:24:43 +0000 Subject: QPID-50 : Patch supplied by Rob Godfrey - Virtual Host implementation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499466 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/virtualhost/VirtualHost.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 15bad19e58..9c14be897f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -85,7 +85,23 @@ public class VirtualHost } // End of MBean class + public VirtualHost(String name, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + _virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _messageStore = store; + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + + } public VirtualHost(String name, Configuration hostConfig) throws Exception { _name = name; -- cgit v1.2.1 From e6c79fe6ee142cba80245456e3525bff40a9aada Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 24 Jan 2007 17:19:19 +0000 Subject: QPID-50 : Patch supplied by Rob Godfrey - Virtual Host implementation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499490 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/ConnectionOpenMethodHandler.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 88717c446b..c3b1ba3b5b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -58,7 +58,16 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener Date: Wed, 24 Jan 2007 17:30:39 +0000 Subject: QPID-50 : Patch supplied by Rob Godfrey - Virtual Host implementation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499493 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQMinaProtocolSession.java | 11 ++++++----- .../org/apache/qpid/server/protocol/AMQProtocolSession.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 9ca11abb56..8cc747200f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -112,8 +112,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _codecFactory = codecFactory; - _managedObject = createMBean(); - _managedObject.register(); + + // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } @@ -127,8 +127,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _codecFactory = codecFactory; - _managedObject = createMBean(); - _managedObject.register(); + } private AMQProtocolSessionMBean createMBean() throws AMQException @@ -567,9 +566,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _virtualHost; } - public void setVirtualHost(VirtualHost virtualHost) + public void setVirtualHost(VirtualHost virtualHost) throws AMQException { _virtualHost = virtualHost; + _managedObject = createMBean(); + _managedObject.register(); } public void addSessionCloseTask(Task task) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index ee7e46eba4..48c05058b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -137,7 +137,7 @@ public interface AMQProtocolSession extends AMQProtocolWriter VirtualHost getVirtualHost(); - void setVirtualHost(VirtualHost virtualHost); + void setVirtualHost(VirtualHost virtualHost) throws AMQException; void addSessionCloseTask(Task task); -- cgit v1.2.1 From 9cc7fadd313161a851b6e72498f822867fea1841 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 24 Jan 2007 20:50:47 +0000 Subject: QPID-317 : Patch supplied by Rob Godfrey - Remove dependency on JMS from common / broker. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499563 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/filter/ArithmeticExpression.java | 4 +- .../qpid/server/filter/BooleanExpression.java | 7 +- .../qpid/server/filter/ComparisonExpression.java | 5 +- .../qpid/server/filter/ConstantExpression.java | 5 +- .../org/apache/qpid/server/filter/Expression.java | 5 +- .../qpid/server/filter/FilterManagerFactory.java | 6 +- .../qpid/server/filter/JMSSelectorFilter.java | 20 +- .../apache/qpid/server/filter/LogicExpression.java | 5 +- .../apache/qpid/server/filter/MessageFilter.java | 5 +- .../qpid/server/filter/PropertyExpression.java | 32 +-- .../qpid/server/filter/SimpleFilterManager.java | 8 +- .../apache/qpid/server/filter/UnaryExpression.java | 5 +- .../apache/qpid/server/filter/XPathExpression.java | 15 +- .../qpid/server/filter/XQueryExpression.java | 5 +- .../qpid/server/filter/XalanXPathEvaluator.java | 50 ++-- .../qpid/server/message/MessageDecorator.java | 25 -- .../apache/qpid/server/message/jms/JMSMessage.java | 307 --------------------- 17 files changed, 62 insertions(+), 447 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageDecorator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index c536f77dde..1b3b116fd0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -21,10 +21,8 @@ package org.apache.qpid.server.filter; // -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; - -import javax.jms.JMSException; +import org.apache.qpid.server.queue.AMQMessage; /** * An expression which performs an operation on two expression values diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index de71e95049..122527d4f3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -21,11 +21,10 @@ package org.apache.qpid.server.filter; // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + -import javax.jms.JMSException; /** @@ -40,7 +39,7 @@ public interface BooleanExpression extends Expression /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws JMSException + * @throws AMQException */ public boolean matches(AMQMessage message) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 07391098ce..25d588a36f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -20,16 +20,13 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; import java.util.HashSet; import java.util.List; import java.util.regex.Pattern; -import javax.jms.JMSException; - /** * A filter performing a comparison of two objects * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 2cd305d4b1..a4aea35079 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -20,14 +20,11 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; import java.math.BigDecimal; -import javax.jms.JMSException; - /** * Represents a constant expression * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index 3b5debd3ee..4a2130e767 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -21,11 +21,8 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; - -import javax.jms.JMSException; +import org.apache.qpid.server.queue.AMQMessage; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index 5c784983cb..311f0680ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -20,13 +20,9 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; - -import java.util.Iterator; +import org.apache.qpid.framing.FieldTable; public class FilterManagerFactory diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 5f505fbeba..cba487c31e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -20,15 +20,13 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidSelectorException; -import org.apache.log4j.Logger; +import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.qpid.server.queue.AMQMessage; -import javax.jms.InvalidSelectorException; -import javax.jms.JMSException; public class JMSSelectorFilter implements MessageFilter { @@ -43,16 +41,8 @@ public class JMSSelectorFilter implements MessageFilter _logger.info("Created JMSSelectorFilter with selector:" + _selector); - try - { - _matcher = new SelectorParser().parse(selector); - } - catch (InvalidSelectorException e) - { - // fixme - // Is this the correct way of throwing exception - throw new AMQInvalidSelectorException(e.getMessage()); - } + _matcher = new SelectorParser().parse(selector); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index e6ad98cb8b..dea6092b8a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -20,11 +20,8 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; - -import javax.jms.JMSException; +import org.apache.qpid.server.queue.AMQMessage; /** * A filter performing a comparison of two objects diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index b8ca75d209..f80b7941b5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -21,10 +21,9 @@ package org.apache.qpid.server.filter; import org.apache.qpid.server.queue.AMQMessage; - -import javax.jms.JMSException; +import org.apache.qpid.AMQException; public interface MessageFilter { - boolean matches(AMQMessage message) throws JMSException; + boolean matches(AMQMessage message) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index ba7000f822..2e74b09d0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -20,23 +20,15 @@ package org.apache.qpid.server.filter; // // Based on like named file from r450141 of the Apache ActiveMQ project // - -import java.io.IOException; -import java.util.HashMap; - -import javax.jms.DeliveryMode; -import javax.jms.JMSException; -import javax.jms.Message; -//import org.apache.activemq.command.ActiveMQDestination; -//import org.apache.activemq.command.Message; -//import org.apache.activemq.command.TransactionId; -//import org.apache.activemq.util.JMSExceptionSupport; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.log4j.Logger; +import org.apache.qpid.server.queue.AMQMessage; + + + +import java.util.HashMap; /** * Represents a property expression @@ -45,8 +37,10 @@ import org.apache.log4j.Logger; */ public class PropertyExpression implements Expression { - - + // Constants - defined the same as JMS + private static final int NON_PERSISTENT = 1; + private static final int PERSISTENT = 2; + private static final int DEFAULT_PRIORITY = 4; private final static Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); @@ -111,7 +105,7 @@ public class PropertyExpression implements Expression { try { - int mode = message.isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; + int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; if(_logger.isDebugEnabled()) { _logger.debug("JMSDeliveryMode is :" + mode); @@ -123,7 +117,7 @@ public class PropertyExpression implements Expression _logger.warn(e); } - return DeliveryMode.NON_PERSISTENT; + return NON_PERSISTENT; } }); @@ -141,7 +135,7 @@ public class PropertyExpression implements Expression { _logger.warn(e); } - return Message.DEFAULT_PRIORITY; + return DEFAULT_PRIORITY; } } ); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index 9065551697..5821a84774 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.log4j.Logger; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; -import javax.jms.JMSException; import java.util.concurrent.ConcurrentLinkedQueue; public class SimpleFilterManager implements FilterManager @@ -59,10 +59,10 @@ public class SimpleFilterManager implements FilterManager return false; } } - catch (JMSException e) + catch (AMQException e) { //fixme - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + e.printStackTrace(); return false; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index abc56f04d0..352a48b7ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -20,9 +20,8 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.message.jms.JMSMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; import java.math.BigDecimal; import java.util.Collection; @@ -30,8 +29,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; -import javax.jms.JMSException; - /** * An expression which performs an operation on two expression values * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index 85402e0781..c51f82ce68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -20,18 +20,13 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -import javax.jms.JMSException; - -//import org.apache.activemq.command.Message; -//import org.apache.activemq.util.JMSExceptionSupport; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; /** * Used to evaluate an XPath Expression in a JMS selector. @@ -121,7 +116,7 @@ public final class XPathExpression implements BooleanExpression { /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws JMSException + * @throws AMQException */ public boolean matches(AMQMessage message) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index da8a61650a..f5debb607a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -17,10 +17,9 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; -import javax.jms.JMSException; // // Based on like named file from r450141 of the Apache ActiveMQ project // @@ -47,7 +46,7 @@ public final class XQueryExpression implements BooleanExpression { /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws JMSException + * @throws AMQException */ public boolean matches(AMQMessage message) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index f74e0cedec..94f063aa95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -21,24 +21,18 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import java.io.StringReader; -import java.io.ByteArrayInputStream; - -import javax.jms.BytesMessage; -import javax.jms.JMSException; -import javax.jms.TextMessage; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -//import org.apache.activemq.command.Message; -//import org.apache.activemq.util.ByteArrayInputStream; -import org.apache.xpath.CachedXPathAPI; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.xpath.CachedXPathAPI; import org.w3c.dom.Document; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; +import java.io.StringReader; + public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private final String xpath; @@ -49,24 +43,22 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { public boolean evaluate(AMQMessage m) throws AMQException { - try - { + // TODO - we would have to check the content type and then evaluate the content + // here... is this really a feature we wish to implement? - RobG + /* - if( m instanceof TextMessage ) { - String text = ((TextMessage)m).getText(); - return evaluate(text); - } else if ( m instanceof BytesMessage ) { - BytesMessage bm = (BytesMessage) m; - byte data[] = new byte[(int) bm.getBodyLength()]; - bm.readBytes(data); - return evaluate(data); - } - return false; - } - catch (JMSException e) - { - throw new AMQException("Error evaluting message: " + e, e); + if( m instanceof TextMessage ) { + String text = ((TextMessage)m).getText(); + return evaluate(text); + } else if ( m instanceof BytesMessage ) { + BytesMessage bm = (BytesMessage) m; + byte data[] = new byte[(int) bm.getBodyLength()]; + bm.readBytes(data); + return evaluate(data); } + */ + return false; + } private boolean evaluate(byte[] data) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageDecorator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageDecorator.java deleted file mode 100644 index aba3b88a59..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageDecorator.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.message; - -public interface MessageDecorator -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java deleted file mode 100644 index ab201c476e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/jms/JMSMessage.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.message.jms; - -import org.apache.qpid.server.message.MessageDecorator; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.AMQException; - -import javax.jms.Message; -import javax.jms.JMSException; -import javax.jms.Destination; -import javax.jms.MessageNotWriteableException; -import java.util.Enumeration; - -public class JMSMessage implements MessageDecorator -{ - - private AMQMessage _message; - private BasicContentHeaderProperties _properties; - - public JMSMessage(AMQMessage message) throws AMQException - { - _message = message; - ContentHeaderBody contentHeader = message.getContentHeaderBody(); - _properties = (BasicContentHeaderProperties) contentHeader.properties; - } - - protected void checkWriteable() throws MessageNotWriteableException - { - //The broker should not modify a message. -// if (_readableMessage) - { - throw new MessageNotWriteableException("The broker should not modify a message."); - } - } - - - public String getJMSMessageID() - { - return _properties.getMessageId(); - } - - public void setJMSMessageID(String string) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setMessageId(string); - } - - public long getJMSTimestamp() - { - return _properties.getTimestamp(); - } - - public void setJMSTimestamp(long l) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setTimestamp(l); - } - - public byte[] getJMSCorrelationIDAsBytes() - { - return _properties.getCorrelationId().getBytes(); - } - -// public void setJMSCorrelationIDAsBytes(byte[] bytes) -// { -// } - - public void setJMSCorrelationID(String string) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setCorrelationId(string); - } - - public String getJMSCorrelationID() - { - return _properties.getCorrelationId(); - } - - public String getJMSReplyTo() - { - return _properties.getReplyTo(); - } - - public void setJMSReplyTo(Destination destination) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setReplyTo(destination.toString()); - } - - public String getJMSDestination() - { - //fixme should be a deestination - return ""; - } - - public void setJMSDestination(Destination destination) throws MessageNotWriteableException - { - checkWriteable(); - //_properties.setDestination(destination.toString()); - } - - public int getJMSDeliveryMode() - { - return _properties.getDeliveryMode(); - } - - public void setJMSDeliveryMode(byte i) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setDeliveryMode(i); - } - - public boolean getJMSRedelivered() - { - return _message.isRedelivered(); - } - - public void setJMSRedelivered(boolean b) throws MessageNotWriteableException - { - checkWriteable(); - _message.setRedelivered(b); - } - - public String getJMSType() - { - return _properties.getType(); - } - - public void setJMSType(String string) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setType(string); - } - - public long getJMSExpiration() - { - return _properties.getExpiration(); - } - - public void setJMSExpiration(long l) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setExpiration(l); - } - - public int getJMSPriority() - { - return _properties.getPriority(); - } - - public void setJMSPriority(byte i) throws MessageNotWriteableException - { - checkWriteable(); - _properties.setPriority(i); - } - - public void clearProperties() throws MessageNotWriteableException - { - checkWriteable(); - _properties.clear(); - } - - public boolean propertyExists(String string) - { - return _properties.propertyExists(string); - } - - public boolean getBooleanProperty(String string) throws JMSException - { - return _properties.getBoolean(string); - } - - public byte getByteProperty(String string) throws JMSException - { - return _properties.getByte(string); - } - - public short getShortProperty(String string) throws JMSException - { - return _properties.getShort(string); - } - - public int getIntProperty(String string) throws JMSException - { - return _properties.getInteger(string); - } - - public long getLongProperty(String string) throws JMSException - { - return _properties.getLong(string); - } - - public float getFloatProperty(String string) throws JMSException - { - return _properties.getFloat(string); - } - - public double getDoubleProperty(String string) throws JMSException - { - return _properties.getDouble(string); - } - - public String getStringProperty(String string) throws JMSException - { - return _properties.getString(string); - } - - public Object getObjectProperty(String string) throws JMSException - { - return _properties.getObject(string); - } - - public Enumeration getPropertyNames() - { - return _properties.getPropertyNames(); - } - - public void setBooleanProperty(String string, boolean b) throws JMSException - { - checkWriteable(); - _properties.setBoolean(string, b); - } - - public void setByteProperty(String string, byte b) throws JMSException - { - checkWriteable(); - _properties.setByte(string, b); - } - - public void setShortProperty(String string, short i) throws JMSException - { - checkWriteable(); - _properties.setShort(string, i); - } - - public void setIntProperty(String string, int i) throws JMSException - { - checkWriteable(); - _properties.setInteger(string, i); - } - - public void setLongProperty(String string, long l) throws JMSException - { - checkWriteable(); - _properties.setLong(string, l); - } - - public void setFloatProperty(String string, float v) throws JMSException - { - checkWriteable(); - _properties.setFloat(string, v); - } - - public void setDoubleProperty(String string, double v) throws JMSException - { - checkWriteable(); - _properties.setDouble(string, v); - } - - public void setStringProperty(String string, String string1) throws JMSException - { - checkWriteable(); - _properties.setString(string, string1); - } - - public void setObjectProperty(String string, Object object) throws JMSException - { - checkWriteable(); - _properties.setObject(string, object); - } - - public void acknowledge() throws MessageNotWriteableException - { - checkWriteable(); - } - - public void clearBody() throws MessageNotWriteableException - { - checkWriteable(); - } - - public AMQMessage getAMQMessage() - { - return _message; - } -} -- cgit v1.2.1 From 8601949672c7ed0e53c4a99a6e5d285682b65a74 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 25 Jan 2007 00:30:16 +0000 Subject: QPID-318 : Patch supplied by Rob Godfrey - Remove hard-coding of protocol version number. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499628 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicGetMethodHandler.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 6 +++--- .../qpid/server/protocol/AMQProtocolSession.java | 5 +++++ .../org/apache/qpid/server/queue/AMQMessage.java | 23 +++++++++++++--------- 4 files changed, 23 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 51b585ecc5..b8db7371b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -72,7 +72,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener Date: Thu, 25 Jan 2007 17:03:28 +0000 Subject: QPID-318 : Patch supplied by Rob Godfrey - remove hard-coding of protocol values git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499851 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/protocol/AMQPFastProtocolHandler.java | 3 ++- .../server/protocol/AMQProtocolSessionMBean.java | 3 ++- .../apache/qpid/server/queue/SubscriptionImpl.java | 21 ++------------------- 3 files changed, 6 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 474714680b..dd56fe87ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -162,7 +162,8 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.write(ConnectionCloseBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) + session.getProtocolMajorVersion(), + session.getProtocolMinorVersion(), // AMQP version (major, minor) 0, // classId 0, // methodId 200, // replyCode diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index b5fec39626..0b21d26d32 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -206,7 +206,8 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) + _session.getProtocolMajorVersion(), + _session.getProtocolMinorVersion(), // AMQP version (major, minor) 0, // classId 0, // methodId AMQConstant.REPLY_SUCCESS.getCode(), // replyCode diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index e120752959..181f41fbec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -399,7 +399,8 @@ public class SubscriptionImpl implements Subscription // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), - (byte)8, (byte)0, // AMQP version (major, minor) + protocolSession.getProtocolMajorVersion(), + protocolSession.getProtocolMinorVersion(), consumerTag // consumerTag )); _closed = true; @@ -417,22 +418,4 @@ public class SubscriptionImpl implements Subscription } - private ByteBuffer createEncodedDeliverFrame(long deliveryTag, AMQShortString routingKey, AMQShortString exchange) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), - (byte)8, (byte)0, // AMQP version (major, minor) - consumerTag, // consumerTag - deliveryTag, // deliveryTag - exchange, // exchange - false, // redelivered - routingKey // routingKey - ); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; - } } -- cgit v1.2.1 From c841dade7baf4fc22db42e89d15a950b3cb09524 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 25 Jan 2007 18:03:08 +0000 Subject: QPID-319 management console view updated for virtual host hierarchy git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499874 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 13 ++++----- .../qpid/server/exchange/AbstractExchange.java | 13 +++++---- .../server/management/DefaultManagedObject.java | 34 +++++++++++++++------- .../qpid/server/management/ManagedBroker.java | 2 +- .../qpid/server/virtualhost/VirtualHost.java | 6 ++-- 5 files changed, 41 insertions(+), 27 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 2e6293081d..204b5674ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -202,12 +202,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr return _virtualHostMBean; } -// public ObjectName getObjectName() throws MalformedObjectNameException -// { -// StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); -// objectName.append(".").append(getVirtualHost().getName()); -// objectName.append(":type=").append(getType()); -// -// return new ObjectName(objectName.toString()); -// } + // This will have a single instance for a virtual host, so not having the name property in the ObjectName + public ObjectName getObjectName() throws MalformedObjectNameException + { + return getObjectNameForSingleInstanceMBean(); + } } // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index caafb83568..8b4f41a7a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -100,12 +100,13 @@ public abstract class AbstractExchange implements Exchange, Managable return _autoDelete; } -// public ObjectName getObjectName() throws MalformedObjectNameException -// { -// String objNameString = super.getObjectName().toString(); -// objNameString = objNameString + ",VirtualHost="+ _virtualHost.getName() +",ExchangeType=" + _exchangeType; -// return new ObjectName(objNameString); -// } + // Added exchangetype in the object name lets maangement apps to do any customization required + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + _exchangeType; + return new ObjectName(objNameString); + } protected ManagedObjectRegistry getManagedObjectRegistry() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 46bac52e78..4fb091df75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -103,8 +103,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana * @return ObjectName * @throws MalformedObjectNameException */ - public ObjectName getObjectName() - throws MalformedObjectNameException + public ObjectName getObjectName() throws MalformedObjectNameException { String name = getObjectInstanceName(); StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); @@ -119,26 +118,41 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana return new ObjectName(objectName.toString()); } - private String getHierarchicalType(ManagedObject obj) + protected ObjectName getObjectNameForSingleInstanceMBean() throws MalformedObjectNameException + { + StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); + + objectName.append(":type="); + objectName.append(getHierarchicalType(this)); + + String hierarchyName = getHierarchicalName(this); + if (hierarchyName != null) + { + objectName.append(","); + objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); + } + + return new ObjectName(objectName.toString()); + } + + protected String getHierarchicalType(ManagedObject obj) { - String parentType = null; if (obj.getParentObject() != null) { - parentType = getHierarchicalType(obj.getParentObject()).toString(); + String parentType = getHierarchicalType(obj.getParentObject()).toString(); return parentType + "." + obj.getType(); } else return obj.getType(); } - private String getHierarchicalName(ManagedObject obj) + protected String getHierarchicalName(ManagedObject obj) { - String parentName = null; if (obj.getParentObject() != null) { - parentName = obj.getParentObject().getType() + "=" + - obj.getParentObject().getObjectInstanceName() + ","+ - getHierarchicalName(obj.getParentObject()); + String parentName = obj.getParentObject().getType() + "=" + + obj.getParentObject().getObjectInstanceName() + ","+ + getHierarchicalName(obj.getParentObject()); return parentName; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index aec7d6cb73..87d9a577e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -37,7 +37,7 @@ import java.io.IOException; */ public interface ManagedBroker { - static final String TYPE = "BrokerManager"; + static final String TYPE = "VirtualHostManager"; /** * Creates a new Exchange. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9c14be897f..1ce5146416 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -90,7 +90,8 @@ public class VirtualHost _name = name; _virtualHostMBean = new VirtualHostMBean(); - _virtualHostMBean.register(); + // This isn't needed to be registered + //_virtualHostMBean.register(); _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); @@ -107,7 +108,8 @@ public class VirtualHost _name = name; _virtualHostMBean = new VirtualHostMBean(); - _virtualHostMBean.register(); + // This isn't needed to be registered + //_virtualHostMBean.register(); _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); -- cgit v1.2.1 From 82e12b97f9dae4e2fc7fd16c07f611a1b62d8c72 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 29 Jan 2007 10:59:33 +0000 Subject: QPID-320 : Patch supplied by Rob Godfrey - Improve performance by remembering protocol version git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501003 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicQosHandler.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 81 ++++++++++++++++------ .../server/protocol/AMQPFastProtocolHandler.java | 5 +- .../qpid/server/protocol/AMQProtocolSession.java | 7 +- .../org/apache/qpid/server/queue/AMQMessage.java | 32 ++++++--- .../apache/qpid/server/queue/AMQMessageHandle.java | 22 +++--- .../org/apache/qpid/server/queue/AMQQueue.java | 12 +++- .../apache/qpid/server/queue/AMQQueueMBean.java | 26 ++----- .../queue/ConcurrentSelectorDeliveryManager.java | 18 +++++ .../apache/qpid/server/queue/DeliveryManager.java | 2 + .../qpid/server/queue/InMemoryMessageHandle.java | 22 +++--- .../qpid/server/queue/MessageCleanupException.java | 4 ++ .../qpid/server/queue/MessageHandleFactory.java | 2 +- .../server/queue/WeakReferenceMessageHandle.java | 43 ++++++++---- .../apache/qpid/server/state/AMQStateManager.java | 39 +++-------- .../qpid/server/store/MemoryMessageStore.java | 34 +++++---- .../org/apache/qpid/server/store/MessageStore.java | 16 ++--- 17 files changed, 220 insertions(+), 147 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java index 325e5226ad..5c176c21cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java @@ -50,6 +50,6 @@ public class BasicQosHandler implements StateAwareMethodListener // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - session.writeFrame(new AMQFrame(evt.getChannelId(), new BasicQosOkBody((byte)8, (byte)0))); + session.writeFrame(BasicQosOkBody.createAMQFrame(evt.getChannelId(),(byte)8, (byte)0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index d87821aa46..5f9fcbdc85 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -61,6 +61,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + // to save boxing the channelId and looking up in a map... cache in an array the low numbered + // channels. This value must be of the form 2^x - 1. + private static final int CHANNEL_CACHE_SIZE = 0xff; private final IoSession _minaProtocolSession; @@ -70,6 +73,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private final Map _channelMap = new HashMap(); + private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE+1]; + private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); private final AMQStateManager _stateManager; @@ -89,10 +94,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private long _maxNoOfChannels = 1000; /* AMQP Version for this session */ - private byte _major; - private byte _minor; + private byte _major = pv[pv.length-1][PROTOCOL_MAJOR]; + private byte _minor = pv[pv.length-1][PROTOCOL_MINOR]; private FieldTable _clientProperties; private final List _taskList = new CopyOnWriteArrayList(); + private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(pv[pv.length-1][PROTOCOL_MAJOR],pv[pv.length-1][PROTOCOL_MINOR]); + public ManagedObject getManagedObject() @@ -165,11 +172,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, 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; + setProtocolVersion(pi.protocolMajor,pi.protocolMinor); + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + String locales = "en_US"; + // Interfacing with generated code - be aware of possible changes to parameter order as versions change. AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, _major, _minor, // AMQP version (major, minor) @@ -200,7 +210,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { AMQFrame frame = (AMQFrame) message; - if (frame.bodyFrame instanceof AMQMethodBody) + if (frame.getBodyFrame() instanceof AMQMethodBody) { methodFrameReceived(frame); } @@ -217,8 +227,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Method frame received: " + frame); } - final AMQMethodEvent evt = new AMQMethodEvent(frame.channel, - (AMQMethodBody) frame.bodyFrame); + final AMQMethodEvent evt = new AMQMethodEvent(frame.getChannel(), + (AMQMethodBody) frame.getBodyFrame()); try { try @@ -241,14 +251,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, catch (AMQChannelException e) { _logger.error("Closing channel due to: " + e.getMessage()); - writeFrame(e.getCloseFrame(frame.channel)); - closeChannel(frame.channel); + writeFrame(e.getCloseFrame(frame.getChannel())); + closeChannel(frame.getChannel()); } catch (AMQConnectionException e) { _logger.error("Closing connection due to: " + e.getMessage()); closeSession(); - writeFrame(e.getCloseFrame(frame.channel)); + writeFrame(e.getCloseFrame(frame.getChannel())); } } catch (Exception e) @@ -264,15 +274,15 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private void contentFrameReceived(AMQFrame frame) throws AMQException { - if (frame.bodyFrame instanceof ContentHeaderBody) + if (frame.getBodyFrame() instanceof ContentHeaderBody) { contentHeaderReceived(frame); } - else if (frame.bodyFrame instanceof ContentBody) + else if (frame.getBodyFrame() instanceof ContentBody) { contentBodyReceived(frame); } - else if (frame.bodyFrame instanceof HeartbeatBody) + else if (frame.getBodyFrame() instanceof HeartbeatBody) { _logger.debug("Received heartbeat from client"); } @@ -288,7 +298,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content header frame received: " + frame); } - getChannel(frame.channel).publishContentHeader((ContentHeaderBody) frame.bodyFrame); + getChannel(frame.getChannel()).publishContentHeader((ContentHeaderBody) frame.getBodyFrame()); } private void contentBodyReceived(AMQFrame frame) throws AMQException @@ -297,7 +307,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } - getChannel(frame.channel).publishContentBody((ContentBody)frame.bodyFrame, this); + getChannel(frame.getChannel()).publishContentBody((ContentBody)frame.getBodyFrame(), this); } /** @@ -329,7 +339,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public AMQChannel getChannel(int channelId) throws AMQException { - return _channelMap.get(channelId); + return ((channelId & CHANNEL_CACHE_SIZE) == channelId) + ? _cachedChannels[channelId] + : _channelMap.get(channelId); } public void addChannel(AMQChannel channel) throws AMQException @@ -339,7 +351,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, throw new AMQException("Session is closed"); } - _channelMap.put(channel.getChannelId(), channel); + final int channelId = channel.getChannelId(); + _channelMap.put(channelId, channel); + + if(((channelId & CHANNEL_CACHE_SIZE) == channelId)) + { + _cachedChannels[channelId] = channel; + } checkForNotification(); } @@ -389,7 +407,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, */ public void closeChannel(int channelId) throws AMQException { - final AMQChannel channel = _channelMap.get(channelId); + final AMQChannel channel = getChannel(channelId); if (channel == null) { throw new IllegalArgumentException("Unknown channel id"); @@ -402,7 +420,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } finally { - _channelMap.remove(channelId); + removeChannel(channelId); + } } } @@ -415,6 +434,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void removeChannel(int channelId) { _channelMap.remove(channelId); + if((channelId & CHANNEL_CACHE_SIZE) == channelId) + { + _cachedChannels[channelId] = null; + } } /** @@ -444,6 +467,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, channel.close(this); } _channelMap.clear(); + for(int i = 0; i <= CHANNEL_CACHE_SIZE; i++) + { + _cachedChannels[i]=null; + } } /** @@ -534,10 +561,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } } - /** - * Convenience methods for managing AMQP version. - * NOTE: Both major and minor will be set to 0 prior to protocol initiation. - */ + private void setProtocolVersion(byte major, byte minor) + { + _major = major; + _minor = minor; + _registry = MainRegistry.getVersionSpecificRegistry(major,minor); + } public byte getProtocolMajorVersion() { @@ -554,6 +583,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _major == major && _minor == minor; } + public VersionSpecificRegistry getRegistry() + { + return _registry; + } + + public Object getClientIdentifier() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index dd56fe87ec..d7e6af0c29 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -120,7 +120,10 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco _logger.info("Protocol Session closed"); final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); //fixme -- this can be null - amqProtocolSession.closeSession(); + if(amqProtocolSession != null) + { + amqProtocolSession.closeSession(); + } } public void sessionIdle(IoSession session, IdleStatus status) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index ed998b33c6..6b3b4f8021 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -24,6 +24,7 @@ import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.protocol.AMQProtocolWriter; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.AMQException; @@ -31,7 +32,7 @@ import org.apache.qpid.AMQException; import javax.security.sasl.SaslServer; -public interface AMQProtocolSession extends AMQProtocolWriter +public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { @@ -144,8 +145,4 @@ public interface AMQProtocolSession extends AMQProtocolWriter void removeSessionCloseTask(Task task); - byte getProtocolMajorVersion(); - - byte getProtocolMinorVersion(); - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 23a5da0a30..7a16901796 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -53,7 +53,7 @@ public class AMQMessage */ private AMQProtocolSession _publisher; - private final long _messageId; + private final Long _messageId; private final AtomicInteger _referenceCount = new AtomicInteger(1); @@ -68,6 +68,13 @@ public class AMQMessage * messages published with the 'immediate' flag. */ private boolean _deliveredToConsumer; + /** + * We need to keep track of whether the message was 'immediate' + * as in extreme circumstances, when the checkDelieveredToConsumer + * is called, the message may already have been received and acknowledged, + * and the body removed from the store. + */ + private boolean _immediate; private AtomicBoolean _taken = new AtomicBoolean(false); @@ -160,11 +167,12 @@ public class AMQMessage } } - public AMQMessage(long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, BasicPublishBody publishBody, TransactionalContext txnContext) { _messageId = messageId; _txnContext = txnContext; + _immediate = publishBody.immediate; _transientMessageData.setPublishBody(publishBody); _taken = new AtomicBoolean(false); @@ -183,7 +191,7 @@ public class AMQMessage * @param factory * @throws AMQException */ - public AMQMessage(long messageId, MessageStore store, MessageHandleFactory factory) throws AMQException + public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory) throws AMQException { _messageId = messageId; _messageHandle = factory.createMessageHandle(messageId, store, true); @@ -198,7 +206,7 @@ public class AMQMessage * @param txnContext * @param contentHeader */ - public AMQMessage(long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, BasicPublishBody publishBody, TransactionalContext txnContext, ContentHeaderBody contentHeader) throws AMQException { this(messageId, publishBody, txnContext); @@ -216,7 +224,7 @@ public class AMQMessage * @param contentBodies * @throws AMQException */ - public AMQMessage(long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, BasicPublishBody publishBody, TransactionalContext txnContext, ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, MessageStore messageStore, StoreContext storeContext, @@ -293,8 +301,9 @@ public class AMQMessage public boolean addContentBodyFrame(StoreContext storeContext, ContentBody contentBody) throws AMQException { _transientMessageData.addBodyLength(contentBody.getSize()); - _messageHandle.addContentBodyFrame(storeContext, _messageId, contentBody); - if (isAllContentReceived()) + final boolean allContentReceived = isAllContentReceived(); + _messageHandle.addContentBodyFrame(storeContext, _messageId, contentBody, allContentReceived); + if (allContentReceived) { deliver(storeContext); return true; @@ -348,6 +357,7 @@ public class AMQMessage { _log.debug("Ref count on message " + _messageId + " is zero; removing message"); } + // must check if the handle is null since there may be cases where we decide to throw away a message // and the handle has not yet been constructed if (_messageHandle != null) @@ -372,6 +382,10 @@ public class AMQMessage Thread.dumpStack(); } } + if(_referenceCount.get()<0) + { + throw new MessageCleanupException("Reference count for message id " + _messageId + " has gone below 0."); + } } } @@ -464,8 +478,8 @@ public class AMQMessage */ public void checkDeliveredToConsumer() throws NoConsumersException, AMQException { - BasicPublishBody pb = getPublishBody(); - if (pb.immediate && !_deliveredToConsumer) + + if (_immediate && !_deliveredToConsumer) { throw new NoConsumersException(this); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index ef5d460b9b..d788d1b9e2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -35,17 +35,17 @@ import org.apache.qpid.framing.ContentHeaderBody; */ public interface AMQMessageHandle { - ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException; + ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException; /** * @return the number of body frames associated with this message */ - int getBodyCount(long messageId) throws AMQException; + int getBodyCount(Long messageId) throws AMQException; /** * @return the size of the body */ - long getBodySize(long messageId) throws AMQException; + long getBodySize(Long messageId) throws AMQException; /** * Get a particular content body @@ -53,25 +53,25 @@ public interface AMQMessageHandle * @return a content body * @throws IllegalArgumentException if the index is invalid */ - ContentBody getContentBody(long messageId, int index) throws IllegalArgumentException, AMQException; + ContentBody getContentBody(Long messageId, int index) throws IllegalArgumentException, AMQException; - void addContentBodyFrame(StoreContext storeContext, long messageId, ContentBody contentBody) throws AMQException; + void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException; - BasicPublishBody getPublishBody(long messageId) throws AMQException; + BasicPublishBody getPublishBody(Long messageId) throws AMQException; boolean isRedelivered(); void setRedelivered(boolean redelivered); - boolean isPersistent(long messageId) throws AMQException; + boolean isPersistent(Long messageId) throws AMQException; - void setPublishAndContentHeaderBody(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody) throws AMQException; - void removeMessage(StoreContext storeContext, long messageId) throws AMQException; + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException; + void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; - void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException; + void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 709dd28ad5..ab7bbefe92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -252,6 +252,12 @@ public class AMQQueue implements Managable, Comparable return _deliveryMgr.getMessages(); } + public long getQueueDepth() + { + return _deliveryMgr.getTotalMessageSize(); + } + + /** * @param messageId * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. @@ -315,13 +321,13 @@ public class AMQQueue implements Managable, Comparable _maxMessageCount = value; } - public Long getMaximumQueueDepth() + public long getMaximumQueueDepth() { return _maxQueueDepth; } // Sets the queue depth, the max queue size - public void setMaximumQueueDepth(Long value) + public void setMaximumQueueDepth(long value) { _maxQueueDepth = value; } @@ -625,4 +631,6 @@ public class AMQQueue implements Managable, Comparable _deleteTaskList.add(task); } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index ab67012b19..e15dc648f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -191,25 +191,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue */ public Long getQueueDepth() throws JMException { - List list = _queue.getMessagesOnTheQueue(); - if (list.size() == 0) - { - return 0l; - } + return getQueueDepthKb(); + } - long queueDepth = 0; - try - { - for (AMQMessage message : list) - { - queueDepth = queueDepth + getMessageSize(message); - } - } - catch (AMQException e) - { - throw new JMException("Unable to get message size: " + e); - } - return (long) Math.round(queueDepth / 1000); + public long getQueueDepthKb() + { + long queueBytesSize = _queue.getQueueDepth(); + return queueBytesSize >> 10 ; } /** @@ -245,7 +233,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue } // Check for threshold queue depth in bytes - long queueDepth = getQueueDepth(); + long queueDepth = getQueueDepthKb(); if (queueDepth >= _queue.getMaximumQueueDepth()) { notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index ba4d0bf4ba..c0c0970c48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -38,6 +38,7 @@ import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; /** @@ -83,6 +84,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. */ private ReentrantLock _lock = new ReentrantLock(); + private AtomicLong _totalMessageSize = new AtomicLong(); ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) @@ -116,6 +118,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _messages.offer(msg); + _totalMessageSize.addAndGet(msg.getSize()); + return true; } @@ -150,6 +154,13 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } + + public long getTotalMessageSize() + { + return _totalMessageSize.get(); + } + + public synchronized List getMessages() { return new ArrayList(_messages); @@ -213,6 +224,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } msg.writeGetOk(protocolSession, channel.getChannelId(), deliveryTag, _queue.getMessageCount()); + _totalMessageSize.addAndGet(-msg.getSize()); } } finally @@ -224,6 +236,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { AMQMessage msg = poll(); @@ -231,6 +244,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { msg.dequeue(storeContext, _queue); } + _totalMessageSize.getAndAdd(-msg.getSize()); } public synchronized long clearAllMessages(StoreContext storeContext) throws AMQException @@ -241,8 +255,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { msg.dequeue(storeContext, _queue); count++; + _totalMessageSize.set(0L); msg = poll(); + } + return count; } @@ -292,6 +309,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //remove sent message from our queue. messageQueue.poll(); + _totalMessageSize.addAndGet(-message.getSize()); } catch (AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 6954be8473..7d7ede0732 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -81,4 +81,6 @@ interface DeliveryManager void populatePreDeliveryQueue(Subscription subscription); boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; + + long getTotalMessageSize(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index e2758ce6cb..186a5c8753 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -47,22 +47,22 @@ public class InMemoryMessageHandle implements AMQMessageHandle { } - public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException { return _contentHeaderBody; } - public int getBodyCount(long messageId) + public int getBodyCount(Long messageId) { return _contentBodies.size(); } - public long getBodySize(long messageId) throws AMQException + public long getBodySize(Long messageId) throws AMQException { return getContentHeaderBody(messageId).bodySize; } - public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException + public ContentBody getContentBody(Long messageId, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -72,13 +72,13 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _contentBodies.get(index); } - public void addContentBodyFrame(StoreContext storeContext, long messageId, ContentBody contentBody) + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException { _contentBodies.add(contentBody); } - public BasicPublishBody getPublishBody(long messageId) throws AMQException + public BasicPublishBody getPublishBody(Long messageId) throws AMQException { return _publishBody; } @@ -94,7 +94,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(long messageId) throws AMQException + public boolean isPersistent(Long messageId) throws AMQException { //todo remove literal values to a constant file such as AMQConstants in common ContentHeaderBody chb = getContentHeaderBody(messageId); @@ -108,7 +108,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody) throws AMQException { @@ -116,17 +116,17 @@ public class InMemoryMessageHandle implements AMQMessageHandle _contentHeaderBody = contentHeaderBody; } - public void removeMessage(StoreContext storeContext, long messageId) throws AMQException + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException { // NO OP } - public void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { // NO OP } - public void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { // NO OP } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java index bfe0a0ecf1..1e7e6f03d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java @@ -32,4 +32,8 @@ public class MessageCleanupException extends AMQException { super("Failed to cleanup message with id " + messageId, e); } + public MessageCleanupException(String message) + { + super(message); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java index a7ada2c1f8..94ab935115 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -31,7 +31,7 @@ import org.apache.qpid.server.store.MessageStore; public class MessageHandleFactory { - public AMQMessageHandle createMessageHandle(long messageId, MessageStore store, boolean persistent) + public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) { // just hardcoded for now if (persistent) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 2fb2bdd2e3..50051fdc34 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -32,6 +32,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.LinkedList; +import java.util.Collections; /** * @author Robert Greig (robert.j.greig@jpmorgan.com) @@ -48,12 +49,13 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle private final MessageStore _messageStore; + public WeakReferenceMessageHandle(MessageStore messageStore) { _messageStore = messageStore; } - public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException { ContentHeaderBody chb = (_contentHeaderBody != null?_contentHeaderBody.get():null); if (chb == null) @@ -66,7 +68,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return chb; } - public int getBodyCount(long messageId) throws AMQException + public int getBodyCount(Long messageId) throws AMQException { if (_contentBodies == null) { @@ -81,12 +83,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return _contentBodies.size(); } - public long getBodySize(long messageId) throws AMQException + public long getBodySize(Long messageId) throws AMQException { return getContentHeaderBody(messageId).bodySize; } - public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException + public ContentBody getContentBody(Long messageId, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -108,19 +110,30 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * @param storeContext * @param messageId * @param contentBody + * @param isLastContentBody * @throws AMQException */ - public void addContentBodyFrame(StoreContext storeContext, long messageId, ContentBody contentBody) throws AMQException + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException { - if (_contentBodies == null) + if(_contentBodies == null && isLastContentBody) { - _contentBodies = new LinkedList>(); + _contentBodies = Collections.singletonList(new WeakReference(contentBody)); + + } + else + { + if (_contentBodies == null) + { + _contentBodies = new LinkedList>(); + } + + + _contentBodies.add(new WeakReference(contentBody)); } - _contentBodies.add(new WeakReference(contentBody)); - _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody); + _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody, isLastContentBody); } - public BasicPublishBody getPublishBody(long messageId) throws AMQException + public BasicPublishBody getPublishBody(Long messageId) throws AMQException { BasicPublishBody bpb = (_publishBody != null?_publishBody.get():null); if (bpb == null) @@ -143,7 +156,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(long messageId) throws AMQException + public boolean isPersistent(Long messageId) throws AMQException { //todo remove literal values to a constant file such as AMQConstants in common ContentHeaderBody chb = getContentHeaderBody(messageId); @@ -157,7 +170,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, long messageId, BasicPublishBody publishBody, + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody) throws AMQException { @@ -173,17 +186,17 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _contentHeaderBody = new WeakReference(contentHeaderBody); } - public void removeMessage(StoreContext storeContext, long messageId) throws AMQException + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException { _messageStore.removeMessage(storeContext, messageId); } - public void enqueue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); } - public void dequeue(StoreContext storeContext, long messageId, AMQQueue queue) throws AMQException + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 7b8ba1d9cc..69b12ec4e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -36,6 +36,7 @@ import org.apache.log4j.Logger; import java.util.HashMap; import java.util.Map; +import java.util.EnumMap; import java.util.concurrent.CopyOnWriteArraySet; /** @@ -59,8 +60,9 @@ public class AMQStateManager implements AMQMethodListener * 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 final EnumMap, StateAwareMethodListener>> _state2HandlersMap = + new EnumMap, StateAwareMethodListener>>(AMQState.class); + private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); @@ -83,14 +85,7 @@ public class AMQStateManager implements AMQMethodListener 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); + Map, StateAwareMethodListener> frame2handlerMap; frame2handlerMap = new HashMap, StateAwareMethodListener>(); frame2handlerMap.put(ConnectionStartOkBody.class, ConnectionStartOkMethodHandler.getInstance()); @@ -205,26 +200,14 @@ public class AMQStateManager implements AMQMethodListener 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()); + final StateAwareMethodListener handler = classToHandlerMap == null + ? null + : (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); - } + _logger.debug("No state transition handler defined for receiving frame " + frame); + return null; } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index eaaffa2dce..1f4cc7530d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -27,11 +27,11 @@ import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; import java.util.List; +import java.util.Collections; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; @@ -87,7 +87,7 @@ public class MemoryMessageStore implements MessageStore } } - public void removeMessage(StoreContext context, long messageId) + public void removeMessage(StoreContext context, Long messageId) { if (_log.isDebugEnabled()) { @@ -107,12 +107,12 @@ public class MemoryMessageStore implements MessageStore // Not required to do anything } - public void enqueueMessage(StoreContext context, AMQShortString name, long messageId) throws AMQException + public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException { // Not required to do anything } - public void dequeueMessage(StoreContext context, AMQShortString name, long messageId) throws AMQException + public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException { // Not required to do anything } @@ -142,36 +142,44 @@ public class MemoryMessageStore implements MessageStore return null; } - public long getNewMessageId() + public Long getNewMessageId() { return _messageId.getAndIncrement(); } - public void storeContentBodyChunk(StoreContext context, long messageId, int index, ContentBody contentBody) + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentBody contentBody, boolean lastContentBody) throws AMQException { List bodyList = _contentBodyMap.get(messageId); - if (bodyList == null) + + if(bodyList == null && lastContentBody) { - bodyList = new ArrayList(); - _contentBodyMap.put(messageId, bodyList); + _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); } + else + { + if (bodyList == null) + { + bodyList = new ArrayList(); + _contentBodyMap.put(messageId, bodyList); + } - bodyList.add(index, contentBody); + bodyList.add(index, contentBody); + } } - public void storeMessageMetaData(StoreContext context, long messageId, MessageMetaData messageMetaData) + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException { _metaDataMap.put(messageId, messageMetaData); } - public MessageMetaData getMessageMetaData(long messageId) throws AMQException + public MessageMetaData getMessageMetaData(Long messageId) throws AMQException { return _metaDataMap.get(messageId); } - public ContentBody getContentBodyChunk(long messageId, int index) throws AMQException + public ContentBody getContentBodyChunk(Long messageId, int index) throws AMQException { List bodyList = _contentBodyMap.get(messageId); return bodyList.get(index); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 8daad0e5e5..b4ccd2cc51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -50,15 +50,15 @@ public interface MessageStore */ void close() throws Exception; - void removeMessage(StoreContext storeContext, long messageId) throws AMQException; + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; void createQueue(AMQQueue queue) throws AMQException; void removeQueue(AMQShortString name) throws AMQException; - void enqueueMessage(StoreContext context, AMQShortString name, long messageId) throws AMQException; + void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; - void dequeueMessage(StoreContext context, AMQShortString name, long messageId) throws AMQException; + void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; void beginTran(StoreContext context) throws AMQException; @@ -79,14 +79,14 @@ public interface MessageStore * Return a valid, currently unused message id. * @return a message id */ - long getNewMessageId(); + Long getNewMessageId(); - void storeContentBodyChunk(StoreContext context, long messageId, int index, ContentBody contentBody) throws AMQException; + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentBody contentBody, boolean lastContentBody) throws AMQException; - void storeMessageMetaData(StoreContext context, long messageId, MessageMetaData messageMetaData) throws AMQException; + void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - MessageMetaData getMessageMetaData(long messageId) throws AMQException; + MessageMetaData getMessageMetaData(Long messageId) throws AMQException; - ContentBody getContentBodyChunk(long messageId, int index) throws AMQException; + ContentBody getContentBodyChunk(Long messageId, int index) throws AMQException; } -- cgit v1.2.1 From b92653bb73b575b0cff7eacce5cf8d71bd1bf2ea Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 29 Jan 2007 11:11:29 +0000 Subject: QPID-322 : Patch supplied by Rob Godfrey - Message reference count not being incremented when message added to UnacknowledgeMap git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501010 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index ac390718c6..ff3c901be5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -39,6 +39,7 @@ public class UnacknowledgedMessage this.message = message; this.consumerTag = consumerTag; this.deliveryTag = deliveryTag; + message.incrementReference(); } public void discard(StoreContext storeContext) throws AMQException -- cgit v1.2.1 From f7ca6dd49e6f5de6e445549ee2f1a942a6456f0c Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 29 Jan 2007 16:37:13 +0000 Subject: QPID-327 : Patch supplied by Rob Godfrey - [race condition] PoolingFilter : Possible race condition when completing a Job git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501096 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 2 +- .../qpid/server/protocol/AMQMinaProtocolSession.java | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index c45d1ad2c2..55009bbf49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -324,7 +324,7 @@ public class Main implements ProtocolVersionList // implementation provided by MINA if (connectorConfig.enableExecutorPool) { - sconfig.setThreadModel(new ReadWriteThreadModel()); + sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } if (connectorConfig.enableNonSSL) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 5f9fcbdc85..460d5126ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -23,10 +23,13 @@ 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.common.IoSessionConfig; +import org.apache.mina.common.IoServiceConfig; import org.apache.mina.transport.vmpipe.VmPipeAddress; import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQMethodEvent; @@ -121,6 +124,23 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _codecFactory = codecFactory; + try + { + IoServiceConfig config = session.getServiceConfig(); + ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); + threadModel.getAsynchronousReadFilter().createNewJobForSession(session); + threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); + } + catch (RuntimeException e) + { + e.printStackTrace(); + // throw e; + + } + + + + // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } -- cgit v1.2.1 From e0f8d9edb4f3e4473c13b9bf34d81cd065051768 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 30 Jan 2007 15:05:28 +0000 Subject: fixed the null pointer, which occurs when there are no messages in the queue git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501412 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index c0c0970c48..2103d79310 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -243,8 +243,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (msg != null) { msg.dequeue(storeContext, _queue); - } - _totalMessageSize.getAndAdd(-msg.getSize()); + _totalMessageSize.getAndAdd(-msg.getSize()); + } } public synchronized long clearAllMessages(StoreContext storeContext) throws AMQException -- cgit v1.2.1 From 72c7f1489dde8278a535061e4143ebb3a86cc1e5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 31 Jan 2007 17:25:42 +0000 Subject: QPID-334 WeakReferenceMessageHandle uses a singleton so when body is purged by gc it cannot be reset Changed to use an Arraylist of size 1 as per JIRA entry. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501914 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/WeakReferenceMessageHandle.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 50051fdc34..0abf464d15 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -57,7 +57,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException { - ContentHeaderBody chb = (_contentHeaderBody != null?_contentHeaderBody.get():null); + ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); if (chb == null) { MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); @@ -107,6 +107,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle /** * Content bodies are set before the publish and header frames + * * @param storeContext * @param messageId * @param contentBody @@ -115,10 +116,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle */ public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException { - if(_contentBodies == null && isLastContentBody) + if (_contentBodies == null && isLastContentBody) { - _contentBodies = Collections.singletonList(new WeakReference(contentBody)); - + _contentBodies = new ArrayList>(1); } else { @@ -126,16 +126,14 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { _contentBodies = new LinkedList>(); } - - - _contentBodies.add(new WeakReference(contentBody)); } + _contentBodies.add(new WeakReference(contentBody)); _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody, isLastContentBody); } public BasicPublishBody getPublishBody(Long messageId) throws AMQException { - BasicPublishBody bpb = (_publishBody != null?_publishBody.get():null); + BasicPublishBody bpb = (_publishBody != null ? _publishBody.get() : null); if (bpb == null) { MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); @@ -166,6 +164,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle /** * This is called when all the content has been received. + * * @param publishBody * @param contentHeaderBody * @throws AMQException -- cgit v1.2.1 From b12db1a36b5d01992b794534cf016189d35efc19 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 1 Feb 2007 10:13:55 +0000 Subject: QPID-331 and setting operation parameters to default values after executing the operation once. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502180 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 204b5674ce..0b8aac67b6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -153,7 +153,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { - queue = new AMQQueue(new AMQShortString(queueName), durable, new AMQShortString(owner), autoDelete, getVirtualHost()); + AMQShortString ownerShortString = null; + if (owner != null) + { + ownerShortString = new AMQShortString(owner); + } + queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, autoDelete, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); -- cgit v1.2.1 From 76ae9278c0bfe184ddbd8a72da56a9c4149b98a1 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 5 Feb 2007 09:40:04 +0000 Subject: QPID-326 : Patch supplied by Rob Godfrey - add oldest message on queue notification, and log notifications in log file git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@503604 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 203 +++++++++------------ .../server/exchange/DefaultExchangeRegistry.java | 5 + .../qpid/server/exchange/ExchangeRegistry.java | 2 + .../org/apache/qpid/server/queue/AMQMessage.java | 6 + .../apache/qpid/server/queue/AMQMessageHandle.java | 2 + .../org/apache/qpid/server/queue/AMQQueue.java | 76 ++++++-- .../apache/qpid/server/queue/AMQQueueMBean.java | 44 +++-- .../queue/ConcurrentSelectorDeliveryManager.java | 6 + .../apache/qpid/server/queue/DeliveryManager.java | 2 + .../qpid/server/queue/InMemoryMessageHandle.java | 9 + .../apache/qpid/server/queue/MessageMetaData.java | 18 ++ .../qpid/server/queue/NotificationCheck.java | 135 ++++++++++++++ .../server/queue/QueueNotificationListener.java | 23 +++ .../server/queue/WeakReferenceMessageHandle.java | 45 ++++- 14 files changed, 412 insertions(+), 164 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 361a21b284..c191bef447 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -34,9 +34,13 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.log4j.Logger; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.CompositeConfiguration; import java.util.Collection; +import java.util.List; +import java.util.Collections; public class VirtualHostConfiguration { @@ -44,11 +48,7 @@ public class VirtualHostConfiguration 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"; + private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; public VirtualHostConfiguration(String configFile) throws ConfigurationException @@ -57,137 +57,66 @@ public class VirtualHostConfiguration _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 + private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException { - 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"; - } + _logger.debug("Loding configuration for virtaulhost: "+virtualHostName); - error += ": " + prop; - } - throw new ConfigurationException(error); - } + VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); - _logger.info("VirtualHost:'" + prop + "'"); - String virtualHost = prop.toString(); - 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(virtualHost, path, dest); - } - } - else - { - loadBinding(virtualHost,path, -1); - } - } - private void loadBinding(String virtualHost, String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException - { - String path = rootpath + "." + XML_BIND; - if (index != -1) + if(virtualHost == null) { - path = path + "(" + index + ")"; + throw new ConfigurationException("Unknown virtual host: " + virtualHostName); } - String bindingString = _config.getString(path); - - AMQBindingURL binding = new AMQBindingURL(bindingString); + List queueNames = configuration.getList("queue.name"); - _logger.debug("Loaded Binding:" + binding); - - try - { - bind(virtualHost, binding); - } - catch (AMQException amqe) + for(Object queueNameObj : queueNames) { - _logger.info("Unable to bind url: " + binding); - throw amqe; + String queueName = String.valueOf(queueNameObj); + configureQueue(virtualHost, queueName, configuration); } + } - private void bind(String virtualHostName, AMQBindingURL binding) throws AMQException, ConfigurationException + private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException { + CompositeConfiguration queueConfiguration = new CompositeConfiguration(); - AMQShortString queueName = binding.getQueueName(); + queueConfiguration.addConfiguration(configuration.subset("queue."+ queueNameString)); + queueConfiguration.addConfiguration(configuration); - // 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 - VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); MessageStore messageStore = virtualHost.getMessageStore(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + AMQShortString queueName = new AMQShortString(queueNameString); + + AMQQueue queue; + synchronized (queueRegistry) { - AMQQueue queue = queueRegistry.getQueue(queueName); + queue = queueRegistry.getQueue(queueName); if (queue == null) { - _logger.info("Queue '" + binding.getQueueName() + "' does not exists. Creating."); + _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName()); + + boolean durable = queueConfiguration.getBoolean("durable" ,false); + boolean autodelete = queueConfiguration.getBoolean("autodelete", false); + String owner = queueConfiguration.getString("owner", null); queue = new AMQQueue(queueName, - Boolean.parseBoolean(binding.getOption(AMQBindingURL.OPTION_DURABLE)), - null /* These queues will have no owner */, - false /* Therefore autodelete makes no sence */, virtualHost); + durable, + owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, + autodelete /* Therefore autodelete makes no sence */, virtualHost); if (queue.isDurable()) { @@ -198,27 +127,69 @@ public class VirtualHostConfiguration } else { - _logger.info("Queue '" + binding.getQueueName() + "' already exists not creating."); + _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating."); } - Exchange defaultExchange = exchangeRegistry.getExchange(binding.getExchangeName()); - synchronized (defaultExchange) + String exchangeName = queueConfiguration.getString("exchange", null); + + Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if(exchange == null) { - if (defaultExchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + binding); - } + exchange = virtualHost.getExchangeRegistry().getDefaultExchange(); + } - defaultExchange.registerQueue(queue.getName(), queue, null); + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } - if (binding.getRoutingKey() == null || binding.getRoutingKey().equals("")) + synchronized (exchange) + { + List routingKeys = queueConfiguration.getList("routingKey"); + if(routingKeys == null || routingKeys.isEmpty()) { - throw new ConfigurationException("Unknown binding not specified on url:" + binding); + routingKeys = Collections.singletonList(queue.getName()); } - queue.bind(binding.getRoutingKey(), defaultExchange); + for(Object routingKeyNameObj : routingKeys) + { + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + exchange.registerQueue(routingKey, queue, null); + + queue.bind(routingKey, exchange); + + _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); + } } - _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + binding.getExchangeName() + " RK:'" + binding.getRoutingKey() + "'"); + } + + + + Configurator.configure(queue, queueConfiguration); } + + + public void performBindings() throws AMQException, ConfigurationException + { + List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); + + _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); + + for(Object nameObject : virtualHostNames) + { + String name = String.valueOf(nameObject); + configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name)); + } + + if (virtualHostNames == null || virtualHostNames.isEmpty()) + { + throw new ConfigurationException( + "Virtualhost Configuration document does not contain a valid virtualhost."); + } + } + + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 374772bc4a..cb3b1eafa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -67,6 +67,11 @@ public class DefaultExchangeRegistry implements ExchangeRegistry _defaultExchange = exchange; } + public Exchange getDefaultExchange() + { + return _defaultExchange; + } + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index 24884d20d7..a022b86299 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -40,4 +40,6 @@ public interface ExchangeRegistry extends MessageRouter Exchange getExchange(AMQShortString name); void setDefaultExchange(Exchange exchange); + + Exchange getDefaultExchange(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 7a16901796..71fecc45fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -509,6 +509,12 @@ public class AMQMessage _messageHandle.setRedelivered(redelivered); } + public long getArrivalTime() + { + return _messageHandle.getArrivalTime(); + } + + /** * Called when this message is delivered to a consumer. (used to * implement the 'immediate' flag functionality). diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index d788d1b9e2..f07706c2e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -74,4 +74,6 @@ public interface AMQMessageHandle void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; + + long getArrivalTime(); } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index ab7bbefe92..aa372a3b99 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; @@ -35,7 +36,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import java.text.MessageFormat; import java.util.List; -import java.util.ArrayList; import java.util.concurrent.Executor; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; @@ -130,22 +130,36 @@ public class AMQQueue implements Managable, Comparable /** * max allowed size(KB) of a single message */ - private long _maxMessageSize = 10000; + private long _maximumMessageSize = 10000; /** * max allowed number of messages on a queue. */ - private Integer _maxMessageCount = 10000; + @Configured(path = "maximumMessageCount", defaultValue = "0") + public int _maximumMessageCount; /** - * max queue depth(KB) for the queue + * max queue depth for the queue */ - private long _maxQueueDepth = 10000000; + @Configured(path = "maximumQueueDepth", defaultValue = "0") + public long _maximumQueueDepth = 10000000; + +/* + * maximum message age before alerts occur + */ + @Configured(path = "maximumMessageAge", defaultValue = "0") + public long _maximumMessageAge = 30000; //0 + + /* + * the minimum interval between sending out consequetive alerts of the same type + */ + @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") + public long _minimumAlertRepeatGap = 30000; /** * total messages received by the queue since startup. */ - private long _totalMessagesReceived = 0; + public long _totalMessagesReceived = 0; public int compareTo(Object o) { @@ -286,50 +300,56 @@ public class AMQQueue implements Managable, Comparable return _managedObject; } - public Long getMaximumMessageSize() + public long getMaximumMessageSize() { - return _maxMessageSize; + return _maximumMessageSize; } - public void setMaximumMessageSize(Long value) + public void setMaximumMessageSize(long value) { - _maxMessageSize = value; + _maximumMessageSize = value; } - public Integer getConsumerCount() + public int getConsumerCount() { return _subscribers.size(); } - public Integer getActiveConsumerCount() + public int getActiveConsumerCount() { return _subscribers.getWeight(); } - public Long getReceivedMessageCount() + public long getReceivedMessageCount() { return _totalMessagesReceived; } - public Integer getMaximumMessageCount() + public int getMaximumMessageCount() { - return _maxMessageCount; + return _maximumMessageCount; } - public void setMaximumMessageCount(Integer value) + public void setMaximumMessageCount(int value) { - _maxMessageCount = value; + _maximumMessageCount = value; } public long getMaximumQueueDepth() { - return _maxQueueDepth; + return _maximumQueueDepth; } // Sets the queue depth, the max queue size public void setMaximumQueueDepth(long value) { - _maxQueueDepth = value; + _maximumQueueDepth = value; + } + + public long getOldestMessageArrivalTime() + { + return _deliveryMgr.getOldestMessageArrival(); + } /** @@ -631,6 +651,24 @@ public class AMQQueue implements Managable, Comparable _deleteTaskList.add(task); } + public long getMinimumAlertRepeatGap() + { + return _minimumAlertRepeatGap; + } + + public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) + { + _minimumAlertRepeatGap = minimumAlertRepeatGap; + } + public long getMaximumMessageAge() + { + return _maximumMessageAge; + } + + public void setMaximumMessageAge(long maximumMessageAge) + { + _maximumMessageAge = maximumMessageAge; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index e15dc648f7..bee2e3950c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -22,12 +22,12 @@ import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.Main; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.mina.common.ByteBuffer; +import org.apache.log4j.Logger; import javax.management.openmbean.*; import javax.management.*; @@ -41,8 +41,11 @@ import java.util.Iterator; * for an AMQQueue. */ @MBeanDescription("Management Interface for AMQQueue") -public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue +public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener { + + private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + /** * Since the MBean is not associated with a real channel we can safely create our own store context * for use in the few methods that require one. @@ -63,6 +66,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue private final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"}; private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; + @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException { @@ -213,38 +219,38 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue return msg.getContentHeaderBody().bodySize; } + + /** * Checks if there is any notification to be send to the listeners */ public void checkForNotification(AMQMessage msg) throws AMQException, JMException { - // Check for threshold message count - Integer msgCount = getMessageCount(); - if (msgCount >= getMaximumMessageCount()) - { - notifyClients("Message count(" + msgCount + ") has reached or exceeded the threshold high value"); - } - // Check for threshold message size - long messageSize = getMessageSize(msg); - if (messageSize >= _queue.getMaximumMessageSize()) - { - notifyClients("Message size(ID=" + msg.getMessageId() + ", size=" + messageSize + " bytes) is higher than the threshold value"); - } + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - // Check for threshold queue depth in bytes - long queueDepth = getQueueDepthKb(); - if (queueDepth >= _queue.getMaximumQueueDepth()) + for(NotificationCheck check : NotificationCheck.values()) { - notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value"); + if(check.isMessageSpecific() || _lastNotificationTimes[check.ordinal()] getMessages() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 7d7ede0732..f7820e1465 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -83,4 +83,6 @@ interface DeliveryManager boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; long getTotalMessageSize(); + + long getOldestMessageArrival(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 186a5c8753..4f7dc21598 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -43,6 +43,8 @@ public class InMemoryMessageHandle implements AMQMessageHandle private boolean _redelivered; + private long _arrivalTime; + public InMemoryMessageHandle() { } @@ -114,6 +116,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle { _publishBody = publishBody; _contentHeaderBody = contentHeaderBody; + _arrivalTime = System.currentTimeMillis(); } public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException @@ -130,4 +133,10 @@ public class InMemoryMessageHandle implements AMQMessageHandle { // NO OP } + + public long getArrivalTime() + { + return _arrivalTime; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java index deed18c188..a66a85e54d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -31,11 +31,19 @@ public class MessageMetaData private int _contentChunkCount; + private long _arrivalTime; + public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); + } + + public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) { _contentHeaderBody = contentHeaderBody; _publishBody = publishBody; _contentChunkCount = contentChunkCount; + _arrivalTime = arrivalTime; } public int getContentChunkCount() @@ -67,4 +75,14 @@ public class MessageMetaData { _publishBody = publishBody; } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void setArrivalTime(long arrivalTime) + { + _arrivalTime = arrivalTime; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java new file mode 100644 index 0000000000..bc8e1232a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 enum NotificationCheck +{ + + MESSAGE_COUNT_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + int msgCount = queue.getMessageCount(); + final int maximumMessageCount = queue.getMaximumMessageCount(); + if (maximumMessageCount!= 0 && msgCount >= maximumMessageCount) + { + listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); + return true; + } + return false; + } + }, + MESSAGE_SIZE_ALERT(true) + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + final long maximumMessageSize = queue.getMaximumMessageSize(); + if(maximumMessageSize != 0) + { + // Check for threshold message size + long messageSize; + try + { + messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + messageSize = 0; + } + + + if (messageSize >= maximumMessageSize) + { + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + return true; + } + } + return false; + } + + }, + QUEUE_DEPTH_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + // Check for threshold queue depth in bytes + final long maximumQueueDepth = queue.getMaximumQueueDepth(); + + if(maximumQueueDepth != 0) + { + final long queueDepth = queue.getQueueDepth(); + + if (queueDepth >= maximumQueueDepth) + { + listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); + return true; + } + } + return false; + } + + }, + MESSAGE_AGE_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + + final long maxMessageAge = queue.getMaximumMessageAge(); + if(maxMessageAge != 0) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - maxMessageAge; + final long firstArrivalTime = queue.getOldestMessageArrivalTime(); + + if(firstArrivalTime < thresholdTime) + { + long oldestAge = currentTime - firstArrivalTime; + listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); + + return true; + } + } + return false; + + } + + } + ; + + private final boolean _messageSpecific; + + NotificationCheck() + { + this(false); + } + + NotificationCheck(boolean messageSpecific) + { + _messageSpecific = messageSpecific; + } + + public boolean isMessageSpecific() + { + return _messageSpecific; + } + + abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java new file mode 100644 index 0000000000..9554d34f00 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.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 QueueNotificationListener +{ + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 0abf464d15..8675a7249a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -49,6 +49,8 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle private final MessageStore _messageStore; + private long _arrivalTime; + public WeakReferenceMessageHandle(MessageStore messageStore) { @@ -60,14 +62,27 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); if (chb == null) { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + MessageMetaData mmd = loadMessageMetaData(messageId); chb = mmd.getContentHeaderBody(); - _contentHeaderBody = new WeakReference(chb); - _publishBody = new WeakReference(mmd.getPublishBody()); } return chb; } + private MessageMetaData loadMessageMetaData(Long messageId) + throws AMQException + { + MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + populateFromMessageMetaData(mmd); + return mmd; + } + + private void populateFromMessageMetaData(MessageMetaData mmd) + { + _arrivalTime = mmd.getArrivalTime(); + _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); + _publishBody = new WeakReference(mmd.getPublishBody()); + } + public int getBodyCount(Long messageId) throws AMQException { if (_contentBodies == null) @@ -136,10 +151,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle BasicPublishBody bpb = (_publishBody != null ? _publishBody.get() : null); if (bpb == null) { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + MessageMetaData mmd = loadMessageMetaData(messageId); + bpb = mmd.getPublishBody(); - _publishBody = new WeakReference(bpb); - _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); } return bpb; } @@ -179,10 +193,15 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { _contentBodies = new LinkedList>(); } - _messageStore.storeMessageMetaData(storeContext, messageId, new MessageMetaData(publishBody, contentHeaderBody, - _contentBodies.size())); - _publishBody = new WeakReference(publishBody); - _contentHeaderBody = new WeakReference(contentHeaderBody); + + final long arrivalTime = System.currentTimeMillis(); + + + MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); + + _messageStore.storeMessageMetaData(storeContext, messageId, mmd); + + populateFromMessageMetaData(mmd); } public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException @@ -199,4 +218,10 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); } + + public long getArrivalTime() + { + return _arrivalTime; + } + } -- cgit v1.2.1 From 4c970eb53248eccbb1daa61062225d3ea0754562 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 5 Feb 2007 17:45:09 +0000 Subject: QPID-326 AMQQueueMBean updated with attribute MaximumMessageAge git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@503790 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 5 +-- .../qpid/server/management/ManagedBroker.java | 2 +- .../server/protocol/AMQProtocolSessionMBean.java | 40 ++++++++++++++-------- .../apache/qpid/server/queue/AMQQueueMBean.java | 10 ++++++ .../org/apache/qpid/server/queue/ManagedQueue.java | 15 ++++++++ 5 files changed, 53 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 0b8aac67b6..ece4a3212b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -61,9 +61,6 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr _virtualHostMBean = virtualHostMBean; VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); - - - _queueRegistry = virtualHost.getQueueRegistry(); _exchangeRegistry = virtualHost.getExchangeRegistry(); _messageStore = virtualHost.getMessageStore(); @@ -142,7 +139,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param autoDelete * @throws JMException */ - public void createNewQueue(String queueName, boolean durable, String owner, boolean autoDelete) + public void createNewQueue(String queueName, String owner, boolean durable,boolean autoDelete) throws JMException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index 87d9a577e5..1b7e906e98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -79,8 +79,8 @@ public interface ManagedBroker */ @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, @MBeanOperationParameter(name="owner", description="Owner name")String owner, + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, @MBeanOperationParameter(name="autoDelete", description="true if the queue should be auto delete") boolean autoDelete) throws IOException, JMException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 0b21d26d32..f62edb2d78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -55,30 +55,43 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed private AMQMinaProtocolSession _session = null; private String _name = null; //openmbean data types for representing the channel attributes - private String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; - private String[] _indexNames = {_channelAtttibuteNames[0]}; - private OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; - private CompositeType _channelType = null; // represents the data type for channel data - private TabularType _channelsType = null; // Data type for list of channels type - private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSING_THE_CONNECTION = - new AMQShortString("Broker Management Console has closing the connection."); + private final static String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; + private final static String[] _indexNames = {_channelAtttibuteNames[0]}; + private final static OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; + private static CompositeType _channelType = null; // represents the data type for channel data + private static TabularType _channelsType = null; // Data type for list of channels type + private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = + new AMQShortString("Broker Management Console has closed the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws JMException { super(ManagedConnection.class, ManagedConnection.TYPE); _session = session; + String remote = getRemoteAddress(); + remote = "anonymous".equals(remote) ? remote + hashCode() : remote; + _name = jmxEncode(new StringBuffer(remote), 0).toString(); init(); } + static + { + try + { + init(); + } + catch(JMException ex) + { + // It should never occur + System.out.println(ex.getMessage()); + } + } /** * initialises the openmbean data types */ - private void init() throws OpenDataException + private static void init() throws OpenDataException { - String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? remote + hashCode() : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); + _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, _channelAttributeTypes); _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); @@ -200,8 +213,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed * @throws JMException */ public void closeConnection() throws JMException - { - + { // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. @@ -211,7 +223,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed 0, // classId 0, // methodId AMQConstant.REPLY_SUCCESS.getCode(), // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSING_THE_CONNECTION // replyText + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText ); _session.writeFrame(response); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index bee2e3950c..a263350cb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -152,6 +152,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _queue.getMaximumMessageSize(); } + public Long getMaximumMessageAge() + { + return _queue.getMaximumMessageAge(); + } + + public void setMaximumMessageAge(Long maximumMessageAge) + { + _queue.setMaximumMessageAge(maximumMessageAge); + } + public void setMaximumMessageSize(Long value) { _queue.setMaximumMessageSize(value); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index c36cc6bd7b..81580d8db5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -113,6 +113,21 @@ public interface ManagedQueue @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") boolean isAutoDelete() throws IOException; + /** + * Returns the maximum age of a message (expiration time) + * @return the maximum age + * @throws IOException + */ + Long getMaximumMessageAge() throws IOException; + + /** + * Sets the maximum age of a message + * @param age maximum age of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on thr broker") + void setMaximumMessageAge(Long age) throws IOException; + /** * Returns the maximum size of a message (in kbytes) allowed to be accepted by the * ManagedQueue. This is useful in setting notifications or taking -- cgit v1.2.1 From 74efb78118ccbac87face808290e2ff1e1d40f1a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 7 Feb 2007 11:27:15 +0000 Subject: QPID-170 Management feature added - moving messages from one Queue to another git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@504507 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 58 ++++++++++++++++++++-- .../apache/qpid/server/queue/AMQQueueMBean.java | 25 ++++++++++ .../queue/ConcurrentSelectorDeliveryManager.java | 10 ++++ .../apache/qpid/server/queue/DeliveryManager.java | 2 + .../org/apache/qpid/server/queue/ManagedQueue.java | 16 ++++++ 5 files changed, 108 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index aa372a3b99..ce1db7d26e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -36,6 +36,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import java.text.MessageFormat; import java.util.List; +import java.util.ArrayList; import java.util.concurrent.Executor; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; @@ -101,11 +102,8 @@ public class AMQQueue implements Managable, Comparable private final AtomicBoolean _deleted = new AtomicBoolean(false); - - private List _deleteTaskList = new CopyOnWriteArrayList(); - /** * Manages message delivery. */ @@ -292,6 +290,60 @@ public class AMQQueue implements Managable, Comparable return msg; } + /** + * @see ManagedQueue#moveMessages + * @param fromMessageId + * @param toMessageId + * @param queueName + * @param storeContext + * @throws AMQException + */ + public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext) throws AMQException + { + AMQQueue anotherQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + List list = getMessagesOnTheQueue(); + List foundMessagesList = new ArrayList(); + int maxMessageCountToBeMoved = (int)(toMessageId - fromMessageId + 1); + for (AMQMessage message : list) + { + long msgId = message.getMessageId(); + if (msgId >= fromMessageId && msgId <= toMessageId) + { + foundMessagesList.add(message); + } + // break the loop as soon as messages to be removed are found + if (foundMessagesList.size() == maxMessageCountToBeMoved) + { + break; + } + } + + // move messages to another queue + for (AMQMessage message : foundMessagesList) + { + try + { + anotherQueue.process(storeContext, message); + } + catch(AMQException ex) + { + foundMessagesList.subList(foundMessagesList.indexOf(message), foundMessagesList.size()).clear(); + // Exception occured, so rollback the changes + anotherQueue.removeMessages(foundMessagesList); + throw ex; + } + } + + // moving is successful, now remove from original queue + removeMessages(foundMessagesList); + } + + public synchronized void removeMessages(List messageList) + { + _deliveryMgr.removeMessages(messageList); + } + /** * @return MBean object associated with this Queue */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index a263350cb0..ba0d3b86d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -381,6 +381,31 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _messageList; } + + /** + * @see ManagedQueue#moveMessages + * @param fromMessageId + * @param toMessageId + * @param toQueueName + * @throws JMException + */ + public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException + { + if (fromMessageId > toMessageId || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + } + + try + { + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + } + catch(AMQException amqex) + { + throw new JMException("Error moving messages to " + toQueueName + ": " + amqex); + } + + } // // public ObjectName getObjectName() throws MalformedObjectNameException // { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 3a9ce64c57..6c89101043 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -242,6 +242,16 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + public synchronized void removeMessages(List messageList) + { + for (AMQMessage msg : messageList) + { + if (_messages.remove(msg)) + { + _totalMessageSize.getAndAdd(-msg.getSize()); + } + } + } public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index f7820e1465..c6f00bd189 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -76,6 +76,8 @@ interface DeliveryManager long clearAllMessages(StoreContext storeContext) throws AMQException; + void removeMessages(List messageListToRemove); + List getMessages(); void populatePreDeliveryQueue(Subscription subscription); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 81580d8db5..67bc830cf6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -225,4 +225,20 @@ public interface ManagedQueue impact= MBeanOperationInfo.ACTION) void clearQueue() throws IOException, JMException; + /** + * Moves the messages in given range of message Ids to given Queue. QPID-170 + * @param fromMessageId first in the range of message ids + * @param toMessageId last in the range of message ids + * @param toQueue where the messages are to be moved + * @throws IOException + * @throws JMException + * @throws AMQException + */ + @MBeanOperation(name="moveMessages", + description="You can move messages to another queue from this queue ", + impact= MBeanOperationInfo.ACTION) + void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, + @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, + @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) + throws IOException, JMException, AMQException; } -- cgit v1.2.1 From 92015a44d95053439c93adad4f1451f53fd427f1 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 9 Feb 2007 10:24:35 +0000 Subject: QPID-357 : Add support for a "default" virtual host git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@505242 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 6 +++++- .../qpid/server/util/NullApplicationRegistry.java | 1 + .../qpid/server/virtualhost/VirtualHostRegistry.java | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index c191bef447..15f1794908 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -174,7 +174,11 @@ public class VirtualHostConfiguration public void performBindings() throws AMQException, ConfigurationException { List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); - + String defaultVirtualHostName = _config.getString("default"); + if(defaultVirtualHostName != null) + { + ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); + } _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); for(Object nameObject : virtualHostNames) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index e9a3a3d048..6bd060bbfd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -65,6 +65,7 @@ public class NullApplicationRegistry extends ApplicationRegistry _virtualHostRegistry = new VirtualHostRegistry(); VirtualHost dummyHost = new VirtualHost("test",getConfiguration()); _virtualHostRegistry.registerVirtualHost(dummyHost); + _virtualHostRegistry.setDefaultVirtualHostName("test"); _authenticationManager = new NullAuthenticationManager(); _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 25f67c1cf3..7fb9b23d3f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -31,6 +31,9 @@ public class VirtualHostRegistry { private final Map _registry = new ConcurrentHashMap(); + + private String _defaultVirtualHostName; + public synchronized void registerVirtualHost(VirtualHost host) throws Exception { if(_registry.containsKey(host.getName())) @@ -42,9 +45,25 @@ public class VirtualHostRegistry public VirtualHost getVirtualHost(String name) { + if(name == null || name.trim().length() == 0 ) + { + name = getDefaultVirtualHostName(); + } + return _registry.get(name); } + private String getDefaultVirtualHostName() + { + return _defaultVirtualHostName; + } + + public void setDefaultVirtualHostName(String defaultVirtualHostName) + { + _defaultVirtualHostName = defaultVirtualHostName; + } + + public Collection getVirtualHosts() { return new ArrayList(_registry.values()); -- cgit v1.2.1 From 96a611197596980667f4e59279f806307ea2fc15 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Fri, 9 Feb 2007 12:29:14 +0000 Subject: QPID-170 predelivery queues will also be cleared with moved messages. Messages will be moved to another queue and predelivery queues of subsribers of another queue will also be populated. the features - removeMmessageFromTop and clearQueue is also modified by using the getNextMessage git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@505268 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 95 +++++++++------ .../apache/qpid/server/queue/AMQQueueMBean.java | 17 +-- .../queue/ConcurrentSelectorDeliveryManager.java | 134 +++++++++++++++++---- .../apache/qpid/server/queue/DeliveryManager.java | 8 +- 4 files changed, 177 insertions(+), 77 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index ce1db7d26e..c114d2d25f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -41,6 +41,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; /** * This is an AMQ Queue, and should not be confused with a JMS queue or any other abstraction like @@ -157,7 +158,7 @@ public class AMQQueue implements Managable, Comparable /** * total messages received by the queue since startup. */ - public long _totalMessagesReceived = 0; + public AtomicLong _totalMessagesReceived = new AtomicLong(); public int compareTo(Object o) { @@ -291,59 +292,77 @@ public class AMQQueue implements Managable, Comparable } /** - * @see ManagedQueue#moveMessages + * moves messages from this queue to another queue. to do this the approach is following- + * - setup the queue for moving messages (hold the lock and stop the async delivery) + * - get all the messages available in the given message id range + * - setup the other queue for moving messages (hold the lock and stop the async delivery) + * - send these available messages to the other queue (enqueue in other queue) + * - Once sending to other Queue is successful, remove messages from this queue + * - remove locks from both queues and start async delivery * @param fromMessageId * @param toMessageId * @param queueName * @param storeContext - * @throws AMQException */ public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) throws AMQException + StoreContext storeContext) { + // prepare the delivery manager for moving messages by stopping the async delivery and creating a lock AMQQueue anotherQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - List list = getMessagesOnTheQueue(); - List foundMessagesList = new ArrayList(); - int maxMessageCountToBeMoved = (int)(toMessageId - fromMessageId + 1); - for (AMQMessage message : list) + try { - long msgId = message.getMessageId(); - if (msgId >= fromMessageId && msgId <= toMessageId) - { - foundMessagesList.add(message); - } - // break the loop as soon as messages to be removed are found - if (foundMessagesList.size() == maxMessageCountToBeMoved) + startMovingMessages(); + List list = getMessagesOnTheQueue(); + List foundMessagesList = new ArrayList(); + int maxMessageCountToBeMoved = (int)(toMessageId - fromMessageId + 1); + + // Run this loop till you find all the messages or the list has no more messages + for (AMQMessage message : list) { - break; + long msgId = message.getMessageId(); + if (msgId >= fromMessageId && msgId <= toMessageId) + { + foundMessagesList.add(message); + } + // break the loop as soon as messages to be removed are found + if (foundMessagesList.size() == maxMessageCountToBeMoved) + { + break; + } } - } - // move messages to another queue - for (AMQMessage message : foundMessagesList) + // move messages to another queue + anotherQueue.startMovingMessages(); + anotherQueue.enqueueMovedMessages(storeContext, foundMessagesList); + + // moving is successful, now remove from original queue + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + finally { - try - { - anotherQueue.process(storeContext, message); - } - catch(AMQException ex) - { - foundMessagesList.subList(foundMessagesList.indexOf(message), foundMessagesList.size()).clear(); - // Exception occured, so rollback the changes - anotherQueue.removeMessages(foundMessagesList); - throw ex; - } + // remove the lock and start the async delivery + anotherQueue.stopMovingMessages(); + stopMovingMessages(); } + } - // moving is successful, now remove from original queue - removeMessages(foundMessagesList); + public void startMovingMessages() + { + _deliveryMgr.startMovingMessages(); } - public synchronized void removeMessages(List messageList) + private void enqueueMovedMessages(StoreContext storeContext, List messageList) { - _deliveryMgr.removeMessages(messageList); + _deliveryMgr.enqueueMovedMessages(storeContext, messageList); + _totalMessagesReceived.addAndGet(messageList.size()); } + public void stopMovingMessages() + { + _deliveryMgr.stopMovingMessages(); + _deliveryMgr.processAsync(_asyncDelivery); + } + /** * @return MBean object associated with this Queue */ @@ -374,7 +393,7 @@ public class AMQQueue implements Managable, Comparable public long getReceivedMessageCount() { - return _totalMessagesReceived; + return _totalMessagesReceived.get(); } public int getMaximumMessageCount() @@ -407,7 +426,7 @@ public class AMQQueue implements Managable, Comparable /** * Removes the AMQMessage from the top of the queue. */ - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException { _deliveryMgr.removeAMessageFromTop(storeContext); } @@ -415,7 +434,7 @@ public class AMQQueue implements Managable, Comparable /** * removes all the messages from the queue. */ - public long clearQueue(StoreContext storeContext) throws AMQException + public synchronized long clearQueue(StoreContext storeContext) throws AMQException { return _deliveryMgr.clearAllMessages(storeContext); } @@ -633,7 +652,7 @@ public class AMQQueue implements Managable, Comparable protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException { - _totalMessagesReceived++; + _totalMessagesReceived.incrementAndGet(); try { _managedObject.checkForNotification(msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index ba0d3b86d2..eb7e87b923 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -395,24 +395,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); } - - try - { - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); - } - catch(AMQException amqex) - { - throw new JMException("Error moving messages to " + toQueueName + ": " + amqex); - } + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); } -// -// public ObjectName getObjectName() throws MalformedObjectNameException -// { -// String objNameString = super.getObjectName().toString(); -// -// return new ObjectName(objNameString); -// } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 6c89101043..858dd5ee09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -75,7 +75,13 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager */ private final AMQQueue _queue; - + /** + * Flag used while moving messages from this queue to another. For moving messages the async delivery + * should also stop. This flat should be set to true to stop async delivery and set to false to enable + * async delivery again. + */ + private AtomicBoolean _movingMessages = new AtomicBoolean(); + /** * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered @@ -167,9 +173,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } - public synchronized List getMessages() + public List getMessages() { - return new ArrayList(_messages); + _lock.lock(); + ArrayList list = new ArrayList(_messages); + _lock.unlock(); + return list; } public void populatePreDeliveryQueue(Subscription subscription) @@ -242,8 +251,52 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - public synchronized void removeMessages(List messageList) + /** + * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, + * so that the asyn delivery is also stopped. + */ + public void startMovingMessages() + { + _lock.lock(); + _movingMessages.set(true); + } + + /** + * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, + * so that the async delivery can start again. + */ + public void stopMovingMessages() + { + _movingMessages.set(false); + if (_lock.isHeldByCurrentThread()) + { + _lock.unlock(); + } + } + + /** + * Messages will be removed from this queue and all preDeliveryQueues + * @param messageList + */ + public void removeMovedMessages(List messageList) { + // Remove from the + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + if (hasSubscribers) + { + for (Subscription sub : _subscriptions.getSubscriptions()) + { + if (!sub.isSuspended() && sub.hasFilters()) + { + Queue preDeliveryQueue = sub.getPreDeliveryQueue(); + for (AMQMessage msg : messageList) + { + preDeliveryQueue.remove(msg); + } + } + } + } + for (AMQMessage msg : messageList) { if (_messages.remove(msg)) @@ -253,29 +306,42 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - public synchronized void removeAMessageFromTop(StoreContext storeContext) throws AMQException + /** + * Now with implementation of predelivery queues, this method will mark the message on the top as taken. + * @param storeContext + * @throws AMQException + */ + public void removeAMessageFromTop(StoreContext storeContext) throws AMQException { - AMQMessage msg = poll(); + _lock.lock(); + AMQMessage msg = getNextMessage(); if (msg != null) { - msg.dequeue(storeContext, _queue); - _totalMessageSize.getAndAdd(-msg.getSize()); - } + // mark this message as taken and get it removed + msg.taken(); + _queue.dequeue(storeContext, msg); + getNextMessage(); + } + + _lock.unlock(); } - public synchronized long clearAllMessages(StoreContext storeContext) throws AMQException + public long clearAllMessages(StoreContext storeContext) throws AMQException { long count = 0; - AMQMessage msg = poll(); + _lock.lock(); + + AMQMessage msg = getNextMessage(); while (msg != null) { - msg.dequeue(storeContext, _queue); + //mark this message as taken and get it removed + msg.taken(); + _queue.dequeue(storeContext, msg); + msg = getNextMessage(); count++; - _totalMessageSize.set(0L); - msg = poll(); - } + _lock.unlock(); return count; } @@ -298,6 +364,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { //remove the already taken message messages.poll(); + _totalMessageSize.addAndGet(-message.getSize()); // try the next message message = messages.peek(); } @@ -334,6 +401,34 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + /** + * enqueues the messages in the list on the queue and all required predelivery queues + * @param storeContext + * @param movedMessageList + */ + public void enqueueMovedMessages(StoreContext storeContext, List movedMessageList) + { + _lock.lock(); + for (AMQMessage msg : movedMessageList) + { + addMessageToQueue(msg); + } + + // enqueue on the pre delivery queues + for (Subscription sub : _subscriptions.getSubscriptions()) + { + for (AMQMessage msg : movedMessageList) + { + // Only give the message to those that want them. + if (sub.hasInterest(msg)) + { + sub.enqueueForPreDelivery(msg); + } + } + } + _lock.unlock(); + } + /** * Only one thread should ever execute this method concurrently, but * it can do so while other threads invoke deliver(). @@ -343,7 +438,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // Continue to process delivery while we haveSubscribers and messages boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - while (hasSubscribers && hasQueuedMessages()) + while (hasSubscribers && hasQueuedMessages() && !_movingMessages.get()) { hasSubscribers = false; @@ -378,11 +473,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - private AMQMessage poll() - { - return _messages.poll(); - } - public void deliver(StoreContext context, AMQShortString name, AMQMessage msg) throws AMQException { if (_log.isDebugEnabled()) @@ -482,7 +572,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void run() { boolean running = true; - while (running) + while (running && !_movingMessages.get()) { processQueue(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index c6f00bd189..0129c3b895 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -76,7 +76,13 @@ interface DeliveryManager long clearAllMessages(StoreContext storeContext) throws AMQException; - void removeMessages(List messageListToRemove); + void startMovingMessages(); + + void enqueueMovedMessages(StoreContext context, List messageList); + + void stopMovingMessages(); + + void removeMovedMessages(List messageListToRemove); List getMessages(); -- cgit v1.2.1 From aa97383bc73a09213063dade4080f7b4c1cf84b8 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Mon, 12 Feb 2007 10:30:54 +0000 Subject: Fix for null virtual host (which got converted to the invalid string 'null'). git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@506405 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index c3b1ba3b5b..308732335e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -66,7 +66,7 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener Date: Wed, 14 Feb 2007 15:39:21 +0000 Subject: QPID-367 added @Configured annotation to the maximumMessageSize attribute git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@507583 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/AMQQueue.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index c114d2d25f..d5a2bb2994 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -129,7 +129,8 @@ public class AMQQueue implements Managable, Comparable /** * max allowed size(KB) of a single message */ - private long _maximumMessageSize = 10000; + @Configured(path = "maximumMessageSize", defaultValue = "0") + public long _maximumMessageSize; /** * max allowed number of messages on a queue. @@ -141,19 +142,19 @@ public class AMQQueue implements Managable, Comparable * max queue depth for the queue */ @Configured(path = "maximumQueueDepth", defaultValue = "0") - public long _maximumQueueDepth = 10000000; + public long _maximumQueueDepth; -/* + /** * maximum message age before alerts occur */ @Configured(path = "maximumMessageAge", defaultValue = "0") - public long _maximumMessageAge = 30000; //0 + public long _maximumMessageAge; - /* + /** * the minimum interval between sending out consequetive alerts of the same type */ @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") - public long _minimumAlertRepeatGap = 30000; + public long _minimumAlertRepeatGap; /** * total messages received by the queue since startup. -- cgit v1.2.1 From f7caf0b19020c0e6116620ea77423d753b8f9fe5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 14 Feb 2007 15:40:47 +0000 Subject: Applied QPID-6 SSL Options patch from Kevin Smith git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@507584 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 5 +- .../server/protocol/AMQPFastProtocolHandler.java | 61 ++++++++++++---------- .../server/transport/ConnectorConfiguration.java | 18 +++++-- 3 files changed, 48 insertions(+), 36 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 55009bbf49..37ac7b8b44 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -327,7 +327,7 @@ public class Main implements ProtocolVersionList sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } - if (connectorConfig.enableNonSSL) + if (!connectorConfig.enableSSL) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); InetSocketAddress bindAddress; @@ -343,10 +343,9 @@ public class Main implements ProtocolVersionList _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } - if (connectorConfig.enableSSL) + else { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - handler.setUseSSL(true); try { acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index d7e6af0c29..76a293c161 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -20,15 +20,8 @@ */ 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 java.io.IOException; + import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.IdleStatus; @@ -37,8 +30,19 @@ 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; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.ssl.SSLContextFactory; /** @@ -56,17 +60,14 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco private final IApplicationRegistry _applicationRegistry; - private boolean _useSSL; - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) { - this(ApplicationRegistry.getInstance(applicationRegistryInstance)); + this(ApplicationRegistry.getInstance(applicationRegistryInstance)); } public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) { _applicationRegistry = applicationRegistry; - _logger.debug("AMQPFastProtocolHandler created"); } @@ -89,16 +90,30 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco getConfiguredObject(ConnectorConfiguration.class); if (connectorConfig.enableExecutorPool) { - if (_useSSL) + if (connectorConfig.enableSSL) { + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(BogusSSLContextFactory.getInstance(true))); + new SSLFilter(sslContextFactory.buildServerContext())); } protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); } else { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); + protocolSession.getFilterChain().addLast("protocolFilter", pcf); + if (connectorConfig.enableSSL) + { + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", + new SSLFilter(sslContextFactory.buildServerContext())); + } + } } @@ -216,14 +231,4 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco _logger.debug("Message sent: " + object); } } - - public boolean isUseSSL() - { - return _useSSL; - } - - public void setUseSSL(boolean useSSL) - { - _useSSL = useSSL; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java index ac164f0cab..12489ad70e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -70,13 +70,21 @@ public class ConnectorConfiguration defaultValue = "false") public boolean enableDirectBuffers; - @Configured(path = "connector.ssl", + @Configured(path = "connector.ssl.enabled", defaultValue = "false") public boolean enableSSL; - - @Configured(path = "connector.nonssl", - defaultValue = "true") - public boolean enableNonSSL; + + @Configured(path = "connector.ssl.keystorePath", + defaultValue = "none") + public String keystorePath; + + @Configured(path = "connector.ssl.keystorePassword", + defaultValue = "none") + public String keystorePassword; + + @Configured(path = "connector.ssl.certType", + defaultValue = "SunX509") + public String certType; public IoAcceptor createAcceptor() { -- cgit v1.2.1 From 763fe9005de09a9983ccc903f323f3d4953d044c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 14 Feb 2007 16:06:18 +0000 Subject: Applied QPID-162 patches from Kevin Smith git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@507595 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 28 ++++----- .../java/org/apache/qpid/server/AMQChannel.java | 21 +++++-- .../src/main/java/org/apache/qpid/server/Main.java | 19 +++--- .../org/apache/qpid/server/ManagedChannel.java | 3 +- .../java/org/apache/qpid/server/ack/TxAck.java | 9 +-- .../qpid/server/ack/UnacknowledgedMessageMap.java | 7 ++- .../server/ack/UnacknowledgedMessageMapImpl.java | 15 +++-- .../qpid/server/configuration/Configurator.java | 8 +-- .../configuration/VirtualHostConfiguration.java | 28 ++++----- .../qpid/server/exchange/AbstractExchange.java | 10 +-- .../server/exchange/DefaultExchangeFactory.java | 10 ++- .../server/exchange/DefaultExchangeRegistry.java | 6 +- .../qpid/server/exchange/DestNameExchange.java | 27 +++++--- .../qpid/server/exchange/DestWildExchange.java | 32 ++++++---- .../org/apache/qpid/server/exchange/Exchange.java | 4 +- .../qpid/server/exchange/FanoutExchange.java | 39 +++++++----- .../qpid/server/exchange/HeadersBinding.java | 10 +-- .../qpid/server/exchange/HeadersExchange.java | 29 ++++++--- .../org/apache/qpid/server/exchange/Index.java | 8 +-- .../qpid/server/exchange/ManagedExchange.java | 13 ++-- .../qpid/server/exchange/NoRouteException.java | 2 +- .../qpid/server/filter/ComparisonExpression.java | 6 +- .../qpid/server/filter/ConstantExpression.java | 4 +- .../qpid/server/filter/JMSSelectorFilter.java | 1 - .../apache/qpid/server/filter/MessageFilter.java | 2 +- .../qpid/server/filter/PropertyExpression.java | 6 +- .../qpid/server/filter/SimpleFilterManager.java | 6 +- .../apache/qpid/server/filter/UnaryExpression.java | 6 +- .../apache/qpid/server/filter/XPathExpression.java | 6 +- .../qpid/server/filter/XalanXPathEvaluator.java | 11 ++-- .../qpid/server/handler/BasicAckMethodHandler.java | 7 +-- .../server/handler/BasicCancelMethodHandler.java | 11 ++-- .../server/handler/BasicConsumeMethodHandler.java | 18 +++--- .../qpid/server/handler/BasicGetMethodHandler.java | 23 +++---- .../server/handler/BasicPublishMethodHandler.java | 14 ++--- .../qpid/server/handler/BasicQosHandler.java | 12 ++-- .../server/handler/BasicRecoverMethodHandler.java | 15 ++--- .../qpid/server/handler/ChannelCloseHandler.java | 5 +- .../qpid/server/handler/ChannelCloseOkHandler.java | 6 +- .../qpid/server/handler/ChannelFlowHandler.java | 14 ++--- .../qpid/server/handler/ChannelOpenHandler.java | 8 +-- .../handler/ConnectionCloseMethodHandler.java | 14 ++--- .../handler/ConnectionCloseOkMethodHandler.java | 6 +- .../handler/ConnectionOpenMethodHandler.java | 6 +- .../handler/ConnectionSecureOkMethodHandler.java | 22 ++++--- .../handler/ConnectionStartOkMethodHandler.java | 11 ++-- .../handler/ConnectionTuneOkMethodHandler.java | 2 - .../qpid/server/handler/ExchangeBoundHandler.java | 5 +- .../server/handler/ExchangeDeclareHandler.java | 11 ++-- .../qpid/server/handler/ExchangeDeleteHandler.java | 3 +- .../qpid/server/handler/QueueBindHandler.java | 4 +- .../qpid/server/handler/QueueDeclareHandler.java | 21 ++++--- .../qpid/server/handler/QueueDeleteHandler.java | 17 +++-- .../qpid/server/handler/QueuePurgeHandler.java | 20 +++--- .../qpid/server/handler/TxCommitHandler.java | 7 +-- .../qpid/server/handler/TxRollbackHandler.java | 5 +- .../qpid/server/handler/TxSelectHandler.java | 3 - .../org/apache/qpid/server/jms/JmsConsumer.java | 2 +- .../server/management/DefaultManagedObject.java | 8 +-- .../management/JMXManagedObjectRegistry.java | 7 ++- .../qpid/server/management/MBeanAttribute.java | 22 +------ .../qpid/server/management/MBeanConstructor.java | 22 +------ .../qpid/server/management/MBeanDescription.java | 22 +------ .../qpid/server/management/MBeanIntrospector.java | 13 ++-- .../qpid/server/management/MBeanOperation.java | 25 +------- .../server/management/MBeanOperationParameter.java | 22 +------ .../qpid/server/management/ManagedBroker.java | 7 ++- .../qpid/server/management/ManagedObject.java | 6 +- .../management/NoopManagedObjectRegistry.java | 4 +- .../server/protocol/AMQMinaProtocolSession.java | 53 +++++++++------- .../server/protocol/AMQPFastProtocolHandler.java | 2 +- .../qpid/server/protocol/AMQProtocolSession.java | 9 ++- .../server/protocol/AMQProtocolSessionMBean.java | 25 ++++---- .../qpid/server/protocol/ExchangeInitialiser.java | 2 +- .../qpid/server/protocol/ManagedConnection.java | 13 ++-- .../org/apache/qpid/server/queue/AMQMessage.java | 26 +++++--- .../apache/qpid/server/queue/AMQMessageHandle.java | 4 +- .../org/apache/qpid/server/queue/AMQQueue.java | 25 ++++---- .../apache/qpid/server/queue/AMQQueueMBean.java | 42 ++++++++----- .../qpid/server/queue/AsyncDeliveryConfig.java | 6 +- .../queue/ConcurrentSelectorDeliveryManager.java | 24 +++---- .../qpid/server/queue/DefaultQueueRegistry.java | 8 +-- .../apache/qpid/server/queue/DeliveryManager.java | 8 +-- .../apache/qpid/server/queue/ExchangeBindings.java | 10 +-- .../qpid/server/queue/InMemoryMessageHandle.java | 8 +-- .../org/apache/qpid/server/queue/ManagedQueue.java | 11 ++-- .../apache/qpid/server/queue/QueueRegistry.java | 2 +- .../org/apache/qpid/server/queue/Subscription.java | 4 +- .../qpid/server/queue/SubscriptionFactory.java | 4 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 9 +-- .../apache/qpid/server/queue/SubscriptionSet.java | 6 +- .../qpid/server/queue/TransientMessageData.java | 10 +-- .../server/queue/WeakReferenceMessageHandle.java | 11 ++-- .../qpid/server/registry/ApplicationRegistry.java | 8 +-- .../ConfigurationFileApplicationRegistry.java | 17 ++--- .../qpid/server/registry/IApplicationRegistry.java | 11 +--- .../security/auth/AuthenticationManager.java | 2 - .../auth/AuthenticationProviderInitialiser.java | 5 +- .../qpid/server/security/auth/JCAProvider.java | 5 +- .../security/auth/NullAuthenticationManager.java | 4 -- .../auth/PasswordFilePrincipalDatabase.java | 13 ++-- .../server/security/auth/PrincipalDatabase.java | 5 +- .../security/auth/SASLAuthenticationManager.java | 22 +++---- .../security/auth/UsernamePasswordInitialiser.java | 15 +++-- .../auth/amqplain/AmqPlainInitialiser.java | 4 +- .../security/auth/amqplain/AmqPlainSaslServer.java | 21 ++++--- .../auth/amqplain/AmqPlainSaslServerFactory.java | 11 ++-- .../security/auth/plain/PlainInitialiser.java | 4 +- .../security/auth/plain/PlainSaslServer.java | 9 ++- .../auth/plain/PlainSaslServerFactory.java | 3 +- .../apache/qpid/server/state/AMQStateManager.java | 73 ++++++++++++++++++---- .../server/state/StateAwareMethodListener.java | 6 +- .../qpid/server/store/MemoryMessageStore.java | 16 ++--- .../org/apache/qpid/server/store/MessageStore.java | 7 +-- .../server/transport/ConnectorConfiguration.java | 2 +- .../qpid/server/transport/ThreadPoolFilter.java | 20 ++++-- .../qpid/server/txn/CleanupMessageOperation.java | 6 +- .../qpid/server/txn/LocalTransactionalContext.java | 6 +- .../qpid/server/txn/NonTransactionalContext.java | 10 +-- .../qpid/server/txn/TransactionalContext.java | 2 +- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 6 +- .../apache/qpid/server/util/CircularBuffer.java | 4 +- .../qpid/server/util/NullApplicationRegistry.java | 22 +++---- .../server/virtualhost/ManagedVirtualHost.java | 11 +--- .../qpid/server/virtualhost/VirtualHost.java | 24 ++++--- .../server/virtualhost/VirtualHostRegistry.java | 5 +- 126 files changed, 751 insertions(+), 776 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index ece4a3212b..adb2630bcf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -17,27 +17,25 @@ */ package org.apache.qpid.server; -import org.apache.qpid.server.management.MBeanDescription; +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.ObjectName; -import javax.management.MalformedObjectNameException; /** * This MBean implements the broker management interface and exposes the diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 2529ddc064..fa4219ecd1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,9 +20,23 @@ */ package org.apache.qpid.server; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.ack.UnacknowledgedMessage; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; @@ -37,11 +51,6 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.mina.common.ByteBuffer; - -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; public class AMQChannel { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 37ac7b8b44..42fe8c5274 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,6 +20,14 @@ */ package org.apache.qpid.server; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; +import java.util.StringTokenizer; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -40,8 +48,6 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.ProtocolVersionList; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -49,15 +55,6 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.url.URLSyntaxException; -import javax.management.JMException; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.List; -import java.util.StringTokenizer; - /** * Main entry point for AMQPD. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java index 74c5366c7d..e76f9c3f6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java @@ -21,9 +21,10 @@ package org.apache.qpid.server; -import javax.management.JMException; import java.io.IOException; +import javax.management.JMException; + /** * The managed interface exposed to allow management of channels. * @author Bhupendra Bhardwaj diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index c0a631080e..bbfab8132c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.server.ack; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TxnOp; -import org.apache.qpid.server.store.StoreContext; - import java.util.LinkedList; import java.util.List; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TxnOp; + /** * A TxnOp implementation for handling accumulated acks */ @@ -127,3 +127,4 @@ public class TxAck implements TxnOp } } + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index 7ea22a447f..b69a917081 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.server.ack; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TransactionalContext; - import java.util.Collection; import java.util.List; import java.util.Set; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TransactionalContext; + public interface UnacknowledgedMessageMap { public interface Visitor @@ -77,3 +77,4 @@ public interface UnacknowledgedMessageMap public long getUnacknowledgeBytes(); } + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index e50d239d57..f8b6babd43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -20,13 +20,18 @@ */ 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 java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; - -import java.util.*; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.txn.TransactionalContext; public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java index 379da94aa3..31c1b61a21 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.configuration; +import java.lang.reflect.Field; + import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.configuration.Configured; -import org.apache.qpid.configuration.PropertyUtils; import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.configuration.PropertyUtils; 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. @@ -115,4 +115,4 @@ public class Configurator _logger.error("Unable to access field " + f + " IGNORING configured value"); } } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 15f1794908..bd8f0c9670 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -20,27 +20,23 @@ */ package org.apache.qpid.server.configuration; -import org.apache.qpid.url.AMQBindingURL; -import org.apache.qpid.url.URLSyntaxException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; 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.server.virtualhost.VirtualHost; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.CompositeConfiguration; - - -import java.util.Collection; -import java.util.List; -import java.util.Collections; public class VirtualHostConfiguration { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 8b4f41a7a0..ff120e6a92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -20,19 +20,19 @@ */ package org.apache.qpid.server.exchange; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; +import org.apache.qpid.server.virtualhost.VirtualHost; public abstract class AbstractExchange implements Exchange, Managable { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index d77f1b6c5a..d90113fa35 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -20,17 +20,15 @@ */ package org.apache.qpid.server.exchange; +import java.util.HashMap; +import java.util.Map; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; - -import java.util.HashMap; -import java.util.Map; +import org.apache.qpid.server.virtualhost.VirtualHost; public class DefaultExchangeFactory implements ExchangeFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index cb3b1eafa6..7e3f9857f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.exchange; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - public class DefaultExchangeRegistry implements ExchangeRegistry { private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 8862bd5104..93e9ff2c5b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -20,24 +20,33 @@ */ package org.apache.qpid.server.exchange; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; public class DestNameExchange extends AbstractExchange { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index c38b9fe9b4..636b4558c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -20,27 +20,35 @@ */ package org.apache.qpid.server.exchange; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.*; -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 { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index c012a1c1c9..7702e8b315 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -21,10 +21,10 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; public interface Exchange diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 82039c345f..01a1b0bbc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -1,25 +1,30 @@ package org.apache.qpid.server.exchange; -import org.apache.log4j.Logger; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.MBeanConstructor; -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.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; +import java.util.concurrent.CopyOnWriteArraySet; -import javax.management.openmbean.*; import javax.management.JMException; import javax.management.MBeanException; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; public class FanoutExchange extends AbstractExchange { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index cf10f219aa..2b7df4361a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -20,12 +20,14 @@ */ package org.apache.qpid.server.exchange; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import org.apache.log4j.Logger; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQTypedValue; - -import java.util.*; +import org.apache.qpid.framing.FieldTable; /** * Defines binding and matching based on a set of headers. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 3a49ff586b..f3dc8131b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -20,20 +20,35 @@ */ package org.apache.qpid.server.exchange; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.management.JMException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.openmbean.*; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; /** * An exchange that binds queues based on a set of required headers and header values diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index 8527a68862..eacdad8a8e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -20,16 +20,16 @@ */ package org.apache.qpid.server.exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.framing.AMQShortString; - +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQQueue; + /** * An index of queues against routing key. Allows multiple queues to be stored * against the same key. Used in the DestNameExchange. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index b61aa233f8..5d6d68b3c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -20,16 +20,17 @@ */ package org.apache.qpid.server.exchange; +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + import org.apache.qpid.server.management.MBeanAttribute; import org.apache.qpid.server.management.MBeanOperation; import org.apache.qpid.server.management.MBeanOperationParameter; import org.apache.qpid.server.queue.ManagedQueue; -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 @@ -94,4 +95,4 @@ public interface ManagedExchange @MBeanOperationParameter(name="Binding", description="New binding")String binding) throws JMException; -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index fb0a330263..ec82fa166e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.server.exchange; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.protocol.AMQConstant; /** * Thrown by an exchange if there is no way to route a message with the diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 25d588a36f..99e4dd09ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -20,13 +20,13 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - import java.util.HashSet; import java.util.List; import java.util.regex.Pattern; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + /** * A filter performing a comparison of two objects * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index a4aea35079..bf0243537d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -20,11 +20,11 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // +import java.math.BigDecimal; + import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; -import java.math.BigDecimal; - /** * Represents a constant expression * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index cba487c31e..2061803d65 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidSelectorException; import org.apache.qpid.server.filter.jms.selector.SelectorParser; import org.apache.qpid.server.queue.AMQMessage; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index f80b7941b5..e6bfe974d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; public interface MessageFilter { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 2e74b09d0d..348bfa5e68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -21,15 +21,13 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // +import java.util.HashMap; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.server.queue.AMQMessage; - - -import java.util.HashMap; - /** * Represents a property expression * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index 5821a84774..62a45f5420 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -20,11 +20,11 @@ */ package org.apache.qpid.server.filter; +import java.util.concurrent.ConcurrentLinkedQueue; + import org.apache.log4j.Logger; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.AMQException; - -import java.util.concurrent.ConcurrentLinkedQueue; +import org.apache.qpid.server.queue.AMQMessage; public class SimpleFilterManager implements FilterManager { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 352a48b7ab..4e8fb1b46e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -20,15 +20,15 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - import java.math.BigDecimal; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + /** * An expression which performs an operation on two expression values * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index c51f82ce68..2fdea208f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -20,14 +20,14 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - /** * Used to evaluate an XPath Expression in a JMS selector. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index 94f063aa95..35d770fd5d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -21,6 +21,12 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // +import java.io.ByteArrayInputStream; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; import org.apache.xpath.CachedXPathAPI; @@ -28,11 +34,6 @@ import org.w3c.dom.Document; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.ByteArrayInputStream; -import java.io.StringReader; - public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private final String xpath; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index b2b1b0a716..6688318a0a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -20,17 +20,14 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicAckBody; import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.AMQChannel; 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; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.log4j.Logger; public class BasicAckMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index 2bbb696e90..1e56542b2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -20,18 +20,15 @@ */ package org.apache.qpid.server.handler; +import org.apache.qpid.AMQException; 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.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; public class BasicCancelMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index bc695431c9..18448848a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -20,25 +20,23 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidSelectorException; -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicConsumeBody; +import org.apache.qpid.framing.BasicConsumeOkBody; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ConsumerTagNotUniqueException; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.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.queue.AMQMessage; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; +import org.apache.qpid.server.virtualhost.VirtualHost; public class BasicConsumeMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index b8db7371b0..72d7e8b8b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -1,22 +1,17 @@ package org.apache.qpid.server.handler; -import org.apache.qpid.framing.*; -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.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidSelectorException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; public class BasicGetMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 78a246d80e..a30cc2ca3c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -20,24 +20,17 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.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; +import org.apache.qpid.server.virtualhost.VirtualHost; public class BasicPublishMethodHandler implements StateAwareMethodListener { @@ -91,3 +84,4 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index a247ee33ce..9f0d096a73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -20,17 +20,14 @@ */ 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.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRecoverBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; public class BasicRecoverMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index d46a4f6424..8faf5eedde 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -22,16 +22,13 @@ 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.ChannelCloseBody; import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.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.virtualhost.VirtualHostRegistry; public class ChannelCloseHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java index be11d5e939..988413a3de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -20,16 +20,12 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.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.virtualhost.VirtualHostRegistry; -import org.apache.log4j.Logger; public class ChannelCloseOkHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java index 62f7ed4b78..bdb877b7ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -21,17 +21,15 @@ 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.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ChannelFlowBody; import org.apache.qpid.framing.ChannelFlowOkBody; -import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; public class ChannelFlowHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index 5cd3f8ac89..fb198ef4f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -24,16 +24,12 @@ 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.virtualhost.VirtualHost; -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.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; 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.virtualhost.VirtualHost; public class ChannelOpenHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java index 8bc849d5cb..21da03d226 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -20,17 +20,15 @@ */ package org.apache.qpid.server.handler; -import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionCloseBody; 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.protocol.AMQMethodEvent; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; public class ConnectionCloseMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java index c10a731cc5..853f4df435 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -20,16 +20,14 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.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; -import org.apache.qpid.server.state.AMQState; -import org.apache.log4j.Logger; public class ConnectionCloseOkMethodHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 308732335e..809676cfbe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -22,14 +22,12 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionOpenBody; import org.apache.qpid.framing.ConnectionOpenOkBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index 11cbaade30..4ad6dcde71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -20,24 +20,26 @@ */ package org.apache.qpid.server.handler; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionSecureOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.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 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 { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index b45a017166..65b79cf8e7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -20,18 +20,19 @@ */ package org.apache.qpid.server.handler; -import org.apache.log4j.Logger; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.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.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; @@ -39,9 +40,6 @@ 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 { @@ -145,3 +143,4 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< } } + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java index 020e93b7d2..ab7695955c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -23,10 +23,8 @@ 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.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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java index 30da1398b3..2b123bcb2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -19,12 +19,11 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ExchangeBoundBody; import org.apache.qpid.framing.ExchangeBoundOkBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index 03af56ff14..575833a68f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -21,23 +21,20 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ExchangeDeclareBody; import org.apache.qpid.framing.ExchangeDeclareOkBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; 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.protocol.AMQMethodEvent; +import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; public class ExchangeDeclareHandler implements StateAwareMethodListener diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java index fc2a4b1fd5..f9926c399c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -24,11 +24,10 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.exchange.ExchangeInUseException; import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.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.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java index 0a23b9bd86..bccb9db967 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -22,13 +22,13 @@ 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.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index fdf98bb49e..1e4b7c9e57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -20,27 +20,30 @@ */ package org.apache.qpid.server.handler; +import java.text.MessageFormat; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.QueueDeclareOkBody; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.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.virtualhost.VirtualHost; -import java.text.MessageFormat; -import java.util.concurrent.atomic.AtomicInteger; - public class QueueDeclareHandler implements StateAwareMethodListener { private static final Logger _log = Logger.getLogger(QueueDeclareHandler.class); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index 3f0833de41..4c875692f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -20,18 +20,17 @@ */ 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.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueueDeleteBody; +import org.apache.qpid.framing.QueueDeleteOkBody; import org.apache.qpid.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.store.MessageStore; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.framing.QueueDeleteBody; -import org.apache.qpid.framing.QueueDeleteOkBody; -import org.apache.qpid.AMQException; public class QueueDeleteHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index c8341ee5b4..3ccc61fff0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -1,18 +1,16 @@ package org.apache.qpid.server.handler; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.registry.ApplicationRegistry; -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.virtualhost.VirtualHost; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueuePurgeBody; +import org.apache.qpid.framing.QueuePurgeOkBody; import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.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.virtualhost.VirtualHost; public class QueuePurgeHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java index 6f6b8b6f3c..caf0efad67 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -20,18 +20,15 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; 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.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; 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 TxCommitHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 31a28d2275..9088240351 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -23,14 +23,11 @@ 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.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; 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; -import org.apache.qpid.server.virtualhost.VirtualHost; public class TxRollbackHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java index 30b70869f9..29795e50ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -23,13 +23,10 @@ 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.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.virtualhost.VirtualHost; public class TxSelectHandler implements StateAwareMethodListener { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java index 41786e84ba..c08fae4e4e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.jms; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.AMQProtocolSession; public class JmsConsumer { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 4fb091df75..84526dbc11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -20,15 +20,15 @@ */ 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; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; + /** * Provides implementation of the boilerplate ManagedObject interface. Most managed objects should find it useful * to extend this class rather than implementing ManagedObject from scratch. @@ -188,4 +188,4 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana } return jmxName; } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 140dbc31bb..c89529f2a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -20,11 +20,12 @@ */ package org.apache.qpid.server.management; -import org.apache.log4j.Logger; +import java.lang.management.ManagementFactory; import javax.management.JMException; import javax.management.MBeanServer; -import java.lang.management.ManagementFactory; + +import org.apache.log4j.Logger; public class JMXManagedObjectRegistry implements ManagedObjectRegistry { @@ -49,4 +50,4 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer.unregisterMBean(managedObject.getObjectName()); } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java index a2e387a9e0..3b5db7d6c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java @@ -2,29 +2,9 @@ package org.apache.qpid.server.management; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; -import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +import java.lang.annotation.Target; /** * Annotation for MBean attributes. This should be used with getter or setter diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java index c2cafcd387..7a600005e2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java @@ -2,29 +2,9 @@ package org.apache.qpid.server.management; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; -import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +import java.lang.annotation.Target; /** * Annotation for MBean constructors. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java index e25ceeab5c..97717662dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java @@ -2,29 +2,9 @@ package org.apache.qpid.server.management; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; -import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +import java.lang.annotation.Target; /** * Annotation for MBean class. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java index 535122efb5..0c2ec2aebd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -20,17 +20,18 @@ */ 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; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; + /** * This class is a utility class to introspect the MBean class and the management * interface class for various purposes. @@ -384,4 +385,4 @@ class MBeanIntrospector { return _defaultMbeanDescription; } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java index ebeccadf70..f94be2f42f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java @@ -1,31 +1,12 @@ package org.apache.qpid.server.management; -import javax.management.MBeanOperationInfo; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; -import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +import java.lang.annotation.Target; + +import javax.management.MBeanOperationInfo; /** * Annotation for MBean operations. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java index adb3c651df..ad03b740ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -1,29 +1,9 @@ package org.apache.qpid.server.management; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ /** * Annotation for MBean operation parameters. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index 1b7e906e98..b2f79b6410 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -21,12 +21,13 @@ package org.apache.qpid.server.management; -import org.apache.qpid.server.exchange.ManagedExchange; -import org.apache.qpid.server.queue.ManagedQueue; +import java.io.IOException; import javax.management.JMException; import javax.management.MBeanOperationInfo; -import java.io.IOException; + +import org.apache.qpid.server.exchange.ManagedExchange; +import org.apache.qpid.server.queue.ManagedQueue; /** * The ManagedBroker is the management interface to expose management diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java index f512c2dea8..42ea8921a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.management; -import org.apache.qpid.AMQException; - -import javax.management.ObjectName; import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.AMQException; /** * This should be implemented by all Managable objects. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java index 121c992c4f..5b86543ea6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.management; -import org.apache.log4j.Logger; - import javax.management.JMException; +import org.apache.log4j.Logger; + /** * 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. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 460d5126ca..27a61f4967 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -20,41 +20,52 @@ */ package org.apache.qpid.server.protocol; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + import org.apache.log4j.Logger; import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoSession; -import org.apache.mina.common.IoSessionConfig; import org.apache.mina.common.IoServiceConfig; +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.AMQConnectionException; -import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionStartBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MainRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.framing.VersionSpecificRegistry; +import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.codec.AMQDecoder; - import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQStateManager; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public class AMQMinaProtocolSession implements AMQProtocolSession, ProtocolVersionList, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 76a293c161..9d397505dc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -30,6 +30,7 @@ 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 org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.framing.AMQDataBlock; @@ -44,7 +45,6 @@ import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.ssl.SSLContextFactory; - /** * The protocol handler handles "protocol events" for all connections. The state * associated with an individual connection is accessed through the protocol session. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 6b3b4f8021..e0fb1eca2f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -20,16 +20,15 @@ */ package org.apache.qpid.server.protocol; +import javax.security.sasl.SaslServer; + +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.protocol.AMQProtocolWriter; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.AMQException; - -import javax.security.sasl.SaslServer; public interface AMQProtocolSession extends AMQVersionAwareProtocolSession diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index f62edb2d78..ea89136a62 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -17,16 +17,8 @@ */ package org.apache.qpid.server.protocol; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; +import java.util.Date; +import java.util.List; import javax.management.JMException; import javax.management.MBeanException; @@ -42,8 +34,17 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import java.util.Date; -import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; /** * This MBean class implements the management interface. In order to make more attributes, operations and notifications diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java index 8b5f05e8ea..6b6163724c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -21,8 +21,8 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 1a7b7e9e96..f9a0c4d18f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -21,15 +21,16 @@ 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 java.io.IOException; +import java.util.Date; -import javax.management.openmbean.TabularData; import javax.management.JMException; import javax.management.MBeanOperationInfo; -import java.util.Date; -import java.io.IOException; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; /** * The management interface exposed to allow management of Connections. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 71fecc45fa..f23ec85391 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,22 +20,32 @@ */ package org.apache.qpid.server.queue; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicDeliverBody; +import org.apache.qpid.framing.BasicGetOkBody; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.BasicReturnBody; +import org.apache.qpid.framing.CompositeAMQDataBlock; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.SmallCompositeAMQDataBlock; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - /** * Combines the information that make up a deliverable message into a more manageable form. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index f07706c2e6..6aa8f98403 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -21,10 +21,10 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.server.store.StoreContext; /** * A pluggable way of getting message data. Implementations can provide intelligent caching for example or @@ -76,4 +76,4 @@ public interface AMQMessageHandle void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; long getArrivalTime(); -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index d5a2bb2994..557d82359f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,29 +20,30 @@ */ package org.apache.qpid.server.queue; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import javax.management.JMException; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHost; -import javax.management.JMException; -import java.text.MessageFormat; -import java.util.List; -import java.util.ArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - /** * 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. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index eb7e87b923..c0b22b541b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -17,24 +17,38 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.management.MBeanDescription; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.OperationsException; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.mina.common.ByteBuffer; -import org.apache.log4j.Logger; - -import javax.management.openmbean.*; -import javax.management.*; -import javax.management.monitor.MonitorNotification; -import java.util.List; -import java.util.ArrayList; -import java.util.Iterator; /** * MBean class for AMQQueue. It implements all the management features exposed diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java index ba60c9e003..290fedcf7b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java @@ -20,12 +20,12 @@ */ 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; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.server.registry.ApplicationRegistry; + public class AsyncDeliveryConfig { private Executor _executor; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 858dd5ee09..d8bc19fcea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -20,25 +20,25 @@ */ package org.apache.qpid.server.queue; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Queue; import java.util.concurrent.Executor; -import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index 084612ca41..c0f1e7f40c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,12 +20,12 @@ */ package org.apache.qpid.server.queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.qpid.AMQException; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.framing.AMQShortString; - -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentHashMap; +import org.apache.qpid.server.virtualhost.VirtualHost; public class DefaultQueueRegistry implements QueueRegistry { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 0129c3b895..27abca012b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.queue; +import java.util.List; +import java.util.concurrent.Executor; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; - -import java.util.concurrent.Executor; -import java.util.List; +import org.apache.qpid.server.store.StoreContext; interface DeliveryManager { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index 656549e025..d15cca72d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; - -import java.util.List; import java.util.HashSet; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; + /** * When a queue is deleted, it should be deregistered from any * exchange it has been bound to. This class assists in this task, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 4f7dc21598..5890d7b72c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.queue; +import java.util.LinkedList; +import java.util.List; + import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; 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; +import org.apache.qpid.server.store.StoreContext; /** */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 67bc830cf6..9b926be82d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -20,16 +20,17 @@ */ 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 java.io.IOException; import javax.management.JMException; import javax.management.MBeanOperationInfo; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; -import java.io.IOException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; /** * The management interface exposed to allow management of a queue. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index c5f235f1b3..3b1b5acf3c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -21,8 +21,8 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; public interface QueueRegistry diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index 5277069d33..fa70c6dbac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.AMQException; - import java.util.Queue; +import org.apache.qpid.AMQException; + public interface Subscription { void send(AMQMessage msg, AMQQueue queue) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java index 6cc55f2818..6902788fc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.protocol.AMQProtocolSession; /** * Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 181f41fbec..8e270f9772 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -20,12 +20,15 @@ */ package org.apache.qpid.server.queue; +import java.util.Queue; + import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicCancelOkBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; @@ -33,8 +36,6 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import java.util.Queue; - /** * Encapsulation of a supscription to a queue. *

      diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index e7c90fb201..871f063725 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -20,13 +20,13 @@ */ 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; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; + /** * Holds a set of subscriptions for a queue and manages the round * robin-ing of deliver etc. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 0c50dc5207..9f3d64f77e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -17,13 +17,13 @@ */ package org.apache.qpid.server.queue; +import java.util.LinkedList; +import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.AMQException; - -import java.util.List; -import java.util.LinkedList; /** * Contains data that is only used in AMQMessage transiently, e.g. while the content diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 8675a7249a..161913ef15 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -20,6 +20,11 @@ */ package org.apache.qpid.server.queue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.BasicPublishBody; @@ -28,12 +33,6 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.LinkedList; -import java.util.Collections; - /** * @author Robert Greig (robert.j.greig@jpmorgan.com) */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 0630d4f39f..14a8063aee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.registry; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.virtualhost.VirtualHost; -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. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 790421b497..70248a8e52 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -20,31 +20,24 @@ */ package org.apache.qpid.server.registry; +import java.io.File; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.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 org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.mina.common.ByteBuffer; - -import java.io.File; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 703aed69d2..5924cdb178 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -20,17 +20,12 @@ */ 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 java.util.Collection; + +import org.apache.commons.configuration.Configuration; 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.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.commons.configuration.Configuration; - -import java.util.Collection; public interface IApplicationRegistry { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java index 6cee2ee452..9f4addd7ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.security.auth; -import org.apache.qpid.framing.AMQShortString; - import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java index b26ba9b3dd..19e562517e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java @@ -20,11 +20,12 @@ */ package org.apache.qpid.server.security.auth; -import org.apache.commons.configuration.Configuration; +import java.util.Map; import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.SaslServerFactory; -import java.util.Map; + +import org.apache.commons.configuration.Configuration; public interface AuthenticationProviderInitialiser { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java index f69e5dc708..ac8eae024e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java @@ -20,11 +20,12 @@ */ package org.apache.qpid.server.security.auth; -import javax.security.sasl.SaslServerFactory; import java.security.Provider; import java.security.Security; import java.util.Map; +import javax.security.sasl.SaslServerFactory; + public final class JCAProvider extends Provider { public JCAProvider(Map> providerMap) @@ -43,4 +44,4 @@ public final class JCAProvider extends Provider put("SaslServerFactory." + me.getKey(), me.getValue().getName()); } } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java index 5c21dd4de4..20f190876f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java @@ -20,10 +20,6 @@ */ package org.apache.qpid.server.security.auth; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.framing.AMQShortString; - import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java index fb2ac612b6..b0592a7173 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java @@ -20,13 +20,18 @@ */ package org.apache.qpid.server.security.auth; -import org.apache.log4j.Logger; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.security.Principal; +import java.util.regex.Pattern; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import java.security.Principal; -import java.io.*; -import java.util.regex.Pattern; + +import org.apache.log4j.Logger; /** * Represents a user database where the account information is stored in a simple flat file. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java index d7fe21735f..e731ea271b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java @@ -20,10 +20,11 @@ */ package org.apache.qpid.server.security.auth; +import java.io.IOException; +import java.security.Principal; + 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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java index e96bd68cad..66923e371b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java @@ -20,23 +20,23 @@ */ 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 org.apache.qpid.framing.AMQShortString; +import java.lang.reflect.Method; +import java.security.Security; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; 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; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.server.registry.ApplicationRegistry; public class SASLAuthenticationManager implements AuthenticationManager { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java index fccb881eaa..d88c6df548 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java @@ -20,14 +20,19 @@ */ package org.apache.qpid.server.security.auth; -import org.apache.commons.configuration.Configuration; +import java.io.IOException; +import java.security.Principal; +import java.util.Map; -import javax.security.auth.callback.*; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.AuthorizeCallback; -import java.util.Map; -import java.io.IOException; -import java.security.Principal; + +import org.apache.commons.configuration.Configuration; public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java index 1d5932ca31..543115fd90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.security.auth.amqplain; -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - import javax.security.sasl.SaslServerFactory; +import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; + public class AmqPlainInitialiser extends UsernamePasswordInitialiser { public String getMechanismName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java index a943003bd3..9e5a8f9a08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java @@ -20,16 +20,21 @@ */ package org.apache.qpid.server.security.auth.amqplain; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTableFactory; -import org.apache.mina.common.ByteBuffer; +import java.io.IOException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.AuthorizeCallback; -import javax.security.auth.callback.*; -import java.io.IOException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; public class AmqPlainSaslServer implements SaslServer { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java index befd724b33..2569314a4a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java @@ -20,13 +20,14 @@ */ 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; +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + public class AmqPlainSaslServerFactory implements SaslServerFactory { public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java index b92e0b9209..9791c13373 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.security.auth.plain; -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - import javax.security.sasl.SaslServerFactory; +import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; + public class PlainInitialiser extends UsernamePasswordInitialiser { public String getMechanismName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java index 7f51260e45..094315dc1f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java @@ -20,11 +20,16 @@ */ package org.apache.qpid.server.security.auth.plain; -import javax.security.auth.callback.*; +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.AuthorizeCallback; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; -import java.io.IOException; public class PlainSaslServer implements SaslServer { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java index 444f7d9b58..3ea720dd8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java @@ -20,12 +20,13 @@ */ package org.apache.qpid.server.security.auth.plain; +import java.util.Map; + import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; -import java.util.Map; public class PlainSaslServerFactory implements SaslServerFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 69b12ec4e5..982443f1e8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -20,24 +20,73 @@ */ package org.apache.qpid.server.state; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.BasicAckBody; +import org.apache.qpid.framing.BasicCancelBody; +import org.apache.qpid.framing.BasicConsumeBody; +import org.apache.qpid.framing.BasicGetBody; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.BasicQosBody; +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.ChannelFlowBody; +import org.apache.qpid.framing.ChannelOpenBody; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.framing.ConnectionOpenBody; +import org.apache.qpid.framing.ConnectionSecureOkBody; +import org.apache.qpid.framing.ConnectionStartOkBody; +import org.apache.qpid.framing.ConnectionTuneOkBody; +import org.apache.qpid.framing.ExchangeBoundBody; +import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.framing.ExchangeDeleteBody; +import org.apache.qpid.framing.QueueBindBody; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.QueueDeleteBody; +import org.apache.qpid.framing.QueuePurgeBody; +import org.apache.qpid.framing.TxCommitBody; +import org.apache.qpid.framing.TxRollbackBody; +import org.apache.qpid.framing.TxSelectBody; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.handler.*; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.server.handler.BasicAckMethodHandler; +import org.apache.qpid.server.handler.BasicCancelMethodHandler; +import org.apache.qpid.server.handler.BasicConsumeMethodHandler; +import org.apache.qpid.server.handler.BasicGetMethodHandler; +import org.apache.qpid.server.handler.BasicPublishMethodHandler; +import org.apache.qpid.server.handler.BasicQosHandler; +import org.apache.qpid.server.handler.BasicRecoverMethodHandler; +import org.apache.qpid.server.handler.ChannelCloseHandler; +import org.apache.qpid.server.handler.ChannelCloseOkHandler; +import org.apache.qpid.server.handler.ChannelFlowHandler; +import org.apache.qpid.server.handler.ChannelOpenHandler; +import org.apache.qpid.server.handler.ConnectionCloseMethodHandler; +import org.apache.qpid.server.handler.ConnectionCloseOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionOpenMethodHandler; +import org.apache.qpid.server.handler.ConnectionSecureOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionStartOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionTuneOkMethodHandler; +import org.apache.qpid.server.handler.ExchangeBoundHandler; +import org.apache.qpid.server.handler.ExchangeDeclareHandler; +import org.apache.qpid.server.handler.ExchangeDeleteHandler; +import org.apache.qpid.server.handler.QueueBindHandler; +import org.apache.qpid.server.handler.QueueDeclareHandler; +import org.apache.qpid.server.handler.QueueDeleteHandler; +import org.apache.qpid.server.handler.QueuePurgeHandler; +import org.apache.qpid.server.handler.TxCommitHandler; +import org.apache.qpid.server.handler.TxRollbackHandler; +import org.apache.qpid.server.handler.TxSelectHandler; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.log4j.Logger; - -import java.util.HashMap; -import java.util.Map; -import java.util.EnumMap; -import java.util.concurrent.CopyOnWriteArraySet; /** * The state manager is responsible for managing the state of the protocol session. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java index 99d5d7fe88..e3af0bc486 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -21,12 +21,8 @@ package org.apache.qpid.server.state; import org.apache.qpid.AMQException; -import org.apache.qpid.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.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; /** * A frame listener that is informed of the protocol state when invoked and has diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 1f4cc7530d..6c4ad10429 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -20,22 +20,22 @@ */ package org.apache.qpid.server.store; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + 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.framing.AMQShortString; +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.virtualhost.VirtualHost; -import java.util.ArrayList; -import java.util.List; -import java.util.Collections; -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. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index b4ccd2cc51..d707ece8da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -20,17 +20,16 @@ */ package org.apache.qpid.server.store; +import java.util.List; + import org.apache.commons.configuration.Configuration; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.AMQShortString; +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 org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.List; - public interface MessageStore { /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java index 12489ad70e..dc9ad65113 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.configuration.Configured; import org.apache.mina.common.IoAcceptor; import org.apache.mina.util.NewThreadExecutor; +import org.apache.qpid.configuration.Configured; public class ConnectorConfiguration { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java index 2ee75c001f..bdd27f2d1c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -20,13 +20,23 @@ */ package org.apache.qpid.server.transport; -import org.apache.mina.common.*; -import org.apache.mina.util.*; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoFilterAdapter; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoSession; +import org.apache.mina.util.BlockingQueue; +import org.apache.mina.util.ByteBufferUtil; +import org.apache.mina.util.IdentityHashSet; 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. @@ -692,4 +702,4 @@ public class ThreadPoolFilter extends IoFilterAdapter { nextFilter.filterClose(session); } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java index 6d5d3c42f3..05d1cd5291 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -17,15 +17,15 @@ */ package org.apache.qpid.server.txn; +import java.util.List; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.store.StoreContext; -import java.util.List; - /** * @author Apache Software Foundation */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index d750ee7f72..7481a96ae4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -17,6 +17,9 @@ */ package org.apache.qpid.server.txn; +import java.util.LinkedList; +import java.util.List; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.RequiredDeliveryException; @@ -28,9 +31,6 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import java.util.LinkedList; -import java.util.List; - /** * A transactional context that only supports local transactions. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index f3e6c69cc5..c7f3a0f0f1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -17,23 +17,23 @@ */ package org.apache.qpid.server.txn; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + 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.protocol.AMQProtocolSession; import org.apache.qpid.server.ack.UnacknowledgedMessage; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.NoConsumersException; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - /** * @author Apache Software Foundation */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index e241ed4874..59d9117fda 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -22,9 +22,9 @@ package org.apache.qpid.server.txn; import org.apache.qpid.AMQException; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java index 069caf0ae1..d04b93a469 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.server.txn; +import java.util.ArrayList; +import java.util.List; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.store.StoreContext; -import java.util.ArrayList; -import java.util.List; - /** * Holds a list of TxnOp instance representing transactional * operations. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java index b58d551226..e730e2f3c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.util; -import org.apache.log4j.Logger; - import java.util.Iterator; +import org.apache.log4j.Logger; + public class CircularBuffer implements Iterable { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 6bd060bbfd..217a524562 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -20,28 +20,19 @@ */ 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 java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.MapConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.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.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.MapConfiguration; - -import java.util.HashMap; -import java.util.Collection; -import java.util.Collections; -import java.util.Arrays; public class NullApplicationRegistry extends ApplicationRegistry { @@ -100,3 +91,4 @@ public class NullApplicationRegistry extends ApplicationRegistry } } + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 2c888caac1..85d804457e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -20,17 +20,10 @@ */ package org.apache.qpid.server.virtualhost; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.queue.ManagedQueue; -import org.apache.qpid.server.exchange.ManagedExchange; - -import javax.management.openmbean.TabularData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; import java.io.IOException; +import org.apache.qpid.server.management.MBeanAttribute; + /** * The management interface exposed to allow management of an Exchange. * @version 0.1 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 1ce5146416..abbd18eff4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,18 +20,22 @@ */ package org.apache.qpid.server.virtualhost; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.exchange.*; -import org.apache.qpid.server.management.*; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.AMQBrokerManagerMBean; +import javax.management.NotCompliantMBeanException; + import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; - -import javax.management.NotCompliantMBeanException; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; public class VirtualHost { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 7fb9b23d3f..27917fac8a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -20,10 +20,9 @@ */ package org.apache.qpid.server.virtualhost; -import java.util.Map; -import java.util.Collection; -import java.util.Collections; import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -- cgit v1.2.1 From 55235ce6194939a8bc9cb50df1732e97e20303ba Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 15 Feb 2007 23:23:48 +0000 Subject: QPID-366 : Reference counting not being decremented correctly and other persistence issues git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508235 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 20 ++++-- .../java/org/apache/qpid/server/ack/TxAck.java | 7 +++ .../qpid/server/ack/UnacknowledgedMessage.java | 10 +++ .../qpid/server/handler/ChannelOpenHandler.java | 2 +- .../org/apache/qpid/server/queue/AMQMessage.java | 72 ++++++++++++++-------- .../apache/qpid/server/queue/AMQMessageHandle.java | 12 ++-- .../qpid/server/queue/InMemoryMessageHandle.java | 16 ++--- .../apache/qpid/server/queue/SubscriptionImpl.java | 2 + .../server/queue/WeakReferenceMessageHandle.java | 28 ++++----- .../qpid/server/store/MemoryMessageStore.java | 4 +- .../org/apache/qpid/server/store/MessageStore.java | 4 +- .../org/apache/qpid/server/store/StoreContext.java | 18 ++++++ .../qpid/server/txn/LocalTransactionalContext.java | 4 +- 13 files changed, 136 insertions(+), 63 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index fa4219ecd1..8b36576a30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -43,6 +43,7 @@ import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.exchange.MessageRouter; import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageHandleFactory; @@ -112,7 +113,7 @@ public class AMQChannel * A context used by the message store enabling it to track context for a given channel even across * thread boundaries */ - private final StoreContext _storeContext = new StoreContext(); + private final StoreContext _storeContext; private final List _returnMessages = new LinkedList(); @@ -120,12 +121,16 @@ public class AMQChannel private Set _browsedAcks = new HashSet(); + private final AMQProtocolSession _session; - public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) + + public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore, MessageRouter exchanges) throws AMQException { + _session = session; _channelId = channelId; + _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); _prefetch_HighWaterMark = DEFAULT_PREFETCH; _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; _messageStore = messageStore; @@ -338,7 +343,8 @@ public class AMQChannel _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); - _txnContext.commit(); + _txnContext.commit(); + } private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException @@ -386,8 +392,10 @@ public class AMQChannel _txnContext.deliver(unacked.message, unacked.queue); } } + } + /** * Called to resend all outstanding unacknowledged messages to this same channel. */ @@ -403,7 +411,7 @@ public class AMQChannel AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; msg.setRedelivered(true); - if((consumerTag != null) && _consumerTag2QueueMap.containsKey(consumerTag)) + if((consumerTag != null) && _consumerTag2QueueMap.containsKey(consumerTag) && !isSuspended()) { msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); } @@ -417,6 +425,7 @@ public class AMQChannel msgToRequeue.add(message); } } + // false means continue processing return false; } @@ -430,6 +439,7 @@ public class AMQChannel { _txnContext.deliver(message.message, message.queue); _unacknowledgedMessageMap.remove(message.deliveryTag); + message.message.decrementReference(_storeContext); } } @@ -559,6 +569,8 @@ public class AMQChannel public void rollback() throws AMQException { _txnContext.rollback(); + + } public String toString() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index bbfab8132c..c987c12154 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -100,6 +100,7 @@ public class TxAck implements TxnOp //make persistent changes, i.e. dequeue and decrementReference for (UnacknowledgedMessage msg : _unacked) { + msg.restoreTransientMessageData(); msg.discard(storeContext); } } @@ -112,6 +113,7 @@ public class TxAck implements TxnOp //in memory (persistent changes will be rolled back by store) for (UnacknowledgedMessage msg : _unacked) { + msg.clearTransientMessageData(); msg.message.incrementReference(); } } @@ -120,6 +122,11 @@ public class TxAck implements TxnOp { //remove the unacked messages from the channels map _map.remove(_unacked); + for (UnacknowledgedMessage msg : _unacked) + { + msg.clearTransientMessageData(); + } + } public void rollback(StoreContext storeContext) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index ff3c901be5..3f2348b71b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -50,5 +50,15 @@ public class UnacknowledgedMessage } message.decrementReference(storeContext); } + + public void restoreTransientMessageData() throws AMQException + { + message.restoreTransientMessageData(); + } + + public void clearTransientMessageData() + { + message.clearTransientMessageData(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index fb198ef4f7..03fc7a3926 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -49,7 +49,7 @@ public class ChannelOpenHandler implements StateAwareMethodListener { @@ -150,7 +152,7 @@ public class AMQMessage { try { - return _index < _messageHandle.getBodyCount(_messageId) - 1; + return _index < _messageHandle.getBodyCount(getStoreContext(),_messageId) - 1; } catch (AMQException e) { @@ -163,7 +165,7 @@ public class AMQMessage { try { - return _messageHandle.getContentBody(_messageId, ++_index); + return _messageHandle.getContentBody(getStoreContext(),_messageId, ++_index); } catch (AMQException e) { @@ -201,10 +203,11 @@ public class AMQMessage * @param factory * @throws AMQException */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory) throws AMQException + public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) throws AMQException { _messageId = messageId; _messageHandle = factory.createMessageHandle(messageId, store, true); + _txnContext = txnConext; _transientMessageData = null; } @@ -276,7 +279,7 @@ public class AMQMessage } else { - return _messageHandle.getContentHeaderBody(_messageId); + return _messageHandle.getContentHeaderBody(getStoreContext(),_messageId); } } @@ -342,14 +345,16 @@ public class AMQMessage _referenceCount.incrementAndGet(); if (_log.isDebugEnabled()) { - _log.debug("Ref count on message " + _messageId + " incremented to " + _referenceCount); + + _log.debug("Ref count on message " + _messageId + " incremented to " + _referenceCount + " " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); + } } /** * 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 */ @@ -365,7 +370,9 @@ public class AMQMessage { if (_log.isDebugEnabled()) { - _log.debug("Ref count on message " + _messageId + " is zero; removing message"); + _log.debug("Ref count on message " + _messageId + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); + + } // must check if the handle is null since there may be cases where we decide to throw away a message @@ -386,7 +393,7 @@ public class AMQMessage { if (_log.isDebugEnabled()) { - _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId); + _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId+ "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); if (_referenceCount.get() < 0) { Thread.dumpStack(); @@ -475,7 +482,7 @@ public class AMQMessage } else { - return _messageHandle.isPersistent(_messageId); + return _messageHandle.isPersistent(getStoreContext(),_messageId); } } @@ -504,7 +511,7 @@ public class AMQMessage } else { - pb = _messageHandle.getPublishBody(_messageId); + pb = _messageHandle.getPublishBody(getStoreContext(),_messageId); } return pb; } @@ -541,7 +548,7 @@ public class AMQMessage List destinationQueues = _transientMessageData.getDestinationQueues(); if (_log.isDebugEnabled()) { - _log.debug("Delivering message " + _messageId); + _log.debug("Delivering message " + _messageId + " to " + destinationQueues); } try { @@ -575,7 +582,7 @@ public class AMQMessage AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, getContentHeaderBody()); - final int bodyCount = _messageHandle.getBodyCount(_messageId); + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(),_messageId); if(bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, @@ -591,7 +598,7 @@ public class AMQMessage // 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. // - ContentBody cb = _messageHandle.getContentBody(_messageId, 0); + ContentBody cb = _messageHandle.getContentBody(getStoreContext(),_messageId, 0); AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; @@ -603,7 +610,7 @@ public class AMQMessage // for(int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentBody(_messageId, i); + cb = _messageHandle.getContentBody(getStoreContext(),_messageId, i); protocolSession.writeFrame(ContentBody.createAMQFrame(channelId, cb)); } @@ -619,7 +626,7 @@ public class AMQMessage AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, getContentHeaderBody()); - final int bodyCount = _messageHandle.getBodyCount(_messageId); + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(),_messageId); if(bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, @@ -634,7 +641,7 @@ public class AMQMessage // 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. // - ContentBody cb = _messageHandle.getContentBody(_messageId, 0); + ContentBody cb = _messageHandle.getContentBody(getStoreContext(),_messageId, 0); AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; @@ -646,7 +653,7 @@ public class AMQMessage // for(int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentBody(_messageId, i); + cb = _messageHandle.getContentBody(getStoreContext(),_messageId, i); protocolSession.writeFrame(ContentBody.createAMQFrame(channelId, cb)); } @@ -749,13 +756,30 @@ public class AMQMessage } catch (AMQException e) { - _log.error(e); + _log.error(e.toString(),e); return 0; } } + + public void restoreTransientMessageData() throws AMQException + { + TransientMessageData transientMessageData = new TransientMessageData(); + transientMessageData.setPublishBody(getPublishBody()); + transientMessageData.setContentHeaderBody(getContentHeaderBody()); + transientMessageData.addBodyLength(getContentHeaderBody().getSize()); + _transientMessageData = transientMessageData; + } + + + public void clearTransientMessageData() + { + _transientMessageData = null; + } + + public String toString() { return "Message: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index 6aa8f98403..210c9f01a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -35,17 +35,17 @@ import org.apache.qpid.server.store.StoreContext; */ public interface AMQMessageHandle { - ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException; + ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException; /** * @return the number of body frames associated with this message */ - int getBodyCount(Long messageId) throws AMQException; + int getBodyCount(StoreContext context, Long messageId) throws AMQException; /** * @return the size of the body */ - long getBodySize(Long messageId) throws AMQException; + long getBodySize(StoreContext context, Long messageId) throws AMQException; /** * Get a particular content body @@ -53,17 +53,17 @@ public interface AMQMessageHandle * @return a content body * @throws IllegalArgumentException if the index is invalid */ - ContentBody getContentBody(Long messageId, int index) throws IllegalArgumentException, AMQException; + ContentBody getContentBody(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException; - BasicPublishBody getPublishBody(Long messageId) throws AMQException; + BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException; boolean isRedelivered(); void setRedelivered(boolean redelivered); - boolean isPersistent(Long messageId) throws AMQException; + boolean isPersistent(StoreContext context, Long messageId) throws AMQException; void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 5890d7b72c..79f875ce1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -49,22 +49,22 @@ public class InMemoryMessageHandle implements AMQMessageHandle { } - public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException { return _contentHeaderBody; } - public int getBodyCount(Long messageId) + public int getBodyCount(StoreContext context, Long messageId) { return _contentBodies.size(); } - public long getBodySize(Long messageId) throws AMQException + public long getBodySize(StoreContext context, Long messageId) throws AMQException { - return getContentHeaderBody(messageId).bodySize; + return getContentHeaderBody(context, messageId).bodySize; } - public ContentBody getContentBody(Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentBody getContentBody(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -80,7 +80,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle _contentBodies.add(contentBody); } - public BasicPublishBody getPublishBody(Long messageId) throws AMQException + public BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException { return _publishBody; } @@ -96,10 +96,10 @@ public class InMemoryMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(Long messageId) throws AMQException + public boolean isPersistent(StoreContext context, Long messageId) throws AMQException { //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(messageId); + ContentHeaderBody chb = getContentHeaderBody(context, messageId); return chb.properties instanceof BasicContentHeaderProperties && ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 8e270f9772..05841ccfc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -267,9 +267,11 @@ public class SubscriptionImpl implements Subscription if (_acks) { channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + msg.decrementReference(storeContext); } msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); + } } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 161913ef15..670d895950 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -56,21 +56,21 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _messageStore = messageStore; } - public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException { ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); if (chb == null) { - MessageMetaData mmd = loadMessageMetaData(messageId); + MessageMetaData mmd = loadMessageMetaData(context, messageId); chb = mmd.getContentHeaderBody(); } return chb; } - private MessageMetaData loadMessageMetaData(Long messageId) + private MessageMetaData loadMessageMetaData(StoreContext context, Long messageId) throws AMQException { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); populateFromMessageMetaData(mmd); return mmd; } @@ -82,11 +82,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _publishBody = new WeakReference(mmd.getPublishBody()); } - public int getBodyCount(Long messageId) throws AMQException + public int getBodyCount(StoreContext context, Long messageId) throws AMQException { if (_contentBodies == null) { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); int chunkCount = mmd.getContentChunkCount(); _contentBodies = new ArrayList>(chunkCount); for (int i = 0; i < chunkCount; i++) @@ -97,12 +97,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return _contentBodies.size(); } - public long getBodySize(Long messageId) throws AMQException + public long getBodySize(StoreContext context, Long messageId) throws AMQException { - return getContentHeaderBody(messageId).bodySize; + return getContentHeaderBody(context, messageId).bodySize; } - public ContentBody getContentBody(Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentBody getContentBody(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -113,7 +113,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle ContentBody cb = wr.get(); if (cb == null) { - cb = _messageStore.getContentBodyChunk(messageId, index); + cb = _messageStore.getContentBodyChunk(context, messageId, index); _contentBodies.set(index, new WeakReference(cb)); } return cb; @@ -145,12 +145,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody, isLastContentBody); } - public BasicPublishBody getPublishBody(Long messageId) throws AMQException + public BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException { BasicPublishBody bpb = (_publishBody != null ? _publishBody.get() : null); if (bpb == null) { - MessageMetaData mmd = loadMessageMetaData(messageId); + MessageMetaData mmd = loadMessageMetaData(context, messageId); bpb = mmd.getPublishBody(); } @@ -167,10 +167,10 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(Long messageId) throws AMQException + public boolean isPersistent(StoreContext context, Long messageId) throws AMQException { //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(messageId); + ContentHeaderBody chb = getContentHeaderBody(context, messageId); return chb.properties instanceof BasicContentHeaderProperties && ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 6c4ad10429..f678cea630 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -174,12 +174,12 @@ public class MemoryMessageStore implements MessageStore _metaDataMap.put(messageId, messageMetaData); } - public MessageMetaData getMessageMetaData(Long messageId) throws AMQException + public MessageMetaData getMessageMetaData(StoreContext context,Long messageId) throws AMQException { return _metaDataMap.get(messageId); } - public ContentBody getContentBodyChunk(Long messageId, int index) throws AMQException + public ContentBody getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException { List bodyList = _contentBodyMap.get(messageId); return bodyList.get(index); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index d707ece8da..7fa46eb1ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -84,8 +84,8 @@ public interface MessageStore void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - MessageMetaData getMessageMetaData(Long messageId) throws AMQException; + MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - ContentBody getContentBodyChunk(Long messageId, int index) throws AMQException; + ContentBody getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index 55e5067852..2e2f2ba7d6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -20,6 +20,9 @@ */ package org.apache.qpid.server.store; +import org.apache.log4j.Logger; + + /** * A context that the store can use to associate with a transactional context. For example, it could store * some kind of txn id. @@ -28,8 +31,22 @@ package org.apache.qpid.server.store; */ public class StoreContext { + + private static final Logger _logger = Logger.getLogger(StoreContext.class); + + private String _name; private Object _payload; + public StoreContext() + { + _name = super.toString(); + } + + public StoreContext(String name) + { + _name = name; + } + public Object getPayload() { return _payload; @@ -37,6 +54,7 @@ public class StoreContext public void setPayload(Object payload) { + _logger.debug("["+_name+"] Setting payload: " + payload); _payload = payload; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 7481a96ae4..5c915b5c84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -168,7 +168,7 @@ public class LocalTransactionalContext implements TransactionalContext { if (_log.isDebugEnabled()) { - _log.debug("Starting transaction on message store"); + _log.debug("Starting transaction on message store: " + this); } _messageStore.beginTran(_storeContext); _inTran = true; @@ -179,7 +179,7 @@ public class LocalTransactionalContext implements TransactionalContext { if (_log.isDebugEnabled()) { - _log.debug("Committing transactional context"); + _log.debug("Committing transactional context: " + this); } if (_ackOp != null) { -- cgit v1.2.1 From 99fca78b4d6c9a34e5c548c7180434d64cf4d01e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Feb 2007 09:06:47 +0000 Subject: BasicConsumeMethodHandler - tidied up local channel/connection close frame writes by using the body.get[Channel|Connection]Exception() to throw a new exception to write out the frames. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508351 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/handler/BasicConsumeMethodHandler.java | 49 ++++++++-------------- 1 file changed, 17 insertions(+), 32 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 18448848a6..feb6f6b1fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -75,7 +75,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener Date: Fri, 16 Feb 2007 11:00:46 +0000 Subject: QPID-372 Broker doesn't wait for ChannelClose-Ok. Updated AMQProtocolSession to have new methods to query and release a channel from the awaiting close-ok state. Once a channel has been signalled to be closed any further methods on that channel are ignored until a close-ok is sent. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508366 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/ChannelCloseOkHandler.java | 6 +- .../server/protocol/AMQMinaProtocolSession.java | 123 ++++++++++++--------- .../qpid/server/protocol/AMQProtocolSession.java | 70 +++++++----- .../apache/qpid/server/state/AMQStateManager.java | 33 +++--- 4 files changed, 134 insertions(+), 98 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java index 988413a3de..ad5604e7ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -44,6 +44,10 @@ public class ChannelCloseOkHandler implements StateAwareMethodListener evt) throws AMQException { - _logger.info("Received channel-close-ok for channel-id " + evt.getChannelId()); + int channelId = evt.getChannelId(); + _logger.info("Received channel-close-ok for channel-id " + channelId); + + // Let the Protocol Session know the channel is now closed. + stateManager.getProtocolSession().closeChannelOk(channelId); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 27a61f4967..e53410420f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -64,6 +64,7 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -87,7 +88,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private final Map _channelMap = new HashMap(); - private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE+1]; + private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); @@ -108,12 +109,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private long _maxNoOfChannels = 1000; /* AMQP Version for this session */ - private byte _major = pv[pv.length-1][PROTOCOL_MAJOR]; - private byte _minor = pv[pv.length-1][PROTOCOL_MINOR]; + private byte _major = pv[pv.length - 1][PROTOCOL_MAJOR]; + private byte _minor = pv[pv.length - 1][PROTOCOL_MINOR]; private FieldTable _clientProperties; private final List _taskList = new CopyOnWriteArrayList(); - private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(pv[pv.length-1][PROTOCOL_MAJOR],pv[pv.length-1][PROTOCOL_MINOR]); - + private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(pv[pv.length - 1][PROTOCOL_MAJOR], pv[pv.length - 1][PROTOCOL_MINOR]); + private List _closingChannelsList = new ArrayList(); public ManagedObject getManagedObject() @@ -129,7 +130,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _stateManager = new AMQStateManager(virtualHostRegistry, this); _minaProtocolSession = session; session.setAttachment(this); - _codecFactory = codecFactory; @@ -145,24 +145,20 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, catch (RuntimeException e) { e.printStackTrace(); - // throw e; + // throw e; } - - - // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, AMQStateManager stateManager) throws AMQException { _stateManager = stateManager; _minaProtocolSession = session; session.setAttachment(this); - _codecFactory = codecFactory; @@ -205,7 +201,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, pi.checkVersion(this); // Fails if not correct // This sets the protocol version (and hence framing classes) for this session. - setProtocolVersion(pi.protocolMajor,pi.protocolMinor); + setProtocolVersion(pi.protocolMajor, pi.protocolMinor); String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); @@ -213,12 +209,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, // Interfacing with generated code - be aware of possible changes to parameter order as versions change. AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, - _major, _minor, // AMQP version (major, minor) - locales.getBytes(), // locales - mechanisms.getBytes(), // mechanisms - null, // serverProperties - (short)_major, // versionMajor - (short)_minor); // versionMinor + _major, _minor, // AMQP version (major, minor) + locales.getBytes(), // locales + mechanisms.getBytes(), // mechanisms + null, // serverProperties + (short) _major, // versionMajor + (short) _minor); // versionMinor _minaProtocolSession.write(response); } catch (AMQException e) @@ -266,7 +262,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { boolean wasAnyoneInterested = _stateManager.methodReceived(evt); - if(!_frameListeners.isEmpty()) + if (!_frameListeners.isEmpty()) { for (AMQMethodListener listener : _frameListeners) { @@ -276,7 +272,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } if (!wasAnyoneInterested) { - throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener."); + throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); } } catch (AMQChannelException e) @@ -338,12 +334,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } - getChannel(frame.getChannel()).publishContentBody((ContentBody)frame.getBodyFrame(), this); + getChannel(frame.getChannel()).publishContentBody((ContentBody) frame.getBodyFrame(), this); } /** - * Convenience method that writes a frame to the protocol session. Equivalent - * to calling getProtocolSession().write(). + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). * * @param frame the frame to write */ @@ -370,22 +366,40 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public AMQChannel getChannel(int channelId) throws AMQException { - return ((channelId & CHANNEL_CACHE_SIZE) == channelId) - ? _cachedChannels[channelId] - : _channelMap.get(channelId); + if (channelAwaitingClosure(channelId)) + { + return null; + } + else + { + return ((channelId & CHANNEL_CACHE_SIZE) == channelId) + ? _cachedChannels[channelId] + : _channelMap.get(channelId); + } + } + + public boolean channelAwaitingClosure(int channelId) + { + return _closingChannelsList.contains(channelId); } public void addChannel(AMQChannel channel) throws AMQException { if (_closed) { - throw new AMQException("Session is closed"); + throw new AMQException("Session is closed"); } final int channelId = channel.getChannelId(); + + if (_closingChannelsList.contains(channelId)) + { + throw new AMQException("Session is marked awaiting channel close"); + } + _channelMap.put(channelId, channel); - if(((channelId & CHANNEL_CACHE_SIZE) == channelId)) + if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) { _cachedChannels[channelId] = channel; } @@ -428,12 +442,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } /** - * 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
      • - *
      + * 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 AMQException if an error occurs closing the channel * @throws IllegalArgumentException if the channel id is not valid */ public void closeChannel(int channelId) throws AMQException @@ -447,16 +461,26 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { try { + markChannelawaitingCloseOk(channelId); channel.close(this); } finally { removeChannel(channelId); - } } } + public void closeChannelOk(int channelId) + { + _closingChannelsList.remove(new Integer(channelId)); + } + + private void markChannelawaitingCloseOk(int channelId) + { + _closingChannelsList.add(channelId); + } + /** * In our current implementation this is used by the clustering code. * @@ -465,7 +489,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void removeChannel(int channelId) { _channelMap.remove(channelId); - if((channelId & CHANNEL_CACHE_SIZE) == channelId) + if ((channelId & CHANNEL_CACHE_SIZE) == channelId) { _cachedChannels[channelId] = null; } @@ -486,8 +510,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } /** - * Closes all channels that were opened by this protocol session. This frees up all resources - * used by the channel. + * 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 */ @@ -498,16 +521,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, channel.close(this); } _channelMap.clear(); - for(int i = 0; i <= CHANNEL_CACHE_SIZE; i++) + for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) { - _cachedChannels[i]=null; + _cachedChannels[i] = null; } } - /** - * This must be called when the session is _closed in order to free up any resources - * managed by the session. - */ + /** 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) @@ -518,7 +538,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _managedObject.unregister(); } - for(Task task : _taskList) + for (Task task : _taskList) { task.doTask(this); } @@ -535,17 +555,15 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; } - /** - * @return an object that can be used to identity - */ + /** @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. + * 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 */ @@ -586,7 +604,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void setClientProperties(FieldTable clientProperties) { _clientProperties = clientProperties; - if((_clientProperties != null) && (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null)) + if ((_clientProperties != null) && (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null)) { setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); } @@ -596,7 +614,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _major = major; _minor = minor; - _registry = MainRegistry.getVersionSpecificRegistry(major,minor); + _registry = MainRegistry.getVersionSpecificRegistry(major, minor); } public byte getProtocolMajorVersion() @@ -620,10 +638,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } - public Object getClientIdentifier() { - return _minaProtocolSession.getRemoteAddress(); + return _minaProtocolSession.getRemoteAddress(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index e0fb1eca2f..503dc8b554 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -34,8 +34,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { - - public static interface Task { public void doTask(AMQProtocolSession session) throws AMQException; @@ -43,88 +41,108 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession /** * 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; /** - * Get the context key associated with this session. Context key is described - * in the AMQ protocol specification (RFC 6). + * Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC + * 6). + * * @return the context key */ AMQShortString getContextKey(); /** - * Set the context key associated with this session. Context key is described - * in the AMQ protocol specification (RFC 6). + * 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(AMQShortString contextKey); /** - * Get the channel for this session associated with the specified id. A channel - * id is unique per connection (i.e. per session). + * 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. + * + * @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) throws AMQException; /** - * 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
      • - *
      + * 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 + * @throws IllegalArgumentException if the channel id is not valid */ void closeChannel(int channelId) throws AMQException; + /** + * Markes the specific channel as closed. This will release the lock for that channel id so a new channel can be + * created on that id. + * + * @param channelId id of the channel to close + */ + void closeChannelOk(int channelId); + + /** + * Check to see if this chanel is closing + * + * @param channelId id to check + * @return boolean with state of channel awaiting closure + */ + boolean channelAwaitingClosure(int channelId); + /** * 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. - */ + /** 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 - */ + /** @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. + * 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. - */ + /** @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/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 982443f1e8..6d1e9ce99d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -89,10 +89,8 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; /** - * The state manager is responsible for managing the state of the protocol session. - *

      - * For each AMQProtocolHandler there is a separate state manager. - * + * 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 { @@ -100,14 +98,12 @@ public class AMQStateManager implements AMQMethodListener private final VirtualHostRegistry _virtualHostRegistry; private final AMQProtocolSession _protocolSession; - /** - * The current state - */ + /** 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. + * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of + * AMQFrame. */ private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = new EnumMap, StateAwareMethodListener>>(AMQState.class); @@ -206,7 +202,7 @@ public class AMQStateManager implements AMQMethodListener public void error(Exception e) { - _logger.error("State manager received error notification: " + e, e); + _logger.error("State manager received error notification[Current State:" + _currentState + "]: " + e, e); for (StateListener l : _stateListeners) { l.error(e); @@ -221,7 +217,7 @@ public class AMQStateManager implements AMQMethodListener checkChannel(evt, _protocolSession); - handler.methodReceived(this, evt); + handler.methodReceived(this, evt); return true; } return false; @@ -230,16 +226,17 @@ public class AMQStateManager implements AMQMethodListener private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) throws AMQException { - if(evt.getChannelId() != 0 - && !(evt.getMethod() instanceof ChannelOpenBody) - && protocolSession.getChannel(evt.getChannelId()) == null) + if (evt.getChannelId() != 0 + && !(evt.getMethod() instanceof ChannelOpenBody) + && (protocolSession.getChannel(evt.getChannelId()) == null) + && !protocolSession.channelAwaitingClosure(evt.getChannelId())) { - throw evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR.getCode(),"No such channel: " + evt.getChannelId()); + throw evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR.getCode(), "No such channel: " + evt.getChannelId()); } } protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, - B frame) + B frame) throws IllegalStateTransitionException { if (_logger.isDebugEnabled()) @@ -250,8 +247,8 @@ public class AMQStateManager implements AMQMethodListener classToHandlerMap = _state2HandlersMap.get(currentState); final StateAwareMethodListener handler = classToHandlerMap == null - ? null - : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); + ? null + : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); if (handler == null) { -- cgit v1.2.1 From f754185b2e9b7739658f59f14bcabaaeafebc129 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Feb 2007 13:00:39 +0000 Subject: QPID-11 remove protocol literals from code. QPID-376 use of getChannel() does not correct handle error cases when null is returned. Updated AMQMethodBody - to have a convenience method getChannelNotFoundException to be used for QPID-376 when channel is null. This allows the replyCode NOT_FOUND=404 to be changed to changed easily if required. QPID-376 - Updated All Handlers to throw channel exception when channel is null. QPID-11 Updated all handlers to use AMQConstant values rather than hardcoded literals. - Updated AMQException to use AMQConstant values rather than int to ensure that no more literal values creep back in to the code base. Replaced all usages of int above framing to store replycode with AMQConstant to prevent creep. Had to create new constants for literals used in code base but not yet part of spec. 405=Already Exists 406=In Use 323=Invalid Routing Key Remove non spec constant 500=Unknown_Exchange_Name replaced with generic NOT_FOUND git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508381 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 2 +- .../qpid/server/RequiredDeliveryException.java | 5 ++- .../qpid/server/handler/BasicAckMethodHandler.java | 8 +++- .../server/handler/BasicCancelMethodHandler.java | 12 ++++-- .../server/handler/BasicConsumeMethodHandler.java | 17 ++++---- .../qpid/server/handler/BasicGetMethodHandler.java | 7 ++-- .../server/handler/BasicPublishMethodHandler.java | 10 ++++- .../qpid/server/handler/BasicQosHandler.java | 13 ++++-- .../server/handler/BasicRecoverMethodHandler.java | 7 ++-- .../qpid/server/handler/ChannelFlowHandler.java | 6 +++ .../handler/ConnectionOpenMethodHandler.java | 2 +- .../server/handler/ExchangeDeclareHandler.java | 6 +-- .../qpid/server/handler/QueueBindHandler.java | 35 ++++++++++++---- .../qpid/server/handler/QueueDeclareHandler.java | 18 ++++++--- .../qpid/server/handler/QueueDeleteHandler.java | 18 +++++++-- .../qpid/server/handler/QueuePurgeHandler.java | 20 +++++++--- .../qpid/server/handler/TxCommitHandler.java | 12 ++++-- .../qpid/server/handler/TxRollbackHandler.java | 17 ++++++-- .../qpid/server/handler/TxSelectHandler.java | 15 +++++-- .../server/protocol/AMQMinaProtocolSession.java | 2 + .../qpid/server/queue/NoConsumersException.java | 4 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 46 ++++++++++------------ .../apache/qpid/server/state/AMQStateManager.java | 3 +- 23 files changed, 193 insertions(+), 92 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 8b36576a30..0879b77f37 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -602,7 +602,7 @@ public class AMQChannel for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); - message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), new AMQShortString(bouncedMessage.getMessage())); + message.writeReturn(session, _channelId, bouncedMessage.getReplyCode().getCode(), new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index b85e3603b7..820f0122f5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -21,6 +21,7 @@ package org.apache.qpid.server; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.queue.AMQMessage; /** @@ -44,10 +45,10 @@ public abstract class RequiredDeliveryException extends AMQException return _amqMessage; } - public int getErrorCode() + public AMQConstant getErrorCode() { return getReplyCode(); } - public abstract int getReplyCode(); + public abstract AMQConstant getReplyCode(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index 6688318a0a..f93b2b25e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -47,13 +47,19 @@ public class BasicAckMethodHandler implements StateAwareMethodListener evt) throws AMQException { AMQProtocolSession protocolSession = stateManager.getProtocolSession(); - + if (_log.isDebugEnabled()) { _log.debug("Ack received on channel " + evt.getChannelId()); } BasicAckBody body = evt.getMethod(); final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + + if (channel == null) + { + throw body.getChannelNotFoundException(evt.getChannelId()); + } + // this method throws an AMQException if the delivery tag is not known channel.acknowledgeMessage(body.deliveryTag, body.multiple); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index 1e56542b2b..7d18043f5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -49,15 +49,21 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener { @@ -40,12 +41,18 @@ public class BasicQosHandler implements StateAwareMethodListener public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); - session.getChannel(evt.getChannelId()).setPrefetchSize(evt.getMethod().prefetchSize); + AMQChannel channel = session.getChannel(evt.getChannelId()); + if (channel == null) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + + channel.setPrefetchCount(evt.getMethod().prefetchCount); + channel.setPrefetchSize(evt.getMethod().prefetchSize); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - session.writeFrame(BasicQosOkBody.createAMQFrame(evt.getChannelId(),(byte)8, (byte)0)); + session.writeFrame(BasicQosOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index 9f0d096a73..5f5b7ccad1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -46,12 +46,13 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener { @@ -57,17 +59,25 @@ public class QueueBindHandler implements StateAwareMethodListener VirtualHost virtualHost = session.getVirtualHost(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - final QueueBindBody body = evt.getMethod(); final AMQQueue queue; if (body.queue == null) { - queue = session.getChannel(evt.getChannelId()).getDefaultQueue(); + AMQChannel channel = session.getChannel(evt.getChannelId()); + +// if (channel == null) +// { +// throw body.getChannelNotFoundException(evt.getChannelId()); +// } + + queue = channel.getDefaultQueue(); + if (queue == null) { - throw new AMQException("No default queue defined on channel and queue was null"); + throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); } + if (body.routingKey == null) { body.routingKey = queue.getName(); @@ -80,14 +90,25 @@ public class QueueBindHandler implements StateAwareMethodListener if (queue == null) { - throw body.getChannelException(AMQConstant.NOT_FOUND.getCode(), "Queue " + body.queue + " does not exist."); + throw body.getChannelException(AMQConstant.NOT_FOUND, "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."); + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); + } + try + { + exch.registerQueue(body.routingKey, queue, body.arguments); + } + catch (AMQInvalidRoutingKeyException rke) + { + throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, body.routingKey.toString()); + } + catch (AMQException e) + { + throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); } - exch.registerQueue(body.routingKey, queue, body.arguments); queue.bind(body.routingKey, exch); if (_log.isInfoEnabled()) { @@ -98,7 +119,7 @@ public class QueueBindHandler implements StateAwareMethodListener // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); + final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0); session.writeFrame(response); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 1e4b7c9e57..2218ff604f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -43,6 +43,7 @@ import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; public class QueueDeclareHandler implements StateAwareMethodListener { @@ -83,7 +84,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -65,7 +67,15 @@ public class QueueDeleteHandler implements StateAwareMethodListener { @@ -39,18 +40,27 @@ public class QueuePurgeHandler implements StateAwareMethodListener public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { - AMQProtocolSession session = stateManager.getProtocolSession(); + AMQProtocolSession session = stateManager.getProtocolSession(); try { @@ -56,14 +56,20 @@ public class TxCommitHandler implements StateAwareMethodListener _log.debug("Commit received on channel " + evt.getChannelId()); } AMQChannel channel = session.getChannel(evt.getChannelId()); + + if (channel == null) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + channel.commit(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + session.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); channel.processReturns(session); } - catch(AMQException e) + catch (AMQException e) { throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 9088240351..8ce5a0ea73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -45,18 +45,27 @@ public class TxRollbackHandler implements StateAwareMethodListener evt) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - - try{ + + try + { AMQChannel channel = session.getChannel(evt.getChannelId()); + + if (channel == null) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + channel.rollback(); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + session.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); //Now resend all the unacknowledged messages back to the original subscribers. //(Must be done after the TxnRollback-ok response). channel.resend(session, false); - }catch(AMQException e){ + } + catch (AMQException e) + { throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java index 29795e50ca..a9e478e301 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -27,6 +27,7 @@ import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; public class TxSelectHandler implements StateAwareMethodListener { @@ -44,11 +45,19 @@ public class TxSelectHandler implements StateAwareMethodListener public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - - session.getChannel(evt.getChannelId()).setLocalTransactional(); + + AMQChannel channel = session.getChannel(evt.getChannelId()); + + if (channel == null) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + + channel.setLocalTransactional(); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0)); + session.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index e53410420f..309fa4663a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -325,6 +325,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content header frame received: " + frame); } + //fixme what happens if getChannel returns null getChannel(frame.getChannel()).publishContentHeader((ContentHeaderBody) frame.getBodyFrame()); } @@ -334,6 +335,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } + //fixme what happens if getChannel returns null getChannel(frame.getChannel()).publishContentBody((ContentBody) frame.getBodyFrame(), this); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java index 2049189e0f..c63490f019 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -35,8 +35,8 @@ public class NoConsumersException extends RequiredDeliveryException super("Immediate delivery is not possible.", message); } - public int getReplyCode() + public AMQConstant getReplyCode() { - return AMQConstant.NO_CONSUMERS.getCode(); + return AMQConstant.NO_CONSUMERS; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 05841ccfc0..6bdfeccc0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -24,6 +24,8 @@ import java.util.Queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; @@ -37,11 +39,8 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; /** - * 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. - *

      + * 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 { @@ -59,9 +58,7 @@ public class SubscriptionImpl implements Subscription private final boolean _noLocal; - /** - * True if messages need to be acknowledged - */ + /** True if messages need to be acknowledged */ private final boolean _acks; private FilterManager _filters; private final boolean _isBrowser; @@ -96,8 +93,8 @@ public class SubscriptionImpl implements Subscription { AMQChannel channel = protocolSession.getChannel(channelId); if (channel == null) - { - throw new NullPointerException("channel not found in protocol session"); + { + throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); } this.channel = channel; @@ -172,9 +169,7 @@ public class SubscriptionImpl implements Subscription return (o instanceof SubscriptionImpl) && equals((SubscriptionImpl) o); } - /** - * Equality holds if the session matches and the channel and consumer tag are the same. - */ + /** 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) @@ -193,11 +188,12 @@ public class SubscriptionImpl implements Subscription } /** - * This method can be called by each of the publisher threads. - * As a result all changes to the channel object must be thread safe. + * 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 @@ -224,7 +220,7 @@ public class SubscriptionImpl implements Subscription // We don't decrement the reference here as we don't want to consume the message // but we do want to send it to the client. - synchronized(channel) + synchronized (channel) { long deliveryTag = channel.getNextDeliveryTag(); @@ -260,7 +256,7 @@ public class SubscriptionImpl implements Subscription } queue.dequeue(storeContext, msg); } - synchronized(channel) + synchronized (channel) { long deliveryTag = channel.getNextDeliveryTag(); @@ -309,11 +305,11 @@ public class SubscriptionImpl implements Subscription Object localInstance; Object msgInstance; - if((protocolSession.getClientProperties() != null) && - (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + if ((protocolSession.getClientProperties() != null) && + (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { - if((msg.getPublisher().getClientProperties() != null) && - (msgInstance = msg.getPublisher().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + if ((msg.getPublisher().getClientProperties() != null) && + (msgInstance = msg.getPublisher().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) { @@ -402,10 +398,10 @@ public class SubscriptionImpl implements Subscription // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - consumerTag // consumerTag - )); + protocolSession.getProtocolMajorVersion(), + protocolSession.getProtocolMinorVersion(), + consumerTag // consumerTag + )); _closed = true; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 6d1e9ce99d..29efdd9513 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -55,7 +55,6 @@ import org.apache.qpid.framing.QueuePurgeBody; import org.apache.qpid.framing.TxCommitBody; import org.apache.qpid.framing.TxRollbackBody; import org.apache.qpid.framing.TxSelectBody; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.handler.BasicAckMethodHandler; @@ -231,7 +230,7 @@ public class AMQStateManager implements AMQMethodListener && (protocolSession.getChannel(evt.getChannelId()) == null) && !protocolSession.channelAwaitingClosure(evt.getChannelId())) { - throw evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR.getCode(), "No such channel: " + evt.getChannelId()); + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); } } -- cgit v1.2.1 From 42218badfdf92007a4a47a3fa7ca38528c62f215 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Feb 2007 13:08:24 +0000 Subject: QPID-11 remove protocol literals from code. Sorry Missed NoRouteException.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508385 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/exchange/NoRouteException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index ec82fa166e..c972b9d078 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -35,8 +35,8 @@ public class NoRouteException extends RequiredDeliveryException super(msg, message); } - public int getReplyCode() + public AMQConstant getReplyCode() { - return AMQConstant.NO_ROUTE.getCode(); + return AMQConstant.NO_ROUTE; } } -- cgit v1.2.1 From dfc8cdf0c0dbcfcbb62b8f6c091f54fa39aae478 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Feb 2007 14:23:23 +0000 Subject: QPID-376 - Updated All Handlers to throw channel exception when channel is null. Updated QueueBindHandler. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508416 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/handler/QueueBindHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java index 3c903b471d..8c722d33cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -66,10 +66,10 @@ public class QueueBindHandler implements StateAwareMethodListener { AMQChannel channel = session.getChannel(evt.getChannelId()); -// if (channel == null) -// { -// throw body.getChannelNotFoundException(evt.getChannelId()); -// } + if (channel == null) + { + throw body.getChannelNotFoundException(evt.getChannelId()); + } queue = channel.getDefaultQueue(); -- cgit v1.2.1 From 21575ca311935f0c308df0062c274f8ce1e9cb4a Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 16 Feb 2007 23:11:41 +0000 Subject: QPID-375 : remove assumptions on standard exchanges (amq.direct, amq.topic, etc), allow other exchanges to be created through virtualhosts.xml git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508649 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 53 ++++++++++++++++++++-- .../server/exchange/DefaultExchangeRegistry.java | 4 -- .../server/handler/BasicPublishMethodHandler.java | 2 +- .../qpid/server/handler/QueueDeclareHandler.java | 2 +- .../qpid/server/protocol/ExchangeInitialiser.java | 5 +- 5 files changed, 55 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index bd8f0c9670..af38a9abe5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -32,6 +32,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -71,7 +72,16 @@ public class VirtualHostConfiguration throw new ConfigurationException("Unknown virtual host: " + virtualHostName); } - List queueNames = configuration.getList("queue.name"); + List exchangeNames = configuration.getList("exchanges.exchange.name"); + + for(Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(virtualHost, exchangeName, configuration); + } + + + List queueNames = configuration.getList("queues.queue.name"); for(Object queueNameObj : queueNames) { @@ -81,12 +91,49 @@ public class VirtualHostConfiguration } + private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) throws AMQException + { + + CompositeConfiguration exchangeConfiguration = new CompositeConfiguration(); + + exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString)); + exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); + + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore messageStore = virtualHost.getMessageStore(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + AMQShortString exchangeName = new AMQShortString(exchangeNameString); + + + Exchange exchange; + + + + synchronized (exchangeRegistry) + { + exchange = exchangeRegistry.getExchange(exchangeName); + if(exchange == null) + { + + AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type","direct")); + boolean durable = exchangeConfiguration.getBoolean("durable",false); + boolean autodelete = exchangeConfiguration.getBoolean("autodelete",false); + + Exchange newExchange = exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); + exchangeRegistry.registerExchange(newExchange); + } + + } + } + private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException { CompositeConfiguration queueConfiguration = new CompositeConfiguration(); - queueConfiguration.addConfiguration(configuration.subset("queue."+ queueNameString)); - queueConfiguration.addConfiguration(configuration); + queueConfiguration.addConfiguration(configuration.subset("queues.queue."+ queueNameString)); + queueConfiguration.addConfiguration(configuration.subset("queues")); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); MessageStore messageStore = virtualHost.getMessageStore(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 7e3f9857f9..c7803133b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -55,10 +55,6 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) { - if(_defaultExchange == null) - { - setDefaultExchange(exchange); - } _exchangeMap.put(exchange.getName(), exchange); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 7e378dfd01..3798918428 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -63,7 +63,7 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener Date: Sun, 18 Feb 2007 18:46:11 +0000 Subject: QPID-375 : remove assumptions on standard exchanges (amq.direct, amq.topic, etc), allow other exchanges to be created through virtualhosts.xml git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508942 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/DefaultExchangeRegistry.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index c7803133b3..00169e44ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -85,14 +85,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public Exchange getExchange(AMQShortString name) { - if(name == null || name.length() == 0) - { - return _defaultExchange; - } - else - { - return _exchangeMap.get(name); - } + return _exchangeMap.get(name); } -- cgit v1.2.1 From 77ef9cb711842aae935b2fbc9622c6f074245779 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Mon, 19 Feb 2007 10:29:23 +0000 Subject: QPID-375 : Default Exchange fixes git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@509147 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/exchange/DefaultExchangeRegistry.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 00169e44ab..9b9765524c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -84,8 +84,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public Exchange getExchange(AMQShortString name) { - - return _exchangeMap.get(name); + if((name == null) || name.length() == 0) + { + return getDefaultExchange(); + } + else + { + return _exchangeMap.get(name); + } } -- cgit v1.2.1 From fa5a45c87b398e6ddd5b21a0accb853ccc151ede Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 19 Feb 2007 11:55:47 +0000 Subject: QPID-372, QPID-376 Broker now ignores all frames for closing channels. When a close-ok is received the channel can be reopened and used All uses of getChannel check the return type is not null and throw a NOT_FOUND AMQException. If the channel is not found during a method handler then the Channel will be closed. ChannelCloseHandler - Now throws a connection exception if trying to close a a non exisitant channel. AMQMinaProtocolSession - Added pre-check for closing channels to ignore all but Close-OK methods - Updated ChannelException method to close connection if the CE was a result of not having a valid channel. - Changed state to CLOSING when writing out a connection close frame. AMQConnection - Wrapped all _logging calls , Updated comment formatting AMQSession - called startDispatcherIfRequired when receiving a message as without it a producer will not get a returned message. This is because there is no consumer setup to consume. ConnectionCloseMethodHandler - Wrapped code in try finally so that the protocol session would always be closed correctly. AMQStateManager - Added state to the logging values Modified AMQTimeoutException to include a new constant value to identify the failure reason. AMQConstant - Added 408 REQUEST_TIMEOUT fixed error with NOT_ALLOWED value was 530 should be 507. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@509172 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/ChannelCloseHandler.java | 16 +++- .../server/protocol/AMQMinaProtocolSession.java | 87 ++++++++++++++++++++-- 2 files changed, 93 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index 8faf5eedde..9a8fce7129 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -26,9 +26,11 @@ import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ChannelCloseBody; import org.apache.qpid.framing.ChannelCloseOkBody; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; public class ChannelCloseHandler implements StateAwareMethodListener { @@ -51,11 +53,21 @@ public class ChannelCloseHandler implements StateAwareMethodListener evt = new AMQMethodEvent(frame.getChannel(), (AMQMethodBody) frame.getBodyFrame()); + + //Check that this channel is not closing + if (channelAwaitingClosure(frame.getChannel())) + { + if ((evt.getMethod() instanceof ChannelCloseOkBody)) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + frame.getChannel() + "] awaiting closure - processing close-ok"); + } + } + else + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + frame.getChannel() + "] awaiting closure ignoring"); + } + return; + } + } + + try { try { + boolean wasAnyoneInterested = _stateManager.methodReceived(evt); if (!_frameListeners.isEmpty()) @@ -277,14 +303,42 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } catch (AMQChannelException e) { - _logger.error("Closing channel due to: " + e.getMessage()); - writeFrame(e.getCloseFrame(frame.getChannel())); - closeChannel(frame.getChannel()); + if (getChannel(frame.getChannel()) != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing channel due to: " + e.getMessage()); + } + writeFrame(e.getCloseFrame(frame.getChannel())); + closeChannel(frame.getChannel()); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); + } + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + closeSession(); + + AMQConnectionException ce = evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); + + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(ce.getCloseFrame(frame.getChannel())); + } } catch (AMQConnectionException e) { - _logger.error("Closing connection due to: " + e.getMessage()); + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } closeSession(); + _stateManager.changeState(AMQState.CONNECTION_CLOSING); writeFrame(e.getCloseFrame(frame.getChannel())); } } @@ -325,8 +379,17 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content header frame received: " + frame); } - //fixme what happens if getChannel returns null - getChannel(frame.getChannel()).publishContentHeader((ContentHeaderBody) frame.getBodyFrame()); + + AMQChannel channel = getChannel(frame.getChannel()); + + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + frame.getChannel()); + } + else + { + channel.publishContentHeader((ContentHeaderBody) frame.getBodyFrame()); + } } private void contentBodyReceived(AMQFrame frame) throws AMQException @@ -335,8 +398,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("Content body frame received: " + frame); } - //fixme what happens if getChannel returns null - getChannel(frame.getChannel()).publishContentBody((ContentBody) frame.getBodyFrame(), this); + AMQChannel channel = getChannel(frame.getChannel()); + + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + frame.getChannel()); + } + else + { + channel.publishContentBody((ContentBody) frame.getBodyFrame(), this); + } } /** -- cgit v1.2.1 From c19d997d6454ab95bc855ac1b79622721aad37fd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 20 Feb 2007 09:16:59 +0000 Subject: Renamed AMQInvalidSelectorException to be AMQInvalidArgumentException to better fit the generic use of the argument table in the AMQP Queue.Bind spec. Adjusted AMQConstant to match the proposal for additional codes AMQP-39,40,41 (https://wiki.108.redhat.com/jira/browse/AMQP-39). git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@509478 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/handler/BasicConsumeMethodHandler.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 090988d304..da61f2ffd5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -22,12 +22,9 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidSelectorException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicConsumeBody; import org.apache.qpid.framing.BasicConsumeOkBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; @@ -106,10 +103,10 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener Date: Tue, 20 Feb 2007 16:20:41 +0000 Subject: QPID-325 : Persist durable exchange information in the store QPID-318 : Remove hardcoding of version numbers (as applies to store) git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@509628 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 11 +- .../configuration/VirtualHostConfiguration.java | 10 +- .../server/exchange/DefaultExchangeRegistry.java | 37 +++++-- .../qpid/server/exchange/DestNameExchange.java | 12 +-- .../qpid/server/exchange/DestWildExchange.java | 10 +- .../org/apache/qpid/server/exchange/Exchange.java | 2 +- .../qpid/server/exchange/ExchangeRegistry.java | 4 +- .../qpid/server/exchange/FanoutExchange.java | 17 ++- .../qpid/server/exchange/HeadersExchange.java | 6 +- .../server/handler/BasicPublishMethodHandler.java | 4 +- .../qpid/server/handler/QueueBindHandler.java | 6 +- .../qpid/server/handler/QueueDeclareHandler.java | 4 +- .../qpid/server/protocol/ExchangeInitialiser.java | 5 +- .../org/apache/qpid/server/queue/AMQMessage.java | 115 +++++++++++---------- .../apache/qpid/server/queue/AMQMessageHandle.java | 12 +-- .../org/apache/qpid/server/queue/AMQQueue.java | 19 +++- .../apache/qpid/server/queue/AMQQueueMBean.java | 7 +- .../queue/ConcurrentSelectorDeliveryManager.java | 10 +- .../apache/qpid/server/queue/ExchangeBindings.java | 43 ++++++-- .../qpid/server/queue/InMemoryMessageHandle.java | 21 ++-- .../apache/qpid/server/queue/MessageMetaData.java | 18 ++-- .../qpid/server/queue/TransientMessageData.java | 12 +-- .../server/queue/WeakReferenceMessageHandle.java | 45 ++++---- .../qpid/server/store/ContentChunkAdapter.java | 57 ++++++++++ .../qpid/server/store/MemoryMessageStore.java | 40 +++++-- .../server/store/MessagePublishInfoAdapter.java | 62 +++++++++++ .../org/apache/qpid/server/store/MessageStore.java | 26 ++--- .../qpid/server/virtualhost/VirtualHost.java | 8 +- 28 files changed, 419 insertions(+), 204 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 0879b77f37..7271bd6e43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -33,17 +33,16 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; 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.exchange.NoRouteException; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageHandleFactory; @@ -202,9 +201,11 @@ public class AMQChannel } - public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException + public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) throws AMQException { - _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), publishBody, + + + _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); // TODO: used in clustering only I think (RG) _currentMessage.setPublisher(publisher); @@ -252,7 +253,7 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received - if (_currentMessage.addContentBodyFrame(_storeContext, contentBody)) + if (_currentMessage.addContentBodyFrame(_storeContext, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk(contentBody))) { // callback to allow the context to do any post message processing // primary use is to allow message return processing in the non-tx case diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index af38a9abe5..a35a46f305 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -198,12 +198,18 @@ public class VirtualHostConfiguration for(Object routingKeyNameObj : routingKeys) { AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - exchange.registerQueue(routingKey, queue, null); + + + queue.bind(routingKey, null, exchange); - queue.bind(routingKey, exchange); _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); } + + if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) + { + queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 9b9765524c..4774383642 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -28,6 +28,8 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.store.MessageStore; public class DefaultExchangeRegistry implements ExchangeRegistry { @@ -39,23 +41,32 @@ public class DefaultExchangeRegistry implements ExchangeRegistry private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); private Exchange _defaultExchange; + private VirtualHost _host; - public DefaultExchangeRegistry(ExchangeFactory exchangeFactory) + public DefaultExchangeRegistry(VirtualHost host) { //create 'standard' exchanges: - try - { - new ExchangeInitialiser().initialise(exchangeFactory, this); - } - catch(AMQException e) - { - _log.error("Failed to initialise exchanges: ", e); - } + _host = host; + } - public void registerExchange(Exchange exchange) + public void initialise() throws AMQException + { + new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); + } + + public MessageStore getMessageStore() + { + return _host.getMessageStore(); + } + + public void registerExchange(Exchange exchange) throws AMQException { _exchangeMap.put(exchange.getName(), exchange); + if(exchange.isDurable()) + { + getMessageStore().createExchange(exchange); + } } public void setDefaultExchange(Exchange exchange) @@ -74,6 +85,10 @@ public class DefaultExchangeRegistry implements ExchangeRegistry Exchange e = _exchangeMap.remove(name); if (e != null) { + if(e.isDurable()) + { + getMessageStore().removeExchange(e); + } e.close(); } else @@ -102,7 +117,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry */ public void routeContent(AMQMessage payload) throws AMQException { - final AMQShortString exchange = payload.getPublishBody().exchange; + final AMQShortString exchange = payload.getMessagePublishInfo().getExchange(); final Exchange exch = getExchange(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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 93e9ff2c5b..4d66e37628 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -43,6 +43,7 @@ import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -126,8 +127,7 @@ public class DestNameExchange extends AbstractExchange try { - registerQueue(new AMQShortString(binding), queue, null); - queue.bind(new AMQShortString(binding), DestNameExchange.this); + queue.bind(new AMQShortString(binding), null, DestNameExchange.this); } catch (AMQException ex) { @@ -170,7 +170,7 @@ public class DestNameExchange extends AbstractExchange } } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; assert routingKey != null; @@ -184,13 +184,13 @@ public class DestNameExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { - final BasicPublishBody publishBody = payload.getPublishBody(); - final AMQShortString routingKey = publishBody.routingKey; + final MessagePublishInfo info = payload.getMessagePublishInfo(); + final AMQShortString routingKey = info.getRoutingKey(); final List queues = (routingKey == null) ? null : _index.get(routingKey); if (queues == null || queues.isEmpty()) { String msg = "Routing key " + routingKey + " is not known to " + this; - if (publishBody.mandatory) + if (info.isMandatory()) { throw new NoRouteException(msg, payload); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 636b4558c6..8a50e93bf9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -45,6 +45,7 @@ import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -125,8 +126,7 @@ public class DestWildExchange extends AbstractExchange try { - registerQueue(new AMQShortString(binding), queue, null); - queue.bind(new AMQShortString(binding), DestWildExchange.this); + queue.bind(new AMQShortString(binding), null, DestWildExchange.this); } catch (AMQException ex) { @@ -168,9 +168,9 @@ public class DestWildExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { - BasicPublishBody publishBody = payload.getPublishBody(); + MessagePublishInfo info = payload.getMessagePublishInfo(); - final AMQShortString routingKey = publishBody.routingKey; + final AMQShortString routingKey = info.getRoutingKey(); List queues = _routingKey2queues.get(routingKey); // if we have no registered queues we have nothing to do // TODO: add support for the immediate flag @@ -221,7 +221,7 @@ public class DestWildExchange extends AbstractExchange return !_routingKey2queues.isEmpty(); } - public synchronized void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + public synchronized void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; assert routingKey != null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 7702e8b315..a5f77cc2a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -47,7 +47,7 @@ public interface Exchange void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException; + void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; void route(AMQMessage message) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index a022b86299..d3a466565f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -26,7 +26,7 @@ import org.apache.qpid.framing.AMQShortString; public interface ExchangeRegistry extends MessageRouter { - void registerExchange(Exchange exchange); + void registerExchange(Exchange exchange) throws AMQException; /** * Unregister an exchange @@ -42,4 +42,6 @@ public interface ExchangeRegistry extends MessageRouter void setDefaultExchange(Exchange exchange); Exchange getDefaultExchange(); + + void initialise() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 01a1b0bbc8..095fd2b7e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -19,8 +19,8 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; @@ -98,9 +98,8 @@ public class FanoutExchange extends AbstractExchange } try - { - registerQueue(new AMQShortString(binding), queue, null); - queue.bind(new AMQShortString(binding), FanoutExchange.this); + { + queue.bind(new AMQShortString(binding), null, FanoutExchange.this); } catch (AMQException ex) { @@ -144,10 +143,10 @@ public class FanoutExchange extends AbstractExchange } } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; - assert routingKey != null; + if (!_queues.remove(queue)) { @@ -158,12 +157,12 @@ public class FanoutExchange extends AbstractExchange public void route(AMQMessage payload) throws AMQException { - final BasicPublishBody publishBody = payload.getPublishBody(); - final AMQShortString routingKey = publishBody.routingKey; + final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); + final AMQShortString routingKey = publishInfo.getRoutingKey(); if (_queues == null || _queues.isEmpty()) { String msg = "No queues bound to " + this; - if (publishBody.mandatory) + if (publishInfo.isMandatory()) { throw new NoRouteException(msg, payload); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index f3dc8131b3..204e2f9f93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -200,10 +200,10 @@ public class HeadersExchange extends AbstractExchange _bindings.add(new Registration(new HeadersBinding(args), queue)); } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - _bindings.remove(new Registration(null, queue)); + _bindings.remove(new Registration(new HeadersBinding(args), queue)); } public void route(AMQMessage payload) throws AMQException @@ -232,7 +232,7 @@ public class HeadersExchange extends AbstractExchange String msg = "Exchange " + getName() + ": message not routable."; - if (payload.getPublishBody().mandatory) + if (payload.getMessagePublishInfo().isMandatory()) { throw new NoRouteException(msg, payload); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 3798918428..67ade0a744 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -27,6 +27,7 @@ import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; @@ -85,7 +86,8 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); } try - { - exch.registerQueue(body.routingKey, queue, body.arguments); + { + queue.bind(body.routingKey, body.arguments, exch); } catch (AMQInvalidRoutingKeyException rke) { @@ -109,7 +109,7 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); } - queue.bind(body.routingKey, exch); + if (_log.isInfoEnabled()) { _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + body.routingKey); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index a35cb9f7d3..8b2467f47d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -108,8 +108,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener + private class BodyContentIterator implements Iterator { private int _index = -1; @@ -161,11 +162,11 @@ public class AMQMessage } } - public ContentBody next() + public ContentChunk next() { try { - return _messageHandle.getContentBody(getStoreContext(),_messageId, ++_index); + return _messageHandle.getContentChunk(getStoreContext(),_messageId, ++_index); } catch (AMQException e) { @@ -179,13 +180,13 @@ public class AMQMessage } } - public AMQMessage(Long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext) { _messageId = messageId; _txnContext = txnContext; - _immediate = publishBody.immediate; - _transientMessageData.setPublishBody(publishBody); + _immediate = info.isImmediate(); + _transientMessageData.setMessagePublishInfo(info); _taken = new AtomicBoolean(false); if (_log.isDebugEnabled()) @@ -215,14 +216,14 @@ public class AMQMessage * Used in testing only. This allows the passing of the content header immediately * on construction. * @param messageId - * @param publishBody + * @param info * @param txnContext * @param contentHeader */ - public AMQMessage(Long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, ContentHeaderBody contentHeader) throws AMQException { - this(messageId, publishBody, txnContext); + this(messageId, info, txnContext); setContentHeaderBody(contentHeader); } @@ -230,23 +231,23 @@ public class AMQMessage * Used in testing only. This allows the passing of the content header and some body fragments on * construction. * @param messageId - * @param publishBody + * @param info * @param txnContext * @param contentHeader * @param destinationQueues * @param contentBodies * @throws AMQException */ - public AMQMessage(Long messageId, BasicPublishBody publishBody, + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, ContentHeaderBody contentHeader, List destinationQueues, - List contentBodies, MessageStore messageStore, StoreContext storeContext, + List contentBodies, MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException { - this(messageId, publishBody, txnContext, contentHeader); + this(messageId, info, txnContext, contentHeader); _transientMessageData.setDestinationQueues(destinationQueues); routingComplete(messageStore, storeContext, messageHandleFactory); - for (ContentBody cb : contentBodies) + for (ContentChunk cb : contentBodies) { addContentBodyFrame(storeContext, cb); } @@ -261,12 +262,12 @@ public class AMQMessage _transientMessageData = msg._transientMessageData; } - public Iterator getBodyFrameIterator(int channel) + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) { - return new BodyFrameIterator(channel); + return new BodyFrameIterator(protocolSession, channel); } - public Iterator getContentBodyIterator() + public Iterator getContentBodyIterator() { return new BodyContentIterator(); } @@ -311,11 +312,11 @@ public class AMQMessage } } - public boolean addContentBodyFrame(StoreContext storeContext, ContentBody contentBody) throws AMQException + public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException { - _transientMessageData.addBodyLength(contentBody.getSize()); + _transientMessageData.addBodyLength(contentChunk.getSize()); final boolean allContentReceived = isAllContentReceived(); - _messageHandle.addContentBodyFrame(storeContext, _messageId, contentBody, allContentReceived); + _messageHandle.addContentBodyFrame(storeContext, _messageId, contentChunk, allContentReceived); if (allContentReceived) { deliver(storeContext); @@ -502,16 +503,16 @@ public class AMQMessage } } - public BasicPublishBody getPublishBody() throws AMQException + public MessagePublishInfo getMessagePublishInfo() throws AMQException { - BasicPublishBody pb; + MessagePublishInfo pb; if (_transientMessageData != null) { - pb = _transientMessageData.getPublishBody(); + pb = _transientMessageData.getMessagePublishInfo(); } else { - pb = _messageHandle.getPublishBody(getStoreContext(),_messageId); + pb = _messageHandle.getMessagePublishInfo(getStoreContext(),_messageId); } return pb; } @@ -554,7 +555,7 @@ public class AMQMessage { // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, _transientMessageData.getPublishBody(), + _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); // we then allow the transactional context to do something with the message content @@ -598,9 +599,9 @@ public class AMQMessage // 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. // - ContentBody cb = _messageHandle.getContentBody(getStoreContext(),_messageId, 0); + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, 0); - AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); + AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); protocolSession.writeFrame(compositeBlock); @@ -610,8 +611,8 @@ public class AMQMessage // for(int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentBody(getStoreContext(),_messageId, i); - protocolSession.writeFrame(ContentBody.createAMQFrame(channelId, cb)); + cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, i); + protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -641,9 +642,9 @@ public class AMQMessage // 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. // - ContentBody cb = _messageHandle.getContentBody(getStoreContext(),_messageId, 0); + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, 0); - AMQDataBlock firstContentBody = ContentBody.createAMQFrame(channelId, cb); + AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); protocolSession.writeFrame(compositeBlock); @@ -653,8 +654,8 @@ public class AMQMessage // for(int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentBody(getStoreContext(),_messageId, i); - protocolSession.writeFrame(ContentBody.createAMQFrame(channelId, cb)); + cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, i); + protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -667,10 +668,10 @@ public class AMQMessage private ByteBuffer createEncodedDeliverFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { - BasicPublishBody pb = getPublishBody(); + MessagePublishInfo pb = getMessagePublishInfo(); AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), (byte) 0, consumerTag, - deliveryTag, pb.exchange, _messageHandle.isRedelivered(), - pb.routingKey); + deliveryTag, pb.getExchange(), _messageHandle.isRedelivered(), + pb.getRoutingKey()); ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? deliverFrame.writePayload(buf); buf.flip(); @@ -680,14 +681,14 @@ public class AMQMessage private ByteBuffer createEncodedGetOkFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) throws AMQException { - BasicPublishBody pb = getPublishBody(); + MessagePublishInfo pb = getMessagePublishInfo(); AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), protocolSession.getProtocolMinorVersion(), - deliveryTag, pb.exchange, + deliveryTag, pb.getExchange(), queueSize, _messageHandle.isRedelivered(), - pb.routingKey); + pb.getRoutingKey()); ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? getOkFrame.writePayload(buf); buf.flip(); @@ -699,9 +700,9 @@ public class AMQMessage AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), protocolSession.getProtocolMinorVersion(), - getPublishBody().exchange, + getMessagePublishInfo().getExchange(), replyCode, replyText, - getPublishBody().routingKey); + getMessagePublishInfo().getRoutingKey()); ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? returnFrame.writePayload(buf); buf.flip(); @@ -716,7 +717,7 @@ public class AMQMessage AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, getContentHeaderBody()); - Iterator bodyFrameIterator = getBodyFrameIterator(channelId); + Iterator bodyFrameIterator = getBodyFrameIterator(protocolSession, 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. @@ -767,7 +768,7 @@ public class AMQMessage public void restoreTransientMessageData() throws AMQException { TransientMessageData transientMessageData = new TransientMessageData(); - transientMessageData.setPublishBody(getPublishBody()); + transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); transientMessageData.setContentHeaderBody(getContentHeaderBody()); transientMessageData.addBodyLength(getContentHeaderBody().getSize()); _transientMessageData = transientMessageData; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index 210c9f01a8..ede55b3bbf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -21,10 +21,10 @@ 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; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; /** * A pluggable way of getting message data. Implementations can provide intelligent caching for example or @@ -53,11 +53,11 @@ public interface AMQMessageHandle * @return a content body * @throws IllegalArgumentException if the index is invalid */ - ContentBody getContentBody(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; + ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; - void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException; + void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException; + MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException; boolean isRedelivered(); @@ -65,7 +65,7 @@ public interface AMQMessageHandle boolean isPersistent(StoreContext context, Long messageId) throws AMQException; - void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, + void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 557d82359f..e9ebe6c541 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -441,9 +441,24 @@ public class AMQQueue implements Managable, Comparable return _deliveryMgr.clearAllMessages(storeContext); } - public void bind(AMQShortString routingKey, Exchange exchange) + public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException { - _bindings.addBinding(routingKey, exchange); + exchange.registerQueue(routingKey, this, arguments); + if(isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().bindQueue(exchange,routingKey,this,arguments); + } + _bindings.addBinding(routingKey, arguments, exchange); + } + + public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException + { + exchange.deregisterQueue(routingKey, this, arguments); + if(isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().unbindQueue(exchange,routingKey,this,arguments); + } + _bindings.remove(routingKey, arguments, exchange); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index c0b22b541b..4fd89f39da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -44,6 +44,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; @@ -322,16 +323,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } // get message content - Iterator cBodies = msg.getContentBodyIterator(); + Iterator cBodies = msg.getContentBodyIterator(); List msgContent = new ArrayList(); while (cBodies.hasNext()) { - ContentBody body = cBodies.next(); + ContentChunk body = cBodies.next(); if (body.getSize() != 0) { if (body.getSize() != 0) { - ByteBuffer slice = body.payload.slice(); + ByteBuffer slice = body.getData().slice(); for (int j = 0; j < slice.limit(); j++) { msgContent.add(slice.get()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index d8bc19fcea..0fc8753a87 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -33,7 +33,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -114,11 +114,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // Shrink the ContentBodies to their actual size to save memory. if (compressBufferOnQueue) { - Iterator it = msg.getContentBodyIterator(); + Iterator it = msg.getContentBodyIterator(); while (it.hasNext()) { - ContentBody cb = it.next(); - cb.reduceBufferToFit(); + ContentChunk cb = it.next(); + cb.reduceToFit(); } } @@ -493,7 +493,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _log.debug(id() + "Testing Message(" + msg + ") for Queued Delivery"); } - if (!msg.getPublishBody().immediate) + if (!msg.getMessagePublishInfo().isImmediate()) { addMessageToQueue(msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index d15cca72d2..a8247aa2db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -26,6 +26,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; /** @@ -35,42 +36,55 @@ import org.apache.qpid.server.exchange.Exchange; */ class ExchangeBindings { + private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + static class ExchangeBinding { - private final Exchange exchange; - private final AMQShortString routingKey; + private final Exchange _exchange; + private final AMQShortString _routingKey; + private final FieldTable _arguments; ExchangeBinding(AMQShortString routingKey, Exchange exchange) { - this.routingKey = routingKey; - this.exchange = exchange; + this(routingKey, exchange,EMPTY_ARGUMENTS); + } + + ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) + { + _routingKey = routingKey; + _exchange = exchange; + _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; } void unbind(AMQQueue queue) throws AMQException { - exchange.deregisterQueue(routingKey, queue); + _exchange.deregisterQueue(_routingKey, queue, _arguments); } public Exchange getExchange() { - return exchange; + return _exchange; } public AMQShortString getRoutingKey() { - return routingKey; + return _routingKey; } public int hashCode() { - return (exchange == null ? 0 : exchange.hashCode()) + (routingKey == null ? 0 : routingKey.hashCode()); + return (_exchange == null ? 0 : _exchange.hashCode()) + + (_routingKey == null ? 0 : _routingKey.hashCode()) + + (_arguments == null ? 0 : _arguments.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); + return _exchange.equals(eb._exchange) + && _routingKey.equals(eb._routingKey) + && _arguments.equals(eb._arguments); } } @@ -88,11 +102,18 @@ class ExchangeBindings * are being tracked by the instance has been bound to the exchange * @param exchange the exchange bound to */ - void addBinding(AMQShortString routingKey, Exchange exchange) + void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + { + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments )); + } + + + public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.add(new ExchangeBinding(routingKey, exchange)); + _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments )); } + /** * Deregisters this queue from any exchange it has been bound to */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 79f875ce1e..630186991b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -25,9 +25,10 @@ import java.util.List; 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.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.store.StoreContext; /** @@ -37,9 +38,9 @@ public class InMemoryMessageHandle implements AMQMessageHandle private ContentHeaderBody _contentHeaderBody; - private BasicPublishBody _publishBody; + private MessagePublishInfo _messagePublishInfo; - private List _contentBodies = new LinkedList(); + private List _contentBodies = new LinkedList(); private boolean _redelivered; @@ -64,7 +65,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle return getContentHeaderBody(context, messageId).bodySize; } - public ContentBody getContentBody(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -74,15 +75,15 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _contentBodies.get(index); } - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException { _contentBodies.add(contentBody); } - public BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException { - return _publishBody; + return _messagePublishInfo; } public boolean isRedelivered() @@ -106,15 +107,15 @@ public class InMemoryMessageHandle implements AMQMessageHandle /** * This is called when all the content has been received. - * @param publishBody + * @param messagePublishInfo * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) throws AMQException { - _publishBody = publishBody; + _messagePublishInfo = messagePublishInfo; _contentHeaderBody = contentHeaderBody; _arrivalTime = System.currentTimeMillis(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java index a66a85e54d..285f05fb20 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -16,8 +16,8 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; /** * Encapsulates a publish body and a content header. In the context of the message store these are treated as a @@ -25,7 +25,7 @@ import org.apache.qpid.framing.ContentHeaderBody; */ public class MessageMetaData { - private BasicPublishBody _publishBody; + private MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; @@ -33,15 +33,15 @@ public class MessageMetaData private long _arrivalTime; - public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) { this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); } - public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) { _contentHeaderBody = contentHeaderBody; - _publishBody = publishBody; + _messagePublishInfo = publishBody; _contentChunkCount = contentChunkCount; _arrivalTime = arrivalTime; } @@ -66,14 +66,14 @@ public class MessageMetaData _contentHeaderBody = contentHeaderBody; } - public BasicPublishBody getPublishBody() + public MessagePublishInfo getMessagePublishInfo() { - return _publishBody; + return _messagePublishInfo; } - public void setPublishBody(BasicPublishBody publishBody) + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) { - _publishBody = publishBody; + _messagePublishInfo = messagePublishInfo; } public long getArrivalTime() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 9f3d64f77e..7c8064789e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -21,8 +21,8 @@ import java.util.LinkedList; import java.util.List; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.ContentHeaderBody; /** @@ -40,7 +40,7 @@ public class TransientMessageData * Stored temporarily until the header has been received at which point it is used when * constructing the handle */ - private BasicPublishBody _publishBody; + private MessagePublishInfo _messagePublishInfo; /** * Also stored temporarily. @@ -59,14 +59,14 @@ public class TransientMessageData */ private List _destinationQueues = new LinkedList(); - public BasicPublishBody getPublishBody() + public MessagePublishInfo getMessagePublishInfo() { - return _publishBody; + return _messagePublishInfo; } - public void setPublishBody(BasicPublishBody publishBody) + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) { - _publishBody = publishBody; + _messagePublishInfo = messagePublishInfo; } public List getDestinationQueues() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 670d895950..373a64e2eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -27,9 +27,9 @@ import java.util.List; 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.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; @@ -40,9 +40,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { private WeakReference _contentHeaderBody; - private WeakReference _publishBody; + private WeakReference _messagePublishInfo; - private List> _contentBodies; + private List> _contentBodies; private boolean _redelivered; @@ -79,7 +79,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { _arrivalTime = mmd.getArrivalTime(); _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); - _publishBody = new WeakReference(mmd.getPublishBody()); + _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); } public int getBodyCount(StoreContext context, Long messageId) throws AMQException @@ -88,10 +88,10 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle { MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); int chunkCount = mmd.getContentChunkCount(); - _contentBodies = new ArrayList>(chunkCount); + _contentBodies = new ArrayList>(chunkCount); for (int i = 0; i < chunkCount; i++) { - _contentBodies.add(new WeakReference(null)); + _contentBodies.add(new WeakReference(null)); } } return _contentBodies.size(); @@ -102,19 +102,19 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return getContentHeaderBody(context, messageId).bodySize; } - public ContentBody getContentBody(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, 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(); + WeakReference wr = _contentBodies.get(index); + ContentChunk cb = wr.get(); if (cb == null) { cb = _messageStore.getContentBodyChunk(context, messageId, index); - _contentBodies.set(index, new WeakReference(cb)); + _contentBodies.set(index, new WeakReference(cb)); } return cb; } @@ -124,35 +124,36 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * * @param storeContext * @param messageId - * @param contentBody + * @param contentChunk * @param isLastContentBody * @throws AMQException */ - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException { if (_contentBodies == null && isLastContentBody) { - _contentBodies = new ArrayList>(1); + _contentBodies = new ArrayList>(1); } else { if (_contentBodies == null) { - _contentBodies = new LinkedList>(); + _contentBodies = new LinkedList>(); } } - _contentBodies.add(new WeakReference(contentBody)); - _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody, isLastContentBody); + _contentBodies.add(new WeakReference(contentChunk)); + _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, + contentChunk, isLastContentBody); } - public BasicPublishBody getPublishBody(StoreContext context, Long messageId) throws AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException { - BasicPublishBody bpb = (_publishBody != null ? _publishBody.get() : null); + MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); if (bpb == null) { MessageMetaData mmd = loadMessageMetaData(context, messageId); - bpb = mmd.getPublishBody(); + bpb = mmd.getMessagePublishInfo(); } return bpb; } @@ -182,7 +183,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, BasicPublishBody publishBody, + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody) throws AMQException { @@ -190,7 +191,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle // create en empty list here if (contentHeaderBody.bodySize == 0) { - _contentBodies = new LinkedList>(); + _contentBodies = new LinkedList>(); } final long arrivalTime = System.currentTimeMillis(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java new file mode 100644 index 0000000000..90aa7bb998 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.abstraction.ContentChunk; + +import org.apache.mina.common.ByteBuffer; + +public class ContentChunkAdapter +{ + public static ContentBody toConentBody(ContentChunk contentBodyChunk) + { + return new ContentBody(contentBodyChunk.getData()); + } + + public static ContentChunk toConentChunk(final ContentBody contentBodyChunk) + { + return new ContentChunk() { + + public int getSize() + { + return contentBodyChunk.getSize(); + } + + public ByteBuffer getData() + { + return contentBodyChunk.payload; + } + + public void reduceToFit() + { + contentBodyChunk.reduceBufferToFit(); + } + }; + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index f678cea630..8ccb0be0a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -31,10 +31,12 @@ import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; /** * A simple message store that stores the messages in a threadsafe structure in memory. @@ -49,7 +51,7 @@ public class MemoryMessageStore implements MessageStore protected ConcurrentMap _metaDataMap; - protected ConcurrentMap> _contentBodyMap; + protected ConcurrentMap> _contentBodyMap; private final AtomicLong _messageId = new AtomicLong(1); @@ -57,7 +59,7 @@ public class MemoryMessageStore implements MessageStore { _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); - _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); + _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); } public void configure(String base, Configuration config) @@ -65,7 +67,7 @@ public class MemoryMessageStore implements MessageStore 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); + _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); } public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception @@ -97,6 +99,26 @@ public class MemoryMessageStore implements MessageStore _contentBodyMap.remove(messageId); } + public void createExchange(Exchange exchange) throws AMQException + { + + } + + public void removeExchange(Exchange exchange) throws AMQException + { + + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + public void createQueue(AMQQueue queue) throws AMQException { // Not required to do anything @@ -147,10 +169,10 @@ public class MemoryMessageStore implements MessageStore return _messageId.getAndIncrement(); } - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentBody contentBody, boolean lastContentBody) + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException { - List bodyList = _contentBodyMap.get(messageId); + List bodyList = _contentBodyMap.get(messageId); if(bodyList == null && lastContentBody) { @@ -160,7 +182,7 @@ public class MemoryMessageStore implements MessageStore { if (bodyList == null) { - bodyList = new ArrayList(); + bodyList = new ArrayList(); _contentBodyMap.put(messageId, bodyList); } @@ -179,9 +201,9 @@ public class MemoryMessageStore implements MessageStore return _metaDataMap.get(messageId); } - public ContentBody getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException { - List bodyList = _contentBodyMap.get(messageId); + List bodyList = _contentBodyMap.get(messageId); return bodyList.get(index); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java new file mode 100644 index 0000000000..6ee2fa784d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java @@ -0,0 +1,62 @@ +package org.apache.qpid.server.store; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +public class MessagePublishInfoAdapter +{ + private final byte _majorVersion; + private final byte _minorVersion; + private final int _classId; + private final int _methodId; + + + public MessagePublishInfoAdapter(byte majorVersion, byte minorVersion) + { + _majorVersion = majorVersion; + _minorVersion = minorVersion; + _classId = BasicPublishBody.getClazz(majorVersion,minorVersion); + _methodId = BasicPublishBody.getMethod(majorVersion,minorVersion); + } + + public BasicPublishBody toMethodBody(MessagePublishInfo pubInfo) + { + return new BasicPublishBody(_majorVersion, + _minorVersion, + _classId, + _methodId, + pubInfo.getExchange(), + pubInfo.isImmediate(), + pubInfo.isMandatory(), + pubInfo.getRoutingKey(), + 0) ; // ticket + } + + public MessagePublishInfo toMessagePublishInfo(final BasicPublishBody body) + { + return new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return body.getExchange(); + } + + public boolean isImmediate() + { + return body.getImmediate(); + } + + public boolean isMandatory() + { + return body.getMandatory(); + } + + public AMQShortString getRoutingKey() + { + return body.getRoutingKey(); + } + }; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 7fa46eb1ca..21988d97a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.store; -import java.util.List; - import org.apache.commons.configuration.Configuration; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; public interface MessageStore { @@ -51,6 +51,15 @@ public interface MessageStore void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + void createExchange(Exchange exchange) throws AMQException; + + void removeExchange(Exchange exchange) throws AMQException; + + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void createQueue(AMQQueue queue) throws AMQException; void removeQueue(AMQShortString name) throws AMQException; @@ -67,25 +76,18 @@ public interface MessageStore boolean inTran(StoreContext context); - /** - * 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(StoreContext context, Long messageId, int index, ContentBody contentBody, boolean lastContentBody) throws AMQException; + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException; void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - ContentBody getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; + ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index abbd18eff4..e09ce9326c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -99,9 +99,11 @@ public class VirtualHost _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _exchangeRegistry = new DefaultExchangeRegistry(this); _messageStore = store; + + _exchangeRegistry.initialise(); _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); @@ -117,10 +119,12 @@ public class VirtualHost _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _exchangeRegistry = new DefaultExchangeRegistry(this); initialiseMessageStore(hostConfig); + _exchangeRegistry.initialise(); + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); -- cgit v1.2.1 From 31348b37b0ad57ee97defdfe97d69611f019e32d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 21 Feb 2007 15:47:17 +0000 Subject: QPID-348 Problems related to prefetching of messages Client caches are now cleared. Partially commented out code in AMQSession and BasicMessageConsumer pending broker fixes to ensure channel suspension is respected. Tests fail otherwise. Tests pass just now as they are not correct, JIRA raised for fix (QPID-386). Spec Changes Added recover-ok method to recover. But to maintain compatibility added a nowait bit to request the response. Java Changes AMQConnection added wrapping of AMQExceptions that can be thrown by the waiting suspend calls. AMQSession Added clean up code for rollback/recover to clean up Session._queue and BMC._syncQueue BasicMessageConsumer - added rollback method to clean up _syncQueue ChannelCloseMethodHandler - reduced logging level from error to debug for received methods. FlowControllingBlockingQueue - added code to return iterator so messages can be purged cleanly. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@510060 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicRecoverMethodHandler.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index 5f5b7ccad1..5a9b9b54af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.BasicRecoverOkBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -43,16 +44,24 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener evt) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - + _logger.debug("Recover received on protocol session " + session + " and channel " + evt.getChannelId()); AMQChannel channel = session.getChannel(evt.getChannelId()); BasicRecoverBody body = evt.getMethod(); - + if (channel == null) { throw body.getChannelNotFoundException(evt.getChannelId()); } channel.resend(session, body.requeue); + + if (!body.nowait) + { + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + session.writeFrame(BasicRecoverOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); + } } } -- cgit v1.2.1 From 272f0d2a1b2134c7cdddcc9e6e951edc696e6054 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 21 Feb 2007 16:03:24 +0000 Subject: QPID-348 Reverted unecessary nowait addition to amqp Basic.Recover spec. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@510076 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/handler/BasicRecoverMethodHandler.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index 5a9b9b54af..bc11e4652c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -56,12 +56,9 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener Date: Fri, 23 Feb 2007 10:20:44 +0000 Subject: QPID-346 Message loss after rollback QPID-348 Problems of prefetching messages QPID-355 Closing a consumer does not ensure messages delivery will stop for that subscription BROKER AMQChannel - updated requeue to either resend via the Delivery Manager not directly via msg.writedeliver. BasicRejectMethodHandler - initial place holder. TxRollbackHandler - Added comment AMQMessage - added ability to record who has taken the message so that it can be resent to that subscriber on resend/requeue. AMQQueue - added the queue reference to the Subscription creation ConcurrentSelectorDeliveryManager - Added methods to correctly monitor the size of queue messages. Including messages on the resend queue of a Subscriber. Additional locking to ensure that messages are not sent to the subscriber after Closure. QPID-355 DeliveryManager - adjusted deliver call to allow delivery to the head of the queue. Subscription - changes to allow selction of queue(resend or predelivery) methods to add to resend and getSendLock to ensure that sending to the Subscription is allowed. SubscriptionFactory - changes to allow the AMQQueue to be passed to the Subscription. SubscriptionImpl - implementation of the interfaces. Local storage of messages to be resent and requeuing of the messages during closure. SubscriptionSet - changes to retrieve the actual stored Subscription when performing removeSubscriber. So we have access to the the resend queue. AMQStateManager - Added BasicRejectMethodHandler TransactionalContext - Added option to deliver the messages to the front of the queue. LocalTransactionalContext - cleared the _postComitDeliveryList on rollback. Added option to deliver the messages to the front of the queue. NonTransactionalContext - Added option to deliver the messages to the front of the queue. DeliverMessageOperation.java DELELTED AS NOT USED. CLIENT AMQSession - added ability to get the pervious state of the dispatcher when settting Stopped, fixed the channel suspension problems on broker so uncommented clean up code in rollback and recover. BasicMessageConsumer - updated the rollback so that it sends reject messages to server. AbstractJMSMessage - whitespace + added extra message properties to the toString() AMQProtocolHandler - whitespace + extra debug output TransactedTest - updated expect to prevent NPEs also added extra logging to help understand what is going on. CLUSTER ClusteredQueue - AMQQueue changes for message deliveryFirst. RemoteSubscriptionImpl - Implementation of Subscription SYSTESTS AbstractHeadersExchangeTestBase - AMQQueue changes for message deliveryFirst. AMQQueueMBeanTest - changes for message deliveryFirst. ConcurrencyTest - changes for message deliveryFirst. DeliveryManagerTest - changes for message deliveryFirst. SubscriptionTestHelper - Implementation of Subscription WhiteSpace only UnacknowledgedMessageMapImpl.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@510897 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 272 +++++++++++++---- .../server/ack/UnacknowledgedMessageMapImpl.java | 1 - .../server/handler/BasicRejectMethodHandler.java | 68 +++++ .../qpid/server/handler/TxRollbackHandler.java | 1 + .../org/apache/qpid/server/queue/AMQMessage.java | 165 ++++++----- .../org/apache/qpid/server/queue/AMQQueue.java | 143 ++++----- .../queue/ConcurrentSelectorDeliveryManager.java | 322 ++++++++++++++------- .../apache/qpid/server/queue/DeliveryManager.java | 36 +-- .../org/apache/qpid/server/queue/Subscription.java | 12 +- .../qpid/server/queue/SubscriptionFactory.java | 8 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 232 +++++++++++++-- .../apache/qpid/server/queue/SubscriptionSet.java | 70 +++-- .../apache/qpid/server/state/AMQStateManager.java | 5 +- .../qpid/server/txn/DeliverMessageOperation.java | 74 ----- .../qpid/server/txn/LocalTransactionalContext.java | 15 +- .../qpid/server/txn/NonTransactionalContext.java | 20 +- .../qpid/server/txn/TransactionalContext.java | 2 +- 17 files changed, 944 insertions(+), 502 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 7271bd6e43..7ceb3a7eef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -46,6 +46,7 @@ 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.queue.Subscription; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; @@ -74,28 +75,20 @@ public class AMQChannel */ 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 - */ + /** 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. - */ + /** 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. + * 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. - */ + /** Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */ private final Map _consumerTag2QueueMap = new HashMap(); private final MessageStore _messageStore; @@ -109,8 +102,8 @@ public class AMQChannel private TransactionalContext _txnContext; /** - * A context used by the message store enabling it to track context for a given channel even across - * thread boundaries + * A context used by the message store enabling it to track context for a given channel even across thread + * boundaries */ private final StoreContext _storeContext; @@ -123,7 +116,6 @@ public class AMQChannel private final AMQProtocolSession _session; - public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore, MessageRouter exchanges) throws AMQException { @@ -138,9 +130,7 @@ public class AMQChannel _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } - /** - * Sets this channel to be part of a local transaction - */ + /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); @@ -293,17 +283,17 @@ public class AMQChannel } /** - * 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. + * 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 + * @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 * @param noLocal * @param exclusive - * @return the consumer tag. This is returned to the subscriber and used in - * subsequent unsubscribe requests + * + * @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 */ @@ -335,7 +325,7 @@ public class AMQChannel } /** - * Called from the protocol session to close this channel and clean up. + * Called from the protocol session to close this channel and clean up. T * * @throws AMQException if there is an error during closure */ @@ -344,8 +334,6 @@ public class AMQChannel _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); - _txnContext.commit(); - } private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException @@ -362,8 +350,8 @@ public class AMQChannel * 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 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, AMQShortString consumerTag, AMQQueue queue) @@ -376,8 +364,8 @@ public class AMQChannel } /** - * Called to attempt re-enqueue all outstanding unacknowledged messages on the channel. - * May result in delivery to this same channel or to other subscribers. + * 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 */ @@ -386,23 +374,75 @@ public class AMQChannel // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); + TransactionalContext nontransacted = null; + if (!(_txnContext instanceof NonTransactionalContext)) + { + nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + for (UnacknowledgedMessage unacked : messagesToBeDelivered) { if (unacked.queue != null) { - _txnContext.deliver(unacked.message, unacked.queue); + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + if (!(_txnContext instanceof NonTransactionalContext)) + { + nontransacted.deliver(unacked.message, unacked.queue, false); + } + else + { + _txnContext.deliver(unacked.message, unacked.queue, false); + } } } } + public void requeue(long deliveryTag) throws AMQException + { + UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); - /** - * Called to resend all outstanding unacknowledged messages to this same channel. - */ + if (unacked != null) + { + TransactionalContext nontransacted = null; + if (!(_txnContext instanceof NonTransactionalContext)) + { + nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + if (!(_txnContext instanceof NonTransactionalContext)) + { + nontransacted.deliver(unacked.message, unacked.queue, false); + } + else + { + _txnContext.deliver(unacked.message, unacked.queue, false); + } + unacked.message.decrementReference(_storeContext); + } + else + { + _log.error("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists"); + } + + + } + + + /** Called to resend all outstanding unacknowledged messages to this same channel. */ public void resend(final AMQProtocolSession session, final boolean requeue) throws AMQException { final List msgToRequeue = new LinkedList(); + final List msgToResend = new LinkedList(); + + if (_log.isInfoEnabled()) + { + _log.info("unacked map contains " + _unacknowledgedMessageMap.size()); + } _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { @@ -412,21 +452,40 @@ public class AMQChannel AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; msg.setRedelivered(true); - if((consumerTag != null) && _consumerTag2QueueMap.containsKey(consumerTag) && !isSuspended()) + if (consumerTag != null) { - msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); + // Consumer exists + if (_consumerTag2QueueMap.containsKey(consumerTag)) + { + msgToResend.add(message); + } + else // consumer has gone + { + msgToRequeue.add(message); + } } else { // Message has no consumer tag, so was "delivered" to a GET // or consumer no longer registered // cannot resend, so re-queue. - if (message.queue != null && (consumerTag == null || requeue)) + if (message.queue != null) + { + if (requeue) + { + msgToRequeue.add(message); + } + else + { + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + } + } + else { - msgToRequeue.add(message); + _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } } - + // false means continue processing return false; } @@ -436,21 +495,112 @@ public class AMQChannel } }); - for(UnacknowledgedMessage message : msgToRequeue) + // Process Messages to Resend + if (_log.isInfoEnabled()) + { + if (!msgToResend.isEmpty()) + { + _log.info("Preparing (" + msgToResend.size() + ") message to resend to."); + } + } + for (UnacknowledgedMessage message : msgToResend) + { + AMQMessage msg = message.message; + + // Our Java Client will always suspend the channel when resending!! +// if (isSuspended()) +// { +// _log.info("Channel is suspended so requeuing"); +// //move this message to requeue +// msgToRequeue.add(message); +// } +// else + { + //release to allow it to be delivered + msg.release(); + + // Without any details from the client about what has been processed we have to mark + // all messages in the unacked map as redelivered. + msg.setRedelivered(true); + + + Subscription sub = msg.getDeliveredSubscription(); + + if (sub != null) + { + synchronized (sub.getSendLock()) + { + if (sub.isClosed()) + { + _log.info("Subscription closed during resend so requeuing message"); + //move this message to requeue + msgToRequeue.add(message); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("Requeuing (" + System.identityHashCode(msg) + ") for resend"); + } + // Will throw an exception if the sub is closed + sub.addToResendQueue(msg); + _unacknowledgedMessageMap.remove(message.deliveryTag); + // Don't decrement as we are bypassing the normal deliver which increments + // this is what there is a decrement on the Requeue as deliver will increment. + // msg.decrementReference(_storeContext); + } + } + } + else + { + _log.info("DeliveredSubscription not recorded so just requeueing to prevent loss"); + //move this message to requeue + msgToRequeue.add(message); + } + } + } + + if (_log.isInfoEnabled()) + { + if (!msgToRequeue.isEmpty()) + { + _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); + } + } + + TransactionalContext nontransacted = null; + if (!(_txnContext instanceof NonTransactionalContext)) { - _txnContext.deliver(message.message, message.queue); + nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + // Process Messages to Requeue at the front of the queue + for (UnacknowledgedMessage message : msgToRequeue) + { + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + if (!(_txnContext instanceof NonTransactionalContext)) + { + nontransacted.deliver(message.message, message.queue, true); + } + else + { + _txnContext.deliver(message.message, message.queue, true); + } + _unacknowledgedMessageMap.remove(message.deliveryTag); message.message.decrementReference(_storeContext); } } /** - * 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. + * 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 @@ -487,6 +637,7 @@ public class AMQChannel * @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 @@ -517,10 +668,10 @@ public class AMQChannel private void checkSuspension() { boolean suspend; - - suspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark) - || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); - + + suspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark) + || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); + setSuspended(suspend); } @@ -570,8 +721,6 @@ public class AMQChannel public void rollback() throws AMQException { _txnContext.rollback(); - - } public String toString() @@ -617,8 +766,8 @@ public class AMQChannel } else { - boolean willSuspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() + 1 > _prefetch_HighWaterMark); - if(!willSuspend) + boolean willSuspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() + 1 > _prefetch_HighWaterMark); + if (!willSuspend) { final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); @@ -626,7 +775,7 @@ public class AMQChannel } - if(willSuspend) + if (willSuspend) { setSuspended(true); } @@ -634,4 +783,9 @@ public class AMQChannel } } + + public TransactionalContext getTransactionalContext() + { + return _txnContext; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index f8b6babd43..fdf087fdea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -85,7 +85,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap for (UnacknowledgedMessage msg : msgs) { remove(msg.deliveryTag); - } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java new file mode 100644 index 0000000000..ed13092ded --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRejectBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicRejectMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRejectMethodHandler.class); + + private static BasicRejectMethodHandler _instance = new BasicRejectMethodHandler(); + + public static BasicRejectMethodHandler getInstance() + { + return _instance; + } + + private BasicRejectMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.info("FIXME: Rejecting:" + evt.getMethod().deliveryTag + ": Requeue:" + evt.getMethod().requeue); + + int channelId = evt.getChannelId(); + UnacknowledgedMessage message = session.getChannel(channelId).getUnacknowledgedMessageMap().get(evt.getMethod().deliveryTag); + + _logger.info("Need to reject message:" + message); +// if (evt.getMethod().requeue) +// { +// session.getChannel(channelId).requeue(evt.getMethod().deliveryTag); +// } +// else +// { +// // session.getChannel(channelId).resend(message); +// } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 8ce5a0ea73..a10f44f906 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -62,6 +62,7 @@ public class TxRollbackHandler implements StateAwareMethodListener _tokens; - /** - * Only use in clustering - should ideally be removed? - */ + /** Only use in clustering - should ideally be removed? */ private AMQProtocolSession _publisher; private final Long _messageId; @@ -63,16 +57,14 @@ public class AMQMessage private TransactionalContext _txnContext; /** - * Flag to indicate whether message has been delivered to a - * consumer. Used in implementing return functionality for + * 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; /** - * We need to keep track of whether the message was 'immediate' - * as in extreme circumstances, when the checkDelieveredToConsumer - * is called, the message may already have been received and acknowledged, - * and the body removed from the store. + * We need to keep track of whether the message was 'immediate' as in extreme circumstances, when the + * checkDelieveredToConsumer is called, the message may already have been received and acknowledged, and the body + * removed from the store. */ private boolean _immediate; @@ -80,11 +72,16 @@ public class AMQMessage private TransientMessageData _transientMessageData = new TransientMessageData(); + private Subscription _takenBySubcription; + public boolean isTaken() + { + return _taken.get(); + } /** - * Used to iterate through all the body frames associated with this message. Will not - * keep all the data in memory therefore is memory-efficient. + * 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 { @@ -103,7 +100,7 @@ public class AMQMessage { try { - return _index < _messageHandle.getBodyCount(getStoreContext(),_messageId) - 1; + return _index < _messageHandle.getBodyCount(getStoreContext(), _messageId) - 1; } catch (AMQException e) { @@ -153,7 +150,7 @@ public class AMQMessage { try { - return _index < _messageHandle.getBodyCount(getStoreContext(),_messageId) - 1; + return _index < _messageHandle.getBodyCount(getStoreContext(), _messageId) - 1; } catch (AMQException e) { @@ -166,7 +163,7 @@ public class AMQMessage { try { - return _messageHandle.getContentChunk(getStoreContext(),_messageId, ++_index); + return _messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index); } catch (AMQException e) { @@ -196,12 +193,14 @@ public class AMQMessage } /** - * Used when recovering, i.e. when the message store is creating references to messages. - * In that case, the normal enqueue/routingComplete is not done since the recovery process - * is responsible for routing the messages to queues. + * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal + * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to + * queues. + * * @param messageId * @param store * @param factory + * * @throws AMQException */ public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) throws AMQException @@ -213,8 +212,8 @@ public class AMQMessage } /** - * Used in testing only. This allows the passing of the content header immediately - * on construction. + * Used in testing only. This allows the passing of the content header immediately on construction. + * * @param messageId * @param info * @param txnContext @@ -228,14 +227,15 @@ public class AMQMessage } /** - * Used in testing only. This allows the passing of the content header and some body fragments on - * construction. + * Used in testing only. This allows the passing of the content header and some body fragments on construction. + * * @param messageId * @param info * @param txnContext * @param contentHeader * @param destinationQueues * @param contentBodies + * * @throws AMQException */ public AMQMessage(Long messageId, MessagePublishInfo info, @@ -280,7 +280,7 @@ public class AMQMessage } else { - return _messageHandle.getContentHeaderBody(getStoreContext(),_messageId); + return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); } } @@ -338,16 +338,14 @@ public class AMQMessage return _messageId; } - /** - * Threadsafe. Increment the reference count on the message. - */ + /** 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 + " " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); + _log.debug("Ref count on message " + _messageId + " incremented to " + _referenceCount + " " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0, 4)); } } @@ -355,7 +353,7 @@ public class AMQMessage /** * 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 */ @@ -371,7 +369,7 @@ public class AMQMessage { if (_log.isDebugEnabled()) { - _log.debug("Ref count on message " + _messageId + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); + _log.debug("Ref count on message " + _messageId + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0, 4)); } @@ -394,13 +392,13 @@ public class AMQMessage { if (_log.isDebugEnabled()) { - _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId+ "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0,4)); + _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId + "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(0, 4)); if (_referenceCount.get() < 0) { Thread.dumpStack(); } } - if(_referenceCount.get()<0) + if (_referenceCount.get() < 0) { throw new MessageCleanupException("Reference count for message id " + _messageId + " has gone below 0."); } @@ -419,7 +417,8 @@ public class AMQMessage /** * Called selectors to determin if the message has already been sent - * @return _deliveredToConsumer + * + * @return _deliveredToConsumer */ public boolean getDeliveredToConsumer() { @@ -427,10 +426,17 @@ public class AMQMessage } - - public boolean taken() + public boolean taken(Subscription sub) { - return _taken.getAndSet(true); + if (_taken.getAndSet(true)) + { + return true; + } + else + { + _takenBySubcription = sub; + return false; + } } public void release() @@ -441,9 +447,9 @@ public class AMQMessage public boolean checkToken(Object token) { - if(_tokens==null) + if (_tokens == null) { - _tokens = new HashSet(); + _tokens = new HashSet(); } if (_tokens.contains(token)) @@ -458,11 +464,12 @@ public class AMQMessage } /** - * 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. + * 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 @@ -483,16 +490,15 @@ public class AMQMessage } else { - return _messageHandle.isPersistent(getStoreContext(),_messageId); + return _messageHandle.isPersistent(getStoreContext(), _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 + * @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 { @@ -500,7 +506,7 @@ public class AMQMessage if (_immediate && !_deliveredToConsumer) { throw new NoConsumersException(this); - } + } } public MessagePublishInfo getMessagePublishInfo() throws AMQException @@ -512,7 +518,7 @@ public class AMQMessage } else { - pb = _messageHandle.getMessagePublishInfo(getStoreContext(),_messageId); + pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); } return pb; } @@ -533,10 +539,7 @@ public class AMQMessage } - /** - * Called when this message is delivered to a consumer. (used to - * implement the 'immediate' flag functionality). - */ + /** Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). */ public void setDeliveredToConsumer() { _deliveredToConsumer = true; @@ -566,7 +569,7 @@ public class AMQMessage for (AMQQueue q : destinationQueues) { - _txnContext.deliver(this, q); + _txnContext.deliver(this, q, true); } } finally @@ -583,23 +586,22 @@ public class AMQMessage AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, getContentHeaderBody()); - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(),_messageId); - if(bodyCount == 0) + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); + if (bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); + contentHeader); protocolSession.writeFrame(compositeBlock); } else { - // // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, 0); + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; @@ -609,9 +611,9 @@ public class AMQMessage // // Now start writing out the other content bodies // - for(int i = 1; i < bodyCount; i++) + for (int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, i); + cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -627,22 +629,21 @@ public class AMQMessage AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, getContentHeaderBody()); - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(),_messageId); - if(bodyCount == 0) + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); + if (bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); + contentHeader); protocolSession.writeFrame(compositeBlock); } else { - // // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, 0); + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; @@ -652,9 +653,9 @@ public class AMQMessage // // Now start writing out the other content bodies // - for(int i = 1; i < bodyCount; i++) + for (int i = 1; i < bodyCount; i++) { - cb = _messageHandle.getContentChunk(getStoreContext(),_messageId, i); + cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -685,10 +686,10 @@ public class AMQMessage AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), protocolSession.getProtocolMinorVersion(), - deliveryTag, pb.getExchange(), - queueSize, - _messageHandle.isRedelivered(), - pb.getRoutingKey()); + deliveryTag, pb.getExchange(), + queueSize, + _messageHandle.isRedelivered(), + pb.getRoutingKey()); ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? getOkFrame.writePayload(buf); buf.flip(); @@ -699,7 +700,7 @@ public class AMQMessage { AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), + protocolSession.getProtocolMinorVersion(), getMessagePublishInfo().getExchange(), replyCode, replyText, getMessagePublishInfo().getRoutingKey()); @@ -757,12 +758,11 @@ public class AMQMessage } catch (AMQException e) { - _log.error(e.toString(),e); + _log.error(e.toString(), e); return 0; } - } - + } public void restoreTransientMessageData() throws AMQException @@ -771,7 +771,7 @@ public class AMQMessage transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); transientMessageData.setContentHeaderBody(getContentHeaderBody()); transientMessageData.addBodyLength(getContentHeaderBody().getSize()); - _transientMessageData = transientMessageData; + _transientMessageData = transientMessageData; } @@ -784,6 +784,11 @@ public class AMQMessage public String toString() { return "Message: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + - _taken; + _taken + " by:" + _takenBySubcription; + } + + public Subscription getDeliveredSubscription() + { + return _takenBySubcription; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index e9ebe6c541..429829e201 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -45,13 +45,11 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.virtualhost.VirtualHost; /** - * 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. + * 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, Comparable { - - public static final class ExistingExclusiveSubscription extends AMQException { @@ -74,26 +72,19 @@ public class AMQQueue implements Managable, Comparable private static final ExistingSubscriptionPreventsExclusive EXISTING_SUBSCRIPTION = new ExistingSubscriptionPreventsExclusive(); - private static final Logger _logger = Logger.getLogger(AMQQueue.class); private final AMQShortString _name; - /** - * null means shared - */ + /** null means shared */ private final AMQShortString _owner; private final boolean _durable; - /** - * If true, this queue is deleted when the last subscriber is removed - */ + /** If true, this queue is deleted when the last subscriber is removed */ private final boolean _autoDelete; - /** - * Holds subscribers to the queue. - */ + /** Holds subscribers to the queue. */ private final SubscriptionSet _subscribers; private final SubscriptionFactory _subscriptionFactory; @@ -106,20 +97,13 @@ public class AMQQueue implements Managable, Comparable private List _deleteTaskList = new CopyOnWriteArrayList(); - /** - * Manages message delivery. - */ + /** Manages message delivery. */ private final DeliveryManager _deliveryMgr; - /** - * Used to track bindings to exchanges so that on deletion they can easily - * be cancelled. - */ + /** 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 - */ + /** Executor on which asynchronous delivery will be carriedout where required */ private final Executor _asyncDelivery; private final AMQQueueMBean _managedObject; @@ -127,39 +111,27 @@ public class AMQQueue implements Managable, Comparable private final VirtualHost _virtualHost; - /** - * max allowed size(KB) of a single message - */ + /** max allowed size(KB) of a single message */ @Configured(path = "maximumMessageSize", defaultValue = "0") public long _maximumMessageSize; - /** - * max allowed number of messages on a queue. - */ + /** max allowed number of messages on a queue. */ @Configured(path = "maximumMessageCount", defaultValue = "0") public int _maximumMessageCount; - /** - * max queue depth for the queue - */ + /** max queue depth for the queue */ @Configured(path = "maximumQueueDepth", defaultValue = "0") public long _maximumQueueDepth; - /** - * maximum message age before alerts occur - */ + /** maximum message age before alerts occur */ @Configured(path = "maximumMessageAge", defaultValue = "0") public long _maximumMessageAge; - /** - * the minimum interval between sending out consequetive alerts of the same type - */ + /** the minimum interval between sending out consequetive alerts of the same type */ @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") public long _minimumAlertRepeatGap; - /** - * total messages received by the queue since startup. - */ + /** total messages received by the queue since startup. */ public AtomicLong _totalMessagesReceived = new AtomicLong(); public int compareTo(Object o) @@ -176,7 +148,6 @@ public class AMQQueue implements Managable, Comparable } - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, SubscriptionSet subscribers) @@ -211,7 +182,7 @@ public class AMQQueue implements Managable, Comparable _subscribers = subscribers; _subscriptionFactory = subscriptionFactory; - _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); + _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); } private AMQQueueMBean createMBean() throws AMQException @@ -251,17 +222,13 @@ public class AMQQueue implements Managable, Comparable return _autoDelete; } - /** - * @return no of messages(undelivered) on the queue. - */ + /** @return no of messages(undelivered) on the queue. */ public int getMessageCount() { return _deliveryMgr.getQueueMessageCount(); } - /** - * @return List of messages(undelivered) on the queue. - */ + /** @return List of messages(undelivered) on the queue. */ public List getMessagesOnTheQueue() { return _deliveryMgr.getMessages(); @@ -275,6 +242,7 @@ public class AMQQueue implements Managable, Comparable /** * @param messageId + * * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. */ public AMQMessage getMessageOnTheQueue(long messageId) @@ -294,13 +262,12 @@ public class AMQQueue implements Managable, Comparable } /** - * moves messages from this queue to another queue. to do this the approach is following- - * - setup the queue for moving messages (hold the lock and stop the async delivery) - * - get all the messages available in the given message id range - * - setup the other queue for moving messages (hold the lock and stop the async delivery) - * - send these available messages to the other queue (enqueue in other queue) - * - Once sending to other Queue is successful, remove messages from this queue - * - remove locks from both queues and start async delivery + * moves messages from this queue to another queue. to do this the approach is following- - setup the queue for + * moving messages (hold the lock and stop the async delivery) - get all the messages available in the given message + * id range - setup the other queue for moving messages (hold the lock and stop the async delivery) - send these + * available messages to the other queue (enqueue in other queue) - Once sending to other Queue is successful, + * remove messages from this queue - remove locks from both queues and start async delivery + * * @param fromMessageId * @param toMessageId * @param queueName @@ -316,7 +283,7 @@ public class AMQQueue implements Managable, Comparable startMovingMessages(); List list = getMessagesOnTheQueue(); List foundMessagesList = new ArrayList(); - int maxMessageCountToBeMoved = (int)(toMessageId - fromMessageId + 1); + int maxMessageCountToBeMoved = (int) (toMessageId - fromMessageId + 1); // Run this loop till you find all the messages or the list has no more messages for (AMQMessage message : list) @@ -344,7 +311,7 @@ public class AMQQueue implements Managable, Comparable { // remove the lock and start the async delivery anotherQueue.stopMovingMessages(); - stopMovingMessages(); + stopMovingMessages(); } } @@ -364,10 +331,8 @@ public class AMQQueue implements Managable, Comparable _deliveryMgr.stopMovingMessages(); _deliveryMgr.processAsync(_asyncDelivery); } - - /** - * @return MBean object associated with this Queue - */ + + /** @return MBean object associated with this Queue */ public ManagedObject getManagedObject() { return _managedObject; @@ -422,20 +387,16 @@ public class AMQQueue implements Managable, Comparable public long getOldestMessageArrivalTime() { return _deliveryMgr.getOldestMessageArrival(); - + } - /** - * Removes the AMQMessage from the top of the queue. - */ + /** Removes the AMQMessage from the top of the queue. */ public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException { _deliveryMgr.removeAMessageFromTop(storeContext); } - /** - * removes all the messages from the queue. - */ + /** removes all the messages from the queue. */ public synchronized long clearQueue(StoreContext storeContext) throws AMQException { return _deliveryMgr.clearAllMessages(storeContext); @@ -443,10 +404,10 @@ public class AMQQueue implements Managable, Comparable public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException { - exchange.registerQueue(routingKey, this, arguments); - if(isDurable() && exchange.isDurable()) + exchange.registerQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().bindQueue(exchange,routingKey,this,arguments); + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); } _bindings.addBinding(routingKey, arguments, exchange); } @@ -454,9 +415,9 @@ public class AMQQueue implements Managable, Comparable public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException { exchange.deregisterQueue(routingKey, this, arguments); - if(isDurable() && exchange.isDurable()) + if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().unbindQueue(exchange,routingKey,this,arguments); + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); } _bindings.remove(routingKey, arguments, exchange); } @@ -466,30 +427,31 @@ public class AMQQueue implements Managable, Comparable FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { - if(incrementSubscriberCount() > 1) + if (incrementSubscriberCount() > 1) { - if(isExclusive()) + if (isExclusive()) { decrementSubscriberCount(); throw EXISTING_EXCLUSIVE; } - else if(exclusive) + else if (exclusive) { decrementSubscriberCount(); throw EXISTING_SUBSCRIPTION; } } - else if(exclusive) + else if (exclusive) { setExclusive(true); } 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, filters, noLocal); + Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, + filters, noLocal, this); - if(subscription.hasFilters()) + if (subscription.hasFilters()) { if (_deliveryMgr.hasQueuedMessages()) { @@ -537,10 +499,10 @@ public class AMQQueue implements Managable, Comparable " and protocol session key " + ps.getKey() + " not registered with queue " + this); } + removedSubscription.close(); setExclusive(false); decrementSubscriberCount(); - // if we are eligible for auto deletion, unregister from the queue registry if (_autoDelete && _subscribers.isEmpty()) { @@ -583,13 +545,13 @@ public class AMQQueue implements Managable, Comparable public void delete() throws AMQException { - if(!_deleted.getAndSet(true)) + if (!_deleted.getAndSet(true)) { _subscribers.queueDeleted(this); _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); _managedObject.unregister(); - for(Task task : _deleteTaskList) + for (Task task : _deleteTaskList) { task.doTask(this); } @@ -605,7 +567,8 @@ public class AMQQueue implements Managable, Comparable public void processGet(StoreContext storeContext, AMQMessage msg) throws AMQException { - _deliveryMgr.deliver(storeContext, getName(), msg); + //fixme not sure what this is doing. should we be passing deliverFirst through here? + _deliveryMgr.deliver(storeContext, getName(), msg, false); try { msg.checkDeliveredToConsumer(); @@ -620,9 +583,9 @@ public class AMQQueue implements Managable, Comparable } - public void process(StoreContext storeContext, AMQMessage msg) throws AMQException + public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { - _deliveryMgr.deliver(storeContext, getName(), msg); + _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); try { msg.checkDeliveredToConsumer(); @@ -731,7 +694,7 @@ public class AMQQueue implements Managable, Comparable public static interface Task { - public void doTask(AMQQueue queue) throws AMQException; + public void doTask(AMQQueue queue) throws AMQException; } public void addQueueDeleteTask(Task task) @@ -759,4 +722,8 @@ public class AMQQueue implements Managable, Comparable _maximumMessageAge = maximumMessageAge; } + public void subscriberHasPendingResend(boolean hasContent, SubscriptionImpl subscription, AMQMessage msg) + { + _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, msg); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 0fc8753a87..208a59516c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -24,9 +24,14 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Queue; +import java.util.Set; +import java.util.Collections; +import java.util.HashSet; import java.util.concurrent.Executor; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; @@ -38,12 +43,12 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.MessageQueue; +import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -/** - * Manages delivery of messages on behalf of a queue - */ +/** Manages delivery of messages on behalf of a queue */ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class); @@ -51,47 +56,36 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager @Configured(path = "advanced.compressBufferOnQueue", defaultValue = "false") public boolean compressBufferOnQueue; - /** - * Holds any queued messages - */ - private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); - - private final ReentrantLock _messageAccessLock = new ReentrantLock(); + /** Holds any queued messages */ + private final MessageQueue _messages = new ConcurrentLinkedMessageQueueAtomicSize(); - //private int _messageCount; - /** - * Ensures that only one asynchronous task is running for this manager at - * any time. - */ + /** 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 - */ + /** The subscriptions on the queue to whom messages are delivered */ private final SubscriptionManager _subscriptions; /** - * A reference to the queue we are delivering messages for. We need this to be able - * to pass the code that handles acknowledgements a handle on the queue. + * 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; /** - * Flag used while moving messages from this queue to another. For moving messages the async delivery - * should also stop. This flat should be set to true to stop async delivery and set to false to enable - * async delivery again. + * Flag used while moving messages from this queue to another. For moving messages the async delivery should also + * stop. This flat should be set to true to stop async delivery and set to false to enable async delivery again. */ private AtomicBoolean _movingMessages = new AtomicBoolean(); - + /** * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced - * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered - * via the async thread. - *

      - * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. + * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be + * delivered via the async thread.

      Lock is used to control access to hasQueuedMessages() and over the addition + * of messages to the queue. */ private ReentrantLock _lock = new ReentrantLock(); private AtomicLong _totalMessageSize = new AtomicLong(); - + private AtomicInteger _extraMessages = new AtomicInteger(); + private Set _hasContent = Collections.synchronizedSet(new HashSet()); ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -109,7 +103,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } - private boolean addMessageToQueue(AMQMessage msg) + private boolean addMessageToQueue(AMQMessage msg, boolean deliverFirst) { // Shrink the ContentBodies to their actual size to save memory. if (compressBufferOnQueue) @@ -122,7 +116,14 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - _messages.offer(msg); + if (deliverFirst) + { + _messages.pushHead(msg); + } + else + { + _messages.offer(msg); + } _totalMessageSize.addAndGet(msg.getSize()); @@ -135,7 +136,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.lock(); try { - return !_messages.isEmpty(); + return !(_messages.isEmpty() && _hasContent.isEmpty()); } finally { @@ -149,18 +150,17 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine size. - * The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. + * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine + * size. The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. * * @return int the number of messages in the delivery queue. */ private int getMessageCount() { - return _messages.size(); + return _messages.size() + _extraMessages.get(); } - public long getTotalMessageSize() { return _totalMessageSize.get(); @@ -172,6 +172,38 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return msg == null ? Long.MAX_VALUE : msg.getArrivalTime(); } + public void subscriberHasPendingResend(boolean hasContent, Subscription subscription, AMQMessage msg) + { + _lock.lock(); + try + { + if (hasContent) + { + _log.debug("Queue has adding subscriber content"); + _hasContent.add(subscription); + _totalMessageSize.addAndGet(msg.getSize()); + _extraMessages.addAndGet(1); + } + else + { + _log.debug("Queue has removing subscriber content"); + if (msg == null) + { + _hasContent.remove(subscription); + } + else + { + _totalMessageSize.addAndGet(-msg.getSize()); + _extraMessages.addAndGet(-1); + } + } + } + finally + { + _lock.unlock(); + } + } + public List getMessages() { @@ -195,7 +227,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager AMQMessage message = currentQueue.next(); if (subscription.hasInterest(message)) { - subscription.enqueueForPreDelivery(message); + subscription.enqueueForPreDelivery(message, false); } } } @@ -203,7 +235,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException { AMQMessage msg = getNextMessage(); - if(msg == null) + if (msg == null) { return false; } @@ -229,7 +261,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } _queue.dequeue(channel.getStoreContext(), msg); } - synchronized(channel) + synchronized (channel) { long deliveryTag = channel.getNextDeliveryTag(); @@ -252,8 +284,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, - * so that the asyn delivery is also stopped. + * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, so that + * the asyn delivery is also stopped. */ public void startMovingMessages() { @@ -262,8 +294,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, - * so that the async delivery can start again. + * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, so that + * the async delivery can start again. */ public void stopMovingMessages() { @@ -276,6 +308,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager /** * Messages will be removed from this queue and all preDeliveryQueues + * * @param messageList */ public void removeMovedMessages(List messageList) @@ -308,7 +341,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager /** * Now with implementation of predelivery queues, this method will mark the message on the top as taken. + * * @param storeContext + * * @throws AMQException */ public void removeAMessageFromTop(StoreContext storeContext) throws AMQException @@ -318,11 +353,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (msg != null) { // mark this message as taken and get it removed - msg.taken(); + msg.taken(null); _queue.dequeue(storeContext, msg); getNextMessage(); } - + _lock.unlock(); } @@ -335,7 +370,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager while (msg != null) { //mark this message as taken and get it removed - msg.taken(); + msg.taken(null); _queue.dequeue(storeContext, msg); msg = getNextMessage(); count++; @@ -347,20 +382,15 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public synchronized AMQMessage getNextMessage() throws AMQException { - return getNextMessage(_messages); + return getNextMessage(_messages, null); } - - private AMQMessage getNextMessage(Queue messages) - { - return getNextMessage(messages, false); - } - - private AMQMessage getNextMessage(Queue messages, boolean browsing) + private AMQMessage getNextMessage(Queue messages, Subscription sub) { AMQMessage message = messages.peek(); - while (message != null && (browsing || message.taken())) + + while (message != null && ((sub == null || sub.isBrowser()) || message.taken(sub))) { //remove the already taken message messages.poll(); @@ -371,27 +401,76 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return message; } - public void sendNextMessage(Subscription sub, Queue messageQueue) + public void sendNextMessage(Subscription sub, AMQQueue queue)//Queue messageQueue) { + + Queue messageQueue = sub.getNextQueue(_messages); + + if (_log.isTraceEnabled()) + { + _log.trace("Async sendNextMessage for sub (" + System.identityHashCode(sub) + + ") from queue (" + System.identityHashCode(messageQueue) + + ") AMQQueue (" + System.identityHashCode(queue) + ")"); + } + + if (messageQueue == null) + { + // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector + if (_log.isDebugEnabled()) + { + _log.debug(sub + ": asked to send messages but has none on given queue:" + queue); + } + return; + } + AMQMessage message = null; try { - message = getNextMessage(messageQueue, sub.isBrowser()); + message = getNextMessage(messageQueue, sub); // message will be null if we have no messages in the messageQueue. if (message == null) { + if (_log.isTraceEnabled()) + { + _log.trace("No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); + } return; } if (_log.isDebugEnabled()) { - _log.debug("Async Delivery Message:" + message + " to :" + sub); + _log.debug("Async Delivery Message (" + System.identityHashCode(message) + + ") by :" + System.identityHashCode(this) + + ") to :" + System.identityHashCode(sub)); } sub.send(message, _queue); //remove sent message from our queue. messageQueue.poll(); + //If we don't remove the message from _messages + // Otherwise the Async send will never end + + if (messageQueue == sub.getResendQueue()) + { + if (_log.isTraceEnabled()) + { + _log.trace("All messages sent from resendQueue for " + sub); + } + if (messageQueue.isEmpty()) + { + subscriberHasPendingResend(false, sub, null); + //better to use the above method as this keeps all the tracking in one location. +// _hasContent.remove(sub); + } + + _extraMessages.decrementAndGet(); + } + else if (messageQueue == sub.getPreDeliveryQueue()) + { + _log.info("We could do clean up of the main _message queue here"); + } + _totalMessageSize.addAndGet(-message.getSize()); } catch (AMQException e) @@ -403,6 +482,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager /** * enqueues the messages in the list on the queue and all required predelivery queues + * * @param storeContext * @param movedMessageList */ @@ -411,7 +491,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.lock(); for (AMQMessage msg : movedMessageList) { - addMessageToQueue(msg); + addMessageToQueue(msg, true); } // enqueue on the pre delivery queues @@ -422,7 +502,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // Only give the message to those that want them. if (sub.hasInterest(msg)) { - sub.enqueueForPreDelivery(msg); + sub.enqueueForPreDelivery(msg, true); } } } @@ -430,8 +510,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * Only one thread should ever execute this method concurrently, but - * it can do so while other threads invoke deliver(). + * Only one thread should ever execute this method concurrently, but it can do so while other threads invoke + * deliver(). */ private void processQueue() { @@ -444,40 +524,43 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager for (Subscription sub : _subscriptions.getSubscriptions()) { - if (!sub.isSuspended()) + synchronized (sub.getSendLock()) { - sendNextMessage(sub); - - hasSubscribers = true; - } - } - } - } + if (!sub.isSuspended()) + { + sendNextMessage(sub, _queue); - private void sendNextMessage(Subscription sub) - { - if (sub.hasFilters()) - { - sendNextMessage(sub, sub.getPreDeliveryQueue()); - if (sub.isAutoClose()) - { - if (sub.getPreDeliveryQueue().isEmpty()) - { - sub.close(); + hasSubscribers = true; + } } } } - else - { - sendNextMessage(sub, _messages); - } } - public void deliver(StoreContext context, AMQShortString name, AMQMessage msg) throws AMQException +// private void sendNextMessage(Subscription sub) +// { +// if (sub.hasFilters()) +// { +// sendNextMessage(sub, sub.getPreDeliveryQueue()); +// if (sub.isAutoClose()) +// { +// if (sub.getPreDeliveryQueue().isEmpty()) +// { +// sub.close(); +// } +// } +// } +// else +// { +// sendNextMessage(sub, _messages); +// } +// } + + public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException { if (_log.isDebugEnabled()) { - _log.debug(id() + "deliver :" + msg); + _log.debug(id() + "deliver :first(" + deliverFirst + ") :" + msg); } msg.release(); @@ -491,11 +574,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Testing Message(" + msg + ") for Queued Delivery"); + _log.debug(id() + "Testing Message(" + msg + ") for Queued Delivery:" + currentStatus()); } if (!msg.getMessagePublishInfo().isImmediate()) { - addMessageToQueue(msg); + addMessageToQueue(msg, deliverFirst); //release lock now message is on queue. _lock.unlock(); @@ -504,7 +587,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (_log.isDebugEnabled()) { _log.debug(id() + "We have " + _subscriptions.getSubscriptions().size() + - " subscribers to give the message to."); + " subscribers to give the message to:" + currentStatus()); } for (Subscription sub : _subscriptions.getSubscriptions()) { @@ -528,7 +611,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _log.debug(id() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); } - sub.enqueueForPreDelivery(msg); + sub.enqueueForPreDelivery(msg, deliverFirst); } } } @@ -537,14 +620,47 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { //release lock now _lock.unlock(); - - if (_log.isDebugEnabled()) + synchronized (s.getSendLock()) { - _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + - System.identityHashCode(s) + ") :" + s); + if (!s.isSuspended()) + { + if (_log.isDebugEnabled()) + { + _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + + System.identityHashCode(s) + ") :" + s); + } + msg.taken(s); + //Deliver the message + s.send(msg, _queue); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug(id() + " Subscription(" + System.identityHashCode(s) + ") became suspended between nextSubscriber and send"); + } + } + + if (!msg.isTaken()) + { + if (_log.isDebugEnabled()) + { + _log.debug(id() + " Message(" + System.identityHashCode(msg) + ") has not been taken so recursing!:" + + " Subscriber:" + System.identityHashCode(s)); + } + + deliver(context, name, msg, deliverFirst); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug(id() + " Message(" + System.identityHashCode(msg) + + ") has been taken so disregarding deliver request to Subscriber:" + + System.identityHashCode(s)); + } + } } - //Deliver the message - s.send(msg, _queue); } } finally @@ -593,9 +709,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get()); + _log.debug("Processing Async." + currentStatus()); } if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) @@ -608,4 +722,16 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } + private String currentStatus() + { + return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains") + + "(" + _messages.size() + ":" + ((ConcurrentLinkedQueue) _messages).size() + ") " + + " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") + + "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + _processing.get() + + " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains") + + "(" + _messages.size() + ":" + ((ConcurrentLinkedQueue) _messages).size() + ") "; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 27abca012b..5b77951dfd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -32,8 +32,8 @@ import org.apache.qpid.server.store.StoreContext; interface DeliveryManager { /** - * Determines whether there are queued messages. Sets _queueing to false if - * there are no queued messages. This needs to be atomic. + * 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 */ @@ -43,34 +43,34 @@ interface DeliveryManager * This method should not be used to determin if there are messages in the queue. * * @return int The number of messages in the queue + * * @use hasQueuedMessages() for all controls relating to having messages on the queue. */ int getQueueMessageCount(); /** - * Requests that the delivery manager start processing the queue asynchronously - * if there is work that can be done (i.e. there are messages queued up and - * subscribers that can receive them. - *

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

      + * Requests that the delivery manager start processing the queue asynchronously if there is work that can be done + * (i.e. there are messages queued up and subscribers that can receive them.

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

      * * @param executor the executor on which the delivery should take place */ void processAsync(Executor executor); /** - * Handles message delivery. The delivery manager is always in one of two modes; - * it is either queueing messages for asynchronous delivery or delivering - * directly. + * 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 storeContext + * @param name the name of the entity on whose behalf we are delivering the message + * @param msg the message to deliver + * @param deliverFirst * - * @param name the name of the entity on whose behalf we are delivering the message - * @param msg the message to deliver - * @throws org.apache.qpid.server.queue.FailedDequeueException if the message could not be dequeued + * @throws org.apache.qpid.server.queue.FailedDequeueException + * if the message could not be dequeued */ - void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg) throws FailedDequeueException, AMQException; + void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws FailedDequeueException, AMQException; void removeAMessageFromTop(StoreContext storeContext) throws AMQException; @@ -93,4 +93,6 @@ interface DeliveryManager long getTotalMessageSize(); long getOldestMessageArrival(); + + void subscriberHasPendingResend(boolean hasContent, Subscription subscription, AMQMessage msg); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index fa70c6dbac..e9f209839a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -38,13 +38,23 @@ public interface Subscription Queue getPreDeliveryQueue(); - void enqueueForPreDelivery(AMQMessage msg); + Queue getResendQueue(); + + Queue getNextQueue(Queue messages); + + void enqueueForPreDelivery(AMQMessage msg, boolean deliverFirst); boolean isAutoClose(); void close(); + boolean isClosed(); + boolean isBrowser(); boolean wouldSuspend(AMQMessage msg); + + void addToResendQueue(AMQMessage msg); + + Object getSendLock(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java index 6902788fc8..917f7c4e97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -26,16 +26,16 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.protocol.AMQProtocolSession; /** - * 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. + * 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, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal) throws AMQException; + FieldTable filters, boolean noLocal, AMQQueue queue) throws AMQException; Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 6bdfeccc0f..ede7731a06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -21,10 +21,10 @@ package org.apache.qpid.server.queue; import java.util.Queue; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; @@ -37,6 +37,8 @@ import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; +import org.apache.qpid.util.MessageQueue; +import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; /** * Encapsulation of a supscription to a queue.

      Ties together the protocol session of a subscriber, the consumer tag @@ -52,9 +54,11 @@ public class SubscriptionImpl implements Subscription public final AMQShortString consumerTag; - private final Object sessionKey; + private final Object _sessionKey; - private Queue _messages; + private MessageQueue _messages; + + private Queue _resendQueue; private final boolean _noLocal; @@ -63,20 +67,27 @@ public class SubscriptionImpl implements Subscription private FilterManager _filters; private final boolean _isBrowser; private final Boolean _autoClose; - private boolean _closed = false; + private boolean _sentClose = false; + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + private AMQQueue _queue; + private final AtomicBoolean _sendLock = new AtomicBoolean(false); + + public static class Factory implements SubscriptionFactory { - public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) throws AMQException + public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, AMQQueue queue) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal); + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal, queue); } public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) throws AMQException { - return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false); + return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false, null); } } @@ -84,25 +95,27 @@ public class SubscriptionImpl implements Subscription AMQShortString consumerTag, boolean acks) throws AMQException { - this(channelId, protocolSession, consumerTag, acks, null, false); + this(channelId, protocolSession, consumerTag, acks, null, false, null); } public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal) + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, AMQQueue queue) throws AMQException { AMQChannel channel = protocolSession.getChannel(channelId); if (channel == null) - { + { throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); } this.channel = channel; this.protocolSession = protocolSession; this.consumerTag = consumerTag; - sessionKey = protocolSession.getKey(); + _sessionKey = protocolSession.getKey(); _acks = acks; _noLocal = noLocal; + _queue = queue; _filters = FilterManagerFactory.createManager(filters); @@ -145,9 +158,7 @@ public class SubscriptionImpl implements Subscription if (_filters != null) { - _messages = new ConcurrentLinkedQueueAtomicSize(); - - + _messages = new ConcurrentLinkedMessageQueueAtomicSize(); } else { @@ -169,30 +180,47 @@ public class SubscriptionImpl implements Subscription return (o instanceof SubscriptionImpl) && equals((SubscriptionImpl) o); } - /** Equality holds if the session matches and the channel and consumer tag are the same. */ + /** + * Equality holds if the session matches and the channel and consumer tag are the same. + * + * @param psc The subscriptionImpl to compare + * + * @return equality + */ private boolean equals(SubscriptionImpl psc) { - return sessionKey.equals(psc.sessionKey) + return _sessionKey.equals(psc._sessionKey) && psc.channel == channel && psc.consumerTag.equals(consumerTag); } public int hashCode() { - return sessionKey.hashCode(); + return _sessionKey.hashCode(); } public String toString() { - return "[channel=" + channel + ", consumerTag=" + consumerTag + ", session=" + protocolSession.getKey() + "]"; + String subscriber = "[channel=" + channel + + ", consumerTag=" + consumerTag + + ", session=" + protocolSession.getKey() + + ", resendQueue=" + (_resendQueue != null); + + if (_resendQueue != null) + { + subscriber += ", resendSize=" + _resendQueue.size(); + } + + + return subscriber + "]"; } /** * 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 + * @param msg The message to send + * @param queue the Queue it has been sent from * * @throws AMQException */ @@ -278,7 +306,18 @@ public class SubscriptionImpl implements Subscription public boolean isSuspended() { - return channel.isSuspended(); + if (_logger.isTraceEnabled()) + { + if (channel.isSuspended()) + { + _logger.trace("Subscription(" + System.identityHashCode(this) + ") channel's is susupended"); + } + if (_sendLock.get()) + { + _logger.trace("Subscription(" + System.identityHashCode(this) + ") has sendLock set so closing."); + } + } + return channel.isSuspended() || _sendLock.get(); } /** @@ -376,11 +415,18 @@ public class SubscriptionImpl implements Subscription return _messages; } - public void enqueueForPreDelivery(AMQMessage msg) + public void enqueueForPreDelivery(AMQMessage msg, boolean deliverFirst) { if (_messages != null) { - _messages.offer(msg); + if (deliverFirst) + { + _messages.pushHead(msg); + } + else + { + _messages.offer(msg); + } } } @@ -391,19 +437,95 @@ public class SubscriptionImpl implements Subscription public void close() { - if (!_closed) + synchronized (_sendLock) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Setting SendLock true"); + } + + _sendLock.set(true); + + } + if (_logger.isInfoEnabled()) + { + _logger.info("Closing subscription (" + System.identityHashCode(this) + "):" + this); + } + + if (_resendQueue != null && !_resendQueue.isEmpty()) + { + requeue(); + } + + //remove references in PDQ + if (_messages != null) + { + _messages.clear(); + } + + if (_autoClose && !_sentClose) { _logger.info("Closing autoclose subscription:" + this); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), + (byte) 8, (byte) 0, // AMQP version (major, minor) consumerTag // consumerTag )); - _closed = true; + _sentClose = true; + } + } + + private void requeue() + { + if (_queue != null) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Requeuing :" + _resendQueue.size() + " messages"); + } + + while (!_resendQueue.isEmpty()) + { + AMQMessage resent = _resendQueue.poll(); + + resent.release(); + _queue.subscriberHasPendingResend(false, this, resent); + + try + { + channel.getTransactionalContext().deliver(resent, _queue, true); + } + catch (AMQException e) + { + _logger.error("Unable to re-deliver messages", e); + } + } + + if (!_resendQueue.isEmpty()) + { + _logger.error("[MESSAGES LOST]Unable to re-deliver messages as queue is null."); + } + + _queue.subscriberHasPendingResend(false, this, null); } + else + { + if (!_resendQueue.isEmpty()) + { + _logger.error("Unable to re-deliver messages as queue is null."); + } + } + + // Clear the messages + _resendQueue = null; + } + + + public boolean isClosed() + { + return _sendLock.get(); // This rather than _close is used to signify the subscriber is now closed. } public boolean isBrowser() @@ -416,5 +538,61 @@ public class SubscriptionImpl implements Subscription return channel.wouldSuspend(msg); } + public Queue getResendQueue() + { + if (_resendQueue == null) + { + _resendQueue = new ConcurrentLinkedQueueAtomicSize(); + } + return _resendQueue; + } + + + public Queue getNextQueue(Queue messages) + { + if (_resendQueue != null && !_resendQueue.isEmpty()) + { + return _resendQueue; + } + + if (_filters != null) + { + if (isAutoClose()) + { + if (_messages.isEmpty()) + { + close(); + return null; + } + } + return _messages; + } + else // we want the DM queue + { + return messages; + } + } + + public void addToResendQueue(AMQMessage msg) + { + // add to our resend queue + getResendQueue().add(msg); + + // Mark Queue has having content. + if (_queue == null) + { + _logger.error("Queue is null won't be able to resend messages"); + } + else + { + _queue.subscriberHasPendingResend(true, this, msg); + } + } + + public Object getSendLock() + { + return _sendLock; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index 871f063725..26b040aae0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -27,27 +27,20 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -/** - * Holds a set of subscriptions for a queue and manages the round - * robin-ing of deliver etc. - */ +/** 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 - */ + /** List of registered subscribers */ private List _subscriptions = new CopyOnWriteArrayList(); - /** - * Used to control the round robin delivery of content - */ + /** Used to control the round robin delivery of content */ private int _currentSubscriber; + private final Object _subscriptionsChange = new Object(); - /** - * Accessor for unit tests. - */ + + /** Accessor for unit tests. */ int getCurrentSubscriber() { return _currentSubscriber; @@ -55,21 +48,43 @@ class SubscriptionSet implements WeightedSubscriptionManager public void addSubscriber(Subscription subscription) { - _subscriptions.add(subscription); + synchronized (_subscriptionsChange) + { + _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) + // TODO: possibly need O(1) operation here. + + Subscription sub = null; + synchronized (_subscriptionsChange) { - return subscription; + int subIndex = _subscriptions.indexOf(subscription); + + if (subIndex != -1) + { + //we can't just return the passed in subscription as it is a new object + // and doesn't contain the stored state we need. + //NOTE while this may be removed now anyone with an iterator will still have it in the list!! + sub = _subscriptions.remove(subIndex); + } + else + { + _log.error("Unable to remove from index(" + subIndex + ")subscription:" + subscription); + } + } + if (sub != null) + { + return sub; } else { @@ -92,14 +107,11 @@ class SubscriptionSet implements WeightedSubscriptionManager } /** - * 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. + * 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) { @@ -156,9 +168,7 @@ class SubscriptionSet implements WeightedSubscriptionManager return null; } - /** - * Overridden in test classes. - */ + /** Overridden in test classes. */ protected void subscriberScanned() { } @@ -199,8 +209,8 @@ class SubscriptionSet implements WeightedSubscriptionManager } /** - * 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. + * 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 */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 29efdd9513..d12f5cd084 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -55,6 +55,7 @@ import org.apache.qpid.framing.QueuePurgeBody; import org.apache.qpid.framing.TxCommitBody; import org.apache.qpid.framing.TxRollbackBody; import org.apache.qpid.framing.TxSelectBody; +import org.apache.qpid.framing.BasicRejectBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.handler.BasicAckMethodHandler; @@ -82,8 +83,9 @@ import org.apache.qpid.server.handler.QueueDeclareHandler; import org.apache.qpid.server.handler.QueueDeleteHandler; import org.apache.qpid.server.handler.QueuePurgeHandler; import org.apache.qpid.server.handler.TxCommitHandler; -import org.apache.qpid.server.handler.TxRollbackHandler; +import org.apache.qpid.server.handler.BasicRejectMethodHandler; import org.apache.qpid.server.handler.TxSelectHandler; +import org.apache.qpid.server.handler.TxRollbackHandler; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -173,6 +175,7 @@ public class AMQStateManager implements AMQMethodListener frame2handlerMap.put(TxSelectBody.class, TxSelectHandler.getInstance()); frame2handlerMap.put(TxCommitBody.class, TxCommitHandler.getInstance()); frame2handlerMap.put(TxRollbackBody.class, TxRollbackHandler.getInstance()); + frame2handlerMap.put(BasicRejectBody.class, BasicRejectMethodHandler.getInstance()); _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java deleted file mode 100644 index 4dff514ff4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DeliverMessageOperation.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.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; -import org.apache.qpid.server.store.StoreContext; - -/** - * @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(StoreContext context) throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit(StoreContext context) throws AMQException - { - //do the memeory part of the record() - _msg.incrementReference(); - //then process the message - try - { - _queue.process(context, _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(StoreContext storeContext) - { - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 5c915b5c84..e5cce672f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -31,9 +31,7 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -/** - * A transactional context that only supports local transactions. - */ +/** A transactional context that only supports local transactions. */ public class LocalTransactionalContext implements TransactionalContext { private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); @@ -62,12 +60,14 @@ public class LocalTransactionalContext implements TransactionalContext { public AMQMessage message; public AMQQueue queue; + private boolean deliverFirst; - public DeliveryDetails(AMQMessage message, AMQQueue queue) + public DeliveryDetails(AMQMessage message, AMQQueue queue, boolean deliverFirst) { this.message = message; this.queue = queue; + this.deliverFirst = deliverFirst; } } @@ -89,9 +89,10 @@ public class LocalTransactionalContext implements TransactionalContext public void rollback() throws AMQException { _txnBuffer.rollback(_storeContext); + _postCommitDeliveryList.clear(); } - public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException { // A publication will result in the enlisting of several // TxnOps. The first is an op that will store the message. @@ -100,7 +101,7 @@ public class LocalTransactionalContext implements TransactionalContext // enqueued. Finally a cleanup op will be added to decrement // the reference associated with the routing. message.incrementReference(); - _postCommitDeliveryList.add(new DeliveryDetails(message, queue)); + _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); _messageDelivered = true; /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); if (_log.isDebugEnabled()) @@ -225,7 +226,7 @@ public class LocalTransactionalContext implements TransactionalContext { for (DeliveryDetails dd : _postCommitDeliveryList) { - dd.queue.process(_storeContext, dd.message); + dd.queue.process(_storeContext, dd.message, dd.deliverFirst); } } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index c7f3a0f0f1..19146da22e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -34,21 +34,15 @@ import org.apache.qpid.server.queue.NoConsumersException; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -/** - * @author Apache Software Foundation - */ +/** @author Apache Software Foundation */ public class NonTransactionalContext implements TransactionalContext { private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - /** - * Channel is useful for logging - */ + /** Channel is useful for logging */ private final AMQChannel _channel; - /** - * Where to put undeliverable messages - */ + /** Where to put undeliverable messages */ private final List _returnMessages; private Set _browsedAcks; @@ -57,9 +51,7 @@ public class NonTransactionalContext implements TransactionalContext private StoreContext _storeContext; - /** - * Whether we are in a transaction - */ + /** Whether we are in a transaction */ private boolean _inTran; public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, @@ -97,12 +89,12 @@ public class NonTransactionalContext implements TransactionalContext // Does not apply to this context } - public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException { try { message.incrementReference(); - queue.process(_storeContext, message); + queue.process(_storeContext, message, deliverFirst); //following check implements the functionality //required by the 'immediate' flag: message.checkDeliveredToConsumer(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index 59d9117fda..88451e2fca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -38,7 +38,7 @@ public interface TransactionalContext void rollback() throws AMQException; - void deliver(AMQMessage message, AMQQueue queue) throws AMQException; + void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException; void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; -- cgit v1.2.1 From 2e9743ac06fc05609155769bf04f4fa442d848c2 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 25 Feb 2007 01:08:57 +0000 Subject: QPID-391 : Broker Refactoring - initial tidy... add some mechanisms for multi version git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@511389 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 9 +- .../src/main/java/org/apache/qpid/server/Main.java | 24 +- .../server/ack/UnacknowledgedMessageMapImpl.java | 2 +- .../qpid/server/filter/PropertyExpression.java | 31 ++- .../server/output/ProtocolOutputConverter.java | 57 ++++ .../output/ProtocolOutputConverterRegistry.java | 62 +++++ .../amqp0_8/ProtocolOutputConverterImpl.java | 288 +++++++++++++++++++++ .../server/protocol/AMQMinaProtocolSession.java | 254 +++++++++--------- .../protocol/AMQNoMethodHandlerException.java | 34 +++ .../server/protocol/AMQPFastProtocolHandler.java | 15 +- .../qpid/server/protocol/AMQProtocolSession.java | 3 + .../server/protocol/AMQProtocolSessionMBean.java | 7 +- .../protocol/UnknnownMessageTypeException.java | 33 +++ .../org/apache/qpid/server/queue/AMQMessage.java | 40 ++- .../apache/qpid/server/queue/AMQQueueMBean.java | 13 +- .../queue/ConcurrentSelectorDeliveryManager.java | 3 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 16 +- .../qpid/server/store/ContentChunkAdapter.java | 57 ---- .../server/store/MessagePublishInfoAdapter.java | 62 ----- 19 files changed, 700 insertions(+), 310 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 7ceb3a7eef..be2cee79ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -433,7 +433,10 @@ public class AMQChannel } - /** Called to resend all outstanding unacknowledged messages to this same channel. */ + /** Called to resend all outstanding unacknowledged messages to this same channel. + * @param session the session + * @param requeue if true then requeue, else resend + * @throws org.apache.qpid.AMQException */ public void resend(final AMQProtocolSession session, final boolean requeue) throws AMQException { final List msgToRequeue = new LinkedList(); @@ -752,7 +755,9 @@ public class AMQChannel for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); - message.writeReturn(session, _channelId, bouncedMessage.getReplyCode().getCode(), new AMQShortString(bouncedMessage.getMessage())); + session.getProtocolOutputConverter().writeReturn(message, _channelId, + bouncedMessage.getReplyCode().getCode(), + new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 42fe8c5274..a48bc5df7f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -45,7 +45,7 @@ import org.apache.mina.common.SimpleByteBufferAllocator; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; @@ -59,7 +59,8 @@ import org.apache.qpid.url.URLSyntaxException; * Main entry point for AMQPD. * */ -public class Main implements ProtocolVersionList +@SuppressWarnings({"AccessStaticViaInstance"}) +public class Main { private static final Logger _logger = Logger.getLogger(Main.class); @@ -143,12 +144,21 @@ public class Main implements ProtocolVersionList 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]; + if(first) + { + first = false; + } + else + { + protocol.append(", "); + } + protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); + } System.out.println(ver + " (" + protocol + ")"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index fdf087fdea..99cc60011a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -209,7 +209,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap if(consumerTag != null) { - msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channelId, deliveryTag, consumerTag); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 348bfa5e68..bdabcbf5be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -25,7 +25,8 @@ import java.util.HashMap; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQMessage; /** @@ -63,8 +64,9 @@ public class PropertyExpression implements Expression { try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getReplyTo(); + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + AMQShortString replyTo = _properties.getReplyTo(); + return replyTo == null ? null : replyTo.toString(); } catch (AMQException e) { @@ -83,8 +85,9 @@ public class PropertyExpression implements Expression { try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getType(); + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + AMQShortString type = _properties.getType(); + return type == null ? null : type.toString(); } catch (AMQException e) { @@ -126,7 +129,7 @@ public class PropertyExpression implements Expression { try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; return (int) _properties.getPriority(); } catch (AMQException e) @@ -147,8 +150,9 @@ public class PropertyExpression implements Expression try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getMessageId(); + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + AMQShortString messageId = _properties.getMessageId(); + return messageId == null ? null : messageId; } catch (AMQException e) { @@ -168,7 +172,7 @@ public class PropertyExpression implements Expression try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; return _properties.getTimestamp(); } catch (AMQException e) @@ -189,8 +193,9 @@ public class PropertyExpression implements Expression try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getCorrelationId(); + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + AMQShortString correlationId = _properties.getCorrelationId(); + return correlationId == null ? null : correlationId.toString(); } catch (AMQException e) { @@ -210,7 +215,7 @@ public class PropertyExpression implements Expression try { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; return _properties.getExpiration(); } catch (AMQException e) @@ -254,7 +259,7 @@ public class PropertyExpression implements Expression else { - BasicContentHeaderProperties _properties = (BasicContentHeaderProperties) message.getContentHeaderBody().properties; + CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; if(_logger.isDebugEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java new file mode 100644 index 0000000000..e01c5aabbf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public interface ProtocolOutputConverter +{ + void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); + + interface Factory + { + ProtocolOutputConverter newInstance(AMQProtocolSession session); + } + + void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException; + + void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + + byte getProtocolMinorVersion(); + + byte getProtocolMajorVersion(); + + void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException; + + void writeFrame(AMQDataBlock block); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java new file mode 100644 index 0000000000..8366c426dd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -0,0 +1,62 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; +import org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +import java.util.Map; +import java.util.HashMap; + +public class ProtocolOutputConverterRegistry +{ + + private static final Map> _registry = + new HashMap>(); + + + static + { + register((byte) 8, (byte) 0, ProtocolOutputConverterImpl.getInstanceFactory()); + } + + private static void register(byte major, byte minor, Factory converter) + { + if(!_registry.containsKey(major)) + { + _registry.put(major, new HashMap()); + } + _registry.get(major).put(minor, converter); + } + + + public static ProtocolOutputConverter getConverter(AMQProtocolSession session) + { + return _registry.get(session.getProtocolMajorVersion()).get(session.getProtocolMinorVersion()).newInstance(session); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java new file mode 100644 index 0000000000..bd5bb632fe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -0,0 +1,288 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + ByteBuffer deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext,messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + ByteBuffer deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + private ByteBuffer createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, getProtocolMajorVersion(), + getProtocolMinorVersion(), + consumerTag, + deliveryTag, pb.getExchange(), messageHandle.isRedelivered(), + pb.getRoutingKey()); + + ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? + deliverFrame.writePayload(buf); + buf.flip(); + return buf; + } + + private ByteBuffer createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, + getProtocolMajorVersion(), + getProtocolMinorVersion(), + deliveryTag, pb.getExchange(), + queueSize, + messageHandle.isRedelivered(), + pb.getRoutingKey()); + ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? + getOkFrame.writePayload(buf); + buf.flip(); + return buf; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private ByteBuffer createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, + getProtocolMajorVersion(), + getProtocolMinorVersion(), + message.getMessagePublishInfo().getExchange(), + replyCode, replyText, + message.getMessagePublishInfo().getRoutingKey()); + ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? + returnFrame.writePayload(buf); + buf.flip(); + return buf; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + ByteBuffer returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, headerAndFirstContent); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, + new AMQDataBlock[]{contentHeader}); + + 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()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + writeFrame(BasicCancelOkBody.createAMQFrame(channelId, + getProtocolMajorVersion(), + getProtocolMinorVersion(), + consumerTag // consumerTag + )); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 2de32c2f0f..d71f6e3046 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -43,25 +43,14 @@ import org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionStartBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MainRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersionList; -import org.apache.qpid.framing.VersionSpecificRegistry; -import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.*; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -71,7 +60,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public class AMQMinaProtocolSession implements AMQProtocolSession, - ProtocolVersionList, Managable { private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); @@ -111,12 +99,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private long _maxNoOfChannels = 1000; /* AMQP Version for this session */ - private byte _major = pv[pv.length - 1][PROTOCOL_MAJOR]; - private byte _minor = pv[pv.length - 1][PROTOCOL_MINOR]; + private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); + private FieldTable _clientProperties; private final List _taskList = new CopyOnWriteArrayList(); - private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(pv[pv.length - 1][PROTOCOL_MAJOR], pv[pv.length - 1][PROTOCOL_MINOR]); + private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); private List _closingChannelsList = new ArrayList(); + private ProtocolOutputConverter _protocolOutputConverter; public ManagedObject getManagedObject() @@ -195,86 +184,116 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _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 + protocolInitiationReceived((ProtocolInitiation) message); - // This sets the protocol version (and hence framing classes) for this session. - setProtocolVersion(pi.protocolMajor, pi.protocolMinor); + } + else if (message instanceof AMQFrame) + { + AMQFrame frame = (AMQFrame) message; + frameReceived(frame); - String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + } + else + { + throw new UnknnownMessageTypeException(message); + } + } - String locales = "en_US"; + private void frameReceived(AMQFrame frame) + throws AMQException + { + int channelId = frame.getChannel(); + AMQBody body = frame.getBodyFrame(); - // Interfacing with generated code - be aware of possible changes to parameter order as versions change. - AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, - _major, _minor, // AMQP version (major, minor) - locales.getBytes(), // locales - mechanisms.getBytes(), // mechanisms - null, // serverProperties - (short) _major, // versionMajor - (short) _minor); // versionMinor - _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?) - // ritchiem 2006-12-04 will this not do? -// WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); -// future.join(); -// close connection + if(_logger.isDebugEnabled()) + { + _logger.debug("Frame Received: " + frame); + } - } + if (body instanceof AMQMethodBody) + { + methodFrameReceived(channelId, (AMQMethodBody)body); + } + else if (body instanceof ContentHeaderBody) + { + contentHeaderReceived(channelId, (ContentHeaderBody)body); + } + else if (body instanceof ContentBody) + { + contentBodyReceived(channelId, (ContentBody)body); + } + else if (body instanceof HeartbeatBody) + { + // NO OP } else { - AMQFrame frame = (AMQFrame) message; - - if (frame.getBodyFrame() instanceof AMQMethodBody) - { - methodFrameReceived(frame); - } - else - { - contentFrameReceived(frame); - } + _logger.warn("Unrecognised frame " + frame.getClass().getName()); } } - private void methodFrameReceived(AMQFrame frame) + private void protocolInitiationReceived(ProtocolInitiation pi) { - if (_logger.isDebugEnabled()) + // this ensures the codec never checks for a PI message again + ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); + try { - _logger.debug("Method frame received: " + frame); + pi.checkVersion(); // Fails if not correct + + // This sets the protocol version (and hence framing classes) for this session. + setProtocolVersion(pi._protocolMajor, pi._protocolMinor); + + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + + String locales = "en_US"; + + // Interfacing with generated code - be aware of possible changes to parameter order as versions change. + AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, + getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor) + locales.getBytes(), // locales + mechanisms.getBytes(), // mechanisms + null, // serverProperties + (short) getProtocolMajorVersion(), // versionMajor + (short) getProtocolMinorVersion()); // versionMinor + _minaProtocolSession.write(response); + } + catch (AMQException e) + { + _logger.error("Received incorrect protocol initiation", e); + + _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + + // TODO: Close connection (but how to wait until message is sent?) + // ritchiem 2006-12-04 will this not do? +// WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); +// future.join(); +// close connection + } + } + - final AMQMethodEvent evt = new AMQMethodEvent(frame.getChannel(), - (AMQMethodBody) frame.getBodyFrame()); + private void methodFrameReceived(int channelId, AMQMethodBody methodBody) + { + + final AMQMethodEvent evt = new AMQMethodEvent(channelId, + methodBody); //Check that this channel is not closing - if (channelAwaitingClosure(frame.getChannel())) + if (channelAwaitingClosure(channelId)) { if ((evt.getMethod() instanceof ChannelCloseOkBody)) { if (_logger.isInfoEnabled()) { - _logger.info("Channel[" + frame.getChannel() + "] awaiting closure - processing close-ok"); + _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); } } else { if (_logger.isInfoEnabled()) { - _logger.info("Channel[" + frame.getChannel() + "] awaiting closure ignoring"); + _logger.info("Channel[" + channelId + "] awaiting closure ignoring"); } return; } @@ -298,19 +317,19 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } if (!wasAnyoneInterested) { - throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + throw new AMQNoMethodHandlerException(evt); } } catch (AMQChannelException e) { - if (getChannel(frame.getChannel()) != null) + if (getChannel(channelId) != null) { if (_logger.isInfoEnabled()) { _logger.info("Closing channel due to: " + e.getMessage()); } - writeFrame(e.getCloseFrame(frame.getChannel())); - closeChannel(frame.getChannel()); + writeFrame(e.getCloseFrame(channelId)); + closeChannel(channelId); } else { @@ -328,7 +347,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, AMQConstant.CHANNEL_ERROR.getName().toString()); _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(ce.getCloseFrame(frame.getChannel())); + writeFrame(ce.getCloseFrame(channelId)); } } catch (AMQConnectionException e) @@ -339,7 +358,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } closeSession(); _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(e.getCloseFrame(frame.getChannel())); + writeFrame(e.getCloseFrame(channelId)); } } catch (Exception e) @@ -353,61 +372,21 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } } - private void contentFrameReceived(AMQFrame frame) throws AMQException - { - if (frame.getBodyFrame() instanceof ContentHeaderBody) - { - contentHeaderReceived(frame); - } - else if (frame.getBodyFrame() instanceof ContentBody) - { - contentBodyReceived(frame); - } - else if (frame.getBodyFrame() instanceof HeartbeatBody) - { - _logger.debug("Received heartbeat from client"); - } - else - { - _logger.warn("Unrecognised frame " + frame.getClass().getName()); - } - } - private void contentHeaderReceived(AMQFrame frame) throws AMQException + private void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException { - if (_logger.isDebugEnabled()) - { - _logger.debug("Content header frame received: " + frame); - } - AMQChannel channel = getChannel(frame.getChannel()); + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentHeader(body); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + frame.getChannel()); - } - else - { - channel.publishContentHeader((ContentHeaderBody) frame.getBodyFrame()); - } } - private void contentBodyReceived(AMQFrame frame) throws AMQException + private void contentBodyReceived(int channelId, ContentBody body) throws AMQException { - if (_logger.isDebugEnabled()) - { - _logger.debug("Content body frame received: " + frame); - } - AMQChannel channel = getChannel(frame.getChannel()); + AMQChannel channel = getAndAssertChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + frame.getChannel()); - } - else - { - channel.publishContentBody((ContentBody) frame.getBodyFrame(), this); - } + channel.publishContentBody(body, this); } /** @@ -437,6 +416,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return new ArrayList(_channelMap.values()); } + public AMQChannel getAndAssertChannel(int channelId) throws AMQException + { + AMQChannel channel = getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); + } + return channel; + } + public AMQChannel getChannel(int channelId) throws AMQException { if (channelAwaitingClosure(channelId)) @@ -685,24 +674,26 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private void setProtocolVersion(byte major, byte minor) { - _major = major; - _minor = minor; - _registry = MainRegistry.getVersionSpecificRegistry(major, minor); + _protocolVersion = new ProtocolVersion(major,minor); + + _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); + + _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); } public byte getProtocolMajorVersion() { - return _major; + return _protocolVersion.getMajorVersion(); } public byte getProtocolMinorVersion() { - return _minor; + return _protocolVersion.getMinorVersion(); } public boolean isProtocolVersion(byte major, byte minor) { - return _major == major && _minor == minor; + return getProtocolMajorVersion() == major && getProtocolMinorVersion() == minor; } public VersionSpecificRegistry getRegistry() @@ -739,5 +730,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, _taskList.remove(task); } + public ProtocolOutputConverter getProtocolOutputConverter() + { + return _protocolOutputConverter; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java new file mode 100644 index 0000000000..16d74b6fc0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.AMQException; + +public class AMQNoMethodHandlerException extends AMQException +{ + + public AMQNoMethodHandlerException(AMQMethodEvent evt) + { + super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 9d397505dc..756a8b5ebe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -39,7 +39,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.HeartbeatBody; import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; @@ -53,7 +53,7 @@ import org.apache.qpid.ssl.SSLContextFactory; * the state for the connection. * */ -public class AMQPFastProtocolHandler extends IoHandlerAdapter implements ProtocolVersionList +public class AMQPFastProtocolHandler extends IoHandlerAdapter { private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); @@ -162,12 +162,11 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco 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.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + protocolSession.close(); + _logger.error("Error in protocol initiation " + session + ": " + throwable.getMessage(), throwable); } else if(throwable instanceof IOException) @@ -176,8 +175,6 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter implements Protoco } else { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.write(ConnectionCloseBody.createAMQFrame(0, session.getProtocolMajorVersion(), diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 503dc8b554..4cfee06850 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -28,6 +28,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -162,4 +163,6 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession void removeSessionCloseTask(Task task); + public ProtocolOutputConverter getProtocolOutputConverter(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index ea89136a62..d2a20cdf57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -24,6 +24,7 @@ import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; +import javax.management.NotCompliantMBeanException; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -65,7 +66,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed new AMQShortString("Broker Management Console has closed the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws JMException + public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException { super(ManagedConnection.class, ManagedConnection.TYPE); _session = session; @@ -74,6 +75,8 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed _name = jmxEncode(new StringBuffer(remote), 0).toString(); init(); } + + static { try @@ -94,7 +97,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, - _channelAtttibuteNames, _channelAttributeTypes); + _channelAtttibuteNames, _channelAttributeTypes); _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java new file mode 100644 index 0000000000..45d09e8f3e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public class UnknnownMessageTypeException extends AMQException +{ + public UnknnownMessageTypeException(AMQDataBlock message) + { + super("Unknown message type: " + message.getClass().getName() + ": " + message); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index aa7ea16afc..dedea68d18 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,23 +20,34 @@ */ package org.apache.qpid.server.queue; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.txn.TransactionalContext; /** Combines the information that make up a deliverable message into a more manageable form. */ + +import org.apache.log4j.Logger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +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); @@ -136,7 +147,7 @@ public class AMQMessage } } - private StoreContext getStoreContext() + public StoreContext getStoreContext() { return _txnContext.getStoreContext(); } @@ -579,6 +590,7 @@ public class AMQMessage } } +/* public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { @@ -746,6 +758,12 @@ public class AMQMessage protocolSession.writeFrame(bodyFrameIterator.next()); } } +*/ + + public AMQMessageHandle getMessageHandle() + { + return _messageHandle; + } public long getSize() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 4fd89f39da..c9329a244c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -41,9 +41,9 @@ import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -344,12 +344,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que try { // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) msg.getContentHeaderBody().properties; + CommonContentHeaderProperties headerProperties = (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; String mimeType = null, encoding = null; if (headerProperties != null) { - mimeType = headerProperties.getContentType(); - encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + AMQShortString mimeTypeShortSting = headerProperties.getContentType(); + mimeType = mimeTypeShortSting == null ? null : mimeTypeShortSting.toString(); + encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding().toString(); } Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); @@ -382,7 +383,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que AMQMessage msg = list.get(i - 1); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + CommonContentHeaderProperties headerProperties = (CommonContentHeaderProperties) headerBody.properties; String[] headerAttributes = headerProperties.toString().split(","); Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 208a59516c..e70926736d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -270,7 +270,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager channel.addUnacknowledgedMessage(msg, deliveryTag, null, _queue); } - msg.writeGetOk(protocolSession, channel.getChannelId(), deliveryTag, _queue.getMessageCount()); + protocolSession.getProtocolOutputConverter().writeGetOk(msg, channel.getChannelId(), + deliveryTag, _queue.getMessageCount()); _totalMessageSize.addAndGet(-msg.getSize()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index ede7731a06..0a2e73880c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -29,9 +29,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicCancelOkBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -258,7 +258,7 @@ public class SubscriptionImpl implements Subscription { channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); } - msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); } } @@ -294,7 +294,7 @@ public class SubscriptionImpl implements Subscription msg.decrementReference(storeContext); } - msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); } } @@ -466,13 +466,9 @@ public class SubscriptionImpl implements Subscription if (_autoClose && !_sentClose) { _logger.info("Closing autoclose subscription:" + this); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - protocolSession.writeFrame(BasicCancelOkBody.createAMQFrame(channel.getChannelId(), - (byte) 8, (byte) 0, // AMQP version (major, minor) - consumerTag // consumerTag - )); + ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag); + _sentClose = true; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java deleted file mode 100644 index 90aa7bb998..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ContentChunkAdapter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.abstraction.ContentChunk; - -import org.apache.mina.common.ByteBuffer; - -public class ContentChunkAdapter -{ - public static ContentBody toConentBody(ContentChunk contentBodyChunk) - { - return new ContentBody(contentBodyChunk.getData()); - } - - public static ContentChunk toConentChunk(final ContentBody contentBodyChunk) - { - return new ContentChunk() { - - public int getSize() - { - return contentBodyChunk.getSize(); - } - - public ByteBuffer getData() - { - return contentBodyChunk.payload; - } - - public void reduceToFit() - { - contentBodyChunk.reduceBufferToFit(); - } - }; - - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java deleted file mode 100644 index 6ee2fa784d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessagePublishInfoAdapter.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.apache.qpid.server.store; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -public class MessagePublishInfoAdapter -{ - private final byte _majorVersion; - private final byte _minorVersion; - private final int _classId; - private final int _methodId; - - - public MessagePublishInfoAdapter(byte majorVersion, byte minorVersion) - { - _majorVersion = majorVersion; - _minorVersion = minorVersion; - _classId = BasicPublishBody.getClazz(majorVersion,minorVersion); - _methodId = BasicPublishBody.getMethod(majorVersion,minorVersion); - } - - public BasicPublishBody toMethodBody(MessagePublishInfo pubInfo) - { - return new BasicPublishBody(_majorVersion, - _minorVersion, - _classId, - _methodId, - pubInfo.getExchange(), - pubInfo.isImmediate(), - pubInfo.isMandatory(), - pubInfo.getRoutingKey(), - 0) ; // ticket - } - - public MessagePublishInfo toMessagePublishInfo(final BasicPublishBody body) - { - return new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return body.getExchange(); - } - - public boolean isImmediate() - { - return body.getImmediate(); - } - - public boolean isMandatory() - { - return body.getMandatory(); - } - - public AMQShortString getRoutingKey() - { - return body.getRoutingKey(); - } - }; - } -} -- cgit v1.2.1 From 6db23548c699d2b49e7809b1c3d8c31f863a710b Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 28 Feb 2007 15:52:00 +0000 Subject: QPID-383 (Patch submitted by Tomas Restrepo) ssl_really.patch The set of known response codes in AMQConstant.cs is out of date for the .NET client and is causing compatibility issues with the java broker trunk. Need to synchronize to the spec again. Patch to synchronize the response code values git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@512818 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/server/Main.java | 11 ++++------- .../qpid/server/protocol/AMQPFastProtocolHandler.java | 12 ++++++++++-- .../qpid/server/transport/ConnectorConfiguration.java | 14 +++++++++----- 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index a48bc5df7f..1d26abb63f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -68,9 +68,6 @@ public class Main private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - - private static Main _instance; - protected static class InitException extends Exception { InitException(String msg) @@ -333,8 +330,8 @@ public class Main { sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } - - if (!connectorConfig.enableSSL) + + if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); InetSocketAddress bindAddress; @@ -350,7 +347,7 @@ public class Main _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } - else + if (connectorConfig.enableSSL) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); try @@ -374,7 +371,7 @@ public class Main public static void main(String[] args) { - _instance = new Main(args); + new Main(args); } private byte[] parseIP(String address) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 756a8b5ebe..03c7051aac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.protocol; import java.io.IOException; +import java.net.InetSocketAddress; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; @@ -90,7 +91,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter getConfiguredObject(ConnectorConfiguration.class); if (connectorConfig.enableExecutorPool) { - if (connectorConfig.enableSSL) + if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) { String keystorePath = connectorConfig.keystorePath; String keystorePassword = connectorConfig.keystorePassword; @@ -104,7 +105,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter else { protocolSession.getFilterChain().addLast("protocolFilter", pcf); - if (connectorConfig.enableSSL) + if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) { String keystorePath = connectorConfig.keystorePath; String keystorePassword = connectorConfig.keystorePassword; @@ -228,4 +229,11 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _logger.debug("Message sent: " + object); } } + + protected boolean isSSLClient(ConnectorConfiguration connectionConfig, + IoSession protocolSession) + { + InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); + return addr.getPort() == connectionConfig.sslPort; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java index dc9ad65113..a4ed859fa7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -41,11 +41,7 @@ public class ConnectorConfiguration @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; @@ -74,6 +70,14 @@ public class ConnectorConfiguration defaultValue = "false") public boolean enableSSL; + @Configured(path = "connector.ssl.sslOnly", + defaultValue = "true") + public boolean sslOnly; + + @Configured(path = "connector.ssl.port", + defaultValue = SSL_PORT) + public int sslPort; + @Configured(path = "connector.ssl.keystorePath", defaultValue = "none") public String keystorePath; -- cgit v1.2.1 From c453c6d2813b878e006bbbeee6b86720bbecf0e5 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 1 Mar 2007 14:58:58 +0000 Subject: (Patch submitted by Rupert Smith) Qpid0394.diff Removes revision tags from source files. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@513360 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/filter/ComparisonExpression.java | 517 +++++++++++++-------- .../qpid/server/filter/ConstantExpression.java | 54 ++- .../qpid/server/filter/PropertyExpression.java | 438 ++++++++--------- .../apache/qpid/server/filter/UnaryExpression.java | 315 ++++++++----- 4 files changed, 778 insertions(+), 546 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 99e4dd09ba..cedb8d7ca8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -1,19 +1,22 @@ -/** +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package org.apache.qpid.server.filter; // @@ -29,22 +32,26 @@ import org.apache.qpid.server.queue.AMQMessage; /** * A filter performing a comparison of two objects - * + * * @version $Revision$ */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression +{ - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) { + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) + { return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); } - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) { + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) + { return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); } - static final private HashSet REGEXP_CONTROL_CHARS = new HashSet(); + private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); - static { + static + { REGEXP_CONTROL_CHARS.add(new Character('.')); REGEXP_CONTROL_CHARS.add(new Character('\\')); REGEXP_CONTROL_CHARS.add(new Character('[')); @@ -67,23 +74,28 @@ public abstract class ComparisonExpression extends BinaryExpression implements B REGEXP_CONTROL_CHARS.add(new Character('!')); } - static class LikeExpression extends UnaryExpression implements BooleanExpression { + static class LikeExpression extends UnaryExpression implements BooleanExpression + { Pattern likePattern; /** * @param right */ - public LikeExpression(Expression right, String like, int escape) { + public LikeExpression(Expression right, String like, int escape) + { super(right); StringBuffer regexp = new StringBuffer(like.length() * 2); regexp.append("\\A"); // The beginning of the input - for (int i = 0; i < like.length(); i++) { + for (int i = 0; i < like.length(); i++) + { char c = like.charAt(i); - if (escape == (0xFFFF & c)) { + if (escape == (0xFFFF & c)) + { i++; - if (i >= like.length()) { + if (i >= like.length()) + { // nothing left to escape... break; } @@ -92,20 +104,25 @@ public abstract class ComparisonExpression extends BinaryExpression implements B regexp.append("\\x"); regexp.append(Integer.toHexString(0xFFFF & t)); } - else if (c == '%') { - regexp.append(".*?"); // Do a non-greedy match + else if (c == '%') + { + regexp.append(".*?"); // Do a non-greedy match } - else if (c == '_') { - regexp.append("."); // match one + else if (c == '_') + { + regexp.append("."); // match one } - else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) { + else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) + { regexp.append("\\x"); regexp.append(Integer.toHexString(0xFFFF & c)); } - else { + else + { regexp.append(c); } } + regexp.append("\\z"); // The end of the input likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); @@ -114,351 +131,467 @@ public abstract class ComparisonExpression extends BinaryExpression implements B /** * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() */ - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "LIKE"; } /** * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) */ - public Object evaluate(AMQMessage message) throws AMQException { + public Object evaluate(AMQMessage message) throws AMQException + { Object rv = this.getRight().evaluate(message); - if (rv == null) { + if (rv == null) + { return null; } - if (!(rv instanceof String)) { - return Boolean.FALSE; - //throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); + if (!(rv instanceof String)) + { + return + Boolean.FALSE; + //throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); } return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; } - - public boolean matches(AMQMessage message) throws AMQException { + + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + + return (object != null) && (object == Boolean.TRUE); } } - public static BooleanExpression createLike(Expression left, String right, String escape) { - if (escape != null && escape.length() != 1) { - throw new RuntimeException("The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); + public static BooleanExpression createLike(Expression left, String right, String escape) + { + if ((escape != null) && (escape.length() != 1)) + { + throw new RuntimeException( + "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); } + int c = -1; - if (escape != null) { + if (escape != null) + { c = 0xFFFF & escape.charAt(0); } return new LikeExpression(left, right, c); } - public static BooleanExpression createNotLike(Expression left, String right, String escape) { + public static BooleanExpression createNotLike(Expression left, String right, String escape) + { return UnaryExpression.createNOT(createLike(left, right, escape)); - } - - public static BooleanExpression createInFilter(Expression left, List elements) { - - if( !(left instanceof PropertyExpression) ) - throw new RuntimeException("Expected a property for In expression, got: "+left); - return UnaryExpression.createInExpression((PropertyExpression)left, elements, false); - } - public static BooleanExpression createNotInFilter(Expression left, List elements) { - - if( !(left instanceof PropertyExpression) ) - throw new RuntimeException("Expected a property for In expression, got: "+left); - return UnaryExpression.createInExpression((PropertyExpression)left, elements, true); + public static BooleanExpression createInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); + + } + + public static BooleanExpression createNotInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); } - public static BooleanExpression createIsNull(Expression left) { + public static BooleanExpression createIsNull(Expression left) + { return doCreateEqual(left, ConstantExpression.NULL); } - public static BooleanExpression createIsNotNull(Expression left) { + public static BooleanExpression createIsNotNull(Expression left) + { return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); } - public static BooleanExpression createNotEqual(Expression left, Expression right) { + public static BooleanExpression createNotEqual(Expression left, Expression right) + { return UnaryExpression.createNOT(createEqual(left, right)); } - public static BooleanExpression createEqual(Expression left, Expression right) { - checkEqualOperand(left); - checkEqualOperand(right); - checkEqualOperandCompatability(left, right); - return doCreateEqual(left, right); + public static BooleanExpression createEqual(Expression left, Expression right) + { + checkEqualOperand(left); + checkEqualOperand(right); + checkEqualOperandCompatability(left, right); + + return doCreateEqual(left, right); } - - private static BooleanExpression doCreateEqual(Expression left, Expression right) { - return new ComparisonExpression(left, right) { - public Object evaluate(AMQMessage message) throws AMQException { + private static BooleanExpression doCreateEqual(Expression left, Expression right) + { + return new ComparisonExpression(left, right) + { + + public Object evaluate(AMQMessage message) throws AMQException + { Object lv = left.evaluate(message); Object rv = right.evaluate(message); - + // Iff one of the values is null - if (lv == null ^ rv == null) { + if ((lv == null) ^ (rv == null)) + { return Boolean.FALSE; } - if (lv == rv || lv.equals(rv)) { + + if ((lv == rv) || lv.equals(rv)) + { return Boolean.TRUE; - } - if( lv instanceof Comparable && rv instanceof Comparable ) { - return compare((Comparable)lv, (Comparable)rv); } + + if ((lv instanceof Comparable) && (rv instanceof Comparable)) + { + return compare((Comparable) lv, (Comparable) rv); + } + return Boolean.FALSE; } - protected boolean asBoolean(int answer) { + protected boolean asBoolean(int answer) + { return answer == 0; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "="; } }; } - public static BooleanExpression createGreaterThan(final Expression left, final Expression right) { - checkLessThanOperand(left); - checkLessThanOperand(right); - return new ComparisonExpression(left, right) { - protected boolean asBoolean(int answer) { + public static BooleanExpression createGreaterThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { return answer > 0; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return ">"; } }; } - public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) { - checkLessThanOperand(left); - checkLessThanOperand(right); - return new ComparisonExpression(left, right) { - protected boolean asBoolean(int answer) { + public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { return answer >= 0; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return ">="; } }; } - public static BooleanExpression createLessThan(final Expression left, final Expression right) { - checkLessThanOperand(left); - checkLessThanOperand(right); - return new ComparisonExpression(left, right) { + public static BooleanExpression createLessThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { - protected boolean asBoolean(int answer) { + protected boolean asBoolean(int answer) + { return answer < 0; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "<"; } }; } - public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) { - checkLessThanOperand(left); - checkLessThanOperand(right); - return new ComparisonExpression(left, right) { + public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { - protected boolean asBoolean(int answer) { + protected boolean asBoolean(int answer) + { return answer <= 0; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "<="; } }; } - /** - * Only Numeric expressions can be used in >, >=, < or <= expressions.s - * - * @param expr - */ - public static void checkLessThanOperand(Expression expr ) { - if( expr instanceof ConstantExpression ) { - Object value = ((ConstantExpression)expr).getValue(); - if( value instanceof Number ) - return; - - // Else it's boolean or a String.. - throw new RuntimeException("Value '"+expr+"' cannot be compared."); - } - if( expr instanceof BooleanExpression ) { - throw new RuntimeException("Value '"+expr+"' cannot be compared."); - } - } - - /** - * Validates that the expression can be used in == or <> expression. + /** + * Only Numeric expressions can be used in >, >=, < or <= expressions.s + * + * @param expr + */ + public static void checkLessThanOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value instanceof Number) + { + return; + } + + // Else it's boolean or a String.. + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + + if (expr instanceof BooleanExpression) + { + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + } + + /** + * Validates that the expression can be used in == or <> expression. * Cannot not be NULL TRUE or FALSE litterals. - * - * @param expr - */ - public static void checkEqualOperand(Expression expr ) { - if( expr instanceof ConstantExpression ) { - Object value = ((ConstantExpression)expr).getValue(); - if( value == null ) - throw new RuntimeException("'"+expr+"' cannot be compared."); - } - } - - /** - * - * @param left - * @param right - */ - private static void checkEqualOperandCompatability(Expression left, Expression right) { - if( left instanceof ConstantExpression && right instanceof ConstantExpression ) { - if( left instanceof BooleanExpression && !(right instanceof BooleanExpression) ) - throw new RuntimeException("'"+left+"' cannot be compared with '"+right+"'"); - } - } - - - + * + * @param expr + */ + public static void checkEqualOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value == null) + { + throw new RuntimeException("'" + expr + "' cannot be compared."); + } + } + } + /** + * * @param left * @param right */ - public ComparisonExpression(Expression left, Expression right) { + private static void checkEqualOperandCompatability(Expression left, Expression right) + { + if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) + { + if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) + { + throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); + } + } + } + + /** + * @param left + * @param right + */ + public ComparisonExpression(Expression left, Expression right) + { super(left, right); } public Object evaluate(AMQMessage message) throws AMQException { Comparable lv = (Comparable) left.evaluate(message); - if (lv == null) { + if (lv == null) + { return null; } + Comparable rv = (Comparable) right.evaluate(message); - if (rv == null) { + if (rv == null) + { return null; } + return compare(lv, rv); } - protected Boolean compare(Comparable lv, Comparable rv) { + protected Boolean compare(Comparable lv, Comparable rv) + { Class lc = lv.getClass(); Class rc = rv.getClass(); // If the the objects are not of the same type, // try to convert up to allow the comparison. - if (lc != rc) { - if (lc == Byte.class) { - if (rc == Short.class) { + if (lc != rc) + { + if (lc == Byte.class) + { + if (rc == Short.class) + { lv = new Short(((Number) lv).shortValue()); } - else if (rc == Integer.class) { + else if (rc == Integer.class) + { lv = new Integer(((Number) lv).intValue()); } - else if (rc == Long.class) { + else if (rc == Long.class) + { lv = new Long(((Number) lv).longValue()); } - else if (rc == Float.class) { + else if (rc == Float.class) + { lv = new Float(((Number) lv).floatValue()); } - else if (rc == Double.class) { + else if (rc == Double.class) + { lv = new Double(((Number) lv).doubleValue()); } - else { + else + { return Boolean.FALSE; } - } else if (lc == Short.class) { - if (rc == Integer.class) { + } + else if (lc == Short.class) + { + if (rc == Integer.class) + { lv = new Integer(((Number) lv).intValue()); } - else if (rc == Long.class) { + else if (rc == Long.class) + { lv = new Long(((Number) lv).longValue()); } - else if (rc == Float.class) { + else if (rc == Float.class) + { lv = new Float(((Number) lv).floatValue()); } - else if (rc == Double.class) { + else if (rc == Double.class) + { lv = new Double(((Number) lv).doubleValue()); } - else { + else + { return Boolean.FALSE; } - } else if (lc == Integer.class) { - if (rc == Long.class) { + } + else if (lc == Integer.class) + { + if (rc == Long.class) + { lv = new Long(((Number) lv).longValue()); } - else if (rc == Float.class) { + else if (rc == Float.class) + { lv = new Float(((Number) lv).floatValue()); } - else if (rc == Double.class) { + else if (rc == Double.class) + { lv = new Double(((Number) lv).doubleValue()); } - else { + else + { return Boolean.FALSE; } } - else if (lc == Long.class) { - if (rc == Integer.class) { + else if (lc == Long.class) + { + if (rc == Integer.class) + { rv = new Long(((Number) rv).longValue()); } - else if (rc == Float.class) { + else if (rc == Float.class) + { lv = new Float(((Number) lv).floatValue()); } - else if (rc == Double.class) { + else if (rc == Double.class) + { lv = new Double(((Number) lv).doubleValue()); } - else { + else + { return Boolean.FALSE; } } - else if (lc == Float.class) { - if (rc == Integer.class) { + else if (lc == Float.class) + { + if (rc == Integer.class) + { rv = new Float(((Number) rv).floatValue()); } - else if (rc == Long.class) { + else if (rc == Long.class) + { rv = new Float(((Number) rv).floatValue()); } - else if (rc == Double.class) { + else if (rc == Double.class) + { lv = new Double(((Number) lv).doubleValue()); } - else { + else + { return Boolean.FALSE; } - } - else if (lc == Double.class) { - if (rc == Integer.class) { + } + else if (lc == Double.class) + { + if (rc == Integer.class) + { rv = new Double(((Number) rv).doubleValue()); } - else if (rc == Long.class) { + else if (rc == Long.class) + { rv = new Double(((Number) rv).doubleValue()); } - else if (rc == Float.class) { - rv = new Float(((Number) rv).doubleValue()); + else if (rc == Float.class) + { + rv = new Float(((Number) rv).doubleValue()); } - else { + else + { return Boolean.FALSE; } - } - else + } + else + { return Boolean.FALSE; + } } + return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; } protected abstract boolean asBoolean(int answer); - - public boolean matches(AMQMessage message) throws AMQException { + + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + + return (object != null) && (object == Boolean.TRUE); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index bf0243537d..0e729cc521 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -1,19 +1,22 @@ -/** +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package org.apache.qpid.server.filter; // @@ -27,8 +30,6 @@ import org.apache.qpid.server.queue.AMQMessage; /** * Represents a constant expression - * - * @version $Revision$ */ public class ConstantExpression implements Expression { @@ -43,7 +44,8 @@ public class ConstantExpression implements Expression public boolean matches(AMQMessage message) throws AMQException { Object object = evaluate(message); - return object != null && object == Boolean.TRUE; + + return (object != null) && (object == Boolean.TRUE); } } @@ -74,10 +76,11 @@ public class ConstantExpression implements Expression } long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { value = new Integer(value.intValue()); } + return new ConstantExpression(value); } @@ -85,10 +88,11 @@ public class ConstantExpression implements Expression { Number value = new Long(Long.parseLong(text.substring(2), 16)); long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { value = new Integer(value.intValue()); } + return new ConstantExpression(value); } @@ -96,16 +100,18 @@ public class ConstantExpression implements Expression { Number value = new Long(Long.parseLong(text, 8)); long l = value.longValue(); - if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { value = new Integer(value.intValue()); } + return new ConstantExpression(value); } public static ConstantExpression createFloat(String text) { Number value = new Double(text); + return new ConstantExpression(value); } @@ -133,14 +139,17 @@ public class ConstantExpression implements Expression { return "NULL"; } + if (value instanceof Boolean) { return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; } + if (value instanceof String) { return encodeString((String) value); } + return value.toString(); } @@ -162,15 +171,15 @@ public class ConstantExpression implements Expression public boolean equals(Object o) { - if (o == null || !this.getClass().equals(o.getClass())) + if ((o == null) || !this.getClass().equals(o.getClass())) { return false; } + return toString().equals(o.toString()); } - /** * Encodes the value of string so that it looks like it would look like * when it was provided in a selector. @@ -189,9 +198,12 @@ public class ConstantExpression implements Expression { b.append(c); } + b.append(c); } + b.append('\''); + return b.toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index bdabcbf5be..5ab360ca19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -1,21 +1,23 @@ -/** +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - package org.apache.qpid.server.filter; // // Based on like named file from r450141 of the Apache ActiveMQ project @@ -24,15 +26,14 @@ package org.apache.qpid.server.filter; import java.util.HashMap; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.server.queue.AMQMessage; /** * Represents a property expression - * - * @version $Revision$ */ public class PropertyExpression implements Expression { @@ -41,201 +42,212 @@ public class PropertyExpression implements Expression private static final int PERSISTENT = 2; private static final int DEFAULT_PRIORITY = 4; - private final static Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - + private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - static final private HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); + private static final HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); static { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", - new Expression() - { - public Object evaluate(AMQMessage message) - { - //TODO - return null; - } - } - ); + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() + { + public Object evaluate(AMQMessage message) + { + //TODO + return null; + } + }); JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - return replyTo == null ? null : replyTo.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSType", - new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - return type == null ? null : type.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - } - ); - - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", - new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; - if(_logger.isDebugEnabled()) - { - _logger.debug("JMSDeliveryMode is :" + mode); - } - return mode; - } - catch (AMQException e) - { - _logger.warn(e); - } - - return NON_PERSISTENT; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", - new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - return (int) _properties.getPriority(); - } - catch (AMQException e) - { - _logger.warn(e); - } - return DEFAULT_PRIORITY; - } - } - ); - - - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", - new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); - return messageId == null ? null : messageId; - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - } - ); - - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", - new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getTimestamp(); - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - } - ); - - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", - new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - return correlationId == null ? null : correlationId.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - } - ); - - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", - new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - return _properties.getExpiration(); - } - catch (AMQException e) - { - _logger.warn(e); - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", - new Expression() - { - public Object evaluate(AMQMessage message) - { - return message.isRedelivered(); - } - } - ); + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString replyTo = _properties.getReplyTo(); + + return (replyTo == null) ? null : replyTo.toString(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString type = _properties.getType(); + + return (type == null) ? null : type.toString(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; + if (_logger.isDebugEnabled()) + { + _logger.debug("JMSDeliveryMode is :" + mode); + } + + return mode; + } + catch (AMQException e) + { + _logger.warn(e); + } + + return NON_PERSISTENT; + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return (int) _properties.getPriority(); + } + catch (AMQException e) + { + _logger.warn(e); + } + + return DEFAULT_PRIORITY; + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString messageId = _properties.getMessageId(); + + return (messageId == null) ? null : messageId; + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getTimestamp(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString correlationId = _properties.getCorrelationId(); + + return (correlationId == null) ? null : correlationId.toString(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getExpiration(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() + { + public Object evaluate(AMQMessage message) + { + return message.isRedelivered(); + } + }); } @@ -245,7 +257,7 @@ public class PropertyExpression implements Expression public PropertyExpression(String name) { this.name = name; - jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); + jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); } public Object evaluate(AMQMessage message) throws AMQException @@ -255,13 +267,13 @@ public class PropertyExpression implements Expression { return jmsPropertyExpression.evaluate(message); } - else { - CommonContentHeaderProperties _properties = (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - if(_logger.isDebugEnabled()) + if (_logger.isDebugEnabled()) { _logger.debug("Looking up property:" + name); _logger.debug("Properties are:" + _properties.getHeaders().keySet()); @@ -276,7 +288,6 @@ public class PropertyExpression implements Expression return name; } - /** * @see java.lang.Object#toString() */ @@ -299,10 +310,11 @@ public class PropertyExpression implements Expression public boolean equals(Object o) { - if (o == null || !this.getClass().equals(o.getClass())) + if ((o == null) || !this.getClass().equals(o.getClass())) { return false; } + return name.equals(((PropertyExpression) o).name); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 4e8fb1b46e..83b4ed5358 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -1,19 +1,22 @@ -/** +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package org.apache.qpid.server.filter; // @@ -31,200 +34,268 @@ import org.apache.qpid.server.queue.AMQMessage; /** * An expression which performs an operation on two expression values - * - * @version $Revision$ */ -public abstract class UnaryExpression implements Expression { +public abstract class UnaryExpression implements Expression +{ private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); protected Expression right; - public static Expression createNegate(Expression left) { - return new UnaryExpression(left) { + public static Expression createNegate(Expression left) + { + return new UnaryExpression(left) + { public Object evaluate(AMQMessage message) throws AMQException { Object rvalue = right.evaluate(message); - if (rvalue == null) { + if (rvalue == null) + { return null; } - if (rvalue instanceof Number) { + + if (rvalue instanceof Number) + { return negate((Number) rvalue); } + return null; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "-"; } }; } - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { - - // Use a HashSet if there are many elements. - Collection t; - if( elements.size()==0 ) - t=null; - else if( elements.size() < 5 ) - t = elements; - else { - t = new HashSet(elements); - } - final Collection inList = t; - - return new BooleanUnaryExpression(right) { - public Object evaluate(AMQMessage message) throws AMQException { - + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + { + + // Use a HashSet if there are many elements. + Collection t; + if (elements.size() == 0) + { + t = null; + } + else if (elements.size() < 5) + { + t = elements; + } + else + { + t = new HashSet(elements); + } + + final Collection inList = t; + + return new BooleanUnaryExpression(right) + { + public Object evaluate(AMQMessage message) throws AMQException + { + Object rvalue = right.evaluate(message); - if (rvalue == null) { + if (rvalue == null) + { + return null; + } + + if (rvalue.getClass() != String.class) + { return null; } - if( rvalue.getClass()!=String.class ) - return null; - - if( (inList!=null && inList.contains(rvalue)) ^ not ) { - return Boolean.TRUE; - } else { - return Boolean.FALSE; + + if (((inList != null) && inList.contains(rvalue)) ^ not) + { + return Boolean.TRUE; + } + else + { + return Boolean.FALSE; } - + } - public String toString() { - StringBuffer answer = new StringBuffer(); - answer.append(right); - answer.append(" "); - answer.append(getExpressionSymbol()); - answer.append(" ( "); - - int count=0; - for (Iterator i = inList.iterator(); i.hasNext();) { - Object o = (Object) i.next(); - if( count!=0 ) { - answer.append(", "); - } - answer.append(o); - count++; - } - - answer.append(" )"); + public String toString() + { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count = 0; + for (Iterator i = inList.iterator(); i.hasNext();) + { + Object o = (Object) i.next(); + if (count != 0) + { + answer.append(", "); + } + + answer.append(o); + count++; + } + + answer.append(" )"); + return answer.toString(); - } - - public String getExpressionSymbol() { - if( not ) - return "NOT IN"; - else - return "IN"; + } + + public String getExpressionSymbol() + { + if (not) + { + return "NOT IN"; + } + else + { + return "IN"; + } } }; } - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { - public BooleanUnaryExpression(Expression left) { + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + { + public BooleanUnaryExpression(Expression left) + { super(left); } - public boolean matches(AMQMessage message) throws AMQException { + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + + return (object != null) && (object == Boolean.TRUE); } - }; + } + ; - - public static BooleanExpression createNOT(BooleanExpression left) { - return new BooleanUnaryExpression(left) { - public Object evaluate(AMQMessage message) throws AMQException { + public static BooleanExpression createNOT(BooleanExpression left) + { + return new BooleanUnaryExpression(left) + { + public Object evaluate(AMQMessage message) throws AMQException + { Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) { + if (lvalue == null) + { return null; } + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "NOT"; } }; } - - public static BooleanExpression createXPath(final String xpath) { + + public static BooleanExpression createXPath(final String xpath) + { return new XPathExpression(xpath); } - public static BooleanExpression createXQuery(final String xpath) { + public static BooleanExpression createXQuery(final String xpath) + { return new XQueryExpression(xpath); } - public static BooleanExpression createBooleanCast(Expression left) { - return new BooleanUnaryExpression(left) { - public Object evaluate(AMQMessage message) throws AMQException { + public static BooleanExpression createBooleanCast(Expression left) + { + return new BooleanUnaryExpression(left) + { + public Object evaluate(AMQMessage message) throws AMQException + { Object rvalue = right.evaluate(message); - if (rvalue == null) + if (rvalue == null) + { return null; - if (!rvalue.getClass().equals(Boolean.class)) + } + + if (!rvalue.getClass().equals(Boolean.class)) + { return Boolean.FALSE; - return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; } - public String toString() { + public String toString() + { return right.toString(); } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return ""; } }; } - private static Number negate(Number left) { - Class clazz = left.getClass(); - if (clazz == Integer.class) { + private static Number negate(Number left) + { + Class clazz = left.getClass(); + if (clazz == Integer.class) + { return new Integer(-left.intValue()); } - else if (clazz == Long.class) { + else if (clazz == Long.class) + { return new Long(-left.longValue()); } - else if (clazz == Float.class) { + else if (clazz == Float.class) + { return new Float(-left.floatValue()); } - else if (clazz == Double.class) { + else if (clazz == Double.class) + { return new Double(-left.doubleValue()); } - else if (clazz == BigDecimal.class) { - // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the - // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it - // as a Big decimal. But it gets Negated right away.. to here we try to covert it back - // to a Long. - BigDecimal bd = (BigDecimal)left; - bd = bd.negate(); - - if( BD_LONG_MIN_VALUE.compareTo(bd)==0 ) { - return new Long(Long.MIN_VALUE); - } + else if (clazz == BigDecimal.class) + { + // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the + // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it + // as a Big decimal. But it gets Negated right away.. to here we try to covert it back + // to a Long. + BigDecimal bd = (BigDecimal) left; + bd = bd.negate(); + + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) + { + return new Long(Long.MIN_VALUE); + } + return bd; } - else { - throw new RuntimeException("Don't know how to negate: "+left); + else + { + throw new RuntimeException("Don't know how to negate: " + left); } } - public UnaryExpression(Expression left) { + public UnaryExpression(Expression left) + { this.right = left; } - public Expression getRight() { + public Expression getRight() + { return right; } - public void setRight(Expression expression) { + public void setRight(Expression expression) + { right = expression; } /** * @see java.lang.Object#toString() */ - public String toString() { + public String toString() + { return "(" + getExpressionSymbol() + " " + right.toString() + ")"; } @@ -233,7 +304,8 @@ public abstract class UnaryExpression implements Expression { * * @see java.lang.Object#hashCode() */ - public int hashCode() { + public int hashCode() + { return toString().hashCode(); } @@ -242,11 +314,14 @@ public abstract class UnaryExpression implements Expression { * * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object o) { + public boolean equals(Object o) + { - if (o == null || !this.getClass().equals(o.getClass())) { + if ((o == null) || !this.getClass().equals(o.getClass())) + { return false; } + return toString().equals(o.toString()); } @@ -257,6 +332,6 @@ public abstract class UnaryExpression implements Expression { * * @return */ - abstract public String getExpressionSymbol(); + public abstract String getExpressionSymbol(); } -- cgit v1.2.1 From 106ecb152c2caeae83431c966b3442b8536eb850 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 5 Mar 2007 15:54:44 +0000 Subject: QPID-388 : hand merged the changes done in perftesting branch QPID-395 : hand merged the changes done in perftesting branch QPID-375 : default queue config properties should now be under tag git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@514703 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 6 +++++- .../apache/qpid/server/queue/AMQQueueMBean.java | 23 ++-------------------- 2 files changed, 7 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 429829e201..5bbe1671a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -632,7 +632,11 @@ public class AMQQueue implements Managable, Comparable protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException { - _totalMessagesReceived.incrementAndGet(); + if (!msg.isRedelivered()) + { + _totalMessagesReceived.incrementAndGet(); + } + try { _managedObject.checkForNotification(msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index c9329a244c..254348dba0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -209,7 +209,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public Long getMaximumQueueDepth() { - return _queue.getMaximumQueueDepth(); + long queueDepthInBytes = _queue.getMaximumQueueDepth(); + return queueDepthInBytes >> 10 ; } public void setMaximumQueueDepth(Long value) @@ -221,31 +222,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que * returns the size of messages(KB) in the queue. */ public Long getQueueDepth() throws JMException - { - return getQueueDepthKb(); - } - - public long getQueueDepthKb() { long queueBytesSize = _queue.getQueueDepth(); return queueBytesSize >> 10 ; } - /** - * returns size of message in bytes - */ - 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 */ -- cgit v1.2.1 From 0c0dbd5e00f5b057867546bb336ece262577841c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 6 Mar 2007 14:12:47 +0000 Subject: QPID-403 QPID-346 QPID-355 QPID-386 QPID-389 Updates to fix Transactional Rollback. QPID-346 Message loss after rollback\recover QPID-355 Closing a consumer does not ensure messages delivery will stop for that subscription QPID-386 Updated Transactional Tests to cover underlying AMQP/Qpid state. QPID-389 Prefetched message are not correctly returned to the queue QPID-403 Implement Basic.Reject Broker UnacknowledgedMessage - Added toString for debug UnacknowledgedMessageMapImpl - Removed resendMessages method as all sending should go via DeliveryManager and Subscription. AMQChannel - Updated resend and requeue methods so they do not directly write messages to a subscriber. This was violating the suspension state. - Used a local non-transactional context to requeue messages as the internal requeuing of messages on the broker should not be part of any client transaction. - Maked messages as resent. - Removed warnings from IDE about missing JavaDoc text etc. BasicAckMethodHandler - Added debugging BasicRecoverMethodHandler - Removed session from the resend call. BasicRejectMethodHandler - Initial implementation. Hooks left for possible 'resend' bit. ChannelCloseHandler - Fixed bug where channel wasn't marked as fully closed on reception of a close from the client. TxRollbackHandler - Removed session from resend call. AMQMinaProtocolSession - Fixed bug where channel was marked as awaiting closure before it had actually been closed. This causes problems as the close looks up the channel by id again which will return null after it has been marked as awaiting closure. AMQMessage - Initial implementation of Rejection. Currently inactive in hasInterest() as we are miss-using reject to requeue prefetched messages from the client. AMQQueue - Removed debug method as it made reading the log very difficult as all the logs had the same line number ConcurrentSelectorDeliveryManager - Fixed clearAllMessages() as it didn't actually remove the messages. - Fixed bad logic in getNextMessage when using null subscriber. (as done by clearAllMessages) - Added more logging messages. Made more frequent logging a trace value. - Added debugIdentity() method to reduce over head in calculating standard log prefix. - Allowed messages to be added to the front of the queue. - Added currentStatus() to an overview of the queue's current state. SubscriptionImpl - Updated to handle closure correctly (QPID-355) -Updated the deliver method so it doesn't use a try->finally to do msg.setDeliveredToConsumer() as this would be done even in the event of an error. - Created an additional logger to log suspension calls rather than through the SI logger which logs a lot of detail. Client pom.xml - Excluded older version of log4j that commons-collections exposes. AMQSession - Added ability for dispatcher to start in stopped state. - Added dispatcher logger - Added checks around logging - Added message rejection if the dispatcher receives a message that it doesn't have a consumer for. - Updated message rejection to allow the dispatcher to perform the rejection if running this ensures that all queued messages are processed correctly and rejection occurs in order. - rollback() before calling rollback all pending queued messages must be rejected as rollback will clear unacked map which the rejects caused by rollback() will need. - fixed closedProducersAndConsumers so that it will rethrow any JMS Exception - recover() as for rollback() the rejects need to be done before the Recover Call to the broker. - Allowed delclareExchange to be done synchronously programatically - Updated confirmConsumerCancelled to use the dispatcher to perform the clean up. This required the creation of the dispatcher in stopped mode so that it does not start and message attempted to be delivered while the subscriber is being cancelled. BasicMessageConsumer - Updated close not to perform the deregistration. This is done in via BasicCancelOkMethodHandler - Added guards on logging - Record all messages that have been received so they can be rejected if rollback occurs. so had to change impl of acknowledgeLastDelivered. - Updated Rollback to initially reject all received messages that are still unAcked. - Added a recursive call should the queue not be empty at the end of the rollback.. with a warning. BasicCancelOkMethodHandler - White space changes to meet style guide. Added guard on logging. UnprocessedMessage - White space changes to meet style guide. StateWaiter - Added comment about timeout bug. FlowControllingBlockingQueue - Tidied imports RecoverTest - Updated as declareExchange is now Synchronous ChannelCloseTest - added guard on logging MessageRequeueTest - Added to better test underlying AMQP/Qpid state QPID-386 StreamMessageTest - Updated as declareExchange is now Synchronous CommitRollbackTest - added Additional test case to ensure prefetch queue is correctly purged. TransactedTest - Added logging and additional tests. Cluster SimpleClusterTest - updated in line with AMQSession.delcareExchange changes Common AMQConstant - Fixed error code 'not allowed' should be 530 not 507. ConcurrentLinkedMessageQueueAtomicSize - Updated to beable to get the size of messages on the 'head' queue along with additional debug Systests ReturnUnroutableMandatoryMessageTest - Updated as declareExchange is now Synchronous git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@515127 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 281 +++++++++++++++------ .../qpid/server/ack/UnacknowledgedMessage.java | 15 ++ .../server/ack/UnacknowledgedMessageMapImpl.java | 20 +- .../qpid/server/handler/BasicAckMethodHandler.java | 5 +- .../server/handler/BasicRecoverMethodHandler.java | 2 +- .../server/handler/BasicRejectMethodHandler.java | 74 +++++- .../qpid/server/handler/ChannelCloseHandler.java | 2 + .../qpid/server/handler/TxRollbackHandler.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 4 +- .../org/apache/qpid/server/queue/AMQMessage.java | 49 +++- .../org/apache/qpid/server/queue/AMQQueue.java | 40 ++- .../queue/ConcurrentSelectorDeliveryManager.java | 173 ++++++++----- .../apache/qpid/server/queue/SubscriptionImpl.java | 121 +++++---- 13 files changed, 538 insertions(+), 250 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index be2cee79ee..5dd6619cff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -99,7 +99,7 @@ public class AMQChannel private final MessageRouter _exchanges; - private TransactionalContext _txnContext; + private TransactionalContext _txnContext, _nonTransactedContext; /** * A context used by the message store enabling it to track context for a given channel even across thread @@ -113,9 +113,9 @@ public class AMQChannel private Set _browsedAcks = new HashSet(); + //Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore, MessageRouter exchanges) throws AMQException { @@ -210,9 +210,9 @@ public class AMQChannel } else { - if (_log.isDebugEnabled()) + if (_log.isTraceEnabled()) { - _log.debug("Content header received on channel " + _channelId); + _log.trace(debugIdentity() + "Content header received on channel " + _channelId); } _currentMessage.setContentHeaderBody(contentHeaderBody); routeCurrentMessage(); @@ -234,9 +234,9 @@ public class AMQChannel throw new AMQException("Received content body without previously receiving a JmsPublishBody"); } - if (_log.isDebugEnabled()) + if (_log.isTraceEnabled()) { - _log.debug("Content body received on channel " + _channelId); + _log.trace(debugIdentity() + "Content body received on channel " + _channelId); } try { @@ -289,8 +289,10 @@ public class AMQChannel * @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 - * @param noLocal - * @param exclusive + * @param noLocal Flag stopping own messages being receivied. + * @param exclusive Flag requesting exclusive access to the queue + * @param acks Are acks enabled for this subscriber + * @param filters Filters to apply to this subscriber * * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests * @@ -327,6 +329,8 @@ public class AMQChannel /** * Called from the protocol session to close this channel and clean up. T * + * @param session The session to close + * * @throws AMQException if there is an error during closure */ public void close(AMQProtocolSession session) throws AMQException @@ -352,10 +356,23 @@ public class AMQChannel * @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 consumerTag The tag for the consumer that is to acknowledge this message. * @param queue the queue from which the message was delivered */ public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) { + if (_log.isDebugEnabled()) + { + if (queue == null) + { + _log.debug("Adding unacked message with a null queue:" + message.debugIdentity()); + } + else + { + _log.debug(debugIdentity() + " Adding unacked message(" + deliveryTag + ") with a queue(" + queue + "):" + message.debugIdentity()); + } + } + synchronized (_unacknowledgedMessageMap.getLock()) { _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); @@ -363,8 +380,15 @@ public class AMQChannel } } + private final String id = "(" + System.identityHashCode(this) + ")"; + + public String debugIdentity() + { + return _channelId + id; + } + /** - * Called to attempt re-enqueue all outstanding unacknowledged messages on the channel. May result in delivery to + * Called to attempt re-delivery 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 @@ -374,11 +398,22 @@ public class AMQChannel // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - TransactionalContext nontransacted = null; + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + if (_nonTransactedContext == null) + { + _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; } @@ -386,72 +421,130 @@ public class AMQChannel { if (unacked.queue != null) { - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - if (!(_txnContext instanceof NonTransactionalContext)) - { - nontransacted.deliver(unacked.message, unacked.queue, false); - } - else - { - _txnContext.deliver(unacked.message, unacked.queue, false); - } + unacked.message.setRedelivered(true); + + // Deliver Message + deliveryContext.deliver(unacked.message, unacked.queue, false); + + // Should we allow access To the DM to directy deliver the message? + // As we don't need to check for Consumers or worry about incrementing the message count? +// unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); } } } + /** + * Requeue a single message + * + * @param deliveryTag The message to requeue + * + * @throws AMQException If something goes wrong. + */ public void requeue(long deliveryTag) throws AMQException { UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); if (unacked != null) { - TransactionalContext nontransacted = null; + + // Ensure message is released for redelivery + unacked.message.release(); + + // Mark message redelivered + unacked.message.setRedelivered(true); + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + if (_nonTransactedContext == null) + { + _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; } - if (!(_txnContext instanceof NonTransactionalContext)) + + if (unacked.queue != null) { - nontransacted.deliver(unacked.message, unacked.queue, false); + //Redeliver the messages to the front of the queue + deliveryContext.deliver(unacked.message, unacked.queue, true); + + unacked.message.decrementReference(_storeContext); } else { - _txnContext.deliver(unacked.message, unacked.queue, false); + _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() + "):" + deliveryTag + + " but no queue defined and no DeadLetter queue so DROPPING message."); +// _log.error("Requested requeue of message:" + deliveryTag + +// " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); +// +// deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); +// +// unacked.message.decrementReference(_storeContext); } - unacked.message.decrementReference(_storeContext); } else { - _log.error("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists"); + _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); + + if (_log.isDebugEnabled()) + { + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + int count = 0; + + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug((count++) + ": (" + message.message.debugIdentity() + ")" + + "[" + message.deliveryTag + "]"); + return false; // Continue + } + + public void visitComplete() + { + + } + }); + } } } - /** Called to resend all outstanding unacknowledged messages to this same channel. - * @param session the session - * @param requeue if true then requeue, else resend - * @throws org.apache.qpid.AMQException */ - public void resend(final AMQProtocolSession session, final boolean requeue) throws AMQException + /** + * Called to resend all outstanding unacknowledged messages to this same channel. + * + * @param requeue Are the messages to be requeued or dropped. + * + * @throws AMQException When something goes wrong. + */ + public void resend(final boolean requeue) throws AMQException { final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); if (_log.isInfoEnabled()) { - _log.info("unacked map contains " + _unacknowledgedMessageMap.size()); + _log.info("unacked map Size:" + _unacknowledgedMessageMap.size()); } + // Process the Unacked-Map. + // Marking messages who still have a consumer for to be resent + // and those that don't to be requeued. _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { public boolean callback(UnacknowledgedMessage message) throws AMQException { - long deliveryTag = message.deliveryTag; AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; msg.setRedelivered(true); @@ -503,14 +596,21 @@ public class AMQChannel { if (!msgToResend.isEmpty()) { - _log.info("Preparing (" + msgToResend.size() + ") message to resend to."); + _log.info("Preparing (" + msgToResend.size() + ") message to resend."); + } + else + { + _log.info("No message to resend."); } } for (UnacknowledgedMessage message : msgToResend) { AMQMessage msg = message.message; - // Our Java Client will always suspend the channel when resending!! + // Our Java Client will always suspend the channel when resending! + // If the client has requested the messages be resent then it is + // their responsibility to ensure that thay are capable of receiving them + // i.e. The channel hasn't been server side suspended. // if (isSuspended()) // { // _log.info("Channel is suspended so requeuing"); @@ -518,50 +618,58 @@ public class AMQChannel // msgToRequeue.add(message); // } // else - { - //release to allow it to be delivered - msg.release(); +// { + //release to allow it to be delivered + msg.release(); - // Without any details from the client about what has been processed we have to mark - // all messages in the unacked map as redelivered. - msg.setRedelivered(true); + // Without any details from the client about what has been processed we have to mark + // all messages in the unacked map as redelivered. + msg.setRedelivered(true); - Subscription sub = msg.getDeliveredSubscription(); + Subscription sub = msg.getDeliveredSubscription(); - if (sub != null) + if (sub != null) + { + // Get the lock so we can tell if the sub scription has closed. + // will stop delivery to this subscription until the lock is released. + // note: this approach would allow the use of a single queue if the + // PreDeliveryQueue would allow head additions. + // In the Java Qpid client we are suspended whilst doing this so it is all rather Mute.. + // needs guidance from AMQP WG Model SIG + synchronized (sub.getSendLock()) { - synchronized (sub.getSendLock()) + if (sub.isClosed()) { - if (sub.isClosed()) + if (_log.isDebugEnabled()) { - _log.info("Subscription closed during resend so requeuing message"); - //move this message to requeue - msgToRequeue.add(message); + _log.debug("Subscription(" + System.identityHashCode(sub) + ") closed during resend so requeuing message"); } - else + //move this message to requeue + msgToRequeue.add(message); + } + else + { + if (_log.isDebugEnabled()) { - if (_log.isDebugEnabled()) - { - _log.debug("Requeuing (" + System.identityHashCode(msg) + ") for resend"); - } - // Will throw an exception if the sub is closed - sub.addToResendQueue(msg); - _unacknowledgedMessageMap.remove(message.deliveryTag); - // Don't decrement as we are bypassing the normal deliver which increments - // this is what there is a decrement on the Requeue as deliver will increment. - // msg.decrementReference(_storeContext); + _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" + System.identityHashCode(sub)); } + sub.addToResendQueue(msg); + _unacknowledgedMessageMap.remove(message.deliveryTag); + // Don't decrement as we are bypassing the normal deliver which increments + // this is why there is a decrement on the Requeue as deliver will increment. + // msg.decrementReference(_storeContext); } - } - else - { - _log.info("DeliveredSubscription not recorded so just requeueing to prevent loss"); - //move this message to requeue - msgToRequeue.add(message); - } + } // sync(sub.getSendLock) } - } + else + { + _log.info("DeliveredSubscription not recorded so just requeueing to prevent loss"); + //move this message to requeue + msgToRequeue.add(message); + } + } // for all messages +// } else !isSuspend if (_log.isInfoEnabled()) { @@ -571,26 +679,31 @@ public class AMQChannel } } - TransactionalContext nontransacted = null; + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - nontransacted = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + if (_nonTransactedContext == null) + { + _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; } // Process Messages to Requeue at the front of the queue for (UnacknowledgedMessage message : msgToRequeue) { - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - if (!(_txnContext instanceof NonTransactionalContext)) - { - nontransacted.deliver(message.message, message.queue, true); - } - else - { - _txnContext.deliver(message.message, message.queue, true); - } + message.message.release(); + message.message.setRedelivered(true); + + deliveryContext.deliver(message.message, message.queue, true); _unacknowledgedMessageMap.remove(message.deliveryTag); message.message.decrementReference(_storeContext); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index 3f2348b71b..940b5b2bf1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -42,6 +42,21 @@ public class UnacknowledgedMessage message.incrementReference(); } + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("Q:"); + sb.append(queue); + sb.append(" M:"); + sb.append(message); + sb.append(" CT:"); + sb.append(consumerTag); + sb.append(" DT:"); + sb.append(deliveryTag); + + return sb.toString(); + } + public void discard(StoreContext storeContext) throws AMQException { if (queue != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 99cc60011a..30bbdea2ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -196,25 +196,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } } - - public void resendMessages(AMQProtocolSession protocolSession, int channelId) throws AMQException - { - synchronized (_lock) - { - for (Map.Entry entry : _map.entrySet()) - { - long deliveryTag = entry.getKey(); - AMQShortString consumerTag = entry.getValue().consumerTag; - AMQMessage msg = entry.getValue().message; - - if(consumerTag != null) - { - protocolSession.getProtocolOutputConverter().writeDeliver(msg, channelId, deliveryTag, consumerTag); - } - } - } - } - + public UnacknowledgedMessage get(long key) { synchronized (_lock) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java index f93b2b25e6..a6972475a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -47,12 +47,13 @@ public class BasicAckMethodHandler implements StateAwareMethodListener evt) throws AMQException { AMQProtocolSession protocolSession = stateManager.getProtocolSession(); + BasicAckBody body = evt.getMethod(); if (_log.isDebugEnabled()) { - _log.debug("Ack received on channel " + evt.getChannelId()); + _log.debug("Ack(Tag:" + body.deliveryTag + ":Mult:" + body.multiple + ") received on channel " + evt.getChannelId()); } - BasicAckBody body = evt.getMethod(); + final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); if (channel == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java index bc11e4652c..a436c35473 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -54,7 +54,7 @@ public class BasicRecoverMethodHandler implements StateAwareMethodListener _rejectedBy = null; + public boolean isTaken() { return _taken.get(); } + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + _messageId + ")"; + } + /** * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory * therefore is memory-efficient. @@ -199,7 +206,7 @@ public class AMQMessage _taken = new AtomicBoolean(false); if (_log.isDebugEnabled()) { - _log.debug("Message created with id " + messageId); + _log.debug("Message(" + System.identityHashCode(this) + ") created with id " + messageId); } } @@ -452,7 +459,9 @@ public class AMQMessage public void release() { + _log.trace("Releasing Message:" + debugIdentity()); _taken.set(false); + _takenBySubcription = null; } public boolean checkToken(Object token) @@ -511,7 +520,7 @@ public class AMQMessage * @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 + public void checkDeliveredToConsumer() throws NoConsumersException { if (_immediate && !_deliveredToConsumer) @@ -580,7 +589,8 @@ public class AMQMessage for (AMQQueue q : destinationQueues) { - _txnContext.deliver(this, q, true); + //normal deliver so add this message at the end. + _txnContext.deliver(this, q, false); } } finally @@ -801,7 +811,7 @@ public class AMQMessage public String toString() { - return "Message: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + _taken + " by:" + _takenBySubcription; } @@ -809,4 +819,35 @@ public class AMQMessage { return _takenBySubcription; } + + public void reject(Subscription subscription) + { + if (subscription != null) + { + if (_rejectedBy == null) + { + _rejectedBy = new HashSet(); + } + + _rejectedBy.add(subscription); + } + else + { + _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + } + } + + public boolean isRejectedBy(Subscription subscription) + { + boolean rejected = _rejectedBy != null; + + if (rejected) // We have subscriptions that rejected this message + { + return _rejectedBy.contains(subscription); + } + else // This messasge hasn't been rejected yet. + { + return rejected; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 5bbe1671a7..7c2fe73386 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -50,6 +50,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; */ public class AMQQueue implements Managable, Comparable { + public static final class ExistingExclusiveSubscription extends AMQException { @@ -446,7 +447,11 @@ public class AMQQueue implements Managable, Comparable setExclusive(true); } - debug("Registering protocol session {0} with channel {1} and consumer tag {2} with {3}", ps, channel, consumerTag, this); + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format("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, filters, noLocal, this); @@ -486,8 +491,11 @@ public class AMQQueue implements Managable, Comparable public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException { - debug("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, - this); + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format("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, @@ -506,6 +514,10 @@ public class AMQQueue implements Managable, Comparable // if we are eligible for auto deletion, unregister from the queue registry if (_autoDelete && _subscribers.isEmpty()) { + if (_logger.isInfoEnabled()) + { + _logger.warn("Auto-deleteing queue:" + this); + } 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 @@ -561,14 +573,18 @@ public class AMQQueue implements Managable, Comparable protected void autodelete() throws AMQException { - debug("autodeleting {0}", this); + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format("autodeleting {0}", this)); + } delete(); } - public void processGet(StoreContext storeContext, AMQMessage msg) throws AMQException + public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { //fixme not sure what this is doing. should we be passing deliverFirst through here? - _deliveryMgr.deliver(storeContext, getName(), msg, false); + // This code is not used so when it is perhaps it should + _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); try { msg.checkDeliveredToConsumer(); @@ -582,6 +598,10 @@ public class AMQQueue implements Managable, Comparable } } +// public DeliveryManager getDeliveryManager() +// { +// return _deliveryMgr; +// } public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { @@ -673,14 +693,6 @@ public class AMQQueue implements Managable, Comparable return "Queue(" + _name + ")@" + System.identityHashCode(this); } - private void debug(String msg, Object... args) - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format(msg, args)); - } - } - public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException { return _deliveryMgr.performGet(session, channel, acks); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index e70926736d..601effcec7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -45,7 +45,6 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.util.MessageQueue; import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; /** Manages delivery of messages on behalf of a queue */ @@ -86,6 +85,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private AtomicLong _totalMessageSize = new AtomicLong(); private AtomicInteger _extraMessages = new AtomicInteger(); private Set _hasContent = Collections.synchronizedSet(new HashSet()); + private final Object _queueHeadLock = new Object(); + private String _processingThreadName = ""; ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -118,7 +119,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (deliverFirst) { - _messages.pushHead(msg); + synchronized (_queueHeadLock) + { + _messages.pushHead(msg); + } } else { @@ -367,16 +371,19 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager long count = 0; _lock.lock(); - AMQMessage msg = getNextMessage(); - while (msg != null) + synchronized (_queueHeadLock) { - //mark this message as taken and get it removed - msg.taken(null); - _queue.dequeue(storeContext, msg); - msg = getNextMessage(); - count++; - } + AMQMessage msg = getNextMessage(); + while (msg != null) + { + //and remove it + _messages.poll(); + _queue.dequeue(storeContext, msg); + msg = getNextMessage(); + count++; + } + } _lock.unlock(); return count; } @@ -390,12 +397,20 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { AMQMessage message = messages.peek(); - - while (message != null && ((sub == null || sub.isBrowser()) || message.taken(sub))) + while (message != null && ((sub != null && sub.isBrowser()) || message.taken(sub))) { //remove the already taken message - messages.poll(); + AMQMessage removed = messages.poll(); + + assert removed == message; + _totalMessageSize.addAndGet(-message.getSize()); + + if (_log.isTraceEnabled()) + { + _log.trace("Removed taken message:" + message.debugIdentity()); + } + // try the next message message = messages.peek(); } @@ -409,7 +424,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (_log.isTraceEnabled()) { - _log.trace("Async sendNextMessage for sub (" + System.identityHashCode(sub) + + _log.trace(debugIdentity() + "Async sendNextMessage for sub (" + System.identityHashCode(sub) + ") from queue (" + System.identityHashCode(messageQueue) + ") AMQQueue (" + System.identityHashCode(queue) + ")"); } @@ -417,46 +432,63 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (messageQueue == null) { // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector - if (_log.isDebugEnabled()) + if (_log.isInfoEnabled()) { - _log.debug(sub + ": asked to send messages but has none on given queue:" + queue); + _log.info(debugIdentity() + sub + ": asked to send messages but has none on given queue:" + queue); } return; } AMQMessage message = null; + AMQMessage removed = null; try { - message = getNextMessage(messageQueue, sub); - - // message will be null if we have no messages in the messageQueue. - if (message == null) + synchronized (_queueHeadLock) { - if (_log.isTraceEnabled()) + message = getNextMessage(messageQueue, sub); + + // message will be null if we have no messages in the messageQueue. + if (message == null) { - _log.trace("No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); + if (_log.isTraceEnabled()) + { + _log.trace(debugIdentity() + "No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); + } + return; + } + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Async Delivery Message " + message.getMessageId() + "(" + System.identityHashCode(message) + + ") by :" + System.identityHashCode(this) + + ") to :" + System.identityHashCode(sub)); } - return; + + sub.send(message, _queue); + + //remove sent message from our queue. + removed = messageQueue.poll(); + //If we don't remove the message from _messages + // Otherwise the Async send will never end } + + if (removed != message) + { + _log.error("Just send message:" + message.debugIdentity() + " BUT removed this from queue:" + removed); + } + if (_log.isDebugEnabled()) { - _log.debug("Async Delivery Message (" + System.identityHashCode(message) + + _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message.debugIdentity() + ") by :" + System.identityHashCode(this) + ") to :" + System.identityHashCode(sub)); } - sub.send(message, _queue); - - //remove sent message from our queue. - messageQueue.poll(); - //If we don't remove the message from _messages - // Otherwise the Async send will never end if (messageQueue == sub.getResendQueue()) { if (_log.isTraceEnabled()) { - _log.trace("All messages sent from resendQueue for " + sub); + _log.trace(debugIdentity() + "All messages sent from resendQueue for " + sub); } if (messageQueue.isEmpty()) { @@ -469,7 +501,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else if (messageQueue == sub.getPreDeliveryQueue()) { - _log.info("We could do clean up of the main _message queue here"); + if (_log.isInfoEnabled()) + { + _log.info(debugIdentity() + "We could do clean up of the main _message queue here"); + } } _totalMessageSize.addAndGet(-message.getSize()); @@ -477,7 +512,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager catch (AMQException e) { message.release(); - _log.error("Unable to deliver message as dequeue failed: " + e, e); + _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -516,6 +551,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager */ private void processQueue() { + //record thread name + if (_log.isDebugEnabled()) + { + _processingThreadName = Thread.currentThread().getName(); + } + // Continue to process delivery while we haveSubscribers and messages boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); @@ -561,9 +602,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "deliver :first(" + deliverFirst + ") :" + msg); + _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); } - msg.release(); + // This shouldn't be done here. +// msg.release(); //Check if we have someone to deliver the message to. _lock.lock(); @@ -575,7 +617,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Testing Message(" + msg + ") for Queued Delivery:" + currentStatus()); + _log.debug(debugIdentity() + "Testing Message(" + msg + ") for Queued Delivery:" + currentStatus()); } if (!msg.getMessagePublishInfo().isImmediate()) { @@ -587,7 +629,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //Pre Deliver to all subscriptions if (_log.isDebugEnabled()) { - _log.debug(id() + "We have " + _subscriptions.getSubscriptions().size() + + _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to:" + currentStatus()); } for (Subscription sub : _subscriptions.getSubscriptions()) @@ -598,7 +640,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + + _log.debug(debugIdentity() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + ") is already delivered."); } continue; @@ -609,7 +651,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(id() + "Queuing message(" + System.identityHashCode(msg) + + _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); } sub.enqueueForPreDelivery(msg, deliverFirst); @@ -625,9 +667,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (!s.isSuspended()) { - if (_log.isDebugEnabled()) + if (_log.isTraceEnabled()) { - _log.debug(id() + "Delivering Message:" + System.identityHashCode(msg) + " to(" + + _log.trace(debugIdentity() + "Delivering Message:" + msg.debugIdentity() + " to(" + System.identityHashCode(s) + ") :" + s); } msg.taken(s); @@ -636,33 +678,35 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else { - if (_log.isDebugEnabled()) + if (_log.isInfoEnabled()) { - _log.debug(id() + " Subscription(" + System.identityHashCode(s) + ") became suspended between nextSubscriber and send"); + _log.info(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + + "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); } } + } - if (!msg.isTaken()) + if (!msg.isTaken()) + { + if (_log.isInfoEnabled()) { - if (_log.isDebugEnabled()) - { - _log.debug(id() + " Message(" + System.identityHashCode(msg) + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); - } - - deliver(context, name, msg, deliverFirst); + _log.info(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + + " Subscriber:" + System.identityHashCode(s)); } - else + + deliver(context, name, msg, deliverFirst); + } + else + { + if (_log.isDebugEnabled()) { - if (_log.isDebugEnabled()) - { - _log.debug(id() + " Message(" + System.identityHashCode(msg) + - ") has been taken so disregarding deliver request to Subscriber:" + - System.identityHashCode(s)); - } + _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + + ") has been taken so disregarding deliver request to Subscriber:" + + System.identityHashCode(s)); } } } + } finally { @@ -674,10 +718,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - //fixme remove private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")"; - private String id() + private String debugIdentity() { return id; } @@ -710,7 +753,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug("Processing Async." + currentStatus()); + _log.debug(debugIdentity() + "Processing Async." + currentStatus()); } if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) @@ -725,14 +768,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private String currentStatus() { - return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains") + - "(" + _messages.size() + ":" + ((ConcurrentLinkedQueue) _messages).size() + ") " + + return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains(M:H)") + + "(" + _messages.size() + ":" + ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize() + ") " + " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") + "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " + " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get() + - " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains") + - "(" + _messages.size() + ":" + ((ConcurrentLinkedQueue) _messages).size() + ") "; + " Processing:" + (_processing.get() ? " true : Processing Thread: " + _processingThreadName : " false"); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 0a2e73880c..20033daac7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -46,6 +46,8 @@ import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; */ public class SubscriptionImpl implements Subscription { + + private static final Logger _suspensionlogger = Logger.getLogger("Suspension"); private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); public final AMQChannel channel; @@ -258,6 +260,12 @@ public class SubscriptionImpl implements Subscription { channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); } + + if (_sendLock.get()) + { + _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); + } + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); } } @@ -265,56 +273,56 @@ public class SubscriptionImpl implements Subscription private void sendToConsumer(StoreContext storeContext, AMQMessage msg, AMQQueue queue) throws AMQException { - try - { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!_acks) + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + if (!_acks) + { + if (_logger.isDebugEnabled()) { - if (_logger.isDebugEnabled()) - { - _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); - } - queue.dequeue(storeContext, msg); + _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); } - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (_acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - msg.decrementReference(storeContext); - } + queue.dequeue(storeContext, msg); + } + synchronized (channel) + { + long deliveryTag = channel.getNextDeliveryTag(); - protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); + if (_sendLock.get()) + { + _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); + } + if (_acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + msg.decrementReference(storeContext); } - } - finally - { + + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. msg.setDeliveredToConsumer(); } } public boolean isSuspended() { - if (_logger.isTraceEnabled()) + if (_suspensionlogger.isInfoEnabled()) { if (channel.isSuspended()) { - _logger.trace("Subscription(" + System.identityHashCode(this) + ") channel's is susupended"); + _suspensionlogger.info("Subscription(" + debugIdentity() + ") channel's is susupended"); } if (_sendLock.get()) { - _logger.trace("Subscription(" + System.identityHashCode(this) + ") has sendLock set so closing."); + _suspensionlogger.info("Subscription(" + debugIdentity() + ") has sendLock set so closing."); } } return channel.isSuspended() || _sendLock.get(); @@ -323,7 +331,7 @@ public class SubscriptionImpl implements Subscription /** * Callback indicating that a queue has been deleted. * - * @param queue + * @param queue The queue to delete */ public void queueDeleted(AMQQueue queue) throws AMQException { @@ -337,9 +345,18 @@ public class SubscriptionImpl implements Subscription public boolean hasInterest(AMQMessage msg) { + //check that the message hasn't been rejected + if (msg.isRejectedBy(this)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + msg.debugIdentity()); + } +// return false; + } + if (_noLocal) { - boolean isLocal; // We don't want local messages so check to see if message is one we sent Object localInstance; Object msgInstance; @@ -350,12 +367,12 @@ public class SubscriptionImpl implements Subscription if ((msg.getPublisher().getClientProperties() != null) && (msgInstance = msg.getPublisher().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { - if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) + if (localInstance == msgInstance || localInstance.equals(msgInstance)) { if (_logger.isTraceEnabled()) { - _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + - System.identityHashCode(msg) + ")"); + _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + + msg.debugIdentity() + ")"); } return false; } @@ -369,8 +386,8 @@ public class SubscriptionImpl implements Subscription { if (_logger.isTraceEnabled()) { - _logger.trace("(" + System.identityHashCode(this) + ") has no interest as it is a local message(" + - System.identityHashCode(msg) + ")"); + _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + + msg.debugIdentity() + ")"); } return false; } @@ -383,19 +400,26 @@ public class SubscriptionImpl implements Subscription if (_logger.isTraceEnabled()) { - _logger.trace("(" + System.identityHashCode(this) + ") checking filters for message (" + System.identityHashCode(msg)); + _logger.trace("(" + debugIdentity() + ") checking filters for message (" + msg.debugIdentity()); } return checkFilters(msg); } + private String id = String.valueOf(System.identityHashCode(this)); + + private String debugIdentity() + { + return id; + } + private boolean checkFilters(AMQMessage msg) { if (_filters != null) { if (_logger.isTraceEnabled()) { - _logger.trace("(" + System.identityHashCode(this) + ") has filters."); + _logger.trace("(" + debugIdentity() + ") has filters."); } return _filters.allAllow(msg); } @@ -403,7 +427,7 @@ public class SubscriptionImpl implements Subscription { if (_logger.isTraceEnabled()) { - _logger.trace("(" + System.identityHashCode(this) + ") has no filters"); + _logger.trace("(" + debugIdentity() + ") has no filters"); } return true; @@ -445,15 +469,19 @@ public class SubscriptionImpl implements Subscription } _sendLock.set(true); - } + if (_logger.isInfoEnabled()) { - _logger.info("Closing subscription (" + System.identityHashCode(this) + "):" + this); + _logger.info("Closing subscription (" + debugIdentity() + "):" + this); } if (_resendQueue != null && !_resendQueue.isEmpty()) { + if (_logger.isInfoEnabled()) + { + _logger.info("Requeuing closing subscription (" + debugIdentity() + "):" + this); + } requeue(); } @@ -486,6 +514,11 @@ public class SubscriptionImpl implements Subscription { AMQMessage resent = _resendQueue.poll(); + if (_logger.isTraceEnabled()) + { + _logger.trace("Removed for resending:" + resent.debugIdentity()); + } + resent.release(); _queue.subscriberHasPendingResend(false, this, resent); @@ -495,7 +528,7 @@ public class SubscriptionImpl implements Subscription } catch (AMQException e) { - _logger.error("Unable to re-deliver messages", e); + _logger.error("MESSAGE LOSS : Unable to re-deliver messages", e); } } -- cgit v1.2.1 From 06b2b7958092a205768cdb1ddd37668a7a288d0f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 6 Mar 2007 15:35:51 +0000 Subject: Marked getNextMessage as private git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@515142 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 601effcec7..5cf08c857e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -388,7 +388,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return count; } - public synchronized AMQMessage getNextMessage() throws AMQException + private AMQMessage getNextMessage() throws AMQException { return getNextMessage(_messages, null); } -- cgit v1.2.1 From 2e6b406378b9974d588d7974c468614b94d76f7a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 7 Mar 2007 11:39:21 +0000 Subject: 1. Fixed the AMQQueueMBeanTest failures due to changes in AMQQueuMBean.getQueueDepth() from queueDepth/1000 to (queueDepth >> 10) 2. Revision: 513748 Author: bhupendrab Date: 13:26:51, 02 March 2007 Message: QPID-390 Added test case for all the AMQQueue alerts ---- Modified : /incubator/qpid/branches/perftesting/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java Added : /incubator/qpid/branches/perftesting/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@515539 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/AMQQueueMBean.java | 14 ++++++++++---- .../server/queue/ConcurrentSelectorDeliveryManager.java | 11 +++-------- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 254348dba0..056fb5fc01 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -81,8 +81,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"}; private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; - private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; + private Notification _lastNotification = null; @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException @@ -256,11 +256,17 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { // important : add log to the log file - monitoring tools may be looking for this _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); - - Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, + notificationMsg = notification.name() + " " + notificationMsg; + + _lastNotification = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); - _broadcaster.sendNotification(n); + _broadcaster.sendNotification(_lastNotification); + } + + public Notification getLastNotification() + { + return _lastNotification; } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 5cf08c857e..87868f0b25 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -354,14 +354,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void removeAMessageFromTop(StoreContext storeContext) throws AMQException { _lock.lock(); - AMQMessage msg = getNextMessage(); - if (msg != null) - { - // mark this message as taken and get it removed - msg.taken(null); - _queue.dequeue(storeContext, msg); - getNextMessage(); - } + + AMQMessage message = _messages.poll(); + _totalMessageSize.addAndGet(-message.getSize()); _lock.unlock(); } -- cgit v1.2.1 From 8606a752312f9c891fa90e36767bff4d348542c5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 13 Mar 2007 10:35:42 +0000 Subject: QPID-346,QPID-386,QPID-403, QPID-410 Rollback, Basic-Reject, QueueBrowser NO_ACK. QPID-346 Message loss after rollback\recover QPID-386 Updated Transactional Tests to cover underlying AMQP/Qpid state. QPID-403 Implement Basic.Reject QPID-410 Queue Browsers should use not acknowledge messages. ------------------------------------- Broker TxAck - Added comment and fixed white space UnacknowledgedMessage - Added comment for messageDecrement AMQChannel - Added extra debugging. + Created a NonTransactionalContext for requeuing messages as using txContext will tie the requeue to any runing transaction. + Updated message reference counting. So it is in terms of queues don't increment when giving to client. BasicCancelMethodHandler - Added Debug log. BasicConsumeMethodHandler - Reverted to directly writes frames to the session, throwing ChannelException caused problems. Added Trace and debug logging. BasicRejectMethodHandler, ChannelCloseHandler, ConnectionCloseMethodHandler - Added Debug logging AMQPFastProtocolHandler - moved error log to before session.write AMQMessage - Added additional debug via debugIdentity() and comments AMQQueue - Decoupled reference counting from dequeue operation. ConcurrentSelectorDeliveryManager - Added comments and increased info in debug logging SubscriptionImpl - Disabled use of acks for browsers. For now put setDeliveredToConsumer back in the finally block. commented that I'm not sure this is correct as even an error writing to client will cause msg to be marked delivered to consumer. + On Close ensured that it is only called once. + Had problem where closing browser was causing two CancelOk frames to be sent back to client. RequiredDeliveryException - Added comment to explain incrementReference LocalTransactionalContext - Commented out incrementReference as it shouldn't be required here. NonTransactionalContext - Removed incrementReference on deliver + - Fixed bug where browsers - acks would cause messages to be discarded. new JIRA this needs tidied up. TxnBuffer - Added debug logging. Client ------ AMQQueueBrowser - Added comments AMQSession - Added comments and debug + Updated to cause closed consumer to reject messages rather than receive them. + Prevented NoConsumer's from rollingback and rejecting.. they simply clear their SyncQueue - JIRA to ensure clean state with rollback BasicMessageConsumer - Added trace level debuging on close calls + Forced noConsume-rs to use NO_ACK + added more logging Closeable - Updated to use isClosed rather than directly calling _closed.get() to aid in future work on ensuring multi threaded close still allows pending acks to be processed first. ChannelCloseOkMethodHandler - updated comment AMQProtocolSession - Update comments,whitespace TransportConnection - removed static block FlowControllingBlockingQueue - Added isEmpty() Method PropertyValueTest - Added VM Broker setup + Updated test to run once and 50 times to pull out delivery tag problems that were occuring. + Adjusted logging level to be more helpful. moved some info down to trace and debug. MessageRequeueTest - Moved QpidClientConnection its own file. + Fixed it so it actually runs more than one consumer, concurrently.Now 3 was 1. ConcurrentLinkedMessageQueueAtomicSize - Implemented iterator(). Added QueueBrowserTest to system tests to test QueueBrowsering. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@517638 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 114 +++++++++++++++------ .../qpid/server/RequiredDeliveryException.java | 4 + .../java/org/apache/qpid/server/ack/TxAck.java | 4 +- .../qpid/server/ack/UnacknowledgedMessage.java | 2 +- .../server/handler/BasicCancelMethodHandler.java | 9 ++ .../server/handler/BasicConsumeMethodHandler.java | 42 +++++++- .../server/handler/BasicRejectMethodHandler.java | 18 ++-- .../qpid/server/handler/ChannelCloseHandler.java | 7 +- .../handler/ConnectionCloseMethodHandler.java | 11 +- .../server/protocol/AMQPFastProtocolHandler.java | 3 +- .../org/apache/qpid/server/queue/AMQMessage.java | 30 +++--- .../org/apache/qpid/server/queue/AMQQueue.java | 3 +- .../queue/ConcurrentSelectorDeliveryManager.java | 12 ++- .../apache/qpid/server/queue/SubscriptionImpl.java | 109 +++++++++++++------- .../qpid/server/txn/LocalTransactionalContext.java | 2 +- .../qpid/server/txn/NonTransactionalContext.java | 22 +++- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 12 ++- 17 files changed, 290 insertions(+), 114 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 5dd6619cff..1ebe5fa0a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -319,6 +319,25 @@ public class AMQChannel public void unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException { + if (_log.isDebugEnabled()) + { + _log.debug("Unacked Map Dump size:" + _unacknowledgedMessageMap.size()); + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug(message); + + return true; + } + + public void visitComplete() + { + } + }); + } + AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); if (q != null) { @@ -342,9 +361,23 @@ public class AMQChannel private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException { - _log.info("Unsubscribing all consumers on channel " + toString()); + if (_log.isInfoEnabled()) + { + if (!_consumerTag2QueueMap.isEmpty()) + { + _log.info("Unsubscribing all consumers on channel " + toString()); + } + else + { + _log.info("No consumers to unsubscribe on channel " + toString()); + } + } for (Map.Entry me : _consumerTag2QueueMap.entrySet()) { + if (_log.isInfoEnabled()) + { + _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); + } me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); } _consumerTag2QueueMap.clear(); @@ -369,7 +402,11 @@ public class AMQChannel } else { - _log.debug(debugIdentity() + " Adding unacked message(" + deliveryTag + ") with a queue(" + queue + "):" + message.debugIdentity()); + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag + + ") with a queue(" + queue + ") for " + consumerTag); + } } } @@ -395,25 +432,38 @@ public class AMQChannel */ public void requeue() throws AMQException { + if (_log.isInfoEnabled()) + { + _log.info("Requeuing for " + toString()); + } + // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); + if (_log.isDebugEnabled()) + { + _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages."); + } // Deliver these messages out of the transaction as their delivery was never // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) + TransactionalContext deliveryContext = null; + + if (!messagesToBeDelivered.isEmpty()) { - if (_nonTransactedContext == null) + if (!(_txnContext instanceof NonTransactionalContext)) { - _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); - } +// if (_nonTransactedContext == null) + { + _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, + _returnMessages, _browsedAcks); + } - deliveryContext = _nonTransactedContext; - } - else - { - deliveryContext = _txnContext; + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; + } } @@ -421,6 +471,10 @@ public class AMQChannel { if (unacked.queue != null) { + // Ensure message is released for redelivery + unacked.message.release(); + + // Mark message redelivered unacked.message.setRedelivered(true); // Deliver Message @@ -459,7 +513,7 @@ public class AMQChannel TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - if (_nonTransactedContext == null) +// if (_nonTransactedContext == null) { _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); @@ -472,13 +526,12 @@ public class AMQChannel deliveryContext = _txnContext; } - if (unacked.queue != null) { //Redeliver the messages to the front of the queue deliveryContext.deliver(unacked.message, unacked.queue, true); - - unacked.message.decrementReference(_storeContext); + //Deliver increments the message count but we have already deliverted this once so don't increment it again + // this was because deliver did an increment changed this. } else { @@ -489,7 +542,6 @@ public class AMQChannel // // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); // -// unacked.message.decrementReference(_storeContext); } } else @@ -656,15 +708,16 @@ public class AMQChannel } sub.addToResendQueue(msg); _unacknowledgedMessageMap.remove(message.deliveryTag); - // Don't decrement as we are bypassing the normal deliver which increments - // this is why there is a decrement on the Requeue as deliver will increment. - // msg.decrementReference(_storeContext); } } // sync(sub.getSendLock) } else { - _log.info("DeliveredSubscription not recorded so just requeueing to prevent loss"); + + if (_log.isInfoEnabled()) + { + _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + ")to prevent loss"); + } //move this message to requeue msgToRequeue.add(message); } @@ -706,7 +759,6 @@ public class AMQChannel deliveryContext.deliver(message.message, message.queue, true); _unacknowledgedMessageMap.remove(message.deliveryTag); - message.message.decrementReference(_storeContext); } } @@ -760,8 +812,18 @@ public class AMQChannel { synchronized (_unacknowledgedMessageMap.getLock()) { + if (_log.isDebugEnabled()) + { + _log.debug("Unacked (PreAck) Size:" + _unacknowledgedMessageMap.size()); + } + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); checkSuspension(); + if (_log.isDebugEnabled()) + { + _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size()); + } + } } @@ -775,12 +837,6 @@ public class AMQChannel return _unacknowledgedMessageMap; } - public void addUnacknowledgedBrowsedMessage(AMQMessage msg, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) - { - _browsedAcks.add(deliveryTag); - addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - } - private void checkSuspension() { boolean suspend; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index 820f0122f5..fb16267d97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -37,6 +37,10 @@ public abstract class RequiredDeliveryException extends AMQException { super(message); _amqMessage = payload; + // Increment the reference as this message is in the routing phase + // and so will have the ref decremented as routing fails. + // we need to keep this message around so we can return it in the + // handler. So increment here. payload.incrementReference(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index c987c12154..aac9408247 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -101,6 +101,8 @@ public class TxAck implements TxnOp for (UnacknowledgedMessage msg : _unacked) { msg.restoreTransientMessageData(); + + //Message has been ack so discard it. This will dequeue and decrement the reference. msg.discard(storeContext); } } @@ -124,7 +126,7 @@ public class TxAck implements TxnOp _map.remove(_unacked); for (UnacknowledgedMessage msg : _unacked) { - msg.clearTransientMessageData(); + msg.clearTransientMessageData(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index 940b5b2bf1..b8c5e821f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -39,7 +39,6 @@ public class UnacknowledgedMessage this.message = message; this.consumerTag = consumerTag; this.deliveryTag = deliveryTag; - message.incrementReference(); } public String toString() @@ -63,6 +62,7 @@ public class UnacknowledgedMessage { message.dequeue(storeContext, queue); } + //if the queue is null then the message is waiting to be acked, but has been removed. message.decrementReference(storeContext); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index 7d18043f5c..8bab96a11b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -29,9 +29,12 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; public class BasicCancelMethodHandler implements StateAwareMethodListener { + private static final Logger _log = Logger.getLogger(BasicCancelMethodHandler.class); + private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); public static BasicCancelMethodHandler getInstance() @@ -55,6 +58,12 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener +public class ConnectionCloseMethodHandler implements StateAwareMethodListener { private static final Logger _logger = Logger.getLogger(ConnectionCloseMethodHandler.class); @@ -49,8 +49,11 @@ public class ConnectionCloseMethodHandler implements StateAwareMethodListener destinationQueues = _transientMessageData.getDestinationQueues(); if (_log.isDebugEnabled()) { - _log.debug("Delivering message " + _messageId + " to " + destinationQueues); + _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues); } try { @@ -589,6 +590,8 @@ public class AMQMessage for (AMQQueue q : destinationQueues) { + //Increment the references to this message for each queue delivery. + incrementReference(); //normal deliver so add this message at the end. _txnContext.deliver(this, q, false); } @@ -596,6 +599,7 @@ public class AMQMessage finally { destinationQueues.clear(); + // Remove refence for routing process . Reference count should now == delivered queue count decrementReference(storeContext); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 7c2fe73386..78f144703b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -516,7 +516,7 @@ public class AMQQueue implements Managable, Comparable { if (_logger.isInfoEnabled()) { - _logger.warn("Auto-deleteing queue:" + this); + _logger.info("Auto-deleteing queue:" + this); } autodelete(); // we need to manually fire the event to the removed subscription (which was the last one left for this @@ -624,7 +624,6 @@ public class AMQQueue implements Managable, Comparable try { msg.dequeue(storeContext, this); - msg.decrementReference(storeContext); } catch (MessageCleanupException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 87868f0b25..6122d191f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -383,6 +383,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return count; } + /** + This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. + */ private AMQMessage getNextMessage() throws AMQException { return getNextMessage(_messages, null); @@ -392,13 +395,14 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { AMQMessage message = messages.peek(); - while (message != null && ((sub != null && sub.isBrowser()) || message.taken(sub))) + //while (we have a message) && (The subscriber is not a browser or we are clearing) && (Check message is taken.) + while (message != null && (sub != null && !sub.isBrowser() || sub == null) && message.taken(sub)) { //remove the already taken message AMQMessage removed = messages.poll(); assert removed == message; - + _totalMessageSize.addAndGet(-message.getSize()); if (_log.isTraceEnabled()) @@ -494,7 +498,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _extraMessages.decrementAndGet(); } - else if (messageQueue == sub.getPreDeliveryQueue()) + else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser()) { if (_log.isInfoEnabled()) { @@ -695,7 +699,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + + _log.debug(debugIdentity() + " Message(" + msg.toString() + ") has been taken so disregarding deliver request to Subscriber:" + System.identityHashCode(s)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 20033daac7..d3578d39e8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -256,10 +256,10 @@ public class SubscriptionImpl implements Subscription // We don't need to add the message to the unacknowledgedMap as we don't need to know if the client // received the message. If it is lost in transit that is not important. - if (_acks) - { - channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); - } +// if (_acks) +// { +// channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); +// } if (_sendLock.get()) { @@ -273,41 +273,49 @@ public class SubscriptionImpl implements Subscription private void sendToConsumer(StoreContext storeContext, AMQMessage msg, AMQQueue queue) throws AMQException { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!_acks) - { - if (_logger.isDebugEnabled()) + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + if (!_acks) { - _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); + if (_logger.isDebugEnabled()) + { + _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); + } + queue.dequeue(storeContext, msg); } - queue.dequeue(storeContext, msg); - } - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - if (_sendLock.get()) + synchronized (channel) { - _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); - } + long deliveryTag = channel.getNextDeliveryTag(); - if (_acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - msg.decrementReference(storeContext); - } + if (_sendLock.get()) + { + _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); + } - protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); + if (_acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } + + protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); + + } + } + finally + { //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. + // using a try->finally would set it even if an error occured. + // Is this what we want? + msg.setDeliveredToConsumer(); } } @@ -461,14 +469,25 @@ public class SubscriptionImpl implements Subscription public void close() { + boolean closed = false; synchronized (_sendLock) { if (_logger.isDebugEnabled()) { - _logger.debug("Setting SendLock true"); + _logger.debug("Setting SendLock true:" + debugIdentity()); + } + + closed = _sendLock.getAndSet(true); + } + + if (closed) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Called close() on a closed subscription"); } - _sendLock.set(true); + return; } if (_logger.isInfoEnabled()) @@ -488,16 +507,36 @@ public class SubscriptionImpl implements Subscription //remove references in PDQ if (_messages != null) { + if (_logger.isInfoEnabled()) + { + _logger.info("Clearing PDQ (" + debugIdentity() + "):" + this); + } + _messages.clear(); } + } + + private void autoclose() + { + close(); if (_autoClose && !_sentClose) { - _logger.info("Closing autoclose subscription:" + this); + _logger.info("Closing autoclose subscription (" + debugIdentity() + "):" + this); + ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter(); converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag); - _sentClose = true; + + //fixme JIRA do this better + try + { + channel.unsubscribeConsumer(protocolSession, consumerTag); + } + catch (AMQException e) + { + // Occurs if we cannot find the subscriber in the channel with protocolSession and consumerTag. + } } } @@ -590,7 +629,7 @@ public class SubscriptionImpl implements Subscription { if (_messages.isEmpty()) { - close(); + autoclose(); return null; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index e5cce672f6..cf0da55f2a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -100,7 +100,7 @@ public class LocalTransactionalContext implements TransactionalContext // 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. - message.incrementReference(); +// message.incrementReference(); _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); _messageDelivered = true; /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 19146da22e..181dfa3a80 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -93,7 +93,6 @@ public class NonTransactionalContext implements TransactionalContext { try { - message.incrementReference(); queue.process(_storeContext, message, deliverFirst); //following check implements the functionality //required by the 'immediate' flag: @@ -128,6 +127,8 @@ public class NonTransactionalContext implements TransactionalContext { _log.debug("Discarding message: " + message.message.getMessageId()); } + + //Message has been ack so discard it. This will dequeue and decrement the reference. message.discard(_storeContext); } else @@ -160,6 +161,8 @@ public class NonTransactionalContext implements TransactionalContext { _log.debug("Discarding message: " + msg.message.getMessageId()); } + + //Message has been ack so discard it. This will dequeue and decrement the reference. msg.discard(_storeContext); } else @@ -181,7 +184,22 @@ public class NonTransactionalContext implements TransactionalContext throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channel.getChannelId()); } - msg.discard(_storeContext); + + if (!_browsedAcks.contains(deliveryTag)) + { + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + msg.message.getMessageId()); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(_storeContext); + } + else + { + _browsedAcks.remove(deliveryTag); + } + if (_log.isDebugEnabled()) { _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java index d04b93a469..339ca8ae1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -27,10 +27,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.store.StoreContext; -/** - * Holds a list of TxnOp instance representing transactional - * operations. - */ +/** Holds a list of TxnOp instance representing transactional operations. */ public class TxnBuffer { private final List _ops = new ArrayList(); @@ -42,6 +39,11 @@ public class TxnBuffer public void commit(StoreContext context) throws AMQException { + if (_log.isDebugEnabled()) + { + _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops.toArray()); + } + if (prepare(context)) { for (TxnOp op : _ops) @@ -64,7 +66,7 @@ public class TxnBuffer catch (Exception e) { //compensate previously prepared ops - for(int j = 0; j < i; j++) + for (int j = 0; j < i; j++) { _ops.get(j).undoPrepare(); } -- cgit v1.2.1 From 1cb785d8ebfb6b810e0b633e72efadbba252e6bd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 13 Mar 2007 13:23:14 +0000 Subject: Fixed bug where non durable queues would be attempted to be deleted from the store git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@517683 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/QueueDeleteHandler.java | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index 0c7de312a7..eb7089afdc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -34,7 +34,7 @@ import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.AMQChannel; -public class QueueDeleteHandler implements StateAwareMethodListener +public class QueueDeleteHandler implements StateAwareMethodListener { private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); @@ -56,7 +56,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); VirtualHost virtualHost = session.getVirtualHost(); @@ -65,9 +65,9 @@ public class QueueDeleteHandler implements StateAwareMethodListener Date: Tue, 13 Mar 2007 16:04:00 +0000 Subject: QPID-411 : ClearQueue functionality of AMQQueue doesn't reset the queue depth AMQQueueMBeanTest.java moved to Broker tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@517745 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 6122d191f8..f9b5b5174c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -378,6 +378,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager msg = getNextMessage(); count++; } + _totalMessageSize.set(0L); } _lock.unlock(); return count; -- cgit v1.2.1 From 7cc13f5f1df30f8b3d6d21c9dc3da3aa72a06a01 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 15 Mar 2007 10:39:31 +0000 Subject: QPID-170 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518569 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index f9b5b5174c..067b6b138b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -527,7 +527,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.lock(); for (AMQMessage msg : movedMessageList) { - addMessageToQueue(msg, true); + addMessageToQueue(msg, false); } // enqueue on the pre delivery queues -- cgit v1.2.1 From 825114e27ef96f8f7b2d6b104092c08cc389202a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 15 Mar 2007 10:42:24 +0000 Subject: QPID-415 Default configuration for queues in virtualHost.xml doesn't get applied to the queue created after broker startup git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518570 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 9 +++++++++ .../configuration/VirtualHostConfiguration.java | 23 +++++++++++++++++++++- .../qpid/server/handler/QueueDeclareHandler.java | 8 ++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index adb2630bcf..386b0e6c45 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -36,6 +36,9 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.commons.configuration.Configuration; /** * This MBean implements the broker management interface and exposes the @@ -158,6 +161,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { _messageStore.createQueue(queue); } + + Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + if (virtualHostDefaultQueueConfiguration != null) + { + Configurator.configure(queue, virtualHostDefaultQueueConfiguration); + } _queueRegistry.registerQueue(queue); } catch (AMQException ex) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index a35a46f305..8573902af4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -43,7 +43,7 @@ public class VirtualHostConfiguration { private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); - XMLConfiguration _config; + private static XMLConfiguration _config; private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; @@ -128,6 +128,27 @@ public class VirtualHostConfiguration } } + public static CompositeConfiguration getDefaultQueueConfiguration(AMQQueue queue) + { + CompositeConfiguration queueConfiguration = null; + if (_config == null) + return null; + + Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + queue.getVirtualHost().getName()); + + if (vHostConfiguration == null) + return null; + + Configuration defaultQueueConfiguration = vHostConfiguration.subset("queues"); + if (defaultQueueConfiguration != null) + { + queueConfiguration = new CompositeConfiguration(); + queueConfiguration.addConfiguration(defaultQueueConfiguration); + } + + return queueConfiguration; + } + private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException { CompositeConfiguration queueConfiguration = new CompositeConfiguration(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 8b2467f47d..9e0a1019f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -34,6 +34,7 @@ import org.apache.qpid.framing.QueueDeclareOkBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -44,6 +45,7 @@ import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.AMQChannel; +import org.apache.commons.configuration.Configuration; public class QueueDeclareHandler implements StateAwareMethodListener { @@ -192,6 +194,12 @@ public class QueueDeclareHandler implements StateAwareMethodListener Date: Thu, 15 Mar 2007 15:39:39 +0000 Subject: Short pause to help ensure connection.close comes after last message ack, added to PropertyValueTest git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518667 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/RequiredDeliveryException.java | 8 +++++--- .../java/org/apache/qpid/server/ack/TxAck.java | 2 +- .../org/apache/qpid/server/queue/AMQMessage.java | 23 +++++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index fb16267d97..ff933d3c0b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -36,12 +36,14 @@ public abstract class RequiredDeliveryException extends AMQException public RequiredDeliveryException(String message, AMQMessage payload) { super(message); - _amqMessage = payload; + // Increment the reference as this message is in the routing phase // and so will have the ref decremented as routing fails. // we need to keep this message around so we can return it in the - // handler. So increment here. - payload.incrementReference(); + // handler. So increment here. + _amqMessage = payload.takeReference(); + + //payload.incrementReference(); } public AMQMessage getAMQMessage() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index aac9408247..5ca8d57f7c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -116,7 +116,7 @@ public class TxAck implements TxnOp for (UnacknowledgedMessage msg : _unacked) { msg.clearTransientMessageData(); - msg.message.incrementReference(); + msg.message.takeReference(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index cdf316f2d7..d6962d28cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -355,15 +355,22 @@ public class AMQMessage return _messageId; } + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic operation. + */ + public AMQMessage takeReference() + { + _referenceCount.incrementAndGet(); + return this; + } + /** Threadsafe. Increment the reference count on the message. */ - public void incrementReference() + protected void incrementReference() { _referenceCount.incrementAndGet(); if (_log.isDebugEnabled()) { - _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - } } @@ -377,11 +384,13 @@ public class AMQMessage */ public void decrementReference(StoreContext storeContext) throws MessageCleanupException { + int count = _referenceCount.decrementAndGet(); + // note that the operation of decrementing the reference count and then removing the message does not // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after // the message has been passed to all queues. i.e. we are // not relying on the all the increments having taken place before the delivery manager decrements. - if (_referenceCount.decrementAndGet() == 0) + if (count == 0) { try { @@ -408,13 +417,13 @@ public class AMQMessage { if (_log.isDebugEnabled()) { - _log.debug("Decremented ref count is now " + _referenceCount + " for message id " + debugIdentity() + "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 5)); - if (_referenceCount.get() < 0) + _log.debug("Decremented ref count is now " + count + " for message id " + debugIdentity() + "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 5)); + if (count < 0) { Thread.dumpStack(); } } - if (_referenceCount.get() < 0) + if (count < 0) { throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0."); } -- cgit v1.2.1 From 5862acc2fffa1b852b7e9be18e6abc29c77b6ba3 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 15 Mar 2007 15:44:01 +0000 Subject: - DeliveryManager.getMessage is reimplmented because the ConcurrentLinkedMessageQueueAtomicSize.toArray is not implemented - Not creating lock while doing startMovingMessages.Just setting movingMessage to true, because that can stop the sync delivery. - And some tidy up of the code. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518669 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 50 ++++++++------------- .../queue/ConcurrentSelectorDeliveryManager.java | 51 ++++++++++++++++++++-- .../apache/qpid/server/queue/DeliveryManager.java | 2 + 3 files changed, 68 insertions(+), 35 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 78f144703b..f17a6fb60a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -235,37 +235,40 @@ public class AMQQueue implements Managable, Comparable return _deliveryMgr.getMessages(); } + /** + * Returns messages within the given range of message Ids + * @param fromMessageId + * @param toMessageId + * @return List of messages + */ + public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) + { + return _deliveryMgr.getMessages(fromMessageId, toMessageId); + } + public long getQueueDepth() { return _deliveryMgr.getTotalMessageSize(); } - /** * @param messageId - * * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. */ public AMQMessage getMessageOnTheQueue(long messageId) { - List list = getMessagesOnTheQueue(); - AMQMessage msg = null; - for (AMQMessage message : list) + List list = getMessagesOnTheQueue(messageId, messageId); + if (list == null || list.size() == 0) { - if (message.getMessageId() == messageId) - { - msg = message; - break; - } + return null; } - - return msg; + return list.get(0); } /** * moves messages from this queue to another queue. to do this the approach is following- - setup the queue for - * moving messages (hold the lock and stop the async delivery) - get all the messages available in the given message - * id range - setup the other queue for moving messages (hold the lock and stop the async delivery) - send these + * moving messages (stop the async delivery) - get all the messages available in the given message + * id range - setup the other queue for moving messages (stop the async delivery) - send these * available messages to the other queue (enqueue in other queue) - Once sending to other Queue is successful, * remove messages from this queue - remove locks from both queues and start async delivery * @@ -282,24 +285,7 @@ public class AMQQueue implements Managable, Comparable try { startMovingMessages(); - List list = getMessagesOnTheQueue(); - List foundMessagesList = new ArrayList(); - int maxMessageCountToBeMoved = (int) (toMessageId - fromMessageId + 1); - - // Run this loop till you find all the messages or the list has no more messages - for (AMQMessage message : list) - { - long msgId = message.getMessageId(); - if (msgId >= fromMessageId && msgId <= toMessageId) - { - foundMessagesList.add(message); - } - // break the loop as soon as messages to be removed are found - if (foundMessagesList.size() == maxMessageCountToBeMoved) - { - break; - } - } + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); // move messages to another queue anotherQueue.startMovingMessages(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 067b6b138b..879080e10c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -208,15 +208,61 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - + /** + * Returns all the messages in the Queue + * @return List of messages + */ public List getMessages() { _lock.lock(); - ArrayList list = new ArrayList(_messages); + List list = new ArrayList(); + + for (AMQMessage message : _messages) + { + list.add(message); + } _lock.unlock(); + return list; } + /** + * Returns messages within the range of given messageIds + * @param fromMessageId + * @param toMessageId + * @return + */ + public List getMessages(long fromMessageId, long toMessageId) + { + if (fromMessageId <= 0 || toMessageId <= 0) + { + return null; + } + + long maxMessageCount = toMessageId - fromMessageId + 1; + + _lock.lock(); + + List foundMessagesList = new ArrayList(); + + for (AMQMessage message : _messages) + { + long msgId = message.getMessageId(); + if (msgId >= fromMessageId && msgId <= toMessageId) + { + foundMessagesList.add(message); + } + // break if the no of messages are found + if (foundMessagesList.size() == maxMessageCount) + { + break; + } + } + _lock.unlock(); + + return foundMessagesList; + } + public void populatePreDeliveryQueue(Subscription subscription) { if (_log.isTraceEnabled()) @@ -294,7 +340,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager */ public void startMovingMessages() { - _lock.lock(); _movingMessages.set(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java index 5b77951dfd..10ba48552c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -86,6 +86,8 @@ interface DeliveryManager List getMessages(); + List getMessages(long fromMessageId, long toMessageId); + void populatePreDeliveryQueue(Subscription subscription); boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; -- cgit v1.2.1 From 394322f25d041bab8617b1a7b96e2dd49835e93b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Mar 2007 14:46:42 +0000 Subject: QPID-70 InVM Authentication QPID-419 Access Control QPID-423 Authentication per virtualhost Restructured auth package. Enabled InVM Authentication Initial changes to allow authenticators per virtualhost. Initial access control classes. Initial work to allow access control testing through inVM broker. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518988 13f79535-47bb-0310-9956-ffa450edef68 --- .../handler/ConnectionOpenMethodHandler.java | 34 ++- .../handler/ConnectionSecureOkMethodHandler.java | 6 +- .../handler/ConnectionStartOkMethodHandler.java | 24 +- .../server/protocol/AMQMinaProtocolSession.java | 20 +- .../qpid/server/protocol/AMQProtocolSession.java | 5 + .../ConfigurationFileApplicationRegistry.java | 58 +++-- .../qpid/server/registry/IApplicationRegistry.java | 8 +- .../qpid/server/security/access/AccessManager.java | 29 +++ .../server/security/access/AccessManagerImpl.java | 136 ++++++++++++ .../qpid/server/security/access/AccessResult.java | 66 ++++++ .../qpid/server/security/access/Accessable.java | 27 +++ .../qpid/server/security/access/AllowAll.java | 35 +++ .../qpid/server/security/access/DenyAll.java | 34 +++ .../access/PrincipalDatabaseAccessManager.java | 84 +++++++ .../security/auth/AuthenticationManager.java | 33 --- .../auth/AuthenticationProviderInitialiser.java | 67 ------ .../server/security/auth/CRAMMD5Initialiser.java | 38 ---- .../qpid/server/security/auth/JCAProvider.java | 47 ---- .../security/auth/NullAuthenticationManager.java | 82 ------- .../auth/PasswordFilePrincipalDatabase.java | 138 ------------ .../server/security/auth/PrincipalDatabase.java | 46 ---- .../security/auth/SASLAuthenticationManager.java | 228 ------------------- .../security/auth/UsernamePasswordInitialiser.java | 107 --------- .../server/security/auth/UsernamePrincipal.java | 42 ---- .../auth/amqplain/AmqPlainInitialiser.java | 38 ---- .../security/auth/amqplain/AmqPlainSaslServer.java | 129 ----------- .../auth/amqplain/AmqPlainSaslServerFactory.java | 60 ----- .../ConfigurationFilePrincipalDatabaseManager.java | 148 +++++++++++++ .../database/MD5PasswordFilePrincipalDatabase.java | 161 ++++++++++++++ .../PlainPasswordFilePrincipalDatabase.java | 163 ++++++++++++++ .../PlainPasswordVhostFilePrincipalDatabase.java | 241 ++++++++++++++++++++ .../security/auth/database/PrincipalDatabase.java | 50 +++++ .../auth/database/PrincipalDatabaseManager.java | 30 +++ .../auth/database/PropertiesPrincipalDatabase.java | 83 +++++++ .../PropertiesPrincipalDatabaseManager.java | 41 ++++ .../auth/manager/AuthenticationManager.java | 37 ++++ .../PrincipalDatabaseAuthenticationManager.java | 246 +++++++++++++++++++++ .../security/auth/plain/PlainInitialiser.java | 38 ---- .../security/auth/plain/PlainSaslServer.java | 149 ------------- .../auth/plain/PlainSaslServerFactory.java | 60 ----- .../sasl/AuthenticationProviderInitialiser.java | 76 +++++++ .../server/security/auth/sasl/JCAProvider.java | 47 ++++ .../auth/sasl/UsernamePasswordInitialiser.java | 118 ++++++++++ .../security/auth/sasl/UsernamePrincipal.java | 42 ++++ .../auth/sasl/crammd5/CRAMMD5Initialiser.java | 71 ++++++ .../qpid/server/util/NullApplicationRegistry.java | 42 +++- .../qpid/server/virtualhost/VirtualHost.java | 134 ++++++----- 47 files changed, 2199 insertions(+), 1399 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index a85af61327..2ecb39254f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -32,9 +32,13 @@ 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.virtualhost.VirtualHost; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.log4j.Logger; public class ConnectionOpenMethodHandler implements StateAwareMethodListener { + private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); + private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); public static ConnectionOpenMethodHandler getInstance() @@ -58,9 +62,9 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener _closingChannelsList = new ArrayList(); private ProtocolOutputConverter _protocolOutputConverter; + private String _authorizedID; public ManagedObject getManagedObject() @@ -205,22 +206,22 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); - if(_logger.isDebugEnabled()) + if (_logger.isDebugEnabled()) { _logger.debug("Frame Received: " + frame); } if (body instanceof AMQMethodBody) { - methodFrameReceived(channelId, (AMQMethodBody)body); + methodFrameReceived(channelId, (AMQMethodBody) body); } else if (body instanceof ContentHeaderBody) { - contentHeaderReceived(channelId, (ContentHeaderBody)body); + contentHeaderReceived(channelId, (ContentHeaderBody) body); } else if (body instanceof ContentBody) { - contentBodyReceived(channelId, (ContentBody)body); + contentBodyReceived(channelId, (ContentBody) body); } else if (body instanceof HeartbeatBody) { @@ -674,7 +675,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private void setProtocolVersion(byte major, byte minor) { - _protocolVersion = new ProtocolVersion(major,minor); + _protocolVersion = new ProtocolVersion(major, minor); _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); @@ -735,5 +736,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _protocolOutputConverter; } + public void setAuthorizedID(String authorizedID) + { + _authorizedID = authorizedID; + } + + public String getAuthorizedID() + { + return _authorizedID; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 4cfee06850..79421dd497 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -165,4 +165,9 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public ProtocolOutputConverter getProtocolOutputConverter(); + void setAuthorizedID(String authorizedID); + + /** @return a username string that was used to authorized this session */ + String getAuthorizedID(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 70248a8e52..739ed9db42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -34,8 +34,12 @@ 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.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.SASLAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -46,6 +50,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry private AuthenticationManager _authenticationManager; + private AccessManager _accessManager; + + private PrincipalDatabaseManager _databaseManager; + private VirtualHostRegistry _virtualHostRegistry; @@ -59,26 +67,33 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry // 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) { + private static class MyConfiguration extends CompositeConfiguration + { + public String interpolate(String obj) + { return super.interpolate(obj); } } - private static final Configuration config(File url) throws ConfigurationException { + 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) { + conf.addConfiguration(new SystemConfiguration() + { + protected String interpolate(String o) + { return conf.interpolate(o); } }); - conf.addConfiguration(new XMLConfiguration(url) { - protected String interpolate(String o) { + conf.addConfiguration(new XMLConfiguration(url) + { + protected String interpolate(String o) + { return conf.interpolate(o); } }); @@ -89,17 +104,22 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { initialiseManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - _authenticationManager = new SASLAuthenticationManager(); + + _accessManager = new AccessManagerImpl("default", _configuration); + + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); initialiseVirtualHosts(); } private void initialiseVirtualHosts() throws Exception { - for(String name : getVirtualHostNames()) + for (String name : getVirtualHostNames()) { - - _virtualHostRegistry.registerVirtualHost(new VirtualHost(name,getConfiguration().subset("virtualhosts.virtualhost."+name))); + + _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name))); } } @@ -122,11 +142,21 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry return _virtualHostRegistry; } + public AccessManager getAccessManager() + { + return _accessManager; + } + public ManagedObjectRegistry getManagedObjectRegistry() { return _managedObjectRegistry; } + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + public AuthenticationManager getAuthenticationManager() { return _authenticationManager; @@ -134,6 +164,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public Collection getVirtualHostNames() { - return getConfiguration().getList("virtualhosts.virtualhost.name"); + return getConfiguration().getList("virtualhosts.virtualhost.name"); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 5924cdb178..5a48431288 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -24,7 +24,9 @@ import java.util.Collection; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public interface IApplicationRegistry @@ -57,9 +59,13 @@ public interface IApplicationRegistry ManagedObjectRegistry getManagedObjectRegistry(); + PrincipalDatabaseManager getDatabaseManager(); + AuthenticationManager getAuthenticationManager(); Collection getVirtualHostNames(); VirtualHostRegistry getVirtualHostRegistry(); + + AccessManager getAccessManager(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java new file mode 100644 index 0000000000..0c0de88182 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public interface AccessManager +{ + AccessResult isAuthorized(Accessable accessObject, String username); + + String getName(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java new file mode 100644 index 0000000000..0b022aa8f7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; +import org.apache.log4j.Logger; + +import java.util.List; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +public class AccessManagerImpl implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(AccessManagerImpl.class); + + AccessManager _accessManager; + + public AccessManagerImpl(String name, Configuration hostConfig) throws ConfigurationException + { + String accessClass = hostConfig.getString("security.access.class"); + + if (accessClass == null) + { + _logger.warn("No access control specified. Using default access controls for VirtualHost:'" + name + "'"); + return; + } + + Object o; + try + { + o = Class.forName(accessClass).newInstance(); + } + catch (Exception e) + { + throw new ConfigurationException("Error initialising access control: " + e, e); + } + + if (!(o instanceof AccessManager)) + { + throw new ConfigurationException("Access control must implement the VirtualHostAccess interface"); + } + + initialiseAccessControl((AccessManager) o, hostConfig); + + _accessManager = (AccessManager) o; + + _logger.info("Initialised access control for virtualhost '" + name + "' successfully"); + + } + + + private void initialiseAccessControl(AccessManager accessManager, Configuration config) + throws ConfigurationException + { + String baseName = "access.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 ConfigurationException("Access Control 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 = null; + try + { + method = accessManager.getClass().getMethod(methodName, String.class); + } + catch (NoSuchMethodException e) + { + //do nothing as method will be null + } + + if (method == null) + { + throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() + + " hence unable to configure access control. The method must be public and " + + "have a single String argument with a void return type"); + } + try + { + method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception e) + { + throw new ConfigurationException(e.getCause()); + } + } + } + + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + if (_accessManager == null) + { + return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, username); + } + else + { + return _accessManager.isAuthorized(accessObject, username); + } + } + + public String getName() + { + return "AccessManagerImpl"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java new file mode 100644 index 0000000000..b8d8fc605a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessResult +{ + public enum AccessStatus + { + GRANTED, REFUSED + } + + StringBuilder _authorizer; + AccessStatus _status; + + public AccessResult(AccessManager authorizer, AccessStatus status) + { + _status = status; + _authorizer = new StringBuilder(authorizer.getName()); + } + + public void setAuthorizer(AccessManager authorizer) + { + _authorizer.append(authorizer.getName()); + } + + public String getAuthorizer() + { + return _authorizer.toString(); + } + + public void setStatus(AccessStatus status) + { + _status = status; + } + + public AccessStatus getStatus() + { + return _status; + } + + public void addAuthorizer(AccessManager accessManager) + { + _authorizer.insert(0, "->"); + _authorizer.insert(0, accessManager.getName()); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java new file mode 100644 index 0000000000..f51cf24caa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public interface Accessable +{ + void setAccessableName(String name); + String getAccessableName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java new file mode 100644 index 0000000000..b2e4094edd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AllowAll implements AccessManager +{ + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + + public String getName() + { + return "AllowAll"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java new file mode 100644 index 0000000000..0e62d2657f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class DenyAll implements AccessManager +{ + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "DenyAll"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java new file mode 100644 index 0000000000..d41e5dfb94 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.log4j.Logger; + +public class PrincipalDatabaseAccessManager implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAccessManager.class); + + PrincipalDatabase _database; + AccessManager _default; + + public PrincipalDatabaseAccessManager() + { + _default = ApplicationRegistry.getInstance().getAccessManager(); + } + + public void setDefaultAccessManager(String defaultAM) + { + if (defaultAM.equals("AllowAll")) + { + _default = new AllowAll(); + } + + if (defaultAM.equals("DenyAll")) + { + _default = new DenyAll(); + } + } + + public void setPrincipalDatabase(String database) + { + _database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(database); + if (!(_database instanceof AccessManager)) + { + _logger.warn("Database '" + database + "' cannot perform access management"); + } + } + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + AccessResult result; + + if (_database == null) + { + result = _default.isAuthorized(accessObject, username); + } + else + { + result = ((AccessManager) _database).isAuthorized(accessObject, username); + } + + result.addAuthorizer(this); + + return result; + } + + public String getName() + { + return "PrincipalDatabaseFileAccessManager"; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java deleted file mode 100644 index 9f4addd7ee..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -public interface AuthenticationManager -{ - String getMechanisms(); - - SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; - - AuthenticationResult authenticate(SaslServer server, byte[] response); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java deleted file mode 100644 index 19e562517e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; - -import org.apache.commons.configuration.Configuration; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java deleted file mode 100644 index 4e428bbf23..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5Initialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "CRAM-MD5"; - } - - public Class getServerFactoryClassForJCARegistration() - { - // since the CRAM-MD5 provider is registered as part of the JDK, we do not - // return the factory class here since we do not need to register it ourselves. - return null; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java deleted file mode 100644 index ac8eae024e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.security.Provider; -import java.security.Security; -import java.util.Map; - -import javax.security.sasl.SaslServerFactory; - -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()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java deleted file mode 100644 index 20f190876f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java deleted file mode 100644 index b0592a7173..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.security.Principal; -import java.util.regex.Pattern; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -import org.apache.log4j.Logger; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java deleted file mode 100644 index e731ea271b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.io.IOException; -import java.security.Principal; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java deleted file mode 100644 index 66923e371b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.lang.reflect.Method; -import java.security.Security; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -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 org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.server.registry.ApplicationRegistry; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java deleted file mode 100644 index d88c6df548..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.io.IOException; -import java.security.Principal; -import java.util.Map; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; - -import org.apache.commons.configuration.Configuration; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java deleted file mode 100644 index e068ba6fe4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.security.Principal; - -/** - * A principal that is just a wrapper for a simple username. - * - */ -public class UsernamePrincipal implements Principal -{ - private String _name; - - public UsernamePrincipal(String name) - { - _name = name; - } - - public String getName() - { - return _name; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java deleted file mode 100644 index 543115fd90..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -public class AmqPlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "AMQPLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return AmqPlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java deleted file mode 100644 index 9e5a8f9a08..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; - -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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.getString("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.getString("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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java deleted file mode 100644 index 2569314a4a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java new file mode 100644 index 0000000000..dde4ce7c4d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.List; +import java.util.HashMap; +import java.lang.reflect.Method; +import java.io.FileNotFoundException; + +public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager +{ + private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); + + private static final String _base = "principal-databases.principal-database"; + + Map _databases; + + public ConfigurationFilePrincipalDatabaseManager() throws Exception + { + _logger.info("Initialising PrincipleDatabase authentication manager"); + _databases = initialisePrincipalDatabases(); + } + + private Map initialisePrincipalDatabases() throws Exception + { + Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + List databaseNames = config.getList(_base + ".name"); + List databaseClasses = config.getList(_base + ".class"); + Map databases = new HashMap(); + + if (databaseNames.size() == 0) + { + _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); + } + + 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 not provided"); + } + _logger.info("Initialised principal database '" + name + "' successfully"); + databases.put(name, (PrincipalDatabase) o); + } + return databases; + } + + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) + throws FileNotFoundException, ConfigurationException + { + String baseName = _base + "(" + 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 ConfigurationException("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 = null; + try + { + method = principalDatabase.getClass().getMethod(methodName, String.class); + } + catch (Exception e) + { + // do nothing.. as on error method will be null + } + + if (method == null) + { + throw new ConfigurationException("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"); + } + + try + { + method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception ite) + { + throw new ConfigurationException(ite.getCause()); + } + } + } + + public Map getDatabases() + { + return _databases; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..98fca99aa3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; + +/** + * 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 MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(MD5PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + public MD5PasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this,CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); + } + + 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); + } + } + + public Map getMechanisms() + { + return _saslServers; + } + + /** + * 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 java.io.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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..6770baaece --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; + +/** + * 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 PlainPasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + public PlainPasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for Plain Password file. + */ + + // Accept Plain incomming and compare it to the file. + PlainInitialiser plain = new PlainInitialiser(); + plain.initialise(this); + + // Accept MD5 incomming and Hash file value for comparison + CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); + cram.initialise(this); + + _saslServers.put(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + File f = new File(passwordFile); + _logger.info("PlainPasswordFile 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); + } + } + + public Map getMechanisms() + { + return _saslServers; + } + + + /** + * 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 java.io.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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java new file mode 100644 index 0000000000..37d883769a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; + +/** + * 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 PlainPasswordVhostFilePrincipalDatabase implements PrincipalDatabase, AccessManager +{ + private static final Logger _logger = Logger.getLogger(PlainPasswordVhostFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + public PlainPasswordVhostFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for Plain Password file. + */ + + // Accept Plain incomming and compare it to the file. + PlainInitialiser plain = new PlainInitialiser(); + plain.initialise(this); + + // Accept MD5 incomming and Hash file value for comparison + CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); + cram.initialise(this); + + _saslServers.put(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + File f = new File(passwordFile); + _logger.info("PlainPasswordFile 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); + } + } + + public Map getMechanisms() + { + return _saslServers; + } + + + /** + * 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 java.io.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(); + } + } + } + + /** + * Looks up the virtual hosts for a specified user in the password file. + * + * @param user The user to lookup + * + * @return a list of virtualhosts + */ + private String[] lookupVirtualHost(String user) + { + try + { + 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 < 3) + { + continue; + } + + if (user.equals(result[0])) + { + return result[2].split(","); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + catch (IOException ioe) + { + //ignore + } + return null; + } + + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + if (accessObject instanceof VirtualHost) + { + String[] hosts = lookupVirtualHost(username); + + if (hosts != null) + { + for (String host : hosts) + { + if (accessObject.getAccessableName().equals(host)) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + } + } + } + + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "PlainPasswordVhostFile"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java new file mode 100644 index 0000000000..6c5a2a44ee --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; + +/** 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; + + public Map getMechanisms(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java new file mode 100644 index 0000000000..83f1201bd8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import java.util.Map; + +public interface PrincipalDatabaseManager +{ + public Map getDatabases(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java new file mode 100644 index 0000000000..9a58acd98c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.util.Properties; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; +import java.io.IOException; + +public class PropertiesPrincipalDatabase implements PrincipalDatabase +{ + private Properties _users; + + private Map _saslServers; + + public PropertiesPrincipalDatabase(Properties users) + { + _users = users; + + _saslServers = new HashMap(); + + /** + * Create Authenticators for Properties Principal Database. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException + { + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + char[] pwd = _users.getProperty(principal.getName()).toCharArray(); + if (pwd != null) + { + callback.setPassword(pwd); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + public Map getMechanisms() + { + return _saslServers; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java new file mode 100644 index 0000000000..89c84e8130 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import java.util.Map; +import java.util.Properties; +import java.util.HashMap; + +public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager +{ + + Map _databases = new HashMap(); + + public PropertiesPrincipalDatabaseManager(String name, Properties users) + { + _databases.put(name, new PropertiesPrincipalDatabase(users)); + } + + public Map getDatabases() + { + return _databases; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java new file mode 100644 index 0000000000..bb94e0b7bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java new file mode 100644 index 0000000000..d0862fbb63 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -0,0 +1,246 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.SubsetConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.JCAProvider; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; +import java.security.Security; + +public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.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>(); + + private AuthenticationManager _default = null; + + public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception + { + _logger.info("Initialising " + (name == null ? " Default" : "'" + name + "'") + + " PrincipleDatabase authentication manager."); + + // Fixme This should be done per Vhost but allowing global hack isn't right but ... + // required as authentication is done before Vhost selection + + Map> providerMap = new TreeMap>(); + + + if (name == null) + { + initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); + } + else + { + String databaseName = hostConfig.getString("security.authentication.name"); + + if (databaseName == null) + { + + if (hostConfig instanceof SubsetConfiguration) + { + _logger.warn("No authentication specified for '" + ((SubsetConfiguration) hostConfig).getPrefix() + "'. Using Default authentication manager"); + } + else + { + _logger.warn("No authentication specified. Using Default authentication manager"); + } + _default = ApplicationRegistry.getInstance().getAuthenticationManager(); + return; + } + else + { + PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Requested database:" + databaseName + " was not found"); + } + + initialiseAuthenticationMechanisms(providerMap, database); + } + } + + if (providerMap.size() > 0) + { + Security.addProvider(new JCAProvider(providerMap)); + } + else + { + _logger.warn("No SASL providers availble."); + } + + } + + + private void initialiseAuthenticationMechanisms(Map> providerMap, 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. + + + if (databases.size() > 1) + { + _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); + } + + for (Map.Entry entry : databases.entrySet()) + { + + // fixme As the database now provide the mechanisms they support, they will ... + // overwrite each other in the map. There should only be one database per vhost. + // But currently we must have authentication before vhost definition. + initialiseAuthenticationMechanisms(providerMap, entry.getValue()); + } + + } + + private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception + { + if (database == null || database.getMechanisms().size() == 0) + { + _logger.warn(""); + return; + } + + for (AuthenticationProviderInitialiser mechanism : database.getMechanisms().values()) + { + initialiseAuthenticationMechanism(mechanism, providerMap); + } + } + + private void initialiseAuthenticationMechanism(AuthenticationProviderInitialiser initialiser, + Map> providerMap) + throws Exception + { + 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); + } + _logger.info("Initialised " + mechanism + " SASL provider successfully"); + } + + public String getMechanisms() + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.getMechanisms(); + } + else + { + return _mechanisms; + } + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.createSaslServer(mechanism, localFQDN); + } + else + { + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); + } + + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + // Use the default AuthenticationManager if present + if (_default != null) + { + return _default.authenticate(server, 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); + } + } + + public AuthenticationResult isAuthorize(VirtualHost vhost, String username) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java deleted file mode 100644 index 9791c13373..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -public class PlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "PLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return PlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java deleted file mode 100644 index 094315dc1f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java deleted file mode 100644 index 3ea720dd8c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java new file mode 100644 index 0000000000..89e545d6f5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +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 + * @throws Exception needs refined Exception is too broad. + */ + void initialise(String baseConfigPath, Configuration configuration, + Map principalDatabases) throws Exception; + + /** + * Initialise the authentication provider. + * @param db The principal database to initialise with + */ + void initialise(PrincipalDatabase db); + + + /** + * @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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java new file mode 100644 index 0000000000..8ffcdc4e36 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.security.Provider; +import java.security.Security; +import java.util.Map; + +import javax.security.sasl.SaslServerFactory; + +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()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java new file mode 100644 index 0000000000..68095de3a0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -0,0 +1,118 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser +{ + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + + 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); + + initialise(db); + } + + public void initialise(PrincipalDatabase db) + { + if (db == null) + { + throw new NullPointerException("Cannot initialise with a null Principal database."); + } + _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java new file mode 100644 index 0000000000..f9aaabd15a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java new file mode 100644 index 0000000000..264832888d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5Initialiser extends UsernamePasswordInitialiser +{ + private HashDirection _hashDirection; + + public enum HashDirection + { + INCOMMING, PASSWORD_FILE + } + + + 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. + if (_hashDirection == HashDirection.PASSWORD_FILE) + { + return null; + } + else + { + //fixme we need a server that will correctly has the incomming plain text for comparison to file. + _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); + return null; + } + } + + public void initialise(PrincipalDatabase passwordFile) + { + initialise(passwordFile, HashDirection.PASSWORD_FILE); + } + + public void initialise(PrincipalDatabase passwordFile, HashDirection direction) + { + super.initialise(passwordFile); + + _hashDirection = direction; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 217a524562..150b98b424 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -23,14 +23,19 @@ package org.apache.qpid.server.util; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.Properties; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.MapConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.NullAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AllowAll; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -42,6 +47,10 @@ public class NullApplicationRegistry extends ApplicationRegistry private VirtualHostRegistry _virtualHostRegistry; + private AccessManager _accessManager; + + private PrincipalDatabaseManager _databaseManager; + public NullApplicationRegistry() { @@ -50,14 +59,23 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { - _configuration.addProperty("store.class","org.apache.qpid.server.store.MemoryMessageStore"); + _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); + + Properties users = new Properties(); + + users.put("guest", "guest"); + + _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); + + _accessManager = new AllowAll(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); _managedObjectRegistry = new NoopManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - VirtualHost dummyHost = new VirtualHost("test",getConfiguration()); + VirtualHost dummyHost = new VirtualHost("test", getConfiguration()); _virtualHostRegistry.registerVirtualHost(dummyHost); _virtualHostRegistry.setDefaultVirtualHostName("test"); - _authenticationManager = new NullAuthenticationManager(); _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes @@ -74,6 +92,11 @@ public class NullApplicationRegistry extends ApplicationRegistry return _managedObjectRegistry; } + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + public AuthenticationManager getAuthenticationManager() { return _authenticationManager; @@ -81,14 +104,19 @@ public class NullApplicationRegistry extends ApplicationRegistry public Collection getVirtualHostNames() { - String[] hosts = {"test"}; - return Arrays.asList( hosts ); + String[] hosts = {"test"}; + return Arrays.asList(hosts); } public VirtualHostRegistry getVirtualHostRegistry() { return _virtualHostRegistry; } + + public AccessManager getAccessManager() + { + return _accessManager; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e09ce9326c..c24d1aa23a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -25,6 +25,11 @@ import javax.management.NotCompliantMBeanException; import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.exchange.DefaultExchangeFactory; import org.apache.qpid.server.exchange.DefaultExchangeRegistry; @@ -37,7 +42,7 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MessageStore; -public class VirtualHost +public class VirtualHost implements Accessable { private static final Logger _logger = Logger.getLogger(VirtualHost.class); @@ -50,84 +55,103 @@ public class VirtualHost private ExchangeFactory _exchangeFactory; - private MessageStore _messageStore; + private MessageStore _messageStore; protected VirtualHostMBean _virtualHostMBean; private AMQBrokerManagerMBean _brokerMBean; + private AuthenticationManager _authenticationManager; - /** - * Abstract MBean class. This has some of the methods implemented from - * management intrerface for exchanges. Any implementaion of an - * Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } + private AccessManager _accessManager; - public String getObjectInstanceName() - { - return _name.toString(); - } + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } - public String getName() - { - return _name.toString(); - } + public String getAccessableName() + { + return _name; + } - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } - } // End of MBean class + public String getObjectInstanceName() + { + return _name.toString(); + } + public String getName() + { + return _name.toString(); + } - public VirtualHost(String name, MessageStore store) throws Exception - { - _name = name; + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - _messageStore = store; - - _exchangeRegistry.initialise(); + } // End of MBean class - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, null, store); } + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception { _name = name; _virtualHostMBean = new VirtualHostMBean(); // This isn't needed to be registered //_virtualHostMBean.register(); - + _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); _exchangeRegistry = new DefaultExchangeRegistry(this); - initialiseMessageStore(hostConfig); + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } _exchangeRegistry.initialise(); + _logger.warn("VirtualHost authentication Managers require spec change to be operational."); + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = new AccessManagerImpl(name, hostConfig); + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); - } private void initialiseMessageStore(Configuration config) throws Exception @@ -140,15 +164,13 @@ public class VirtualHost if (!(o instanceof MessageStore)) { throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); + " does not."); } _messageStore = (MessageStore) o; _messageStore.configure(this, "store", config); } - - public T getConfiguredObject(Class instanceType, Configuration config) { T instance; @@ -171,7 +193,7 @@ public class VirtualHost { return _name; } - + public QueueRegistry getQueueRegistry() { return _queueRegistry; @@ -189,7 +211,7 @@ public class VirtualHost public ApplicationRegistry getApplicationRegistry() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } public MessageStore getMessageStore() @@ -197,9 +219,19 @@ public class VirtualHost return _messageStore; } + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public AccessManager getAccessManager() + { + return _accessManager; + } + public void close() throws Exception { - if(_messageStore != null) + if (_messageStore != null) { _messageStore.close(); } @@ -210,8 +242,6 @@ public class VirtualHost return _brokerMBean; } - - public ManagedObject getManagedObject() { return _virtualHostMBean; -- cgit v1.2.1 From 461f686d380296bc12e0c04b8e8ff218be6fa148 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 16 Mar 2007 14:51:49 +0000 Subject: Correctly moved amqplain and plain sasl implementations git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518989 13f79535-47bb-0310-9956-ffa450edef68 --- .../auth/sasl/amqplain/AmqPlainInitialiser.java | 38 ++++++ .../auth/sasl/amqplain/AmqPlainSaslServer.java | 129 ++++++++++++++++++ .../sasl/amqplain/AmqPlainSaslServerFactory.java | 60 +++++++++ .../security/auth/sasl/plain/PlainInitialiser.java | 38 ++++++ .../security/auth/sasl/plain/PlainSaslServer.java | 149 +++++++++++++++++++++ .../auth/sasl/plain/PlainSaslServerFactory.java | 60 +++++++++ 6 files changed, 474 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java new file mode 100644 index 0000000000..7acc6322d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class AmqPlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "AMQPLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return AmqPlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java new file mode 100644 index 0000000000..7842f376fb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java @@ -0,0 +1,129 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); + String username = (String) ft.getString("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.getString("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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java new file mode 100644 index 0000000000..67d20136bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java new file mode 100644 index 0000000000..1d16cd8755 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class PlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "PLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return PlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java new file mode 100644 index 0000000000..36aeb77fe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -0,0 +1,149 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java new file mode 100644 index 0000000000..ff3e87e3a0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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}; + } + } +} -- cgit v1.2.1 From 2794677387ce1ae11960f8c611a264f34302447e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 19 Mar 2007 11:52:33 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519912 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r519909 | ritchiem | 2007-03-19 11:13:45 +0000 (Mon, 19 Mar 2007) | 4 lines Moved the principal-database and access sections in the xml under security. Updated PlainPasswordFilePrincipalDatabase to include an AMQPLAIN authentication mechanism Changed PlainPasswordVhostFilePrincipalDatabase to extend PlainPasswordFilePrincipalDatabase as it was the same code. A few other whitespace changes and additional logging to better show why an error occurred such as was shown by the python tests. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@519916 13f79535-47bb-0310-9956-ffa450edef68 --- .../handler/ConnectionStartOkMethodHandler.java | 6 +- .../server/security/access/AccessManagerImpl.java | 2 +- .../access/PrincipalDatabaseAccessManager.java | 11 +- .../ConfigurationFilePrincipalDatabaseManager.java | 2 +- .../database/MD5PasswordFilePrincipalDatabase.java | 1 - .../PlainPasswordFilePrincipalDatabase.java | 12 ++- .../PlainPasswordVhostFilePrincipalDatabase.java | 114 +-------------------- .../PrincipalDatabaseAuthenticationManager.java | 2 +- 8 files changed, 26 insertions(+), 124 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index d8a20071b9..6c14aae7ed 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -75,9 +75,10 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< if (ss == null) { - throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server"); + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.mechanism + ); } - + session.setSaslServer(ss); AuthenticationResult authResult = authMgr.authenticate(ss, body.response); @@ -152,3 +153,4 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< } + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java index 0b022aa8f7..0feb2791da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java @@ -74,7 +74,7 @@ public class AccessManagerImpl implements AccessManager private void initialiseAccessControl(AccessManager accessManager, Configuration config) throws ConfigurationException { - String baseName = "access.attributes.attribute."; + String baseName = "security.access.attributes.attribute."; List argumentNames = config.getList(baseName + "name"); List argumentValues = config.getList(baseName + "value"); for (int i = 0; i < argumentNames.size(); i++) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java index d41e5dfb94..0e447b5744 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java @@ -33,7 +33,7 @@ public class PrincipalDatabaseAccessManager implements AccessManager public PrincipalDatabaseAccessManager() { - _default = ApplicationRegistry.getInstance().getAccessManager(); + _default = null; } public void setDefaultAccessManager(String defaultAM) @@ -64,7 +64,14 @@ public class PrincipalDatabaseAccessManager implements AccessManager if (_database == null) { - result = _default.isAuthorized(accessObject, username); + if (_default != null) + { + result = _default.isAuthorized(accessObject, username); + } + else + { + throw new RuntimeException("Principal Database and default Access Manager are both null unable to perform Access Control"); + } } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index dde4ce7c4d..0c35206dd3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -38,7 +38,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); - private static final String _base = "principal-databases.principal-database"; + private static final String _base = "security.principal-databases.principal-database"; Map _databases; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java index 98fca99aa3..c24a5f21e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 6770baaece..3abdd9a7ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -49,11 +50,11 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase { private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); - private File _passwordFile; + protected File _passwordFile; - private Pattern _regexp = Pattern.compile(":"); + protected Pattern _regexp = Pattern.compile(":"); - private Map _saslServers; + protected Map _saslServers; public PlainPasswordFilePrincipalDatabase() { @@ -63,6 +64,10 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase * Create Authenticators for Plain Password file. */ + // Accept AMQPlain incomming and compare it to the file. + AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); + amqplain.initialise(this); + // Accept Plain incomming and compare it to the file. PlainInitialiser plain = new PlainInitialiser(); plain.initialise(this); @@ -71,6 +76,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); cram.initialise(this); + _saslServers.put(amqplain.getMechanismName(), amqplain); _saslServers.put(plain.getMechanismName(), plain); _saslServers.put(cram.getMechanismName(), cram); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java index 37d883769a..c8318d6e64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -49,122 +49,10 @@ import java.security.Principal; * * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. */ -public class PlainPasswordVhostFilePrincipalDatabase implements PrincipalDatabase, AccessManager +public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePrincipalDatabase implements AccessManager { private static final Logger _logger = Logger.getLogger(PlainPasswordVhostFilePrincipalDatabase.class); - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map _saslServers; - - public PlainPasswordVhostFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for Plain Password file. - */ - - // Accept Plain incomming and compare it to the file. - PlainInitialiser plain = new PlainInitialiser(); - plain.initialise(this); - - // Accept MD5 incomming and Hash file value for comparison - CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); - cram.initialise(this); - - _saslServers.put(plain.getMechanismName(), plain); - _saslServers.put(cram.getMechanismName(), cram); - } - - public void setPasswordFile(String passwordFile) throws FileNotFoundException - { - File f = new File(passwordFile); - _logger.info("PlainPasswordFile 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); - } - } - - public Map getMechanisms() - { - return _saslServers; - } - - - /** - * 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 java.io.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(); - } - } - } - /** * Looks up the virtual hosts for a specified user in the password file. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index d0862fbb63..0546bbb81e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -62,7 +62,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception { - _logger.info("Initialising " + (name == null ? " Default" : "'" + name + "'") + _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") + " PrincipleDatabase authentication manager."); // Fixme This should be done per Vhost but allowing global hack isn't right but ... -- cgit v1.2.1 From 1b0c34d63206b35307df80686ea6549daf1a1608 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 21 Mar 2007 11:54:38 +0000 Subject: QPID-420 Adding clientID, AuthorizedId and client version on management console git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@520847 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/protocol/AMQMinaProtocolSession.java | 18 +++++++++++++++--- .../qpid/server/protocol/AMQProtocolSessionMBean.java | 17 ++++++++++++++++- .../apache/qpid/server/protocol/ManagedConnection.java | 9 +++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 1c741ead1e..fd8fb2d5cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -74,6 +74,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private AMQShortString _contextKey; + private AMQShortString _clientVersion = null; + private VirtualHost _virtualHost; private final Map _channelMap = new HashMap(); @@ -667,9 +669,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void setClientProperties(FieldTable clientProperties) { _clientProperties = clientProperties; - if ((_clientProperties != null) && (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null)) + if (_clientProperties != null) { - setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); + if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) + { + setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); + } + if (_clientProperties.getString(ClientProperties.version.toString()) != null) + { + _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); + } } } @@ -745,5 +754,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { return _authorizedID; } - + public String getClientVersion() + { + return _clientVersion == null ? null : _clientVersion.toString(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index d2a20cdf57..5eebd4c524 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -56,6 +56,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { private AMQMinaProtocolSession _session = null; private String _name = null; + //openmbean data types for representing the channel attributes private final static String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; private final static String[] _indexNames = {_channelAtttibuteNames[0]}; @@ -95,12 +96,26 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ private static void init() throws OpenDataException { - _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, _channelAttributeTypes); _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); } + public String getClientId() + { + return _session.getContextKey() == null ? null : _session.getContextKey().toString(); + } + + public String getAuthorizedId() + { + return _session.getAuthorizedID(); + } + + public String getVersion() + { + return _session.getClientVersion() == null ? null : _session.getClientVersion().toString(); + } + public Date getLastIoTime() { return new Date(_session.getIOSession().getLastIoTime()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index f9a0c4d18f..990c4c0794 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -41,6 +41,15 @@ public interface ManagedConnection { static final String TYPE = "Connection"; + @MBeanAttribute(name = "ClientId", description = "Client Id") + String getClientId(); + + @MBeanAttribute(name = "AuthorizedId", description = "User Name") + String getAuthorizedId(); + + @MBeanAttribute(name = "Version", description = "Client Version") + String getVersion(); + /** * Tells the remote address of this connection. * @return remote address -- cgit v1.2.1 From c34d844fcd591e1edc676201034cd1b0a437addd Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 21 Mar 2007 12:03:51 +0000 Subject: Exception thrown should be JMException, because management application don't know about AMQException git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@520850 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 386b0e6c45..23c32aceab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -171,7 +171,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex,"Error in creating queue " + queueName); + throw new MBeanException(new JMException(ex.getMessage()),"Error in creating queue " + queueName); } } @@ -202,7 +202,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex, ex.toString()); + throw new MBeanException(new JMException(ex.getMessage()), "Error in deleting queue " + queueName); } } -- cgit v1.2.1 From ab77fcc2ed974e8d4ac2a56be62cc2cb3f8e2c11 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 27 Mar 2007 09:07:30 +0000 Subject: merged from M2 (r521792:522567) QPID-408 QPID-421 QPID-428 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@522821 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 6 ++-- .../apache/qpid/server/queue/AMQQueueMBean.java | 41 +++++++++++++++++++--- .../queue/ConcurrentSelectorDeliveryManager.java | 12 +++++-- .../org/apache/qpid/server/queue/ManagedQueue.java | 4 +-- .../qpid/server/queue/NotificationCheck.java | 2 +- 5 files changed, 51 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index f17a6fb60a..a418bb8f8a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -118,7 +118,7 @@ public class AMQQueue implements Managable, Comparable /** max allowed number of messages on a queue. */ @Configured(path = "maximumMessageCount", defaultValue = "0") - public int _maximumMessageCount; + public long _maximumMessageCount; /** max queue depth for the queue */ @Configured(path = "maximumQueueDepth", defaultValue = "0") @@ -350,12 +350,12 @@ public class AMQQueue implements Managable, Comparable return _totalMessagesReceived.get(); } - public int getMaximumMessageCount() + public long getMaximumMessageCount() { return _maximumMessageCount; } - public void setMaximumMessageCount(int value) + public void setMaximumMessageCount(long value) { _maximumMessageCount = value; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 056fb5fc01..7a32848c44 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -20,6 +20,8 @@ package org.apache.qpid.server.queue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Date; +import java.text.SimpleDateFormat; import javax.management.JMException; import javax.management.MBeanException; @@ -44,6 +46,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -58,8 +61,8 @@ import org.apache.qpid.server.store.StoreContext; @MBeanDescription("Management Interface for AMQQueue") public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener { - private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); /** * Since the MBean is not associated with a real channel we can safely create our own store context @@ -197,12 +200,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _queue.getReceivedMessageCount(); } - public Integer getMaximumMessageCount() + public Long getMaximumMessageCount() { return _queue.getMaximumMessageCount(); } - public void setMaximumMessageCount(Integer value) + public void setMaximumMessageCount(Long value) { _queue.setMaximumMessageCount(value); } @@ -370,8 +373,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que AMQMessage msg = list.get(i - 1); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list - CommonContentHeaderProperties headerProperties = (CommonContentHeaderProperties) headerBody.properties; - String[] headerAttributes = headerProperties.toString().split(","); + String[] headerAttributes = getMessageHeaderProperties(headerBody); Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); _messageList.put(messageData); @@ -385,6 +387,35 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _messageList; } + private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) + { + List list = new ArrayList(); + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + list.add("reply-to = " + headerProperties.getReplyToAsString()); + list.add("propertyFlags = " + headerProperties.getPropertyFlags()); + list.add("ApplicationID = " + headerProperties.getAppIdAsString()); + list.add("ClusterID = " + headerProperties.getClusterIdAsString()); + list.add("UserId = " + headerProperties.getUserIdAsString()); + list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); + list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); + + int delMode = headerProperties.getDeliveryMode(); + list.add("JMSDeliveryMode = " + (delMode == 1 ? "Persistent" : "Non_Persistent")); + + list.add("JMSPriority = " + headerProperties.getPriority()); + list.add("JMSType = " + headerProperties.getType()); + + long longDate = headerProperties.getExpiration(); + String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSExpiration = " + strDate); + + longDate = headerProperties.getTimestamp(); + strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSTimestamp = " + strDate); + + return list.toArray(new String[list.size()]); + } + /** * @see ManagedQueue#moveMessages * @param fromMessageId diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 879080e10c..cfa13c87fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -401,7 +401,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.lock(); AMQMessage message = _messages.poll(); - _totalMessageSize.addAndGet(-message.getSize()); + if (message != null) + { + _totalMessageSize.addAndGet(-message.getSize()); + } _lock.unlock(); } @@ -539,7 +542,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { subscriberHasPendingResend(false, sub, null); //better to use the above method as this keeps all the tracking in one location. -// _hasContent.remove(sub); + // _hasContent.remove(sub); } _extraMessages.decrementAndGet(); @@ -552,7 +555,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - _totalMessageSize.addAndGet(-message.getSize()); + if ((message != null) && (messageQueue == _messages)) + { + _totalMessageSize.addAndGet(-message.getSize()); + } } catch (AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 9b926be82d..061ab56024 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -156,7 +156,7 @@ public interface ManagedQueue * @return maximum muber of message allowed to be stored in the queue. * @throws IOException */ - Integer getMaximumMessageCount() throws IOException; + Long getMaximumMessageCount() throws IOException; /** * Sets the maximum number of messages allowed to be stored in the queue. @@ -164,7 +164,7 @@ public interface ManagedQueue * @throws IOException */ @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") - void setMaximumMessageCount(Integer value) throws IOException; + void setMaximumMessageCount(Long value) throws IOException; /** * This is useful for setting notifications or taking required action if the size of messages diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index bc8e1232a7..00ccffdea1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -27,7 +27,7 @@ public enum NotificationCheck boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) { int msgCount = queue.getMessageCount(); - final int maximumMessageCount = queue.getMaximumMessageCount(); + final long maximumMessageCount = queue.getMaximumMessageCount(); if (maximumMessageCount!= 0 && msgCount >= maximumMessageCount) { listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); -- cgit v1.2.1 From 0370e5550e1d9bc72d742bbbee1f6f0e2835406e Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 5 Apr 2007 13:36:04 +0000 Subject: Merged revisions 525531-525536 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r525531 | rgreig | 2007-04-04 16:18:44 +0100 (Wed, 04 Apr 2007) | 1 line Added standard command line handline ........ r525533 | rgreig | 2007-04-04 16:19:38 +0100 (Wed, 04 Apr 2007) | 1 line Added simeple file copy function. ........ r525535 | rgreig | 2007-04-04 16:20:30 +0100 (Wed, 04 Apr 2007) | 1 line Added comments and logging to track down bug. ........ r525536 | rgreig | 2007-04-04 16:21:43 +0100 (Wed, 04 Apr 2007) | 1 line Fixed dangling transaction problem by correctly binding queue. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@525825 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/store/MessageStore.java | 190 +++++++++++++++++++-- .../org/apache/qpid/server/store/StoreContext.java | 16 +- 2 files changed, 191 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 21988d97a8..2a83d9b649 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -21,73 +21,241 @@ package org.apache.qpid.server.store; import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.Exchange; +/** + * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues + * and exchanges in a transactional manner. + * + *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which + * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single + * transaction. + * + *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. + * + *

      + *
      CRC Card
      Responsibilities + *
      Accept transaction boundary demarcations: Begin, Commit, Abort. + *
      Store and remove queues. + *
      Store and remove exchanges. + *
      Store and remove messages. + *
      Bind and unbind queues to exchanges. + *
      Enqueue and dequeue messages to queues. + *
      Generate message identifiers. + *
      + */ public interface MessageStore { /** * Called after instantiation in order to configure the message store. A particular implementation can define * whatever parameters it wants. - * @param virtualHost the virtual host using by this store - * @param base the base element identifier from which all configuration items are relative. For example, if the base - * element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config the apache commons configuration object - * @throws Exception if an error occurs that means the store is unable to configure itself + * + * @param virtualHost The virtual host using by this store + * @param base The base element identifier from which all configuration items are relative. For example, if + * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. */ void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. - * @throws Exception if close fails + * + * @throws Exception If the close fails. */ void close() throws Exception; + /** + * Removes the specified message from the store in the given transactional store context. + * + * @param storeContext The transactional context to remove the message in. + * @param messageId Identifies the message to remove. + * + * @throws AMQException If the operation fails for any reason. + */ void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws AMQException If the operation fails for any reason. + */ void createExchange(Exchange exchange) throws AMQException; + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws AMQException If the operation fails for any reason. + */ void removeExchange(Exchange exchange) throws AMQException; + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws AMQException If the operation fails for any reason. + */ void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws AMQException If the operation fails for any reason. + */ void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws AMQException If the operation fails for any reason. + */ void createQueue(AMQQueue queue) throws AMQException; + /** + * Removes the specified queue from the persistent store. + * + * @param name The queue to remove. + * + * @throws AMQException If the operation fails for any reason. + */ void removeQueue(AMQShortString name) throws AMQException; + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param name The name of the queue to place the message on. + * @param messageId The message to enqueue. + * + * @throws AMQException If the operation fails for any reason. + */ void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param name The name of the queue to take the message from. + * @param messageId The message to dequeue. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + /** + * Begins a transactional context. + * + * @param context The transactional context to begin. + * + * @throws AMQException If the operation fails for any reason. + */ void beginTran(StoreContext context) throws AMQException; + /** + * Commits all operations performed within a given transactional context. + * + * @param context The transactional context to commit all operations for. + * + * @throws AMQException If the operation fails for any reason. + */ void commitTran(StoreContext context) throws AMQException; + /** + * Abandons all operations performed within a given transactional context. + * + * @param context The transactional context to abandon. + * + * @throws AMQException If the operation fails for any reason. + */ void abortTran(StoreContext context) throws AMQException; + /** + * Tests a transactional context to see if it has been begun but not yet committed or aborted. + * + * @param context The transactional context to test. + * + * @return true if the transactional context is live, false otherwise. + */ boolean inTran(StoreContext context); /** * Return a valid, currently unused message id. - * @return a message id + * + * @return A fresh message id. */ Long getNewMessageId(); - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException; + /** + * Stores a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param index The index of the data chunk. + * @param contentBody The content of the data chunk. + * @param lastContentBody Flag to indicate that this is the last such chunk for the message. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, + boolean lastContentBody) throws AMQException; + /** + * Stores message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param messageMetaData The message meta data to store. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; + /** + * Retrieves message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the meta-data for. + * + * @return The message meta data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; + /** + * Retrieves a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the data chunk for. + * @param index The offset index of the data chunk within the message. + * + * @return A chunk of message data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index 2e2f2ba7d6..3ee49d58cf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -22,16 +22,14 @@ package org.apache.qpid.server.store; import org.apache.log4j.Logger; - /** * A context that the store can use to associate with a transactional context. For example, it could store * some kind of txn id. - * + * * @author Apache Software Foundation */ public class StoreContext { - private static final Logger _logger = Logger.getLogger(StoreContext.class); private String _name; @@ -54,7 +52,17 @@ public class StoreContext public void setPayload(Object payload) { - _logger.debug("["+_name+"] Setting payload: " + payload); + _logger.debug("public void setPayload(Object payload = " + payload + "): called"); _payload = payload; } + + /** + * Prints out the transactional context as a string, mainly for debugging purposes. + * + * @return The transactional context as a string. + */ + public String toString() + { + return "<_name = " + _name + ", _payload = " + _payload + ">"; + } } -- cgit v1.2.1 From faf86c6e5f484feef6102533b177202282b7f091 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 9 Apr 2007 11:45:48 +0000 Subject: Merged revisions 526714 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r526714 | rgreig | 2007-04-09 12:25:32 +0100 (Mon, 09 Apr 2007) | 1 line Purged logging from exception constructors. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@526720 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index d90113fa35..c349b44d6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -65,11 +65,11 @@ public class DefaultExchangeFactory implements ExchangeFactory } catch (InstantiationException e) { - throw new AMQException(_logger, "Unable to create exchange: " + e, e); + throw new AMQException("Unable to create exchange: " + e, e); } catch (IllegalAccessException e) { - throw new AMQException(_logger, "Unable to create exchange: " + e, e); + throw new AMQException("Unable to create exchange: " + e, e); } } } -- cgit v1.2.1 From 719564278e3360c6aab401332f8866d657c157fa Mon Sep 17 00:00:00 2001 From: Tejeswar Das Date: Mon, 16 Apr 2007 21:11:57 +0000 Subject: Fix for QPID-439 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@529402 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 36 +++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 1d26abb63f..38a505c6c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -67,6 +67,10 @@ public class Main private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + + private static final int IPV4_ADDRESS_LENGTH = 4; + + private static final char IPV4_LITERAL_SEPARATOR = '.'; protected static class InitException extends Exception { @@ -376,26 +380,30 @@ public class Main private byte[] parseIP(String address) throws Exception { - StringTokenizer tokenizer = new StringTokenizer(address, "."); - byte[] ip = new byte[4]; - int index = 0; - while (tokenizer.hasMoreTokens()) + char[] literalBuffer = address.toCharArray(); + int byteCount = 0; + int currByte = 0; + byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; + for (int i = 0 ; i < literalBuffer.length ; i++) { - String token = tokenizer.nextToken(); - try + char currChar = literalBuffer[i]; + if ((currChar >= '0') && (currChar <= '9')) { - ip[index++] = Byte.parseByte(token); - } - catch (NumberFormatException e) + currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); + } + + if (currChar == IPV4_LITERAL_SEPARATOR || (i + 1 == literalBuffer.length)) { - throw new Exception("Error parsing IP address: " + address, e); - } + ip[byteCount++] = (byte)currByte; + currByte = 0; + } } - if (index != 4) + + if (byteCount != 4) { throw new Exception("Invalid IP address: " + address); - } - return ip; + } + return ip; } private void configureLogging(File logConfigFile, String logWatchConfig) -- cgit v1.2.1 From 8c67d6f374a8f0de6ff88a63e85e8760e510263c Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 19 Apr 2007 09:46:33 +0000 Subject: Merged revisions 520938 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r520938 | ritchiem | 2007-03-21 16:26:03 +0000 (Wed, 21 Mar 2007) | 1 line Added a new Appender from the Log4j contrib code base as QpidCompositeRollingAppender. This will allow us to roll the broker log files on a set time frame AND to a maximum file size. The CompositeRollingAppender was contributed by Kevin Steppe to the log4j project but as it is not part of the log4j.jar we must include it in our own code base until log4j provide a core implementation. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530354 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 710 +++++++++++++++++++++ 1 file changed, 710 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java new file mode 100644 index 0000000000..171e1cb155 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -0,0 +1,710 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.log4j; + +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.helpers.CountingQuietWriter; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; + +import java.util.Date; +import java.text.SimpleDateFormat; +import java.io.IOException; +import java.io.Writer; +import java.io.File; + +/** + *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      + * It can function as either or do both at the same time (making size + * based rolling files like RollingFileAppender until a data/time boundary + * is crossed at which time it rolls all of those files as per the DailyRollingFileAppender) + * based on the setting for rollingStyle.
      + *
      + * To use CompositeRollingAppender to roll log files as they reach a certain + * size (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      + * To use CompositeRollingAppender to roll log files at certain time intervals + * (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      + * To have CompositeRollingAppender roll log files at a certain size AND rename those + * according to time intervals, set rollingStyle=3 (@see config.composite)
      + * + *

      A of few additional optional features have been added:
      + * -- Attach date pattern for current log file (@see staticLogFileName)
      + * -- Backup number increments for newer files (@see countDirection)
      + * -- Infinite number of backups by file size (@see maxSizeRollBackups)
      + *
      + *

      A few notes and warnings: For large or infinite number of backups + * countDirection > 0 is highly recommended, with staticLogFileName = false if + * time based rolling is also used -- this will reduce the number of file renamings + * to few or none. Changing staticLogFileName or countDirection without clearing + * the directory could have nasty side effects. If Date/Time based rolling + * is enabled, CompositeRollingAppender will attempt to roll existing files + * in the directory without a date/time tag based on the last modified date + * of the base log files last modification.
      + *
      + *

      A maximum number of backups based on date/time boundries would be nice + * but is not yet implemented.
      + * + * @author Kevin Steppe + * @author Heinz Richter + * @author Eirik Lygre + * @author Ceki Gülcü + * @author Martin Ritchie + */ +public class QpidCompositeRollingAppender extends FileAppender +{ + // The code assumes that the following 'time' constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE=-1; + static final int TOP_OF_MINUTE = 0; + static final int TOP_OF_HOUR = 1; + static final int HALF_DAY = 2; + static final int TOP_OF_DAY = 3; + static final int TOP_OF_WEEK = 4; + static final int TOP_OF_MONTH = 5; + + /** Style of rolling to use */ + static final int BY_SIZE = 1; + static final int BY_DATE = 2; + static final int BY_COMPOSITE = 3; + + //Not currently used + static final String S_BY_SIZE = "Size"; + static final String S_BY_DATE = "Date"; + static final String S_BY_COMPOSITE = "Composite"; + + /** + The date pattern. By default, the pattern is set to + "'.'yyyy-MM-dd" meaning daily rollover. + */ + private String datePattern = "'.'yyyy-MM-dd"; + + /** The actual formatted filename that is currently being written to + or will be the file transferred to on roll over + (based on staticLogFileName). */ + private String scheduledFilename = null; + + /** The timestamp when we shall next recompute the filename. */ + private long nextCheck = System.currentTimeMillis () - 1; + + /** Holds date of last roll over */ + Date now = new Date(); + + SimpleDateFormat sdf; + + /** Helper class to determine next rollover time */ + RollingCalendar rc = new RollingCalendar(); + + /** Current period for roll overs */ + int checkPeriod = TOP_OF_TROUBLE; + + /** The default maximum file size is 10MB. */ + protected long maxFileSize = 10*1024*1024; + + /** There is zero backup files by default. */ + protected int maxSizeRollBackups = 0; + /** How many sized based backups have been made so far */ + protected int curSizeRollBackups = 0; + + /** not yet implemented */ + protected int maxTimeRollBackups = -1; + protected int curTimeRollBackups = 0; + + /** By default newer files have lower numbers. (countDirection < 0) + * ie. log.1 is most recent, log.5 is the 5th backup, etc... + * countDirection > 0 does the opposite ie. + * log.1 is the first backup made, log.5 is the 5th backup made, etc. + * For infinite backups use countDirection > 0 to reduce rollOver costs. + */ + protected int countDirection = -1; + + /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ + protected int rollingStyle = BY_COMPOSITE; + protected boolean rollDate = true; + protected boolean rollSize = true; + + /** By default file.log is always the current file. Optionally + * file.log.yyyy-mm-dd for current formated datePattern can by the currently + * logging file (or file.log.curSizeRollBackup or even + * file.log.yyyy-mm-dd.curSizeRollBackup) This will make time based roll + * overs with a large number of backups much faster -- it won't have to + * rename all the backups! + */ + protected boolean staticLogFileName = true; + + /** FileName provided in configuration. Used for rolling properly */ + protected String baseFileName; + + /** The default constructor does nothing. */ + public QpidCompositeRollingAppender() { + } + + /** + Instantiate a CompositeRollingAppender and open the + file designated by filename. The opened filename will + become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, + String datePattern) throws IOException + { + this(layout, filename, datePattern, true); + } + + /** + Instantiate a CompositeRollingAppender and open the file designated by + filename. The opened filename will become the ouput + destination for this appender. + +

      If the append parameter is true, the file will be + appended to. Otherwise, the file desginated by + filename will be truncated before being opened. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) + throws IOException { + super(layout, filename, append); + } + + /** + Instantiate a CompositeRollingAppender and open the file designated by + filename. The opened filename will become the ouput + destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, + String datePattern, boolean append) throws IOException { + super(layout, filename, append); + this.datePattern = datePattern; + activateOptions(); + } + /** + Instantiate a CompositeRollingAppender and open the file designated by + filename. The opened filename will become the output + destination for this appender. + +

      The file will be appended to. DatePattern is default. + */ + public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException { + super(layout, filename); + } + + /** + The DatePattern takes a string in the same format as + expected by {@link java.text.SimpleDateFormat}. This options determines the + rollover schedule. + */ + public void setDatePattern(String pattern) { + datePattern = pattern; + } + + /** Returns the value of the DatePattern option. */ + public String getDatePattern() { + return datePattern; + } + + /** + Returns the value of the maxSizeRollBackups option. + */ + public int getMaxSizeRollBackups() { + return maxSizeRollBackups; + } + + /** + Get the maximum size that the output file is allowed to reach + before being rolled over to backup files. + + @since 1.1 + */ + public long getMaximumFileSize() { + return maxFileSize; + } + + /** +

      Set the maximum number of backup files to keep around based on file size. + +

      The MaxSizeRollBackups option determines how many backup + files are kept before the oldest is erased. This option takes + an integer value. If set to zero, then there will be no + backup files and the log file will be truncated when it reaches + MaxFileSize. If a negative number is supplied then + no deletions will be made. Note that this could result in + very slow performance as a large number of files are rolled over unless + {@link #setCountDirection} up is used. + +

      The maximum applys to -each- time based group of files and -not- the total. + Using a daily roll the maximum total files would be (#days run) * (maxSizeRollBackups) + + */ + public void setMaxSizeRollBackups(int maxBackups) { + maxSizeRollBackups = maxBackups; + } + + /** + Set the maximum size that the output file is allowed to reach + before being rolled over to backup files. + +

      This method is equivalent to {@link #setMaxFileSize} except + that it is required for differentiating the setter taking a + long argument from the setter taking a + String argument by the JavaBeans {@link + java.beans.Introspector Introspector}. + + @see #setMaxFileSize(String) + */ + public void setMaxFileSize(long maxFileSize) { + this.maxFileSize = maxFileSize; + } + + /** + Set the maximum size that the output file is allowed to reach + before being rolled over to backup files. + +

      This method is equivalent to {@link #setMaxFileSize} except + that it is required for differentiating the setter taking a + long argument from the setter taking a + String argument by the JavaBeans {@link + java.beans.Introspector Introspector}. + + @see #setMaxFileSize(String) + */ + public void setMaximumFileSize(long maxFileSize) { + this.maxFileSize = maxFileSize; + } + + /** + Set the maximum size that the output file is allowed to reach + before being rolled over to backup files. + +

      In configuration files, the MaxFileSize option takes an + long integer in the range 0 - 2^63. You can specify the value + with the suffixes "KB", "MB" or "GB" so that the integer is + interpreted being expressed respectively in kilobytes, megabytes + or gigabytes. For example, the value "10KB" will be interpreted + as 10240. + */ + public void setMaxFileSize(String value) { + maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); + } + + protected void setQWForFiles(Writer writer) { + qw = new CountingQuietWriter(writer, errorHandler); + } + + //Taken verbatum from DailyRollingFileAppender + int computeCheckPeriod() { + RollingCalendar c = new RollingCalendar(); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date(0); + if(datePattern != null) { + for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) { + String r0 = sdf.format(epoch); + c.setType(i); + Date next = new Date(c.getNextCheckMillis(epoch)); + String r1 = sdf.format(next); + //LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if(r0 != null && r1 != null && !r0.equals(r1)) { + return i; + } + } + } + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + //Now for the new stuff + /** + * Handles append time behavior for CompositeRollingAppender. This checks + * if a roll over either by date (checked first) or time (checked second) + * is need and then appends to the file last. + */ + protected void subAppend(LoggingEvent event) { + + if (rollDate) { + long n = System.currentTimeMillis(); + if (n >= nextCheck) { + now.setTime(n); + nextCheck = rc.getNextCheckMillis(now); + + rollOverTime(); + } + } + + if (rollSize) { + if ((fileName != null) && ((CountingQuietWriter) qw).getCount() >= maxFileSize) { + rollOverSize(); + } + } + + super.subAppend(event); + } + + public void setFile(String file) + { + baseFileName = file.trim(); + fileName = file.trim(); + } + + /** + * Creates and opens the file for logging. If staticLogFileName + * is false then the fully qualified name is determined and used. + */ + public synchronized void setFile(String fileName, boolean append) throws IOException { + if (!staticLogFileName) { + scheduledFilename = fileName = fileName.trim() + sdf.format(now); + if (countDirection > 0) { + scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); + } + } + + super.setFile(fileName, append, bufferedIO, bufferSize); + + if(append) { + File f = new File(fileName); + ((CountingQuietWriter) qw).setCount(f.length()); + } + } + + public int getCountDirection() { + return countDirection; + } + + public void setCountDirection(int direction) { + countDirection = direction; + } + + public int getRollingStyle () { + return rollingStyle; + } + + public void setRollingStyle(int style) { + rollingStyle = style; + switch (rollingStyle) { + case BY_SIZE: + rollDate = false; + rollSize = true; + break; + case BY_DATE: + rollDate = true; + rollSize = false; + break; + case BY_COMPOSITE: + rollDate = true; + rollSize = true; + break; + default: + errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); + } + } + +/* + public void setRollingStyle(String style) { + if (style == S_BY_SIZE) { + rollingStyle = BY_SIZE; + } + else if (style == S_BY_DATE) { + rollingStyle = BY_DATE; + } + else if (style == S_BY_COMPOSITE) { + rollingStyle = BY_COMPOSITE; + } + } +*/ + public boolean getStaticLogFileName() { + return staticLogFileName; + } + + public void setStaticLogFileName(boolean s) { + staticLogFileName = s; + } + + public void setStaticLogFileName(String value) { + setStaticLogFileName(OptionConverter.toBoolean(value, true)); + } + + /** + * Initializes based on exisiting conditions at time of + * activateOptions. The following is done:
      + *
      + * A) determine curSizeRollBackups
      + * B) determine curTimeRollBackups (not implemented)
      + * C) initiates a roll over if needed for crossing a date boundary since + * the last run. + */ + protected void existingInit() { + + curSizeRollBackups = 0; + curTimeRollBackups = 0; + + //part A starts here + String filter; + if (staticLogFileName || !rollDate) { + filter = baseFileName + ".*"; + } + else { + filter = scheduledFilename + ".*"; + } + + File f = new File(baseFileName); + f = f.getParentFile(); + if (f == null) + f = new File("."); + + LogLog.debug("Searching for existing files in: " + f); + String[] files = f.list(); + + if (files != null) { + for (int i = 0; i < files.length; i++) { + if (!files[i].startsWith(baseFileName)) + continue; + + int index = files[i].lastIndexOf("."); + + if (staticLogFileName) { + int endLength = files[i].length() - index; + if (baseFileName.length() + endLength != files[i].length()) { + //file is probably scheduledFilename + .x so I don't care + continue; + } + } + + try { + int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); + LogLog.debug("From file: " + files[i] + " -> " + backup); + if (backup > curSizeRollBackups) + curSizeRollBackups = backup; + } + catch (Exception e) { + //this happens when file.log -> file.log.yyyy-mm-dd which is normal + //when staticLogFileName == false + LogLog.debug("Encountered a backup file not ending in .x " + files[i]); + } + } + } + LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); + //part A ends here + + //part B not yet implemented + + //part C + if (staticLogFileName && rollDate) { + File old = new File(baseFileName); + if (old.exists()) { + Date last = new Date(old.lastModified()); + if (!(sdf.format(last).equals(sdf.format(now)))) { + scheduledFilename = baseFileName + sdf.format(last); + LogLog.debug("Initial roll over to: " + scheduledFilename); + rollOverTime(); + } + } + } + LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); + //part C ends here + + } + + /** + * Sets initial conditions including date/time roll over information, first check, + * scheduledFilename, and calls existingInit to initialize + * the current # of backups. + */ + public void activateOptions() { + + //REMOVE removed rollDate from boolean to enable Alex's change + if(datePattern != null) { + now.setTime(System.currentTimeMillis()); + sdf = new SimpleDateFormat(datePattern); + int type = computeCheckPeriod(); + //printPeriodicity(type); + rc.setType(type); + //next line added as this removes the name check in rollOver + nextCheck = rc.getNextCheckMillis(now); + } else { + if (rollDate) + LogLog.error("Either DatePattern or rollingStyle options are not set for ["+ + name+"]."); + } + + existingInit(); + + super.activateOptions(); + + if (rollDate && fileName != null && scheduledFilename == null) + scheduledFilename = fileName + sdf.format(now); + } + + /** + Rollover the file(s) to date/time tagged file(s). + Opens the new file (through setFile) and resets curSizeRollBackups. + */ + protected void rollOverTime() { + + curTimeRollBackups++; + + //delete the old stuff here + + if (staticLogFileName) { + /* Compute filename, but only if datePattern is specified */ + if (datePattern == null) { + errorHandler.error("Missing DatePattern option in rollOver()."); + return; + } + + //is the new file name equivalent to the 'current' one + //something has gone wrong if we hit this -- we should only + //roll over if the new file will be different from the old + String dateFormat = sdf.format(now); + if (scheduledFilename.equals(fileName + dateFormat)) { + errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); + return; + } + + // close current file, and rename it to datedFilename + this.closeFile(); + + //we may have to roll over a large number of backups here + String from, to; + for (int i = 1; i <= curSizeRollBackups; i++) { + from = fileName + '.' + i; + to = scheduledFilename + '.' + i; + rollFile(from, to); + } + + rollFile(fileName, scheduledFilename); + } + + try { + // This will also close the file. This is OK since multiple + // close operations are safe. + curSizeRollBackups = 0; //We're cleared out the old date and are ready for the new + + //new scheduled name + scheduledFilename = fileName + sdf.format(now); + this.setFile(baseFileName, false); + } + catch(IOException e) { + errorHandler.error("setFile("+fileName+", false) call failed."); + } + + } + + /** Renames file from to file to. It + * also checks for existence of target file and deletes if it does. + */ + protected static void rollFile(String from, String to) { + File target = new File(to); + if (target.exists()) { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + File file = new File(from); + file.renameTo(target); + LogLog.debug(from +" -> "+ to); + } + + /** Delete's the specified file if it exists */ + protected static void deleteFile(String fileName) { + File file = new File(fileName); + if (file.exists()) { + file.delete(); + } + } + + /** + Implements roll overs base on file size. + +

      If the maximum number of size based backups is reached + (curSizeRollBackups == maxSizeRollBackups + If countDirection < 0, then files + {File.1, ..., File.curSizeRollBackups -1} + are renamed to {File.2, ..., + File.curSizeRollBackups}. Moreover, File is + renamed File.1 and closed.
      + + A new file is created to receive further log output. + +

      If maxSizeRollBackups is equal to zero, then the + File is truncated with no backup files created. + +

      If maxSizeRollBackups < 0, then File is + renamed if needed and no files are deleted. + */ + + // synchronization not necessary since doAppend is alreasy synched + protected void rollOverSize() { + File file; + + this.closeFile(); // keep windows happy. + + LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); + LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); + LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); + LogLog.debug("countDirection = " + countDirection); + + // If maxBackups <= 0, then there is no file renaming to be done. + if (maxSizeRollBackups != 0) { + + if (countDirection < 0) { + // Delete the oldest file, to keep Windows happy. + if (curSizeRollBackups == maxSizeRollBackups) { + deleteFile(fileName + '.' + maxSizeRollBackups); + curSizeRollBackups--; + } + + // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} + for (int i = curSizeRollBackups; i >= 1; i--) { + rollFile((fileName + "." + i), (fileName + '.' + (i + 1))); + } + + curSizeRollBackups++; + // Rename fileName to fileName.1 + rollFile(fileName, fileName + ".1"); + + } //REMOVE This code branching for Alexander Cerna's request + else if (countDirection == 0) { + //rollFile based on date pattern + curSizeRollBackups++; + now.setTime(System.currentTimeMillis()); + scheduledFilename = fileName + sdf.format(now); + rollFile(fileName, scheduledFilename); + } + else { //countDirection > 0 + if (curSizeRollBackups >= maxSizeRollBackups && maxSizeRollBackups > 0) { + //delete the first and keep counting up. + int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + deleteFile(fileName + '.' + oldestFileIndex); + } + + if (staticLogFileName) { + curSizeRollBackups++; + rollFile(fileName, fileName + '.' + curSizeRollBackups); + } + } + } + + try { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(baseFileName, false); + } + catch(IOException e) { + LogLog.error("setFile("+fileName+", false) call failed.", e); + } + } + +} -- cgit v1.2.1 From c40abb2580b2da657249b74a202d75eaee3362e2 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 19 Apr 2007 09:58:42 +0000 Subject: Merged revisions 521363 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r521363 | ritchiem | 2007-03-22 17:36:15 +0000 (Thu, 22 Mar 2007) | 2 lines Updated the new Log4j appender to compress the backup files and move them to a new location.(Compression occurs async so as not to slow down the main program). Enable the logger in the log4j.xml Disabled by default. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530356 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 1607 ++++++++++++-------- 1 file changed, 948 insertions(+), 659 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 171e1cb155..eac7ed21f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -24,687 +24,976 @@ import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; +import org.apache.qpid.framing.FieldTable; import java.util.Date; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.GZIPOutputStream; import java.text.SimpleDateFormat; import java.io.IOException; import java.io.Writer; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; /** - *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      - * It can function as either or do both at the same time (making size - * based rolling files like RollingFileAppender until a data/time boundary - * is crossed at which time it rolls all of those files as per the DailyRollingFileAppender) - * based on the setting for rollingStyle.
      - *
      - * To use CompositeRollingAppender to roll log files as they reach a certain - * size (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      - * To use CompositeRollingAppender to roll log files at certain time intervals - * (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      - * To have CompositeRollingAppender roll log files at a certain size AND rename those - * according to time intervals, set rollingStyle=3 (@see config.composite)
      + *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either + * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is + * crossed at which time it rolls all of those files as per the DailyRollingFileAppender) based on the setting for + * rollingStyle.

      To use CompositeRollingAppender to roll log files as they reach a certain size + * (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      To use CompositeRollingAppender to roll log + * files at certain time intervals (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      To + * have CompositeRollingAppender roll log files at a certain size AND rename those according to time intervals, set + * rollingStyle=3 (@see config.composite)
      * - *

      A of few additional optional features have been added:
      - * -- Attach date pattern for current log file (@see staticLogFileName)
      - * -- Backup number increments for newer files (@see countDirection)
      - * -- Infinite number of backups by file size (@see maxSizeRollBackups)
      - *
      - *

      A few notes and warnings: For large or infinite number of backups - * countDirection > 0 is highly recommended, with staticLogFileName = false if - * time based rolling is also used -- this will reduce the number of file renamings - * to few or none. Changing staticLogFileName or countDirection without clearing - * the directory could have nasty side effects. If Date/Time based rolling - * is enabled, CompositeRollingAppender will attempt to roll existing files - * in the directory without a date/time tag based on the last modified date - * of the base log files last modification.
      - *
      - *

      A maximum number of backups based on date/time boundries would be nice - * but is not yet implemented.
      + *

      A of few additional optional features have been added:
      -- Attach date pattern for current log file (@see + * staticLogFileName)
      -- Backup number increments for newer files (@see countDirection)
      -- Infinite number of + * backups by file size (@see maxSizeRollBackups)

      A few notes and warnings: For large or infinite number of + * backups countDirection > 0 is highly recommended, with staticLogFileName = false if time based rolling is also used + * -- this will reduce the number of file renamings to few or none. Changing staticLogFileName or countDirection + * without clearing the directory could have nasty side effects. If Date/Time based rolling is enabled, + * CompositeRollingAppender will attempt to roll existing files in the directory without a date/time tag based on the + * last modified date of the base log files last modification.

      A maximum number of backups based on + * date/time boundries would be nice but is not yet implemented.
      * - * @author Kevin Steppe - * @author Heinz Richter - * @author Eirik Lygre - * @author Ceki Gülcü - * @author Martin Ritchie + * @author Kevin Steppe + * @author Heinz Richter + * @author Eirik Lygre + * @author Ceki Gülcü + * @author Martin Ritchie */ public class QpidCompositeRollingAppender extends FileAppender { - // The code assumes that the following 'time' constants are in a increasing - // sequence. - static final int TOP_OF_TROUBLE=-1; - static final int TOP_OF_MINUTE = 0; - static final int TOP_OF_HOUR = 1; - static final int HALF_DAY = 2; - static final int TOP_OF_DAY = 3; - static final int TOP_OF_WEEK = 4; - static final int TOP_OF_MONTH = 5; - - /** Style of rolling to use */ - static final int BY_SIZE = 1; - static final int BY_DATE = 2; - static final int BY_COMPOSITE = 3; - - //Not currently used - static final String S_BY_SIZE = "Size"; - static final String S_BY_DATE = "Date"; - static final String S_BY_COMPOSITE = "Composite"; - - /** - The date pattern. By default, the pattern is set to - "'.'yyyy-MM-dd" meaning daily rollover. - */ - private String datePattern = "'.'yyyy-MM-dd"; - - /** The actual formatted filename that is currently being written to - or will be the file transferred to on roll over - (based on staticLogFileName). */ - private String scheduledFilename = null; - - /** The timestamp when we shall next recompute the filename. */ - private long nextCheck = System.currentTimeMillis () - 1; - - /** Holds date of last roll over */ - Date now = new Date(); - - SimpleDateFormat sdf; - - /** Helper class to determine next rollover time */ - RollingCalendar rc = new RollingCalendar(); - - /** Current period for roll overs */ - int checkPeriod = TOP_OF_TROUBLE; - - /** The default maximum file size is 10MB. */ - protected long maxFileSize = 10*1024*1024; - - /** There is zero backup files by default. */ - protected int maxSizeRollBackups = 0; - /** How many sized based backups have been made so far */ - protected int curSizeRollBackups = 0; - - /** not yet implemented */ - protected int maxTimeRollBackups = -1; - protected int curTimeRollBackups = 0; - - /** By default newer files have lower numbers. (countDirection < 0) - * ie. log.1 is most recent, log.5 is the 5th backup, etc... - * countDirection > 0 does the opposite ie. - * log.1 is the first backup made, log.5 is the 5th backup made, etc. - * For infinite backups use countDirection > 0 to reduce rollOver costs. - */ - protected int countDirection = -1; - - /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ - protected int rollingStyle = BY_COMPOSITE; - protected boolean rollDate = true; - protected boolean rollSize = true; - - /** By default file.log is always the current file. Optionally - * file.log.yyyy-mm-dd for current formated datePattern can by the currently - * logging file (or file.log.curSizeRollBackup or even - * file.log.yyyy-mm-dd.curSizeRollBackup) This will make time based roll - * overs with a large number of backups much faster -- it won't have to - * rename all the backups! - */ - protected boolean staticLogFileName = true; - - /** FileName provided in configuration. Used for rolling properly */ - protected String baseFileName; + // The code assumes that the following 'time' constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE = -1; + static final int TOP_OF_MINUTE = 0; + static final int TOP_OF_HOUR = 1; + static final int HALF_DAY = 2; + static final int TOP_OF_DAY = 3; + static final int TOP_OF_WEEK = 4; + static final int TOP_OF_MONTH = 5; + + /** Style of rolling to use */ + static final int BY_SIZE = 1; + static final int BY_DATE = 2; + static final int BY_COMPOSITE = 3; + + //Not currently used + static final String S_BY_SIZE = "Size"; + static final String S_BY_DATE = "Date"; + static final String S_BY_COMPOSITE = "Composite"; + + /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ + private String datePattern = "'.'yyyy-MM-dd"; + + /** + * The actual formatted filename that is currently being written to or will be the file transferred to on roll over + * (based on staticLogFileName). + */ + private String scheduledFilename = null; + + /** The timestamp when we shall next recompute the filename. */ + private long nextCheck = System.currentTimeMillis() - 1; + + /** Holds date of last roll over */ + Date now = new Date(); + + SimpleDateFormat sdf; + + /** Helper class to determine next rollover time */ + RollingCalendar rc = new RollingCalendar(); + + /** Current period for roll overs */ + int checkPeriod = TOP_OF_TROUBLE; + + /** The default maximum file size is 10MB. */ + protected long maxFileSize = 10 * 1024 * 1024; + + /** There is zero backup files by default. */ + protected int maxSizeRollBackups = 0; + /** How many sized based backups have been made so far */ + protected int curSizeRollBackups = 0; + + /** not yet implemented */ + protected int maxTimeRollBackups = -1; + protected int curTimeRollBackups = 0; + + /** + * By default newer files have lower numbers. (countDirection < 0) ie. log.1 is most recent, log.5 is the 5th + * backup, etc... countDirection > 0 does the opposite ie. log.1 is the first backup made, log.5 is the 5th backup + * made, etc. For infinite backups use countDirection > 0 to reduce rollOver costs. + */ + protected int countDirection = -1; + + /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ + protected int rollingStyle = BY_COMPOSITE; + protected boolean rollDate = true; + protected boolean rollSize = true; + + /** + * By default file.log is always the current file. Optionally file.log.yyyy-mm-dd for current formated datePattern + * can by the currently logging file (or file.log.curSizeRollBackup or even file.log.yyyy-mm-dd.curSizeRollBackup) + * This will make time based roll overs with a large number of backups much faster -- it won't have to rename all + * the backups! + */ + protected boolean staticLogFileName = true; + + /** FileName provided in configuration. Used for rolling properly */ + protected String baseFileName; + + + /** Do we want to .gz our backup files. */ + protected boolean compress = false; + + /** Do we want to use a second thread when compressing our backup files. */ + protected boolean compressAsync = false; + + /** Do we want to start numbering files at zero. */ + protected boolean zeroBased = false; + + /** Path provided in configuration. Used for moving backup files to */ + protected String backupFilesToPath = null; + private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); + private AtomicBoolean _compressing = new AtomicBoolean(false); /** The default constructor does nothing. */ - public QpidCompositeRollingAppender() { - } - - /** - Instantiate a CompositeRollingAppender and open the - file designated by filename. The opened filename will - become the ouput destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, - String datePattern) throws IOException - { - this(layout, filename, datePattern, true); - } - - /** - Instantiate a CompositeRollingAppender and open the file designated by - filename. The opened filename will become the ouput - destination for this appender. - -

      If the append parameter is true, the file will be - appended to. Otherwise, the file desginated by - filename will be truncated before being opened. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) - throws IOException { - super(layout, filename, append); - } - - /** - Instantiate a CompositeRollingAppender and open the file designated by - filename. The opened filename will become the ouput - destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, - String datePattern, boolean append) throws IOException { - super(layout, filename, append); - this.datePattern = datePattern; - activateOptions(); - } - /** - Instantiate a CompositeRollingAppender and open the file designated by - filename. The opened filename will become the output - destination for this appender. - -

      The file will be appended to. DatePattern is default. - */ - public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException { - super(layout, filename); - } - - /** - The DatePattern takes a string in the same format as - expected by {@link java.text.SimpleDateFormat}. This options determines the - rollover schedule. - */ - public void setDatePattern(String pattern) { - datePattern = pattern; - } - - /** Returns the value of the DatePattern option. */ - public String getDatePattern() { - return datePattern; - } - - /** - Returns the value of the maxSizeRollBackups option. - */ - public int getMaxSizeRollBackups() { - return maxSizeRollBackups; - } - - /** - Get the maximum size that the output file is allowed to reach - before being rolled over to backup files. - - @since 1.1 - */ - public long getMaximumFileSize() { - return maxFileSize; - } - - /** -

      Set the maximum number of backup files to keep around based on file size. - -

      The MaxSizeRollBackups option determines how many backup - files are kept before the oldest is erased. This option takes - an integer value. If set to zero, then there will be no - backup files and the log file will be truncated when it reaches - MaxFileSize. If a negative number is supplied then - no deletions will be made. Note that this could result in - very slow performance as a large number of files are rolled over unless - {@link #setCountDirection} up is used. - -

      The maximum applys to -each- time based group of files and -not- the total. - Using a daily roll the maximum total files would be (#days run) * (maxSizeRollBackups) - - */ - public void setMaxSizeRollBackups(int maxBackups) { - maxSizeRollBackups = maxBackups; - } - - /** - Set the maximum size that the output file is allowed to reach - before being rolled over to backup files. - -

      This method is equivalent to {@link #setMaxFileSize} except - that it is required for differentiating the setter taking a - long argument from the setter taking a - String argument by the JavaBeans {@link - java.beans.Introspector Introspector}. - - @see #setMaxFileSize(String) - */ - public void setMaxFileSize(long maxFileSize) { - this.maxFileSize = maxFileSize; - } - - /** - Set the maximum size that the output file is allowed to reach - before being rolled over to backup files. - -

      This method is equivalent to {@link #setMaxFileSize} except - that it is required for differentiating the setter taking a - long argument from the setter taking a - String argument by the JavaBeans {@link - java.beans.Introspector Introspector}. - - @see #setMaxFileSize(String) - */ - public void setMaximumFileSize(long maxFileSize) { - this.maxFileSize = maxFileSize; - } - - /** - Set the maximum size that the output file is allowed to reach - before being rolled over to backup files. - -

      In configuration files, the MaxFileSize option takes an - long integer in the range 0 - 2^63. You can specify the value - with the suffixes "KB", "MB" or "GB" so that the integer is - interpreted being expressed respectively in kilobytes, megabytes - or gigabytes. For example, the value "10KB" will be interpreted - as 10240. - */ - public void setMaxFileSize(String value) { - maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); - } - - protected void setQWForFiles(Writer writer) { - qw = new CountingQuietWriter(writer, errorHandler); - } - - //Taken verbatum from DailyRollingFileAppender - int computeCheckPeriod() { - RollingCalendar c = new RollingCalendar(); - // set sate to 1970-01-01 00:00:00 GMT - Date epoch = new Date(0); - if(datePattern != null) { - for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) { - String r0 = sdf.format(epoch); - c.setType(i); - Date next = new Date(c.getNextCheckMillis(epoch)); - String r1 = sdf.format(next); - //LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); - if(r0 != null && r1 != null && !r0.equals(r1)) { - return i; - } - } - } - return TOP_OF_TROUBLE; // Deliberately head for trouble... - } - - //Now for the new stuff - /** - * Handles append time behavior for CompositeRollingAppender. This checks - * if a roll over either by date (checked first) or time (checked second) - * is need and then appends to the file last. - */ - protected void subAppend(LoggingEvent event) { - - if (rollDate) { - long n = System.currentTimeMillis(); - if (n >= nextCheck) { - now.setTime(n); - nextCheck = rc.getNextCheckMillis(now); - - rollOverTime(); - } - } - - if (rollSize) { - if ((fileName != null) && ((CountingQuietWriter) qw).getCount() >= maxFileSize) { - rollOverSize(); - } - } - - super.subAppend(event); - } - - public void setFile(String file) - { - baseFileName = file.trim(); - fileName = file.trim(); - } - - /** - * Creates and opens the file for logging. If staticLogFileName - * is false then the fully qualified name is determined and used. - */ - public synchronized void setFile(String fileName, boolean append) throws IOException { - if (!staticLogFileName) { - scheduledFilename = fileName = fileName.trim() + sdf.format(now); - if (countDirection > 0) { - scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); - } - } + public QpidCompositeRollingAppender() + { + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The + * opened filename will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, + String datePattern) throws IOException + { + this(layout, filename, datePattern, true); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + * + *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by + * filename will be truncated before being opened. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) + throws IOException + { + super(layout, filename, append); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, + String datePattern, boolean append) throws IOException + { + super(layout, filename, append); + this.datePattern = datePattern; + activateOptions(); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the output destination for this appender. + * + *

      The file will be appended to. DatePattern is default. + */ + public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException + { + super(layout, filename); + } + + /** + * The DatePattern takes a string in the same format as expected by {@link java.text.SimpleDateFormat}. This + * options determines the rollover schedule. + */ + public void setDatePattern(String pattern) + { + datePattern = pattern; + } + + /** Returns the value of the DatePattern option. */ + public String getDatePattern() + { + return datePattern; + } + + /** Returns the value of the maxSizeRollBackups option. */ + public int getMaxSizeRollBackups() + { + return maxSizeRollBackups; + } + + /** + * Get the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + * @since 1.1 + */ + public long getMaximumFileSize() + { + return maxFileSize; + } + + /** + *

      Set the maximum number of backup files to keep around based on file size. + * + *

      The MaxSizeRollBackups option determines how many backup files are kept before the oldest is erased. + * This option takes an integer value. If set to zero, then there will be no backup files and the log file will be + * truncated when it reaches MaxFileSize. If a negative number is supplied then no deletions will be + * made. Note that this could result in very slow performance as a large number of files are rolled over unless + * {@link #setCountDirection} up is used. + * + *

      The maximum applys to -each- time based group of files and -not- the total. Using a daily roll the maximum + * total files would be (#days run) * (maxSizeRollBackups) + */ + public void setMaxSizeRollBackups(int maxBackups) + { + maxSizeRollBackups = maxBackups; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaxFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaximumFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      In configuration files, the MaxFileSize option takes an long integer in the range 0 - 2^63. You can + * specify the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed + * respectively in kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240. + */ + public void setMaxFileSize(String value) + { + maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); + } + + protected void setQWForFiles(Writer writer) + { + qw = new CountingQuietWriter(writer, errorHandler); + } + + //Taken verbatum from DailyRollingFileAppender + int computeCheckPeriod() + { + RollingCalendar c = new RollingCalendar(); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date(0); + if (datePattern != null) + { + for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) + { + String r0 = sdf.format(epoch); + c.setType(i); + Date next = new Date(c.getNextCheckMillis(epoch)); + String r1 = sdf.format(next); + //LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if (r0 != null && r1 != null && !r0.equals(r1)) + { + return i; + } + } + } + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + //Now for the new stuff + /** + * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked + * first) or time (checked second) is need and then appends to the file last. + */ + protected void subAppend(LoggingEvent event) + { + + if (rollDate) + { + long n = System.currentTimeMillis(); + if (n >= nextCheck) + { + now.setTime(n); + nextCheck = rc.getNextCheckMillis(now); + + rollOverTime(); + } + } + + if (rollSize) + { + if ((fileName != null) && ((CountingQuietWriter) qw).getCount() >= maxFileSize) + { + rollOverSize(); + } + } + + super.subAppend(event); + } + + public void setFile(String file) + { + baseFileName = file.trim(); + fileName = file.trim(); + } + + /** + * Creates and opens the file for logging. If staticLogFileName is false then the fully qualified name + * is determined and used. + */ + public synchronized void setFile(String fileName, boolean append) throws IOException + { + if (!staticLogFileName) + { + scheduledFilename = fileName = fileName.trim() + sdf.format(now); + if (countDirection > 0) + { + scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); + } + } super.setFile(fileName, append, bufferedIO, bufferSize); - if(append) { - File f = new File(fileName); - ((CountingQuietWriter) qw).setCount(f.length()); - } - } + if (append) + { + File f = new File(fileName); + ((CountingQuietWriter) qw).setCount(f.length()); + } + } - public int getCountDirection() { - return countDirection; - } + public int getCountDirection() + { + return countDirection; + } - public void setCountDirection(int direction) { - countDirection = direction; - } + public void setCountDirection(int direction) + { + countDirection = direction; + } - public int getRollingStyle () { + public int getRollingStyle() + { return rollingStyle; - } - - public void setRollingStyle(int style) { - rollingStyle = style; - switch (rollingStyle) { - case BY_SIZE: - rollDate = false; - rollSize = true; - break; - case BY_DATE: - rollDate = true; - rollSize = false; - break; - case BY_COMPOSITE: - rollDate = true; - rollSize = true; - break; - default: - errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); - } - } + } -/* - public void setRollingStyle(String style) { - if (style == S_BY_SIZE) { - rollingStyle = BY_SIZE; - } - else if (style == S_BY_DATE) { - rollingStyle = BY_DATE; - } - else if (style == S_BY_COMPOSITE) { - rollingStyle = BY_COMPOSITE; - } - } -*/ - public boolean getStaticLogFileName() { - return staticLogFileName; - } - - public void setStaticLogFileName(boolean s) { - staticLogFileName = s; - } - - public void setStaticLogFileName(String value) { - setStaticLogFileName(OptionConverter.toBoolean(value, true)); - } - - /** - * Initializes based on exisiting conditions at time of - * activateOptions. The following is done:
      - *
      - * A) determine curSizeRollBackups
      - * B) determine curTimeRollBackups (not implemented)
      - * C) initiates a roll over if needed for crossing a date boundary since - * the last run. - */ - protected void existingInit() { - - curSizeRollBackups = 0; - curTimeRollBackups = 0; - - //part A starts here - String filter; - if (staticLogFileName || !rollDate) { - filter = baseFileName + ".*"; - } - else { - filter = scheduledFilename + ".*"; - } - - File f = new File(baseFileName); - f = f.getParentFile(); - if (f == null) - f = new File("."); - - LogLog.debug("Searching for existing files in: " + f); - String[] files = f.list(); - - if (files != null) { - for (int i = 0; i < files.length; i++) { - if (!files[i].startsWith(baseFileName)) - continue; - - int index = files[i].lastIndexOf("."); - - if (staticLogFileName) { - int endLength = files[i].length() - index; - if (baseFileName.length() + endLength != files[i].length()) { - //file is probably scheduledFilename + .x so I don't care - continue; - } - } - - try { - int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); - LogLog.debug("From file: " + files[i] + " -> " + backup); - if (backup > curSizeRollBackups) - curSizeRollBackups = backup; - } - catch (Exception e) { - //this happens when file.log -> file.log.yyyy-mm-dd which is normal - //when staticLogFileName == false - LogLog.debug("Encountered a backup file not ending in .x " + files[i]); - } - } - } - LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); - //part A ends here - - //part B not yet implemented - - //part C - if (staticLogFileName && rollDate) { - File old = new File(baseFileName); - if (old.exists()) { - Date last = new Date(old.lastModified()); - if (!(sdf.format(last).equals(sdf.format(now)))) { - scheduledFilename = baseFileName + sdf.format(last); - LogLog.debug("Initial roll over to: " + scheduledFilename); - rollOverTime(); - } - } - } - LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); - //part C ends here - - } - - /** - * Sets initial conditions including date/time roll over information, first check, - * scheduledFilename, and calls existingInit to initialize - * the current # of backups. - */ - public void activateOptions() { - - //REMOVE removed rollDate from boolean to enable Alex's change - if(datePattern != null) { - now.setTime(System.currentTimeMillis()); - sdf = new SimpleDateFormat(datePattern); - int type = computeCheckPeriod(); - //printPeriodicity(type); - rc.setType(type); - //next line added as this removes the name check in rollOver - nextCheck = rc.getNextCheckMillis(now); - } else { - if (rollDate) - LogLog.error("Either DatePattern or rollingStyle options are not set for ["+ - name+"]."); - } - - existingInit(); - - super.activateOptions(); - - if (rollDate && fileName != null && scheduledFilename == null) - scheduledFilename = fileName + sdf.format(now); - } - - /** - Rollover the file(s) to date/time tagged file(s). - Opens the new file (through setFile) and resets curSizeRollBackups. - */ - protected void rollOverTime() { - - curTimeRollBackups++; - - //delete the old stuff here - - if (staticLogFileName) { - /* Compute filename, but only if datePattern is specified */ - if (datePattern == null) { - errorHandler.error("Missing DatePattern option in rollOver()."); - return; - } - - //is the new file name equivalent to the 'current' one - //something has gone wrong if we hit this -- we should only - //roll over if the new file will be different from the old - String dateFormat = sdf.format(now); - if (scheduledFilename.equals(fileName + dateFormat)) { - errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); - return; - } - - // close current file, and rename it to datedFilename - this.closeFile(); - - //we may have to roll over a large number of backups here - String from, to; - for (int i = 1; i <= curSizeRollBackups; i++) { - from = fileName + '.' + i; - to = scheduledFilename + '.' + i; - rollFile(from, to); - } - - rollFile(fileName, scheduledFilename); - } - - try { - // This will also close the file. This is OK since multiple - // close operations are safe. - curSizeRollBackups = 0; //We're cleared out the old date and are ready for the new - - //new scheduled name - scheduledFilename = fileName + sdf.format(now); - this.setFile(baseFileName, false); - } - catch(IOException e) { - errorHandler.error("setFile("+fileName+", false) call failed."); - } - - } - - /** Renames file from to file to. It - * also checks for existence of target file and deletes if it does. - */ - protected static void rollFile(String from, String to) { - File target = new File(to); - if (target.exists()) { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } - - File file = new File(from); - file.renameTo(target); - LogLog.debug(from +" -> "+ to); - } - - /** Delete's the specified file if it exists */ - protected static void deleteFile(String fileName) { - File file = new File(fileName); - if (file.exists()) { - file.delete(); - } - } - - /** - Implements roll overs base on file size. - -

      If the maximum number of size based backups is reached - (curSizeRollBackups == maxSizeRollBackups - If countDirection < 0, then files - {File.1, ..., File.curSizeRollBackups -1} - are renamed to {File.2, ..., - File.curSizeRollBackups}. Moreover, File is - renamed File.1 and closed.
      - - A new file is created to receive further log output. - -

      If maxSizeRollBackups is equal to zero, then the - File is truncated with no backup files created. - -

      If maxSizeRollBackups < 0, then File is - renamed if needed and no files are deleted. - */ - - // synchronization not necessary since doAppend is alreasy synched - protected void rollOverSize() { - File file; - - this.closeFile(); // keep windows happy. - - LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); - LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); - LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); - LogLog.debug("countDirection = " + countDirection); - - // If maxBackups <= 0, then there is no file renaming to be done. - if (maxSizeRollBackups != 0) { - - if (countDirection < 0) { - // Delete the oldest file, to keep Windows happy. - if (curSizeRollBackups == maxSizeRollBackups) { - deleteFile(fileName + '.' + maxSizeRollBackups); - curSizeRollBackups--; - } - - // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} - for (int i = curSizeRollBackups; i >= 1; i--) { - rollFile((fileName + "." + i), (fileName + '.' + (i + 1))); - } - - curSizeRollBackups++; - // Rename fileName to fileName.1 - rollFile(fileName, fileName + ".1"); - - } //REMOVE This code branching for Alexander Cerna's request - else if (countDirection == 0) { - //rollFile based on date pattern - curSizeRollBackups++; - now.setTime(System.currentTimeMillis()); - scheduledFilename = fileName + sdf.format(now); - rollFile(fileName, scheduledFilename); - } - else { //countDirection > 0 - if (curSizeRollBackups >= maxSizeRollBackups && maxSizeRollBackups > 0) { - //delete the first and keep counting up. - int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; - deleteFile(fileName + '.' + oldestFileIndex); - } - - if (staticLogFileName) { - curSizeRollBackups++; - rollFile(fileName, fileName + '.' + curSizeRollBackups); - } - } - } - - try { - // This will also close the file. This is OK since multiple - // close operations are safe. - this.setFile(baseFileName, false); - } - catch(IOException e) { - LogLog.error("setFile("+fileName+", false) call failed.", e); - } - } + public void setRollingStyle(int style) + { + rollingStyle = style; + switch (rollingStyle) + { + case BY_SIZE: + rollDate = false; + rollSize = true; + break; + case BY_DATE: + rollDate = true; + rollSize = false; + break; + case BY_COMPOSITE: + rollDate = true; + rollSize = true; + break; + default: + errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); + } + } + /* + public void setRollingStyle(String style) { + if (style == S_BY_SIZE) { + rollingStyle = BY_SIZE; + } + else if (style == S_BY_DATE) { + rollingStyle = BY_DATE; + } + else if (style == S_BY_COMPOSITE) { + rollingStyle = BY_COMPOSITE; + } + } + */ + public boolean getStaticLogFileName() + { + return staticLogFileName; + } + + public void setStaticLogFileName(boolean s) + { + staticLogFileName = s; + } + + public void setStaticLogFileName(String value) + { + setStaticLogFileName(OptionConverter.toBoolean(value, true)); + } + + public boolean getCompressBackupFiles() + { + return compress; + } + + public void setCompressBackupFiles(boolean c) + { + compress = c; + } + + public boolean getCompressAsync() + { + return compressAsync; + } + + public void setCompressAsync(boolean c) + { + compressAsync = c; + if (compressAsync) + { + executor = Executors.newFixedThreadPool(1); + + compressor = new Compressor(); + } + } + + + public boolean getZeroBased() + { + return zeroBased; + } + + public void setZeroBased(boolean z) + { + zeroBased = z; + } + + public String getBackupFilesToPath() + { + return backupFilesToPath; + } + + public void setbackupFilesToPath(String path) + { + File td = new File(path); + if (!td.exists()) + { + td.mkdirs(); + } + backupFilesToPath = path; + } + + /** + * Initializes based on exisiting conditions at time of activateOptions. The following is done:
      + *
      A) determine curSizeRollBackups
      B) determine curTimeRollBackups (not implemented)
      C) initiates a + * roll over if needed for crossing a date boundary since the last run. + */ + protected void existingInit() + { + + if (zeroBased) + { + curSizeRollBackups = -1; + } + curTimeRollBackups = 0; + + //part A starts here + String filter; + if (staticLogFileName || !rollDate) + { + filter = baseFileName + ".*"; + } + else + { + filter = scheduledFilename + ".*"; + } + + File f = new File(baseFileName); + f = f.getParentFile(); + if (f == null) + { + f = new File("."); + } + + LogLog.debug("Searching for existing files in: " + f); + String[] files = f.list(); + + if (files != null) + { + for (int i = 0; i < files.length; i++) + { + if (!files[i].startsWith(baseFileName)) + { + continue; + } + + int index = files[i].lastIndexOf("."); + + if (staticLogFileName) + { + int endLength = files[i].length() - index; + if (baseFileName.length() + endLength != files[i].length()) + { + //file is probably scheduledFilename + .x so I don't care + continue; + } + } + + try + { + int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); + LogLog.debug("From file: " + files[i] + " -> " + backup); + if (backup > curSizeRollBackups) + { + curSizeRollBackups = backup; + } + } + catch (Exception e) + { + //this happens when file.log -> file.log.yyyy-mm-dd which is normal + //when staticLogFileName == false + LogLog.debug("Encountered a backup file not ending in .x " + files[i]); + } + } + } + LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); + //part A ends here + + //part B not yet implemented + + //part C + if (staticLogFileName && rollDate) + { + File old = new File(baseFileName); + if (old.exists()) + { + Date last = new Date(old.lastModified()); + if (!(sdf.format(last).equals(sdf.format(now)))) + { + scheduledFilename = baseFileName + sdf.format(last); + LogLog.debug("Initial roll over to: " + scheduledFilename); + rollOverTime(); + } + } + } + LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); + //part C ends here + + } + + /** + * Sets initial conditions including date/time roll over information, first check, scheduledFilename, and calls + * existingInit to initialize the current # of backups. + */ + public void activateOptions() + { + + //REMOVE removed rollDate from boolean to enable Alex's change + if (datePattern != null) + { + now.setTime(System.currentTimeMillis()); + sdf = new SimpleDateFormat(datePattern); + int type = computeCheckPeriod(); + //printPeriodicity(type); + rc.setType(type); + //next line added as this removes the name check in rollOver + nextCheck = rc.getNextCheckMillis(now); + } + else + { + if (rollDate) + { + LogLog.error("Either DatePattern or rollingStyle options are not set for [" + + name + "]."); + } + } + + existingInit(); + + if (rollDate && fileName != null && scheduledFilename == null) + { + scheduledFilename = fileName + sdf.format(now); + } + + try + { + this.setFile(fileName, true); + } + catch (IOException e) + { + errorHandler.error("Cannot set file name:" + fileName); + } + + super.activateOptions(); + } + + /** + * Rollover the file(s) to date/time tagged file(s). Opens the new file (through setFile) and resets + * curSizeRollBackups. + */ + protected void rollOverTime() + { + + curTimeRollBackups++; + + this.closeFile(); // keep windows happy. + + //delete the old stuff here + + if (staticLogFileName) + { + /* Compute filename, but only if datePattern is specified */ + if (datePattern == null) + { + errorHandler.error("Missing DatePattern option in rollOver()."); + return; + } + + //is the new file name equivalent to the 'current' one + //something has gone wrong if we hit this -- we should only + //roll over if the new file will be different from the old + String dateFormat = sdf.format(now); + if (scheduledFilename.equals(fileName + dateFormat)) + { + errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); + return; + } + + // close current file, and rename it to datedFilename + this.closeFile(); + + //we may have to roll over a large number of backups here + String from, to; + for (int i = 1; i <= curSizeRollBackups; i++) + { + from = fileName + '.' + i; + to = scheduledFilename + '.' + i; + rollFile(from, to, false); + } + + rollFile(fileName, scheduledFilename, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + curSizeRollBackups = 0; //We're cleared out the old date and are ready for the new + + //new scheduled name + scheduledFilename = fileName + sdf.format(now); + this.setFile(baseFileName, false); + } + catch (IOException e) + { + errorHandler.error("setFile(" + fileName + ", false) call failed."); + } + + } + + /** + * Renames file from to file to. It also checks for existence of target file and deletes + * if it does. + */ + protected void rollFile(String from, String to, boolean compress) + { + if (from.equals(to)) + { + if (compress) + { + LogLog.debug("Attempting to compress file with same output name."); + } + return; + } + File target = new File(to); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + File file = new File(from); + if (compress) + { + compress(file, target); + } + else + { + if (!file.getPath().equals(target.getPath())) + { + file.renameTo(target); + } + } + LogLog.debug(from + " -> " + to); + } + + + protected void compress(String file) + { + File f = new File(file); + compress(f, f); + } + + private void compress(File from, File target) + { + if (compressAsync) + { + synchronized (_compress) + { + _compress.offer(new CompressJob(from, target)); + } + startCompression(); + } + else + { + doCompress(from, target); + } + } + + private void startCompression() + { + if (_compressing.compareAndSet(false, true)) + { + executor.execute(compressor); + } + } + + /** Delete's the specified file if it exists */ + protected static void deleteFile(String fileName) + { + File file = new File(fileName); + if (file.exists()) + { + file.delete(); + } + } + + /** + * Implements roll overs base on file size. + * + *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If + * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} + * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is + * renamed File.1 and closed.
      + * + * A new file is created to receive further log output. + * + *

      If maxSizeRollBackups is equal to zero, then the File is truncated with no backup + * files created. + * + *

      If maxSizeRollBackups < 0, then File is renamed if needed and no files are deleted. + */ + + // synchronization not necessary since doAppend is alreasy synched + protected void rollOverSize() + { + File file; + + this.closeFile(); // keep windows happy. + + LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); + LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); + LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); + LogLog.debug("countDirection = " + countDirection); + + // If maxBackups <= 0, then there is no file renaming to be done. + if (maxSizeRollBackups != 0) + { + + if (countDirection < 0) + { + // Delete the oldest file, to keep Windows happy. + if (curSizeRollBackups == maxSizeRollBackups) + { + deleteFile(fileName + '.' + maxSizeRollBackups); + curSizeRollBackups--; + } + + // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} + for (int i = curSizeRollBackups; i >= 1; i--) + { + rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); + } + + curSizeRollBackups++; + // Rename fileName to fileName.1 + rollFile(fileName, fileName + ".1", compress); + + } //REMOVE This code branching for Alexander Cerna's request + else if (countDirection == 0) + { + //rollFile based on date pattern + curSizeRollBackups++; + now.setTime(System.currentTimeMillis()); + scheduledFilename = fileName + sdf.format(now); + rollFile(fileName, scheduledFilename, compress); + } + else + { //countDirection > 0 + if (curSizeRollBackups >= maxSizeRollBackups && maxSizeRollBackups > 0) + { + //delete the first and keep counting up. + int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + deleteFile(fileName + '.' + oldestFileIndex); + } + + if (staticLogFileName) + { + curSizeRollBackups++; + rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(baseFileName, false); + } + catch (IOException e) + { + LogLog.error("setFile(" + fileName + ", false) call failed.", e); + } + } + + protected synchronized void doCompress(File from, File to) + { + String toFile; + if (backupFilesToPath == null) + { + toFile = to.getPath() + ".gz"; + } + else + { + toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; + } + + File target = new File(toFile); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + try + { + // Create the GZIP output stream + GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); + + // Open the input file + FileInputStream in = new FileInputStream(from); + + // Transfer bytes from the input file to the GZIP output stream + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + in.close(); + + // Complete the GZIP file + out.finish(); + out.close(); + // Remove old file. + from.delete(); + } + catch (IOException e) + { + if (target.exists()) + { + target.delete(); + } + rollFile(from.getPath(), to.getPath(), false); + } + } + + private class CompressJob + { + File _from, _to; + + CompressJob(File from, File to) + { + _from = from; + _to = to; + } + + File getFrom() + { + return _from; + } + + File getTo() + { + return _to; + } + } + + Compressor compressor = null; + + Executor executor; + + private class Compressor implements Runnable + { + public void run() + { + boolean running = true; + while (running) + { + CompressJob job = _compress.poll(); + + doCompress(job.getFrom(), job.getTo()); + + synchronized (_compress) + { + if (_compress.isEmpty()) + { + running = false; + _compressing.set(false); + } + } + } + + } + } } -- cgit v1.2.1 From ffe5e29f94b376c6f5900b2f9577c8bbaef7407b Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 19 Apr 2007 16:24:30 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522993,522995-523244,523246-525530,525532,525534,525537-526149,526151-526682,526686-526713,526715-530399 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r521682 | bhupendrab | 2007-03-23 11:50:55 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-418 (merged from trunk) svn merge -r521336:521345 https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/java . ........ r521705 | rgreig | 2007-03-23 12:44:14 +0000 (Fri, 23 Mar 2007) | 1 line Updates to performance tests. ........ r521710 | ritchiem | 2007-03-23 12:59:18 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-419 Access Control QPID-423 Authentication per virtualhost Improved error handling when hostconfig is not specifed. Was NPE-ing ........ r521715 | ritchiem | 2007-03-23 13:10:33 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-423 Authentication per virtualhost Improved error handling when hostconfig is not specifed. Was NPE-ing ........ r521782 | bhupendrab | 2007-03-23 16:02:51 +0000 (Fri, 23 Mar 2007) | 1 line QPID-420 (merged from trunk) And r518998:518999 and r520846:520850 ........ r522959 | ritchiem | 2007-03-27 16:39:51 +0100 (Tue, 27 Mar 2007) | 2 lines Updated assembly/bin.xml to include transient_config.xml persistent_config.xml ........ r522961 | ritchiem | 2007-03-27 16:42:40 +0100 (Tue, 27 Mar 2007) | 1 line forgot to rename files after they had been copied ........ r522967 | ritchiem | 2007-03-27 16:56:03 +0100 (Tue, 27 Mar 2007) | 1 line correctly renamed transient and persistent config files ........ r522977 | ritchiem | 2007-03-27 17:06:15 +0100 (Tue, 27 Mar 2007) | 1 line updated config files ........ r522981 | ritchiem | 2007-03-27 17:10:45 +0100 (Tue, 27 Mar 2007) | 1 line Added echo of progress and reduced timeout ........ r522989 | ritchiem | 2007-03-27 17:33:04 +0100 (Tue, 27 Mar 2007) | 1 line fixed error where script wouldn't pickup running pids ........ r522990 | ritchiem | 2007-03-27 17:36:34 +0100 (Tue, 27 Mar 2007) | 1 line Added additional logging and comments ........ r522991 | ritchiem | 2007-03-27 17:37:17 +0100 (Tue, 27 Mar 2007) | 1 line Added additional comments ........ r523747 | rajith | 2007-03-29 16:32:56 +0100 (Thu, 29 Mar 2007) | 1 line Fix for setting the message id ........ r524050 | rgreig | 2007-03-30 12:51:09 +0100 (Fri, 30 Mar 2007) | 1 line Removed excess logging to optimize performance. ........ r524739 | ritchiem | 2007-04-02 08:29:06 +0100 (Mon, 02 Apr 2007) | 1 line Added BDB Test scripts and updated pom to contain same tests as were used in perftesting ........ r524740 | ritchiem | 2007-04-02 08:47:29 +0100 (Mon, 02 Apr 2007) | 1 line Fixed error with passwordfile parameter ........ r524743 | ritchiem | 2007-04-02 09:07:55 +0100 (Mon, 02 Apr 2007) | 1 line Added CTQ tests ........ r524763 | ritchiem | 2007-04-02 11:50:06 +0100 (Mon, 02 Apr 2007) | 1 line Added verify password method to PrincipalDatabase ........ r524765 | ritchiem | 2007-04-02 11:55:12 +0100 (Mon, 02 Apr 2007) | 1 line Moved broker details to a separate variable. ........ r524767 | ritchiem | 2007-04-02 12:17:54 +0100 (Mon, 02 Apr 2007) | 1 line ignored idea files ........ r525487 | ritchiem | 2007-04-04 11:42:59 +0100 (Wed, 04 Apr 2007) | 3 lines Added default timeout to AMQConnection.close(); ........ r525553 | ritchiem | 2007-04-04 17:34:35 +0100 (Wed, 04 Apr 2007) | 1 line Updated case of properties ........ r525766 | ritchiem | 2007-04-05 09:51:55 +0100 (Thu, 05 Apr 2007) | 1 line QPID-308 Added test case to demonstrate heap exhaustion of broker. Can't be run InVM as it kills the broker. ........ r525777 | ritchiem | 2007-04-05 10:29:22 +0100 (Thu, 05 Apr 2007) | 20 lines QPID-414 : Addition of CRAM-MD5-HASHED authentication. Same as CRAM-MD5 but the client uses the hash of the password rather than the original password. This allows the broker to store the hash not the original password. Added initial tool for generation passwords. Broker: Renamed MD5PasswordFilePrincipalDatabase.java to Base64MD5PasswordFilePrincipalDatabase.java as that more accurately represents the file contents. PlainPasswordVhostFilePrincipalDatabase.java - import tidy up PrincipalDatabaseAuthenticationManager.java - Changed to add our SASL providers at the start of the SASL list. CRAMMD5Hashed* - New SASL mechanism that delegates to CRAM-MD5 but understands that the password to use is the hash of the users password. JCAProvider - Removed the addProvider() line as this is done after the construction in PrincipalDatabaseAuthenticationManager. PlainSaslServerFactory - White Space Passwd.java - New util stub for managing passwords ala htpasswd. Client Added CRAM-MD5-HASHED to CallbackHandlerRegistry Added ClientFactory for CRAMMD5Hashed that returns the first CRAM-MD5 SaslClient. DynamicSaslRegistrar.java - Tidied imports added new JCAProviders at the start of the Sasl lists. DynamicSaslRegistrar.properties - Added CRAM-MD5-HASHED handler. JCAProvider.java - as with broker stopped JCAProvider.java adding itself as the DynamicSaslRegistrar.java does this on the client. UsernameHashedPasswordCallbackHandler.java - New callback handler that is used by CRAM-MD5-HASHED. It hashes the client's password and uses that in the CRAM-MD5 algorithm. ........ r525785 | ritchiem | 2007-04-05 10:48:43 +0100 (Thu, 05 Apr 2007) | 1 line Old ant folder ........ r525786 | ritchiem | 2007-04-05 10:57:33 +0100 (Thu, 05 Apr 2007) | 1 line QPID-440 - added comments in the code relating to this bug. ........ r525787 | ritchiem | 2007-04-05 10:58:20 +0100 (Thu, 05 Apr 2007) | 2 lines QPID-308 removed closeConnection() that calls close(-1) and may result in a client hang. better to call closeConnection(long timeout) so forced this my removing closeConnection(); ........ r525788 | ritchiem | 2007-04-05 11:00:56 +0100 (Thu, 05 Apr 2007) | 1 line QPID-414 update to config.xml to give usage example. ........ r525804 | ritchiem | 2007-04-05 13:19:31 +0100 (Thu, 05 Apr 2007) | 1 line QPID-308 Updated HeapExhaustion to be able to be run from command line ........ r525817 | ritchiem | 2007-04-05 14:14:50 +0100 (Thu, 05 Apr 2007) | 1 line Update to qpid stop scripts to properly check for existing broker instances and promptly stop them. ........ r525829 | ritchiem | 2007-04-05 14:50:56 +0100 (Thu, 05 Apr 2007) | 1 line Updated scripts to work correctly under solaris and bash 2.0 ........ r525862 | rgodfrey | 2007-04-05 17:37:40 +0100 (Thu, 05 Apr 2007) | 1 line QPID-443 : Fix to transactionality of message publishing ........ r525867 | ritchiem | 2007-04-05 17:47:59 +0100 (Thu, 05 Apr 2007) | 2 lines QPID-416 Provided simple update to Access Control via FileAccessManager to allow access rights for a virtualhost to be stored in a separate file. Updated PrincipalDatabaseAccessManager to use the default AccessManager if the specified PrincipalDatabase is not an AccessManager. ........ r526091 | ritchiem | 2007-04-06 09:21:01 +0100 (Fri, 06 Apr 2007) | 5 lines QPID-416 Update to Access control to allow simply read/write permissions per Virtual host. access - updated file to have examples of access control. AccessManager - Deprecated old isAuthorised method Implemented new isAuthorized method on all AccessManagers ........ r526113 | ritchiem | 2007-04-06 11:28:43 +0100 (Fri, 06 Apr 2007) | 1 line Updated case of properties to be true cammelCase and updated tests to run for a duration of 10 minutes rather than set message count. To provide better results for graphing. ........ r526117 | ritchiem | 2007-04-06 11:42:11 +0100 (Fri, 06 Apr 2007) | 9 lines QPID-416 Update to Access control to allow simply read/write permissions per Virtual host. access - updated file to have examples of access control. Changed AMQProtocolSession to record an authorized Principal not just a String. - Required Added AccessRights files needed for VirtualHostAccess control. Updated ConnectionOpenMethodHandler to allow Principals with any access to connect not just read. UsernamePrincipal - Added a toString ........ r526118 | rgodfrey | 2007-04-06 11:55:17 +0100 (Fri, 06 Apr 2007) | 1 line ........ r526122 | ritchiem | 2007-04-06 12:26:06 +0100 (Fri, 06 Apr 2007) | 1 line removed pauses between batches ........ r526154 | rgodfrey | 2007-04-06 14:24:46 +0100 (Fri, 06 Apr 2007) | 1 line QPID-443 : Fix to transactionality of message publishing ........ r526157 | bhupendrab | 2007-04-06 14:32:56 +0100 (Fri, 06 Apr 2007) | 1 line QPID-444 : Enabling the Qpid to use SASL. jmxmp can be plugged into for SASL. Can be configured to use security. ........ r526158 | ritchiem | 2007-04-06 14:34:52 +0100 (Fri, 06 Apr 2007) | 1 line Duplicate of BDB-Qpid.sh ........ r526159 | bhupendrab | 2007-04-06 14:37:47 +0100 (Fri, 06 Apr 2007) | 1 line QPID-444 : adding jmxport, which is used when out of the box JMXAgent is not used ........ r526166 | ritchiem | 2007-04-06 14:51:41 +0100 (Fri, 06 Apr 2007) | 1 line QPID-414 - Initial script to run the passwd gen. ........ r526187 | bhupendrab | 2007-04-06 15:53:36 +0100 (Fri, 06 Apr 2007) | 2 lines QPID-444 : Enabling the SASL support. jmxmp can be plugged into for SASL. ........ r526194 | rgreig | 2007-04-06 16:21:19 +0100 (Fri, 06 Apr 2007) | 1 line Added some ramping up performance tests. ........ r526195 | marnie | 2007-04-06 16:21:33 +0100 (Fri, 06 Apr 2007) | 1 line QPID-381 Amended session constructor to be non-transactional and use client ack mode. ........ r526198 | rgreig | 2007-04-06 16:26:02 +0100 (Fri, 06 Apr 2007) | 1 line Fixed message sizes. ........ r526199 | rgreig | 2007-04-06 16:29:06 +0100 (Fri, 06 Apr 2007) | 1 line Fixed commit batch size. ........ r526666 | ritchiem | 2007-04-09 08:47:14 +0100 (Mon, 09 Apr 2007) | 1 line Updated so the FileAppender includes time stamps by default.. ConversionPattern made the same as STDOUT and RollingFileAppender ........ r526691 | ritchiem | 2007-04-09 10:39:47 +0100 (Mon, 09 Apr 2007) | 1 line Added $@ to allow pass through of command line args to each sub process ........ r526692 | bhupendrab | 2007-04-09 10:45:06 +0100 (Mon, 09 Apr 2007) | 4 lines QPID-444 : added log statements and some config parameters. Removed the autoDelete parameter from createNewQueue method used from Management Console. ........ r526694 | bhupendrab | 2007-04-09 10:51:46 +0100 (Mon, 09 Apr 2007) | 1 line ........ r526709 | bhupendrab | 2007-04-09 12:02:08 +0100 (Mon, 09 Apr 2007) | 2 lines QPID-444 : updated the management console dependency configuration for sasl support ........ r526776 | rgreig | 2007-04-09 16:26:04 +0100 (Mon, 09 Apr 2007) | 1 line Stopped throwing away exception causes. ........ r526803 | rgreig | 2007-04-09 17:09:24 +0100 (Mon, 09 Apr 2007) | 1 line Got rid of some uses of System.out instead of log4j logging. ........ r526807 | rgreig | 2007-04-09 17:12:49 +0100 (Mon, 09 Apr 2007) | 1 line Got rid of some uses of System.out instead of log4j logging. ........ r527049 | ritchiem | 2007-04-10 08:58:26 +0100 (Tue, 10 Apr 2007) | 1 line Moved bdb tests to bdbstore package ........ r527050 | ritchiem | 2007-04-10 09:00:42 +0100 (Tue, 10 Apr 2007) | 1 line QueueDeclareHandler.java - Added more detail to error messages. Such as returning the queue name that was attempted to be declared but failed. ........ r527053 | ritchiem | 2007-04-10 09:03:15 +0100 (Tue, 10 Apr 2007) | 1 line Added a test to check that Persistent Queues do actually persist. ........ r527182 | ritchiem | 2007-04-10 17:29:47 +0100 (Tue, 10 Apr 2007) | 1 line QPID-446 Initial MBean framework. ........ r527487 | ritchiem | 2007-04-11 14:31:18 +0100 (Wed, 11 Apr 2007) | 5 lines QPID-446 AMQUserManagementMBean Initial implementation of user management in authentication file. UserManagement - Added annotations for MBeanOperations PrincipalDatabase - Added new methods to update,create,delete Principal. - Implemented method on all PrincipalDatabase implementations, most return false to say not complete except Base64MD5PasswordFilePrincipalDatabase - which now stores in memory the password file and flushes any changes to disk. ........ r527493 | ritchiem | 2007-04-11 14:50:40 +0100 (Wed, 11 Apr 2007) | 1 line QPID-446 Missed the commit of JMXManagedObjectRegistry change on verifyPassword char[] to String ........ r527499 | bhupendrab | 2007-04-11 15:16:02 +0100 (Wed, 11 Apr 2007) | 1 line QPID-444 : added CRAM-MD5-HASHED mechanism for sasl ........ r527509 | bhupendrab | 2007-04-11 15:47:22 +0100 (Wed, 11 Apr 2007) | 1 line ........ r527518 | ritchiem | 2007-04-11 16:21:37 +0100 (Wed, 11 Apr 2007) | 14 lines QPID-446 JMXManagedObjectRegistry - Split instantiation from starting up. To all the setting of the Access file when loaded later in the startup sequence. ManagedObjectRegistry - Added Start method MBeanInvocationHandlerImpl - Updated to allow the setting of the access properties object from the AMQUserManagementMBean NoopManagedObjectRegistry - implemented no-op start ConfigurationFileApplicationRegistry - Adjusted to split creation of ManagedObjectRegistry from starting server to allow the setting of access rights. AMQUserManagementMBean - Implemented reading of access rights file. Base64MD5PasswordFilePrincipalDatabase - added comment for future Management. PrincipalDatabaseManager - added initialiseManagement method ConfigurationFilePrincipalDatabaseManager - implemented general Management initialisation. PropertiesPrincipalDatabaseManager - no-op implementation ........ r527537 | ritchiem | 2007-04-11 16:47:30 +0100 (Wed, 11 Apr 2007) | 2 lines QPID-446 Update to contain jmx config settings. ........ r527556 | bhupendrab | 2007-04-11 17:07:58 +0100 (Wed, 11 Apr 2007) | 1 line synchronized with hash mechanism used in Broker ........ r527557 | ritchiem | 2007-04-11 17:08:54 +0100 (Wed, 11 Apr 2007) | 1 line Fixed Bug in convertPassword where data wasn't correctly updated PropertiesPrincipalDatabase, ........ r527558 | ritchiem | 2007-04-11 17:09:54 +0100 (Wed, 11 Apr 2007) | 1 line QpiQPID-446 Update to ensure qpid.password file is correctly written in savePasswordFile ........ r527803 | ritchiem | 2007-04-12 08:16:54 +0100 (Thu, 12 Apr 2007) | 5 lines QPID-446 Update to write accessRights file and correctly write Base64 MD5 Hashed password to password file. MBeanInvocationHandlerImpl - made statics ADMIN,READONLY,READWRITE public so they can be used in writing the access file. AMQUserManagementMBean - Update to write the access File. PrincipalDatabase - create getUser(username) to retrieve a Principal from the database this is then implemented in all PDs. Used to check for existence of a user. ........ r527843 | ritchiem | 2007-04-12 09:52:19 +0100 (Thu, 12 Apr 2007) | 10 lines QPID-446 Update to send userList to JMX Management console. Currently niave implementation just sending ALL users in one go. If a LDAPPrincipalDatabase was created this could be quite a lot of data a) to send but b) to create in broker Heap. PrincipalDatabase - javadoc'd and getUsers method, -changed verifyPassword method to take String for username rather than Principal only the Managment Console uses this method and it the MC should be changed to use the Broker SASL modules directly rather than having very similar ones of its own. - Removed AccountNotFound exception from createPrincipal as it made no sence No-op implementation in PlainPasswordFilePrincipalDatabase and PropertiesPrincipalDatabase Base64MD5PasswordFilePrincipalDatabase changed local User class to implement Principal so current Map can be returned via getUsers - Added locking to ensure integrity of files in the face of multiple edits. ........ r527848 | ritchiem | 2007-04-12 10:11:19 +0100 (Thu, 12 Apr 2007) | 1 line QPID-446 Removed hashing of presented password in Base64MD5PasswordFilePrincipalDatabase. ........ r527876 | rgodfrey | 2007-04-12 11:31:51 +0100 (Thu, 12 Apr 2007) | 3 lines QPID-451 Throw InvalidDestinationException on attempt to publish to a Queue which does not exist Changed QueueSenderAdapter to check if the routing key is bound to a queue on the given exchange. The checking can be turned off by setting the system property org.apache.qpid.client.verifyQueueBindingBeforePublish to anything but true ........ r527941 | bhupendrab | 2007-04-12 14:49:10 +0100 (Thu, 12 Apr 2007) | 1 line not needed for management console ........ r527959 | bhupendrab | 2007-04-12 15:40:36 +0100 (Thu, 12 Apr 2007) | 1 line refining the mbean operations ........ r527972 | ritchiem | 2007-04-12 16:11:16 +0100 (Thu, 12 Apr 2007) | 3 lines QPID-446 Updated sample configs to contain jmx security options. ........ r528003 | marnie | 2007-04-12 17:15:48 +0100 (Thu, 12 Apr 2007) | 1 line QPID-352 Changes ........ r528005 | marnie | 2007-04-12 17:16:34 +0100 (Thu, 12 Apr 2007) | 1 line QPID-352 Changes ........ r528424 | rgreig | 2007-04-13 11:17:12 +0100 (Fri, 13 Apr 2007) | 1 line Created new ping client that sends messages only. Usefull for examaning known queue states in mgmnt console. ........ r529233 | bhupendrab | 2007-04-16 14:25:58 +0100 (Mon, 16 Apr 2007) | 1 line added parameter for SASL ........ r529246 | bhupendrab | 2007-04-16 14:48:31 +0100 (Mon, 16 Apr 2007) | 1 line removed default username as guest. Added hashing for new user password field. ........ r529297 | rgodfrey | 2007-04-16 16:53:45 +0100 (Mon, 16 Apr 2007) | 1 line QPID-453 : AMQShortString should implement Comparable ........ r529635 | bhupendrab | 2007-04-17 16:07:06 +0100 (Tue, 17 Apr 2007) | 1 line QPID-422 : Combined all user configured notifications on one view. ........ r529659 | ritchiem | 2007-04-17 17:08:00 +0100 (Tue, 17 Apr 2007) | 7 lines QPID-454 Message 'taken' notion is per message. But should be per message per queue AMQChannel - pass queue in on all take/release/getSubscriptionDelievered calls BasicRejectMethodHandler - pass queue in on getSubscriptionDelievered calls AMQMessage - Changes to require AMQQueue on all take/release/getSubscriptionDelievered calls ConcurrentSelectorDeliveryManager - pass queue in on take/release/getSubscriptionDelievered calls SubscriptionImpl - - pass queue in on release calls ........ r529666 | ritchiem | 2007-04-17 17:19:59 +0100 (Tue, 17 Apr 2007) | 11 lines QPID-455 Prefetched messages can cause problems with client tools. AMQSession - suspend channel at startup until start() and recieve/setMessageListener are called. BasicMessageConsumer - mainly style sheet changes MessageListenerMultiConsumerTest - removed one test case as we cannot ensure round-robin effect at start up .. added test case for only c2 consuming when c1 does nothing. MessageListenerTest - added new test that can demonstrate a further bug of message 'loss' when a receive is called only once before a message listener is set. Prefetched message end up on _SynchronousQueue regression of QPID-293 as of r501004. MessageRequeueTest - Was missing a conn.start() DurableSubscriptionTest - Removed blocking receives() so we don't block on failure CommitRollbackTest - Text message was wrong on testGetThenDisconnect tests so adjusted ........ r529669 | bhupendrab | 2007-04-17 17:43:53 +0100 (Tue, 17 Apr 2007) | 1 line QPID-417 ........ r530034 | bhupendrab | 2007-04-18 15:32:02 +0100 (Wed, 18 Apr 2007) | 2 lines AMQUserManagementMBean.java - calling relaod within viewUsers method. Creating user list on management console instead of typing the user name. ........ r530037 | ritchiem | 2007-04-18 15:37:30 +0100 (Wed, 18 Apr 2007) | 1 line QPID-454 Message 'taken' notion is per message. REVERTED as it just wasn't right.. needs to be refactored. ........ r530041 | ritchiem | 2007-04-18 15:40:47 +0100 (Wed, 18 Apr 2007) | 1 line QPID-457 Fixed rollback inTran problem with test case ........ r530042 | ritchiem | 2007-04-18 15:42:16 +0100 (Wed, 18 Apr 2007) | 1 line QPID-457 Fixed rollback inTran problem with test case Missed the actual file fix. ........ r530043 | ritchiem | 2007-04-18 15:46:36 +0100 (Wed, 18 Apr 2007) | 1 line QPID-458 Fix to make the CSDM check if a message is taken when deliverying to browser. Removing the message from the queue and continuing if that is the caee. ........ r530044 | ritchiem | 2007-04-18 15:54:36 +0100 (Wed, 18 Apr 2007) | 1 line Removed e.printstacktrace that sneaked in with the other code style changes. ........ r530047 | ritchiem | 2007-04-18 16:09:28 +0100 (Wed, 18 Apr 2007) | 1 line Fix for intermittent CRT expected <1> but was <2> errors ........ r530048 | ritchiem | 2007-04-18 16:10:24 +0100 (Wed, 18 Apr 2007) | 3 lines ResetMessageListenerTest was using the wrong queue for running tests. This was causing problems during testing. Changed queue to use ResetMessageListenerTest queue ........ r530049 | ritchiem | 2007-04-18 16:11:22 +0100 (Wed, 18 Apr 2007) | 2 lines QPID-455 Prefetched messages can cause problems with client tools. Removed the changes as this was causing problems. Guarded with a check for now but solution is till not correct. ........ r530052 | ritchiem | 2007-04-18 16:12:45 +0100 (Wed, 18 Apr 2007) | 1 line QPID-455 - Guarded test with a check until a full solution is found ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530474 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 53 +- .../java/org/apache/qpid/server/AMQChannel.java | 13 +- .../src/main/java/org/apache/qpid/server/Main.java | 91 +-- .../qpid/server/exchange/DestNameExchange.java | 1 + .../server/handler/BasicRejectMethodHandler.java | 2 +- .../handler/ConnectionOpenMethodHandler.java | 16 +- .../handler/ConnectionSecureOkMethodHandler.java | 3 +- .../handler/ConnectionStartOkMethodHandler.java | 3 +- .../qpid/server/handler/QueueDeclareHandler.java | 52 +- .../management/JMXManagedObjectRegistry.java | 258 ++++++++- .../management/MBeanInvocationHandlerImpl.java | 217 +++++++ .../qpid/server/management/ManagedBroker.java | 6 +- .../server/management/ManagedObjectRegistry.java | 5 + .../management/NoopManagedObjectRegistry.java | 12 + .../server/protocol/AMQMinaProtocolSession.java | 7 +- .../qpid/server/protocol/AMQProtocolSession.java | 8 +- .../server/protocol/AMQProtocolSessionMBean.java | 96 ++-- .../qpid/server/protocol/ManagedConnection.java | 8 +- .../org/apache/qpid/server/queue/AMQMessage.java | 38 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 136 +++-- .../queue/ConcurrentSelectorDeliveryManager.java | 31 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 2 +- .../qpid/server/registry/ApplicationRegistry.java | 10 +- .../ConfigurationFileApplicationRegistry.java | 9 +- .../org/apache/qpid/server/security/Passwd.java | 81 +++ .../security/access/AMQUserManagementMBean.java | 457 +++++++++++++++ .../qpid/server/security/access/AccessManager.java | 5 + .../server/security/access/AccessManagerImpl.java | 33 +- .../qpid/server/security/access/AccessRights.java | 63 +++ .../qpid/server/security/access/AllowAll.java | 7 + .../qpid/server/security/access/DenyAll.java | 7 + .../server/security/access/FileAccessManager.java | 183 ++++++ .../access/PrincipalDatabaseAccessManager.java | 21 +- .../server/security/access/UserManagement.java | 111 ++++ .../server/security/access/VirtualHostAccess.java | 68 +++ .../Base64MD5PasswordFilePrincipalDatabase.java | 626 +++++++++++++++++++++ .../ConfigurationFilePrincipalDatabaseManager.java | 144 ++++- .../database/MD5PasswordFilePrincipalDatabase.java | 160 ------ .../PlainPasswordFilePrincipalDatabase.java | 92 ++- .../PlainPasswordVhostFilePrincipalDatabase.java | 22 +- .../security/auth/database/PrincipalDatabase.java | 50 ++ .../auth/database/PrincipalDatabaseManager.java | 4 + .../auth/database/PropertiesPrincipalDatabase.java | 82 +++ .../PropertiesPrincipalDatabaseManager.java | 7 + .../PrincipalDatabaseAuthenticationManager.java | 19 +- .../server/security/auth/sasl/JCAProvider.java | 2 +- .../auth/sasl/UsernamePasswordInitialiser.java | 15 +- .../security/auth/sasl/UsernamePrincipal.java | 10 +- .../sasl/crammd5/CRAMMD5HashedInitialiser.java | 50 ++ .../auth/sasl/crammd5/CRAMMD5HashedSaslServer.java | 105 ++++ .../sasl/crammd5/CRAMMD5HashedServerFactory.java | 61 ++ .../auth/sasl/plain/PlainSaslServerFactory.java | 2 +- .../qpid/server/txn/CleanupMessageOperation.java | 13 +- .../qpid/server/txn/LocalTransactionalContext.java | 10 +- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 2 +- .../qpid/server/virtualhost/VirtualHost.java | 2 +- 56 files changed, 3119 insertions(+), 472 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 23c32aceab..d31359b019 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ /* * * Copyright (c) 2006 The Apache Software Foundation @@ -22,8 +42,12 @@ import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -36,9 +60,6 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.commons.configuration.Configuration; /** * This MBean implements the broker management interface and exposes the @@ -82,8 +103,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param autoDelete * @throws JMException */ - public void createNewExchange(String exchangeName, String type, boolean durable, boolean autoDelete) - throws JMException + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException { try { @@ -92,7 +112,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); if (exchange == null) { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, autoDelete, 0); + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), + durable, false, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -140,8 +161,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param autoDelete * @throws JMException */ - public void createNewQueue(String queueName, String owner, boolean durable,boolean autoDelete) - throws JMException + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue != null) @@ -156,22 +176,27 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { ownerShortString = new AMQShortString(owner); } - queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, autoDelete, getVirtualHost()); + + queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); } - Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + Configuration virtualHostDefaultQueueConfiguration = + VirtualHostConfiguration.getDefaultQueueConfiguration(queue); if (virtualHostDefaultQueueConfiguration != null) { Configurator.configure(queue, virtualHostDefaultQueueConfiguration); } + _queueRegistry.registerQueue(queue); } catch (AMQException ex) { - throw new MBeanException(new JMException(ex.getMessage()),"Error in creating queue " + queueName); + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in creating queue " + queueName); } } @@ -202,7 +227,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(new JMException(ex.getMessage()), "Error in deleting queue " + queueName); + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in deleting queue " + queueName); } } @@ -213,7 +240,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr // This will have a single instance for a virtual host, so not having the name property in the ObjectName public ObjectName getObjectName() throws MalformedObjectNameException - { + { return getObjectNameForSingleInstanceMBean(); } } // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1ebe5fa0a2..2e1653e69d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -472,7 +472,7 @@ public class AMQChannel if (unacked.queue != null) { // Ensure message is released for redelivery - unacked.message.release(); + unacked.message.release(unacked.queue); // Mark message redelivered unacked.message.setRedelivered(true); @@ -503,7 +503,10 @@ public class AMQChannel { // Ensure message is released for redelivery - unacked.message.release(); + if (unacked.queue != null) + { + unacked.message.release(unacked.queue); + } // Mark message redelivered unacked.message.setRedelivered(true); @@ -672,14 +675,14 @@ public class AMQChannel // else // { //release to allow it to be delivered - msg.release(); + msg.release(message.queue); // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. msg.setRedelivered(true); - Subscription sub = msg.getDeliveredSubscription(); + Subscription sub = msg.getDeliveredSubscription(message.queue); if (sub != null) { @@ -753,7 +756,7 @@ public class AMQChannel // Process Messages to Requeue at the front of the queue for (UnacknowledgedMessage message : msgToRequeue) { - message.message.release(); + message.message.release(message.queue); message.message.setRedelivered(true); deliveryContext.deliver(message.message, message.queue, true); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 38a505c6c7..146d0566ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -36,14 +36,17 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; 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 org.apache.qpid.AMQException; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; @@ -59,7 +62,7 @@ import org.apache.qpid.url.URLSyntaxException; * Main entry point for AMQPD. * */ -@SuppressWarnings({"AccessStaticViaInstance"}) +@SuppressWarnings({ "AccessStaticViaInstance" }) public class Main { private static final Logger _logger = Logger.getLogger(Main.class); @@ -74,9 +77,9 @@ public class Main protected static class InitException extends Exception { - InitException(String msg) + InitException(String msg, Throwable cause) { - super(msg); + super(msg, cause); } } @@ -97,6 +100,7 @@ public class Main try { commandLine = new PosixParser().parse(options, args); + return true; } catch (ParseException e) @@ -104,6 +108,7 @@ public class Main System.err.println("Error: " + e.getMessage()); HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("Qpid", options, true); + return false; } } @@ -112,17 +117,26 @@ public class Main { 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"); + 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); @@ -150,7 +164,7 @@ public class Main boolean first = true; for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) { - if(first) + if (first) { first = false; } @@ -158,9 +172,11 @@ public class Main { protocol.append(", "); } + protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); } + System.out.println(ver + " (" + protocol + ")"); } else @@ -186,7 +202,6 @@ public class Main } } - protected void startup() throws InitException, ConfigurationException, Exception { final String QpidHome = System.getProperty("QPID_HOME"); @@ -201,7 +216,7 @@ public class Main error = error + "\nNote: Qpid_HOME is not set."; } - throw new InitException(error); + throw new InitException(error, null); } else { @@ -226,8 +241,8 @@ public class Main _logger.info("Starting Qpid.AMQP broker"); - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); + ConnectorConfiguration connectorConfig = + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); @@ -249,7 +264,7 @@ public class Main } catch (NumberFormatException e) { - throw new InitException("Invalid port: " + portStr); + throw new InitException("Invalid port: " + portStr, e); } } @@ -264,19 +279,21 @@ public class Main int totalVHosts = ((Collection) virtualHosts).size(); for (int vhost = 0; vhost < totalVHosts; vhost++) { - setupVirtualHosts(configFile.getParent() , (String)((List)virtualHosts).get(vhost)); + setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost)); } } else { - setupVirtualHosts(configFile.getParent() , (String)virtualHosts); + setupVirtualHosts(configFile.getParent(), (String) virtualHosts); } } + bind(port, connectorConfig); } - protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException + protected void setupVirtualHosts(String configFileParent, String configFilePath) + throws ConfigurationException, AMQException, URLSyntaxException { String configVar = "${conf}"; @@ -285,7 +302,7 @@ public class Main configFilePath = configFileParent + configFilePath.substring(configVar.length()); } - if (configFilePath.indexOf(".xml") != -1 ) + if (configFilePath.indexOf(".xml") != -1) { VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath); vHostConfig.performBindings(); @@ -298,11 +315,12 @@ public class Main String[] fileNames = virtualHostDir.list(); - for (int each=0; each < fileNames.length; each++) + for (int each = 0; each < fileNames.length; each++) { if (fileNames[each].endsWith(".xml")) { - VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath+"/"+fileNames[each]); + VirtualHostConfiguration vHostConfig = + new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); vHostConfig.performBindings(); } } @@ -319,7 +337,7 @@ public class Main try { - //IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); + // IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); IoAcceptor acceptor = connectorConfig.createAcceptor(); SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); @@ -334,7 +352,7 @@ public class Main { sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } - + if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); @@ -347,6 +365,7 @@ public class Main { bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); } + acceptor.bind(bindAddress, handler, sconfig); _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -356,8 +375,7 @@ public class Main AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); try { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), - handler, sconfig); + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); } catch (IOException e) @@ -415,16 +433,17 @@ public class Main } 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"); + 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"); + 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); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 4d66e37628..de3905268e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -196,6 +196,7 @@ public class DestNameExchange extends AbstractExchange } else { + _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); _logger.warn(msg); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index 14687c40ae..9052b2e81f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -98,7 +98,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener @@ -75,23 +76,26 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = null; + + for (Map.Entry entry : map.entrySet()) + { + if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) + { + db = entry.getValue(); + break; + } + else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) + { + db = entry.getValue(); + } + } + + if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); + CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + } + else if (db instanceof PlainPasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/PLAIN"); + env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); + } + + // Enable the SSL security and server authentication + /* + SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); + SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); + */ + + try + { + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + _log.info("JMX: Starting JMXConnector server with SASL"); + } + catch (java.net.MalformedURLException urlException) + { + // When JMXMPConnector is not available + // java.net.MalformedURLException: Unsupported protocol: jmxmp + _log.info("JMX: Starting JMXConnector server"); + startJMXConnectorServer(port); + } + } + else + { + startJMXConnectorServer(port); + } + } + catch (Exception ex) + { + _log.error("Error in initialising Managed Object Registry." + ex.getMessage()); + ex.printStackTrace(); + } + } + + /** + * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it. + * + * @param port + * + * @throws IOException + */ + private void startJMXConnectorServer(int port) throws IOException + { + startRMIRegistry(port); + _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); + cs.start(); } public void registerObject(ManagedObject managedObject) throws JMException { - _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); + _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); } public void unregisterObject(ManagedObject managedObject) throws JMException @@ -50,4 +195,105 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer.unregisterMBean(managedObject.getObjectName()); } + /** + * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent. + * + * @return + */ + private boolean areOutOfTheBoxJMXOptionsSet() + { + if (System.getProperty("com.sun.management.jmxremote") != null) + { + return true; + } + + if (System.getProperty("com.sun.management.jmxremote.port") != null) + { + return true; + } + + return false; + } + + /** + * Starts the rmi registry at given port + * + * @param port + * + * @throws RemoteException + */ + private void startRMIRegistry(int port) throws RemoteException + { + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port); + } + + // stops the RMIRegistry, if it was running and bound to a port + public void close() throws RemoteException + { + if (_rmiRegistry != null) + { + // Stopping the RMI registry + UnicastRemoteObject.unexportObject(_rmiRegistry, true); + } + } + + /** This class is used for SASL enabled JMXConnector for performing user authentication. */ + private class UserCallbackHandler implements CallbackHandler + { + private final PrincipalDatabase _principalDatabase; + + protected UserCallbackHandler(PrincipalDatabase database) + { + _principalDatabase = database; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + // Retrieve callbacks + NameCallback ncb = null; + PasswordCallback pcb = null; + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + ncb = (NameCallback) callbacks[i]; + } + else if (callbacks[i] instanceof PasswordCallback) + { + pcb = (PasswordCallback) callbacks[i]; + } + else if (callbacks[i] instanceof AuthorizeCallback) + { + ((AuthorizeCallback) callbacks[i]).setAuthorized(true); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + + boolean authorized = false; + // Process retrieval of password; can get password if username is available in NameCallback + if ((ncb != null) && (pcb != null)) + { + String username = ncb.getDefaultName(); + try + { + authorized = _principalDatabase.verifyPassword(username, new String(pcb.getPassword())); + } + catch (AccountNotFoundException e) + { + IOException ioe = new IOException("User not authorized. " + e); + ioe.initCause(e); + throw ioe; + } + } + + if (!authorized) + { + throw new IOException("User not authorized."); + } + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java new file mode 100644 index 0000000000..a79d993afc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.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.management; + +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.JMXPrincipal; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.JMException; +import javax.security.auth.Subject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Principal; +import java.security.AccessControlContext; +import java.util.Set; +import java.util.Properties; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.FileInputStream; + +/** + * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements + * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite + * and admin users. + */ +public class MBeanInvocationHandlerImpl implements InvocationHandler +{ + private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); + + public final static String ADMIN = "admin"; + public final static String READWRITE = "readwrite"; + public final static String READONLY = "readonly"; + private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; + private MBeanServer mbs; + private static Properties _userRoles = new Properties(); + + public static MBeanServerForwarder newProxyInstance() + { + final InvocationHandler handler = new MBeanInvocationHandlerImpl(); + final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + + Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); + return MBeanServerForwarder.class.cast(proxy); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + final String methodName = method.getName(); + + if (methodName.equals("getMBeanServer")) + { + return mbs; + } + + if (methodName.equals("setMBeanServer")) + { + if (args[0] == null) + { + throw new IllegalArgumentException("Null MBeanServer"); + } + if (mbs != null) + { + throw new IllegalArgumentException("MBeanServer object already initialized"); + } + mbs = (MBeanServer) args[0]; + return null; + } + + // Retrieve Subject from current AccessControlContext + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) + { + return method.invoke(mbs, args); + } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + throw new SecurityException("Access denied"); + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied"); + } + + Principal principal = principals.iterator().next(); + String identity = principal.getName(); + + // Following users can perform any operation other than "createMBean" and "unregisterMBean" + if (isAdmin(identity) || isAllowedToModify(identity)) + { + return method.invoke(mbs, args); + } + + // These users can only call "getAttribute" on the MBeanServerDelegate MBean + // Here we can add other fine grained permissions like specific method for a particular mbean + if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + { + return method.invoke(mbs, args); + } + + throw new SecurityException("Access denied"); + } + + // Initialises the user roles + public static void setAccessRights(Properties accessRights) + { + _userRoles = accessRights; + } + + private boolean isAdmin(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isAllowedToModify(String userName) + { + if (READWRITE.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyUser(String userName) + { + if (READONLY.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyMethod(Method method, Object[] args) + { + String methodName = method.getName(); + if (methodName.equals("queryMBeans") || + methodName.equals("getDefaultDomain") || + methodName.equals("getMBeanInfo") || + methodName.equals("getAttribute") || + methodName.equals("getAttributes")) + { + return true; + } + + if (args[0] instanceof ObjectName) + { + String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + return false; + } + + try + { + MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); + if (mbeanInfo != null) + { + MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); + for (MBeanOperationInfo opInfo : opInfos) + { + if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + { + return true; + } + } + } + } + catch (JMException ex) + { + ex.printStackTrace(); + } + } + + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index b2f79b6410..45e2e91ed7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -52,8 +52,7 @@ public interface ManagedBroker @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable, - @MBeanOperationParameter(name="passive", description="true of the Exchange should be passive")boolean passive) + @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) throws IOException, JMException; /** @@ -81,8 +80,7 @@ public interface ManagedBroker @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, - @MBeanOperationParameter(name="autoDelete", description="true if the queue should be auto delete") boolean autoDelete) + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) throws IOException, JMException; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java index 32298f05e3..5f9bc9ddad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.management; import javax.management.JMException; +import java.rmi.RemoteException; /** * Handles the registration (and unregistration and so on) of managed objects. @@ -36,7 +37,11 @@ import javax.management.JMException; */ public interface ManagedObjectRegistry { + void start(); + void registerObject(ManagedObject managedObject) throws JMException; void unregisterObject(ManagedObject managedObject) throws JMException; + + void close() throws RemoteException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java index 5b86543ea6..b4fbed6948 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -24,6 +24,8 @@ import javax.management.JMException; import org.apache.log4j.Logger; +import java.rmi.RemoteException; + /** * 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. @@ -38,6 +40,11 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry _log.info("Management is disabled"); } + public void start() + { + //no-op + } + public void registerObject(ManagedObject managedObject) throws JMException { } @@ -45,4 +52,9 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry public void unregisterObject(ManagedObject managedObject) throws JMException { } + + public void close() throws RemoteException + { + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index fd8fb2d5cb..2e62c2f1e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import java.security.Principal; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -108,7 +109,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); private List _closingChannelsList = new ArrayList(); private ProtocolOutputConverter _protocolOutputConverter; - private String _authorizedID; + private Principal _authorizedID; public ManagedObject getManagedObject() @@ -745,12 +746,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _protocolOutputConverter; } - public void setAuthorizedID(String authorizedID) + public void setAuthorizedID(Principal authorizedID) { _authorizedID = authorizedID; } - public String getAuthorizedID() + public Principal getAuthorizedID() { return _authorizedID; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 79421dd497..390117acf6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -31,6 +31,8 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.security.Principal; + public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { @@ -165,9 +167,9 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public ProtocolOutputConverter getProtocolOutputConverter(); - void setAuthorizedID(String authorizedID); + void setAuthorizedID(Principal authorizedID); - /** @return a username string that was used to authorized this session */ - String getAuthorizedID(); + /** @return a Principal that was used to authorized this session */ + Principal getAuthorizedID(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 5eebd4c524..66f928a70e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ /* * * Copyright (c) 2006 The Apache Software Foundation @@ -17,14 +37,15 @@ */ package org.apache.qpid.server.protocol; +import java.security.Principal; import java.util.Date; import java.util.List; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; -import javax.management.Notification; import javax.management.NotCompliantMBeanException; +import javax.management.Notification; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -56,15 +77,17 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { private AMQMinaProtocolSession _session = null; private String _name = null; - - //openmbean data types for representing the channel attributes - private final static String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; - private final static String[] _indexNames = {_channelAtttibuteNames[0]}; - private final static OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; - private static CompositeType _channelType = null; // represents the data type for channel data - private static TabularType _channelsType = null; // Data type for list of channels type + + // openmbean data types for representing the channel attributes + private static final String[] _channelAtttibuteNames = + { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; + private static final String[] _indexNames = { _channelAtttibuteNames[0] }; + private static final OpenType[] _channelAttributeTypes = + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; + private static CompositeType _channelType = null; // represents the data type for channel data + private static TabularType _channelsType = null; // Data type for list of channels type private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = - new AMQShortString("Broker Management Console has closed the connection."); + new AMQShortString("Broker Management Console has closed the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException @@ -72,22 +95,21 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed super(ManagedConnection.class, ManagedConnection.TYPE); _session = session; String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? remote + hashCode() : remote; + remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; _name = jmxEncode(new StringBuffer(remote), 0).toString(); init(); } - static { try { init(); } - catch(JMException ex) + catch (JMException ex) { - // It should never occur - System.out.println(ex.getMessage()); + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); } } @@ -96,26 +118,27 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ private static void init() throws OpenDataException { - _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, - _channelAtttibuteNames, _channelAttributeTypes); + _channelType = + new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, + _channelAttributeTypes); _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); } public String getClientId() { - return _session.getContextKey() == null ? null : _session.getContextKey().toString(); + return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); } public String getAuthorizedId() { - return _session.getAuthorizedID(); + return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; } public String getVersion() { - return _session.getClientVersion() == null ? null : _session.getClientVersion().toString(); + return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); } - + public Date getLastIoTime() { return new Date(_session.getIOSession().getLastIoTime()); @@ -171,6 +194,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } + _session.commitTransactions(channel); } catch (AMQException ex) @@ -194,6 +218,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } + _session.rollbackTransactions(channel); } catch (AMQException ex) @@ -215,9 +240,12 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed for (AMQChannel channel : list) { - Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), + Object[] itemValues = + { + channel.getChannelId(), channel.isTransactional(), (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, - channel.getUnacknowledgedMessageMap().size()}; + channel.getUnacknowledgedMessageMap().size() + }; CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); channelsList.put(channelData); @@ -232,17 +260,16 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed * @throws JMException */ public void closeConnection() throws JMException - { + { // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, - _session.getProtocolMajorVersion(), - _session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - AMQConstant.REPLY_SUCCESS.getCode(), // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText + final AMQFrame response = + ConnectionCloseBody.createAMQFrame(0, _session.getProtocolMajorVersion(), _session.getProtocolMinorVersion(), // AMQP version (major, minor) + 0, // classId + 0, // methodId + AMQConstant.REPLY_SUCCESS.getCode(), // replyCode + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText ); _session.writeFrame(response); @@ -259,18 +286,19 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; String name = MonitorNotification.class.getName(); String description = "Channel count has reached threshold value"; MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - return new MBeanNotificationInfo[]{info1}; + return new MBeanNotificationInfo[] { info1 }; } public void notifyClients(String notificationMsg) { - Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, - ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); + Notification n = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); _broadcaster.sendNotification(n); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 990c4c0794..e6e713ac6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.protocol; import java.io.IOException; import java.util.Date; +import java.security.Principal; import javax.management.JMException; import javax.management.MBeanOperationInfo; @@ -67,16 +68,17 @@ public interface ManagedConnection /** * Tells the total number of bytes written till now. * @return number of bytes written. - */ + * @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") Long getWrittenBytes(); - + */ /** * Tells the total number of bytes read till now. * @return number of bytes read. - */ + * @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") Long getReadBytes(); + */ /** * Threshold high value for no of channels. This is useful in setting notifications or diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index d6962d28cd..b2046efee3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; @@ -42,6 +43,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -78,19 +81,20 @@ public class AMQMessage private boolean _immediate; private AtomicBoolean _taken = new AtomicBoolean(false); - private TransientMessageData _transientMessageData = new TransientMessageData(); private Subscription _takenBySubcription; - private Set _rejectedBy = null; + private Map _takenMap = new HashMap(); + private Map _takenBySubcriptionMap = new HashMap(); - public boolean isTaken() + public boolean isTaken(AMQQueue queue) { return _taken.get(); } private final int hashcode = System.identityHashCode(this); + public String debugIdentity() { return "(HC:" + hashcode + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; @@ -203,9 +207,10 @@ public class AMQMessage _transientMessageData.setMessagePublishInfo(info); _taken = new AtomicBoolean(false); + if (_log.isDebugEnabled()) { - _log.debug("Message(" + System.identityHashCode(this) + ") created (" + debugIdentity()+")"); + _log.debug("Message(" + System.identityHashCode(this) + ") created (" + debugIdentity() + ")"); } } @@ -318,8 +323,10 @@ public class AMQMessage // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store + for (AMQQueue q : _transientMessageData.getDestinationQueues()) { + _takenMap.put(q, new AtomicBoolean(false)); _messageHandle.enqueue(storeContext, _messageId, q); } @@ -356,12 +363,13 @@ public class AMQMessage } /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic operation. + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. */ public AMQMessage takeReference() { _referenceCount.incrementAndGet(); - return this; + return this; } /** Threadsafe. Increment the reference count on the message. */ @@ -378,9 +386,10 @@ public class AMQMessage * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the * message store. * + * @param storeContext + * * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that * failed - * @param storeContext */ public void decrementReference(StoreContext storeContext) throws MessageCleanupException { @@ -451,7 +460,7 @@ public class AMQMessage } - public boolean taken(Subscription sub) + public boolean taken(AMQQueue queue, Subscription sub) { if (_taken.getAndSet(true)) { @@ -464,7 +473,7 @@ public class AMQMessage } } - public void release() + public void release(AMQQueue queue) { if (_log.isTraceEnabled()) { @@ -600,7 +609,7 @@ public class AMQMessage for (AMQQueue q : destinationQueues) { //Increment the references to this message for each queue delivery. - incrementReference(); + incrementReference(); //normal deliver so add this message at the end. _txnContext.deliver(this, q, false); } @@ -824,11 +833,14 @@ public class AMQMessage public String toString() { - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + - _taken + " by:" + _takenBySubcription; + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + _taken + " by :" + _takenBySubcription; + +// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + +// _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } - public Subscription getDeliveredSubscription() + public Subscription getDeliveredSubscription(AMQQueue queue) { return _takenBySubcription; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 7a32848c44..bbaa7379f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ /* * * Copyright (c) 2006 The Apache Software Foundation @@ -17,11 +37,11 @@ */ package org.apache.qpid.server.queue; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Iterator; import java.util.List; -import java.util.Date; -import java.text.SimpleDateFormat; import javax.management.JMException; import javax.management.MBeanException; @@ -41,12 +61,14 @@ import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; + import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -73,15 +95,15 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method - private final static String[] _msgAttributeNames = {"AMQ MessageId", "Header", "Size(bytes)", "Redelivered"}; - private static String[] _msgAttributeIndex = {_msgAttributeNames[0]}; + private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; + private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. // OpenMBean data types for viewMessageContent method private static CompositeType _msgContentType = null; - private final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"}; + private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; @@ -95,7 +117,6 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } - public ManagedObject getParentObject() { return _queue.getVirtualHost().getManagedObject(); @@ -107,10 +128,10 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { init(); } - catch(JMException ex) + catch (JMException ex) { - // It should never occur - System.out.println(ex.getMessage()); + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); } } @@ -119,19 +140,21 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ private static void init() throws OpenDataException { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, - _msgContentAttributes, _msgContentAttributeTypes); - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = + new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, + _msgContentAttributeTypes); + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = + new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); } @@ -213,7 +236,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public Long getMaximumQueueDepth() { long queueDepthInBytes = _queue.getMaximumQueueDepth(); - return queueDepthInBytes >> 10 ; + + return queueDepthInBytes >> 10; } public void setMaximumQueueDepth(Long value) @@ -227,7 +251,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public Long getQueueDepth() throws JMException { long queueBytesSize = _queue.getQueueDepth(); - return queueBytesSize >> 10 ; + + return queueBytesSize >> 10; } /** @@ -237,13 +262,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); + final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - for(NotificationCheck check : NotificationCheck.values()) + for (NotificationCheck check : NotificationCheck.values()) { - if(check.isMessageSpecific() || _lastNotificationTimes[check.ordinal()] endIndex) || (beginIndex < 1)) { - throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + - "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); } List list = _queue.getMessagesOnTheQueue(); @@ -368,20 +399,22 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que try { // Create the tabular list of message header contents - for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) + for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) { AMQMessage msg = list.get(i - 1); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); _messageList.put(messageData); } } catch (AMQException e) { - throw new JMException("Error creating message contents: " + e); + JMException jme = new JMException("Error creating message contents: " + e); + jme.initCause(e); + throw jme; } return _messageList; @@ -400,11 +433,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + (delMode == 1 ? "Persistent" : "Non_Persistent")); + list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); list.add("JMSPriority = " + headerProperties.getPriority()); list.add("JMSType = " + headerProperties.getType()); - + long longDate = headerProperties.getExpiration(); String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; list.add("JMSExpiration = " + strDate); @@ -425,27 +458,26 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException { - if (fromMessageId > toMessageId || (fromMessageId < 1)) + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) { - throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); } _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); } - /** * returns Notifications sent by this MBean. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; String name = MonitorNotification.class.getName(); String description = "Either Message count or Queue depth or Message size has reached threshold high value"; MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - return new MBeanNotificationInfo[]{info1}; + return new MBeanNotificationInfo[] { info1 }; } } // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index cfa13c87fd..979f692361 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -210,6 +210,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager /** * Returns all the messages in the Queue + * * @return List of messages */ public List getMessages() @@ -222,14 +223,16 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager list.add(message); } _lock.unlock(); - + return list; } /** * Returns messages within the range of given messageIds + * * @param fromMessageId * @param toMessageId + * * @return */ public List getMessages(long fromMessageId, long toMessageId) @@ -242,7 +245,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager long maxMessageCount = toMessageId - fromMessageId + 1; _lock.lock(); - + List foundMessagesList = new ArrayList(); for (AMQMessage message : _messages) @@ -399,7 +402,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void removeAMessageFromTop(StoreContext storeContext) throws AMQException { _lock.lock(); - + AMQMessage message = _messages.poll(); if (message != null) { @@ -432,9 +435,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return count; } - /** - This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. - */ + /** This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. */ private AMQMessage getNextMessage() throws AMQException { return getNextMessage(_messages, null); @@ -444,8 +445,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { AMQMessage message = messages.peek(); - //while (we have a message) && (The subscriber is not a browser or we are clearing) && (Check message is taken.) - while (message != null && (sub != null && !sub.isBrowser() || sub == null) && message.taken(sub)) + //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) + while (message != null + && ( + ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) + || sub == null) + && message.taken(_queue, sub)) { //remove the already taken message AMQMessage removed = messages.poll(); @@ -506,7 +511,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + "Async Delivery Message " + message.getMessageId() + "(" + System.identityHashCode(message) + + _log.debug(debugIdentity() + "Async Delivery Message :" + message + "(" + System.identityHashCode(message) + ") by :" + System.identityHashCode(this) + ") to :" + System.identityHashCode(sub)); } @@ -526,7 +531,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message.debugIdentity() + + _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message + ") by :" + System.identityHashCode(this) + ") to :" + System.identityHashCode(sub)); } @@ -562,7 +567,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } catch (AMQException e) { - message.release(); + message.release(_queue); _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -723,7 +728,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _log.trace(debugIdentity() + "Delivering Message:" + msg.debugIdentity() + " to(" + System.identityHashCode(s) + ") :" + s); } - msg.taken(s); + msg.taken(_queue, s); //Deliver the message s.send(msg, _queue); } @@ -737,7 +742,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - if (!msg.isTaken()) + if (!msg.isTaken(_queue)) { if (_log.isInfoEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index d3578d39e8..e3944954f3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -558,7 +558,7 @@ public class SubscriptionImpl implements Subscription _logger.trace("Removed for resending:" + resent.debugIdentity()); } - resent.release(); + resent.release(_queue); _queue.subscriberHasPendingResend(false, this, resent); try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 14a8063aee..89f0b7b39d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -153,7 +153,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _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"); + throw new RuntimeException("Unable to create Application Registry", e); } } else @@ -168,6 +168,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { virtualHost.close(); } + + // close the rmi registry(if any) started for management + if (getInstance().getManagedObjectRegistry() != null) + { + getInstance().getManagedObjectRegistry().close(); + } } public Configuration getConfiguration() @@ -187,7 +193,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry 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"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); } Configurator.configure(instance); _configuredObjects.put(instanceType, instance); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 739ed9db42..1cca259a8d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -42,6 +42,7 @@ import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.security.access.AccessManagerImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { @@ -103,6 +104,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { initialiseManagedObjectRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(); _accessManager = new AccessManagerImpl("default", _configuration); @@ -111,7 +113,12 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + _databaseManager.initialiseManagement(_configuration); + + _managedObjectRegistry.start(); + initialiseVirtualHosts(); + } private void initialiseVirtualHosts() throws Exception @@ -123,7 +130,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - private void initialiseManagedObjectRegistry() + private void initialiseManagedObjectRegistry() throws AMQException { ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); if (config.enabled) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java new file mode 100644 index 0000000000..f9e093dba7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java new file mode 100644 index 0000000000..a43474559d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -0,0 +1,457 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.log4j.Logger; +import org.apache.commons.configuration.ConfigurationException; + +import javax.management.JMException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.List; +import java.util.Enumeration; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; + +/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ +@MBeanDescription("User Management Interface") +public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement +{ + + private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + + private PrincipalDatabase _principalDatabase; + private String _accessFileName; + private Properties _accessRights; + // private File _accessFile; + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); + + // Setup for the TabularType + static TabularType _userlistDataType; // Datatype for representing User Lists + + static CompositeType _userDataType; // Composite type for representing User + static String[] _userItemNames = {"Username", "Read", "Write", "Admin"}; + + static + { + String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", + "Management Console Write Permission", "Management Console Admin Permission"}; + + OpenType[] userItemTypes = new OpenType[4]; // User item types. + userItemTypes[0] = SimpleType.STRING; // For Username + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + String[] userDataIndex = {_userItemNames[0]}; + + try + { + _userDataType = + new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); + + _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing users incorrect."); + _userlistDataType = null; + } + } + + + public AMQUserManagementMBean() throws JMException + { + super(UserManagement.class, UserManagement.TYPE); + } + + public String getObjectInstanceName() + { + return UserManagement.TYPE; + } + + public boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password) + { + try + { + //delegate password changes to the Principal Database + return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + return false; + } + } + + public boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + { + + if (_accessRights.get(username) == null) + { + // If the user doesn't exist in the user rights file check that they at least have an account. + if (_principalDatabase.getUser(username) == null) + { + return false; + } + } + + try + { + + _accessRightsUpdate.lock(); + + // Update the access rights + if (admin) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); + } + else + { + if (read | write) + { + if (read) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); + } + if (write) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); + } + } + else + { + _accessRights.remove(username); + } + } + + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + return true; + } + + public boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) + { + _accessRights.put(username, ""); + + return setRights(username, read, write, admin); + } + + return false; + } + + public boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username) + { + + try + { + if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) + { + try + { + _accessRightsUpdate.lock(); + + _accessRights.remove(username); + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + return true; + } + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + } + + return false; + } + + public boolean reloadData() + { + try + { + try + { + loadAccessFile(); + } + catch (ConfigurationException e) + { + _logger.info("Reload failed due to:" + e); + return false; + } + + // Reload successful + return true; + } + catch (IOException e) + { + _logger.info("Reload failed due to:" + e); + // Reload unsuccessful + return false; + } + } + + + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + public TabularData viewUsers() + { + // Table of users + // Username(string), Access rights Read,Write,Admin(bool,bool,bool) + + reloadData(); + + if (_userlistDataType == null) + { + _logger.warn("TabluarData not setup correctly"); + return null; + } + + List users = _principalDatabase.getUsers(); + + TabularDataSupport userList = new TabularDataSupport(_userlistDataType); + + try + { + // Create the tabular list of message header contents + for (Principal user : users) + { + // Create header attributes list + + String rights = (String) _accessRights.get(user.getName()); + + Boolean read = false; + Boolean write = false; + Boolean admin = false; + + if (rights != null) + { + read = rights.equals(MBeanInvocationHandlerImpl.READONLY) + || rights.equals(MBeanInvocationHandlerImpl.READWRITE); + write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); + admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); + } + + Object[] itemData = {user.getName(), read, write, admin}; + CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); + userList.put(messageData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create user list due to :" + e); + return null; + } + + return userList; + } + + /*** Broker Methods **/ + + /** + * setPrincipalDatabase + * + * @param database set The Database to use for user lookup + */ + public void setPrincipalDatabase(PrincipalDatabase database) + { + _principalDatabase = database; + } + + /** + * setAccessFile + * + * @param accessFile the file to use for updating. + * + * @throws java.io.IOException If the file cannot be accessed + * @throws org.apache.commons.configuration.ConfigurationException + * if checks on the file fail. + */ + public void setAccessFile(String accessFile) throws IOException, ConfigurationException + { + _accessFileName = accessFile; + + if (_accessFileName != null) + { + loadAccessFile(); + } + else + { + _logger.warn("Access rights file specified is null. Access rights not changed."); + } + } + + private void loadAccessFile() throws IOException, ConfigurationException + { + try + { + _accessRightsUpdate.lock(); + + Properties accessRights = new Properties(); + + File accessFile = new File(_accessFileName); + + if (!accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFileName + "' does not exist"); + } + + if (!accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFileName + "'."); + } + + if (!accessFile.canWrite()) + { + _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved."); + } + + accessRights.load(new FileInputStream(accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + private void checkAccessRights(Properties accessRights) + { + Enumeration values = accessRights.propertyNames(); + + while (values.hasMoreElements()) + { + String user = (String) values.nextElement(); + + if (_principalDatabase.getUser(user) == null) + { + _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); + } + } + } + + private void saveAccessFile() + { + try + { + _accessRightsUpdate.lock(); + try + { + // remove old temporary file + File tmp = new File(_accessFileName + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + + //remove old backup + File old = new File(_accessFileName + ".old"); + if (old.exists()) + { + old.delete(); + } + + // Rename current file + File rights = new File(_accessFileName); + rights.renameTo(old); + + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, ""); + output.close(); + + // Rename new file to main file + tmp.renameTo(rights); + + // delete tmp + tmp.delete(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e); + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + /** + * user=read user=write user=readwrite user=admin + * + * @param accessRights The properties list of access rights to process + */ + private void setAccessRights(Properties accessRights) + { + _logger.debug("Setting Access Rights:" + accessRights); + _accessRights = accessRights; + MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java index 0c0de88182..d70a6dc8f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java @@ -20,8 +20,13 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public interface AccessManager { + AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights); + + @Deprecated AccessResult isAuthorized(Accessable accessObject, String username); String getName(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java index 0feb2791da..35d036d20f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java @@ -23,13 +23,13 @@ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.configuration.PropertyException; import org.apache.log4j.Logger; import java.util.List; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.security.Principal; public class AccessManagerImpl implements AccessManager { @@ -39,8 +39,13 @@ public class AccessManagerImpl implements AccessManager public AccessManagerImpl(String name, Configuration hostConfig) throws ConfigurationException { - String accessClass = hostConfig.getString("security.access.class"); + if (hostConfig == null) + { + _logger.warn("No Configuration specified. Using default access controls for VirtualHost:'" + name + "'"); + return; + } + String accessClass = hostConfig.getString("security.access.class"); if (accessClass == null) { _logger.warn("No access control specified. Using default access controls for VirtualHost:'" + name + "'"); @@ -111,21 +116,35 @@ public class AccessManagerImpl implements AccessManager } catch (Exception e) { - throw new ConfigurationException(e.getCause()); + ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause()); + ce.initCause(e); + throw ce; } } } - public AccessResult isAuthorized(Accessable accessObject, String username) + { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) { if (_accessManager == null) { - return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, username); + if (ApplicationRegistry.getInstance().getAccessManager() == this) + { + _logger.warn("No Default access manager specified DENYING ALL ACCESS"); + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + else + { + return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, user, rights); + } } else { - return _accessManager.isAuthorized(accessObject, username); + return _accessManager.isAuthorized(accessObject, user, rights); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java new file mode 100644 index 0000000000..1b79a5a0e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessRights +{ + public enum Rights + { + ANY, + READ, + WRITE, + READWRITE + } + + Rights _right; + + public AccessRights(Rights right) + { + _right = right; + } + + public boolean allows(Rights rights) + { + switch (_right) + { + case ANY: + return (rights.equals(Rights.WRITE) + || rights.equals(Rights.READ) + || rights.equals(Rights.READWRITE) + || rights.equals(Rights.ANY)); + case READ: + return rights.equals(Rights.READ) || rights.equals(Rights.ANY); + case WRITE: + return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); + case READWRITE: + return true; + } + return false; + } + + public Rights getRights() + { + return _right; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java index b2e4094edd..1ddca3a64e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java @@ -20,9 +20,16 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public class AllowAll implements AccessManager { + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + public AccessResult isAuthorized(Accessable accessObject, String username) { return new AccessResult(this, AccessResult.AccessStatus.GRANTED); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java index 0e62d2657f..bf40eeba4e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java @@ -20,8 +20,15 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public class DenyAll implements AccessManager { + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + public AccessResult isAuthorized(Accessable accessObject, String username) { return new AccessResult(this, AccessResult.AccessStatus.REFUSED); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java new file mode 100644 index 0000000000..291bc714ed --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.File; +import java.util.regex.Pattern; +import java.security.Principal; + +/** + * 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 FileAccessManager implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(FileAccessManager.class); + + protected File _accessFile; + + protected Pattern _regexp = Pattern.compile(":"); + + private static final short USER_INDEX = 0; + private static final short VIRTUALHOST_INDEX = 1; + + public void setAccessFile(String accessFile) throws FileNotFoundException + { + File f = new File(accessFile); + _logger.info("FileAccessManager using file " + f.getAbsolutePath()); + _accessFile = f; + if (!f.exists()) + { + throw new FileNotFoundException("Cannot find access file " + f); + } + if (!f.canRead()) + { + throw new FileNotFoundException("Cannot read access file " + f + + ". Check permissions."); + } + } + + /** + * Looks up the virtual hosts for a specified user in the access file. + * + * @param user The user to lookup + * + * @return a list of virtualhosts + */ + private VirtualHostAccess[] lookupVirtualHost(String user) + { + String[] results = lookup(user, VIRTUALHOST_INDEX); + VirtualHostAccess vhosts[] = new VirtualHostAccess[results.length]; + + for (int index = 0; index < results.length; index++) + { + vhosts[index] = new VirtualHostAccess(results[index]); + } + + return vhosts; + } + + + private String[] lookup(String user, int index) + { + try + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_accessFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < (index + 1)) + { + continue; + } + + if (user.equals(result[USER_INDEX])) + { + return result[index].split(","); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + catch (IOException ioe) + { + //ignore + } + return null; + } + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) + { + if (accessObject instanceof VirtualHost) + { + VirtualHostAccess[] hosts = lookupVirtualHost(user.getName()); + + if (hosts != null) + { + for (VirtualHostAccess host : hosts) + { + if (accessObject.getAccessableName().equals(host.getVirtualHost())) + { + if (host.getAccessRights().allows(rights)) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + else + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + } + } + } + } +// else if (accessObject instanceof AMQQueue) +// { +// String[] queues = lookupQueue(username, ((AMQQueue) accessObject).getVirtualHost()); +// +// if (queues != null) +// { +// for (String queue : queues) +// { +// if (accessObject.getAccessableName().equals(queue)) +// { +// return new AccessResult(this, AccessResult.AccessStatus.GRANTED); +// } +// } +// } +// } + + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "FileAccessManager"; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java index 0e447b5744..6ccadb2e7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java @@ -22,8 +22,11 @@ package org.apache.qpid.server.security.access; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.log4j.Logger; +import java.security.Principal; + public class PrincipalDatabaseAccessManager implements AccessManager { private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAccessManager.class); @@ -58,7 +61,13 @@ public class PrincipalDatabaseAccessManager implements AccessManager } } + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) { AccessResult result; @@ -66,7 +75,7 @@ public class PrincipalDatabaseAccessManager implements AccessManager { if (_default != null) { - result = _default.isAuthorized(accessObject, username); + result = _default.isAuthorized(accessObject, username, rights); } else { @@ -75,7 +84,15 @@ public class PrincipalDatabaseAccessManager implements AccessManager } else { - result = ((AccessManager) _database).isAuthorized(accessObject, username); + if (!(_database instanceof AccessManager)) + { + _logger.warn("Specified PrincipalDatabase is not an AccessManager so using default AccessManager"); + result = _default.isAuthorized(accessObject, username, rights); + } + else + { + result = ((AccessManager) _database).isAuthorized(accessObject, username, rights); + } } result.addAuthorizer(this); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java new file mode 100644 index 0000000000..6381213398 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.AMQException; + +import javax.management.openmbean.TabularData; +import javax.management.openmbean.CompositeData; +import javax.management.JMException; +import java.io.IOException; + +public interface UserManagement +{ + String TYPE = "UserManagement"; + + //********** Operations *****************// + /** + * set password for user + * + * @param username The username to create + * @param password The password for the user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setPassword", description = "Set password for user.") + boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password); + + /** + * set rights for users with given details + * + * @param username The username to create + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setRights", description = "Set access rights for user.") + boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * Create users with given details + * + * @param username The username to create + * @param password The password for the user + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "createUser", description = "Create new user from system.") + boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * View users returns all the users that are currently available to the system. + * + * @param username The user to delete + * + * @return The result of the operation + */ + @MBeanOperation(name = "deleteUser", description = "Delete user from system.") + boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); + + + /** + * Reload the date from disk + * + * @return The result of the operation + */ +// @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.") +// boolean reloadData(); + + /** + * View users returns all the users that are currently available to the system. + * + * @return a table of users data (Username, read, write, admin) + */ + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + TabularData viewUsers(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java new file mode 100644 index 0000000000..13151a66b8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class VirtualHostAccess +{ + private String _vhost; + private AccessRights _rights; + + public VirtualHostAccess(String vhostaccess) + { + //format () + int hostend = vhostaccess.indexOf('('); + + if (hostend == -1) + { + throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); + } + + _vhost = vhostaccess.substring(0, hostend); + + String rights = vhostaccess.substring(hostend); + + if (rights.indexOf('r') != -1) + { + if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.READWRITE); + } + else + { + _rights = new AccessRights(AccessRights.Rights.READ); + } + } + else if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.WRITE); + } + } + + public AccessRights getAccessRights() + { + return _rights; + } + + public String getVirtualHost() + { + return _vhost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..956db64d90 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -0,0 +1,626 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.EncoderException; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.UnsupportedEncodingException; +import java.io.PrintStream; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; +import java.security.NoSuchAlgorithmException; +import java.security.MessageDigest; + +/** + * 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 Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + AMQUserManagementMBean _mbean; + private static final String DEFAULT_ENCODING = "utf-8"; + private Map _users = new HashMap(); + private ReentrantLock _userUpdate = new ReentrantLock(); + + public Base64MD5PasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); + cram.initialise(this); + _saslServers.put(cram.getMechanismName(), cram); + + //fixme The PDs should setup a PD Mangement MBean +// try +// { +// _mbean = new AMQUserManagementMBean(); +// _mbean.setPrincipalDatabase(this); +// } +// catch (JMException e) +// { +// _logger.warn("User management disabled as unable to create MBean:" + e); +// } + } + + public void setPasswordFile(String passwordFile) throws IOException + { + 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."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannont be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws 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); + } + } + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + try + { + char[] pwd = lookupPassword(principal); + byte[] passwordBytes = password.getBytes(DEFAULT_ENCODING); + + int index = 0; + boolean verified = true; + + while (verified & index < passwordBytes.length) + { + verified = (pwd[index] == (char) passwordBytes[index]); + index++; + } + return verified; + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + + char[] passwd = convertPassword(password); + + try + { + _userUpdate.lock(); + user.setPassword(passwd); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user'" + + principal + "' will revert at restart"); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes(DEFAULT_ENCODING); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public boolean createPrincipal(Principal principal, String password) + { + if (_users.get(principal.getName()) != null) + { + return false; + } + + User user; + try + { + user = new User(principal.getName(), convertPassword(password)); + } + catch (UnsupportedEncodingException e) + { + _logger.warn("Unable to encode password:" + e); + return false; + } + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + return false; + } + + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; + } + + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(_users.values()); + } + + public Principal getUser(String username) + { + if (_users.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + /** + * 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 The principal name to lookup + * + * @return a char[] for use in SASL. + */ + private char[] lookupPassword(String name) + { + User user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + 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 || result[0].startsWith("#")) + { + continue; + } + + User user = new User(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + continue; + } + + User user = _users.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + try + { + byte[] encodedPassword = user.getEncodePassword(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to encode new password reverting to old password."); + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + } + } + } + + for (User user : _users.values()) + { + if (user.isModified()) + { + byte[] encodedPassword; + try + { + encodedPassword = user.getEncodePassword(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); + } + } + } + } + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private class User implements Principal + { + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + User(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be lenght 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public User(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + if (_logger.isDebugEnabled()) + { + return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); + } + else + { + return _name; + } + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + + byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + Base64 b64 = new Base64(); + _encodedPassword = b64.encode(new String(_password).getBytes(DEFAULT_ENCODING)); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 0c35206dd3..2d3f5e5131 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -1,38 +1,46 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server.security.auth.database; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; +import org.apache.qpid.AMQException; -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.lang.reflect.Method; -import java.io.FileNotFoundException; +import javax.management.JMException; public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager { @@ -80,18 +88,21 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab initialisePrincipalDatabase((PrincipalDatabase) o, config, i); String name = databaseNames.get(i); - if (name == null || name.length() == 0) + 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 not provided"); } + _logger.info("Initialised principal database '" + name + "' successfully"); databases.put(name, (PrincipalDatabase) o); } + return databases; } @@ -104,14 +115,16 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab for (int i = 0; i < argumentNames.size(); i++) { String argName = argumentNames.get(i); - if (argName == null || argName.length() == 0) + if ((argName == null) || (argName.length() == 0)) { throw new ConfigurationException("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 = null; try @@ -125,9 +138,10 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (method == null) { - throw new ConfigurationException("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"); + throw new ConfigurationException("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"); } try @@ -136,7 +150,14 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab } catch (Exception ite) { - throw new ConfigurationException(ite.getCause()); + if (ite instanceof ConfigurationException) + { + throw(ConfigurationException) ite; + } + else + { + throw new ConfigurationException(ite.getMessage(), ite); + } } } } @@ -145,4 +166,71 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { return _databases; } + + public void initialiseManagement(Configuration config) throws ConfigurationException + { + try + { + AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); + + String baseSecurity = "security.jmx"; + List principalDBs = config.getList(baseSecurity + ".principal-database"); + + if (principalDBs.size() == 0) + { + throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)"); + } + + String databaseName = principalDBs.get(0); + + PrincipalDatabase database = getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); + } + + _mbean.setPrincipalDatabase(database); + + List jmxaccesslist = config.getList(baseSecurity + ".access"); + + if (jmxaccesslist.size() == 0) + { + throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)"); + } + + String jmxaccesssFile = null; + + try + { + jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); + } + catch (PropertyException e) + { + throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); + } + + try + { + _mbean.setAccessFile(jmxaccesssFile); + } + catch (IOException e) + { + _logger.warn("Unable to load access file:" + jmxaccesssFile); + } + + try + { + _mbean.register(); + } + catch (AMQException e) + { + _logger.warn("Unable to register user management MBean"); + } + } + catch (JMException e) + { + _logger.warn("User management disabled as unable to create MBean:" + e); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java deleted file mode 100644 index c24a5f21e9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.util.regex.Pattern; -import java.util.Map; -import java.util.HashMap; -import java.security.Principal; - -/** - * 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 MD5PasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(MD5PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map _saslServers; - - public MD5PasswordFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for MD5 Password file. - */ - - // Accept MD5 incomming and use plain comparison with the file - PlainInitialiser cram = new PlainInitialiser(); - cram.initialise(this); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); - plain.initialise(this,CRAMMD5Initialiser.HashDirection.INCOMMING); - - _saslServers.put(plain.getMechanismName(), cram); - _saslServers.put(cram.getMechanismName(), plain); - } - - 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); - } - } - - public Map getMechanisms() - { - return _saslServers; - } - - /** - * 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 java.io.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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 3abdd9a7ff..3f6794aaaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -21,8 +21,8 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -34,9 +34,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.BufferedReader; import java.io.FileReader; +import java.io.UnsupportedEncodingException; import java.util.regex.Pattern; import java.util.Map; import java.util.HashMap; +import java.util.List; import java.security.Principal; /** @@ -119,21 +121,103 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + try + { + char[] pwd = lookupPassword(principal); + + return compareCharArray(pwd, convertPassword(password)); + } + catch (IOException e) + { + return false; + } + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, String password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + public Map getMechanisms() { return _saslServers; } + public List getUsers() + { + return null; //todo + } + + public Principal getUser(String username) + { + try + { + if (lookupPassword(username) != null) + { + return new UsernamePrincipal(username); + } + } + catch (IOException e) + { + //fall through to null return + } + return null; + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + /** * 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 + * @param name the name of the principal to lookup * - * @return + * @return char[] of the password * - * @throws java.io.IOException + * @throws java.io.IOException whilst accessing the file */ private char[] lookupPassword(String name) throws IOException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java index c8318d6e64..598f8f8b4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -20,26 +20,17 @@ */ package org.apache.qpid.server.security.auth.database; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.access.AccessRights; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.log4j.Logger; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.BufferedReader; import java.io.FileReader; -import java.util.regex.Pattern; -import java.util.Map; -import java.util.HashMap; import java.security.Principal; /** @@ -103,9 +94,15 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr public AccessResult isAuthorized(Accessable accessObject, String username) { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) + { + if (accessObject instanceof VirtualHost) { - String[] hosts = lookupVirtualHost(username); + String[] hosts = lookupVirtualHost(user.getName()); if (hosts != null) { @@ -126,4 +123,5 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr { return "PlainPasswordVhostFile"; } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index 6c5a2a44ee..8073fcc3c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -23,8 +23,10 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.Map; +import java.util.List; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -46,5 +48,53 @@ public interface PrincipalDatabase void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException; + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * @param principal The principal to authenticate + * @param password The password to check + * @return true if password is correct + * @throws AccountNotFoundException if the principal cannot be found + */ + boolean verifyPassword(String principal, String password) + throws AccountNotFoundException; + + /** + * Update(Change) the password for the given principal + * @param principal Who's password is to be changed + * @param password The new password to use + * @return True if change was successful + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean updatePassword(Principal principal, String password) + throws AccountNotFoundException; + + /** + * Create a new principal in the database + * @param principal The principal to create + * @param password The password to set for the principal + * @return True on a successful creation + */ + boolean createPrincipal(Principal principal, String password); + + /** + * Delete a principal + * @param principal The principal to delete + * @return True on a successful creation + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean deletePrincipal(Principal principal) + throws AccountNotFoundException; + + /** + * Get the principal from the database with the given username + * @param username of the principal to lookup + * @return The Principal object for the given username or null if not found. + */ + Principal getUser(String username); + + public Map getMechanisms(); + + + List getUsers(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java index 83f1201bd8..2c553ae76a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -21,10 +21,14 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import java.util.Map; public interface PrincipalDatabaseManager { public Map getDatabases(); + + public void initialiseManagement(Configuration config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index 9a58acd98c..b1ac0e1f00 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -29,8 +30,10 @@ import javax.security.auth.login.AccountNotFoundException; import java.util.Properties; import java.util.Map; import java.util.HashMap; +import java.util.List; import java.security.Principal; import java.io.IOException; +import java.io.UnsupportedEncodingException; public class PropertiesPrincipalDatabase implements PrincipalDatabase { @@ -76,8 +79,87 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase } } + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + char[] pwd = _users.getProperty(principal).toCharArray(); + + try + { + return compareCharArray(pwd, convertPassword(password)); + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, String password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public Map getMechanisms() { return _saslServers; } + + public List getUsers() + { + return null; //todo + } + + public Principal getUser(String username) + { + if (_users.getProperty(username) != null) + { + return new UsernamePrincipal(username); + } + else + { + return null; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java index 89c84e8130..6b86a46bd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.security.auth.database; +import org.apache.commons.configuration.Configuration; + import java.util.Map; import java.util.Properties; import java.util.HashMap; @@ -38,4 +40,9 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana { return _databases; } + + public void initialiseManagement(Configuration config) + { + //todo + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 0546bbb81e..ce5e0cd748 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -71,7 +71,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan Map> providerMap = new TreeMap>(); - if (name == null) + if (name == null || hostConfig == null) { initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); } @@ -108,11 +108,15 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan if (providerMap.size() > 0) { - Security.addProvider(new JCAProvider(providerMap)); + // Ensure we are used before the defaults + if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1) + { + _logger.warn("Unable to set order of providers."); + } } else { - _logger.warn("No SASL providers availble."); + _logger.warn("No additional SASL providers registered."); } } @@ -148,21 +152,20 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { if (database == null || database.getMechanisms().size() == 0) { - _logger.warn(""); + _logger.warn("No Database or no mechanisms to initialise authentication"); return; } - for (AuthenticationProviderInitialiser mechanism : database.getMechanisms().values()) + for (Map.Entry mechanism : database.getMechanisms().entrySet()) { - initialiseAuthenticationMechanism(mechanism, providerMap); + initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); } } - private void initialiseAuthenticationMechanism(AuthenticationProviderInitialiser initialiser, + private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, Map> providerMap) throws Exception { - String mechanism = initialiser.getMechanismName(); if (_mechanisms == null) { _mechanisms = mechanism; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java index 8ffcdc4e36..fd4ad86055 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -33,7 +33,7 @@ public final class JCAProvider extends Provider super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + "AMQ SASL providers that want to be registered"); register(providerMap); - Security.addProvider(this); + //Security.addProvider(this); } private void register(Map> providerMap) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java index 68095de3a0..dd0bd096c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -33,14 +33,16 @@ import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.AuthorizeCallback; import org.apache.commons.configuration.Configuration; + import org.apache.log4j.Logger; + import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser { - protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); private ServerCallbackHandler _callbackHandler; @@ -72,7 +74,9 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi { // very annoyingly the callback handler does not throw anything more appropriate than // IOException - throw new IOException("Error looking up user " + e); + IOException ioe = new IOException("Error looking up user " + e); + ioe.initCause(e); + throw ioe; } } else if (callback instanceof AuthorizeCallback) @@ -88,7 +92,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi } public void initialise(String baseConfigPath, Configuration configuration, - Map principalDatabases) throws Exception + Map principalDatabases) throws Exception { String principalDatabaseName = configuration.getString(baseConfigPath + ".principal-database"); PrincipalDatabase db = principalDatabases.get(principalDatabaseName); @@ -102,6 +106,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi { throw new NullPointerException("Cannot initialise with a null Principal database."); } + _callbackHandler = new ServerCallbackHandler(db); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java index f9aaabd15a..d7c8383690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -22,10 +22,7 @@ package org.apache.qpid.server.security.auth.sasl; import java.security.Principal; -/** - * A principal that is just a wrapper for a simple username. - * - */ +/** A principal that is just a wrapper for a simple username. */ public class UsernamePrincipal implements Principal { private String _name; @@ -39,4 +36,9 @@ public class UsernamePrincipal implements Principal { return _name; } + + public String toString() + { + return _name; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java new file mode 100644 index 0000000000..97f9a4e91a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return CRAMMD5HashedSaslServer.MECHANISM; + } + + public Class getServerFactoryClassForJCARegistration() + { + return CRAMMD5HashedServerFactory.class; + } + + public void initialise(PrincipalDatabase passwordFile) + { + super.initialise(passwordFile); + } + + public Map getProperties() + { + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java new file mode 100644 index 0000000000..f6cab084ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.CallbackHandler; +import java.util.Enumeration; +import java.util.Map; + +public class CRAMMD5HashedSaslServer implements SaslServer +{ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + private SaslServer _realServer; + + public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + Enumeration factories = Sasl.getSaslServerFactories(); + + while (factories.hasMoreElements()) + { + SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); + + if (factory instanceof CRAMMD5HashedServerFactory) + { + continue; + } + + String[] mechs = factory.getMechanismNames(props); + + for (String mech : mechs) + { + if (mech.equals("CRAM-MD5")) + { + _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); + return; + } + } + } + + throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return _realServer.evaluateResponse(response); + } + + public boolean isComplete() + { + return _realServer.isComplete(); + } + + public String getAuthorizationID() + { + return _realServer.getAuthorizationID(); + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return _realServer.unwrap(incoming, offset, len); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return _realServer.wrap(outgoing, offset, len); + } + + public Object getNegotiatedProperty(String propName) + { + return _realServer.getNegotiatedProperty(propName); + } + + public void dispose() throws SaslException + { + _realServer.dispose(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java new file mode 100644 index 0000000000..5298b5cc63 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5HashedServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) + { + return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java index ff3e87e3a0..f0dd9eeb6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -29,7 +29,7 @@ import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; public class PlainSaslServerFactory implements SaslServerFactory -{ +{ public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, CallbackHandler cbh) throws SaslException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java index 05d1cd5291..609a85c22f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -56,18 +56,7 @@ public class CleanupMessageOperation implements TxnOp public void commit(StoreContext context) { - //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(context); - } - catch (AMQException e) - { - _log.error("On commiting transaction, failed to cleanup unused message: " + e, e); - } + try { _msg.checkDeliveredToConsumer(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index cf0da55f2a..6d776eec0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -89,6 +89,12 @@ public class LocalTransactionalContext implements TransactionalContext public void rollback() throws AMQException { _txnBuffer.rollback(_storeContext); + // Hack to deal with uncommitted non-transactional writes + if(_messageStore.inTran(_storeContext)) + { + _messageStore.abortTran(_storeContext); + _inTran = false; + } _postCommitDeliveryList.clear(); } @@ -103,6 +109,7 @@ public class LocalTransactionalContext implements TransactionalContext // message.incrementReference(); _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); _messageDelivered = true; + _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); if (_log.isDebugEnabled()) { @@ -111,7 +118,7 @@ public class LocalTransactionalContext implements TransactionalContext } message.incrementReference(); _messageDelivered = true; - _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); + */ } @@ -195,6 +202,7 @@ public class LocalTransactionalContext implements TransactionalContext { _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); } + //fixme fail commit here ... QPID-440 try { _txnBuffer.commit(_storeContext); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java index 339ca8ae1a..405c233552 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -41,7 +41,7 @@ public class TxnBuffer { if (_log.isDebugEnabled()) { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops.toArray()); + _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); } if (prepare(context)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index c24d1aa23a..b5c59dbbb7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -181,7 +181,7 @@ public class VirtualHost implements Accessable 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"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); } Configurator.configure(instance); -- cgit v1.2.1 From b35d61bbd09573c6d3a076299f67aacbd819d60f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Apr 2007 10:52:26 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530696,530698-530735 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r530432 | ritchiem | 2007-04-19 15:42:53 +0100 (Thu, 19 Apr 2007) | 8 lines QPID-459 - NoLocal broken when messages already exist on queue from consumer. With test. AMQChannel remove comment around setPublisher - this is used by noLocal implementation. Subscription - rename of hasFilters to filtersMessages AMQQueue/RemoteSubscriptionImpl/SubscriptionTestHelper/SubscriptionSet - rename of hasFilters to filtersMessages SubscriptionImpl - rename of hasFilters to filtersMessages and changes to include noLocal in that check. TopicSessionTest - Additional testing for NoLocal to ensure. ........ r530437 | ritchiem | 2007-04-19 15:52:49 +0100 (Thu, 19 Apr 2007) | 5 lines QPID-459 - NoLocal broken when messages already exist on queue from consumer. With test. TopicSessionTest - Additional testing for NoLocal to ensure. Forgot to include the file in the commit. ........ r530438 | ritchiem | 2007-04-19 15:53:32 +0100 (Thu, 19 Apr 2007) | 1 line Added Test logging to aid in diagnosing problems ........ r530441 | ritchiem | 2007-04-19 16:07:54 +0100 (Thu, 19 Apr 2007) | 5 lines QPID-459 - NoLocal broken when messages already exist on queue from consumer. With test. ConcurrentSelectorDeliveryManager - method changes from hasFilter to filtersMessages. Forgot to include the file in the commit. ........ r530442 | ritchiem | 2007-04-19 16:08:04 +0100 (Thu, 19 Apr 2007) | 5 lines QPID-455 Pre-fetched messages can cause problems with client tools. Set IMMEDIATE_PREFETCH="true" for previous behaviour. Inverted check now setting System proprety IMMEDIATE_PREFETCH="true" will cause existing messages to be immediately pre-fetched to the newly registered consumer. Solved out standing broker issues see QPID-458 and QPID-459. ........ r530444 | ritchiem | 2007-04-19 16:10:10 +0100 (Thu, 19 Apr 2007) | 3 lines QPID-454 - Message 'taken' notion is per message. Adjusted to be per message per queue. Previous commit was not sufficiently tested and other bugs were causing problems that were not related to this change. ........ r530447 | ritchiem | 2007-04-19 16:15:25 +0100 (Thu, 19 Apr 2007) | 1 line Committed test with localhost as the broker ........ r530449 | ritchiem | 2007-04-19 16:16:32 +0100 (Thu, 19 Apr 2007) | 1 line Additional test to ensure connection closure doesn't cause problems. ........ r530683 | ritchiem | 2007-04-20 09:11:05 +0100 (Fri, 20 Apr 2007) | 2 lines Reinstated the two consumer receive test. Added additional test class to cover the IMMEDIATE_PREFETCHs. ........ r530685 | ritchiem | 2007-04-20 09:13:03 +0100 (Fri, 20 Apr 2007) | 1 line Made IMMEDIATE_PREFETCH to allow access from additional test class. ........ r530686 | ritchiem | 2007-04-20 09:14:57 +0100 (Fri, 20 Apr 2007) | 1 line Moved string literal 'Qpid_HOME' to constant QPID_HOME ........ r530734 | bhupendrab | 2007-04-20 11:42:52 +0100 (Fri, 20 Apr 2007) | 1 line QPID-445 : md5 hashed password will be sent from management console to Qpid ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530737 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 1 - .../src/main/java/org/apache/qpid/server/Main.java | 6 +- .../org/apache/qpid/server/queue/AMQMessage.java | 100 ++++++++++++++++----- .../org/apache/qpid/server/queue/AMQQueue.java | 16 ++-- .../queue/ConcurrentSelectorDeliveryManager.java | 20 ++++- .../org/apache/qpid/server/queue/Subscription.java | 2 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 24 +++-- .../apache/qpid/server/queue/SubscriptionSet.java | 2 +- .../security/access/AMQUserManagementMBean.java | 17 +--- .../server/security/access/UserManagement.java | 4 +- .../Base64MD5PasswordFilePrincipalDatabase.java | 31 +++---- .../PlainPasswordFilePrincipalDatabase.java | 4 +- .../security/auth/database/PrincipalDatabase.java | 4 +- .../auth/database/PropertiesPrincipalDatabase.java | 4 +- 14 files changed, 148 insertions(+), 87 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 2e1653e69d..97c95dae5e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -197,7 +197,6 @@ public class AMQChannel _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); - // TODO: used in clustering only I think (RG) _currentMessage.setPublisher(publisher); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 146d0566ce..14aa919356 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -70,7 +70,7 @@ public class Main private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - + public static final String QPID_HOME = "QPID_HOME"; private static final int IPV4_ADDRESS_LENGTH = 4; private static final char IPV4_LITERAL_SEPARATOR = '.'; @@ -204,7 +204,7 @@ public class Main protected void startup() throws InitException, ConfigurationException, Exception { - final String QpidHome = System.getProperty("QPID_HOME"); + 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()) @@ -213,7 +213,7 @@ public class Main if (QpidHome == null) { - error = error + "\nNote: Qpid_HOME is not set."; + error = error + "\nNote: "+QPID_HOME+" is not set."; } throw new InitException(error, null); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index b2046efee3..e19038504f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -80,18 +80,17 @@ public class AMQMessage */ private boolean _immediate; - private AtomicBoolean _taken = new AtomicBoolean(false); + // private Subscription _takenBySubcription; + // private AtomicBoolean _taken = new AtomicBoolean(false); private TransientMessageData _transientMessageData = new TransientMessageData(); - private Subscription _takenBySubcription; + private Set _rejectedBy = null; + + private Map _takenMap = new HashMap(); private Map _takenBySubcriptionMap = new HashMap(); - public boolean isTaken(AMQQueue queue) - { - return _taken.get(); - } private final int hashcode = System.identityHashCode(this); @@ -206,7 +205,7 @@ public class AMQMessage _immediate = info.isImmediate(); _transientMessageData.setMessagePublishInfo(info); - _taken = new AtomicBoolean(false); +// _taken = new AtomicBoolean(false); if (_log.isDebugEnabled()) { @@ -326,7 +325,6 @@ public class AMQMessage for (AMQQueue q : _transientMessageData.getDestinationQueues()) { - _takenMap.put(q, new AtomicBoolean(false)); _messageHandle.enqueue(storeContext, _messageId, q); } @@ -459,17 +457,53 @@ public class AMQMessage return _deliveredToConsumer; } - - public boolean taken(AMQQueue queue, Subscription sub) + public boolean isTaken(AMQQueue queue) { - if (_taken.getAndSet(true)) + //return _taken.get(); + + synchronized (this) { - return true; + AtomicBoolean taken = _takenMap.get(queue); + if (taken == null) + { + taken = new AtomicBoolean(false); + _takenMap.put(queue, taken); + } + + return taken.get(); } - else + } + + public boolean taken(AMQQueue queue, Subscription sub) + { +// if (_taken.getAndSet(true)) +// { +// return true; +// } +// else +// { +// _takenBySubcription = sub; +// return false; +// } + + synchronized (this) { - _takenBySubcription = sub; - return false; + AtomicBoolean taken = _takenMap.get(queue); + if (taken == null) + { + taken = new AtomicBoolean(false); + } + + if (taken.getAndSet(true)) + { + return true; + } + else + { + _takenMap.put(queue, taken); + _takenBySubcriptionMap.put(queue, sub); + return false; + } } } @@ -479,8 +513,26 @@ public class AMQMessage { _log.trace("Releasing Message:" + debugIdentity()); } - _taken.set(false); - _takenBySubcription = null; + +// _taken.set(false); +// _takenBySubcription = null; + + + synchronized (this) + { + AtomicBoolean taken = _takenMap.get(queue); + if (taken == null) + { + taken = new AtomicBoolean(false); + } + else + { + taken.set(false); + } + + _takenMap.put(queue, taken); + _takenBySubcriptionMap.put(queue, null); + } } public boolean checkToken(Object token) @@ -833,16 +885,20 @@ public class AMQMessage public String toString() { - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - _taken + " by :" + _takenBySubcription; +// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + +// _taken + " by :" + _takenBySubcription; -// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + -// _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } public Subscription getDeliveredSubscription(AMQQueue queue) { - return _takenBySubcription; +// return _takenBySubcription; + synchronized (this) + { + return _takenBySubcriptionMap.get(queue); + } } public void reject(Subscription subscription) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index a418bb8f8a..65d5906d05 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.queue; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -237,8 +236,10 @@ public class AMQQueue implements Managable, Comparable /** * Returns messages within the given range of message Ids + * * @param fromMessageId * @param toMessageId + * * @return List of messages */ public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) @@ -253,6 +254,7 @@ public class AMQQueue implements Managable, Comparable /** * @param messageId + * * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. */ public AMQMessage getMessageOnTheQueue(long messageId) @@ -267,10 +269,10 @@ public class AMQQueue implements Managable, Comparable /** * moves messages from this queue to another queue. to do this the approach is following- - setup the queue for - * moving messages (stop the async delivery) - get all the messages available in the given message - * id range - setup the other queue for moving messages (stop the async delivery) - send these - * available messages to the other queue (enqueue in other queue) - Once sending to other Queue is successful, - * remove messages from this queue - remove locks from both queues and start async delivery + * moving messages (stop the async delivery) - get all the messages available in the given message id range - setup + * the other queue for moving messages (stop the async delivery) - send these available messages to the other queue + * (enqueue in other queue) - Once sending to other Queue is successful, remove messages from this queue - remove + * locks from both queues and start async delivery * * @param fromMessageId * @param toMessageId @@ -442,7 +444,7 @@ public class AMQQueue implements Managable, Comparable Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); - if (subscription.hasFilters()) + if (subscription.filtersMessages()) { if (_deliveryMgr.hasQueuedMessages()) { @@ -641,7 +643,7 @@ public class AMQQueue implements Managable, Comparable { _totalMessagesReceived.incrementAndGet(); } - + try { _managedObject.checkForNotification(msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 979f692361..1f92cee1df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -28,7 +28,6 @@ import java.util.Set; import java.util.Collections; import java.util.HashSet; import java.util.concurrent.Executor; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicInteger; @@ -372,7 +371,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { for (Subscription sub : _subscriptions.getSubscriptions()) { - if (!sub.isSuspended() && sub.hasFilters()) + if (!sub.isSuspended() && sub.filtersMessages()) { Queue preDeliveryQueue = sub.getPreDeliveryQueue(); for (AMQMessage msg : messageList) @@ -613,6 +612,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _processingThreadName = Thread.currentThread().getName(); } + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Running process Queue." + currentStatus()); + } + // Continue to process delivery while we haveSubscribers and messages boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); @@ -633,11 +637,17 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Done process Queue." + currentStatus()); + } + } // private void sendNextMessage(Subscription sub) // { -// if (sub.hasFilters()) +// if (sub.filtersMessages()) // { // sendNextMessage(sub, sub.getPreDeliveryQueue()); // if (sub.isAutoClose()) @@ -817,6 +827,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //are we already running? if so, don't re-run if (_processing.compareAndSet(false, true)) { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Executing Async process."); + } executor.execute(asyncDelivery); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index e9f209839a..e6d5d0c88d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -32,7 +32,7 @@ public interface Subscription void queueDeleted(AMQQueue queue) throws AMQException; - boolean hasFilters(); + boolean filtersMessages(); boolean hasInterest(AMQMessage msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index e3944954f3..3bce950ba9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -158,7 +158,7 @@ public class SubscriptionImpl implements Subscription } - if (_filters != null) + if (filtersMessages()) { _messages = new ConcurrentLinkedMessageQueueAtomicSize(); } @@ -346,9 +346,9 @@ public class SubscriptionImpl implements Subscription channel.queueDeleted(queue); } - public boolean hasFilters() + public boolean filtersMessages() { - return _filters != null; + return _filters != null || _noLocal; } public boolean hasInterest(AMQMessage msg) @@ -363,7 +363,10 @@ public class SubscriptionImpl implements Subscription // return false; } - if (_noLocal) + final AMQProtocolSession publisher = msg.getPublisher(); + + //todo - client id should be recoreded and this test removed but handled below + if (_noLocal && publisher != null) { // We don't want local messages so check to see if message is one we sent Object localInstance; @@ -372,8 +375,9 @@ public class SubscriptionImpl implements Subscription if ((protocolSession.getClientProperties() != null) && (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { - if ((msg.getPublisher().getClientProperties() != null) && - (msgInstance = msg.getPublisher().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + + if ((publisher.getClientProperties() != null) && + (msgInstance = publisher.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) { if (localInstance == msgInstance || localInstance.equals(msgInstance)) { @@ -388,8 +392,11 @@ public class SubscriptionImpl implements Subscription } else { + localInstance = protocolSession.getClientIdentifier(); - msgInstance = msg.getPublisher().getClientIdentifier(); + //todo - client id should be recoreded and this test removed but handled here + + msgInstance = publisher.getClientIdentifier(); if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) { if (_logger.isTraceEnabled()) @@ -399,7 +406,6 @@ public class SubscriptionImpl implements Subscription } return false; } - } @@ -623,7 +629,7 @@ public class SubscriptionImpl implements Subscription return _resendQueue; } - if (_filters != null) + if (filtersMessages()) { if (isAutoClose()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java index 26b040aae0..b500247fa4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -157,7 +157,7 @@ class SubscriptionSet implements WeightedSubscriptionManager //FIXME the queue could be full of sent messages. // Either need to clean all PDQs after sending a message // OR have a clean up thread that runs the PDQs expunging the messages. - if (!subscription.hasFilters() || subscription.getPreDeliveryQueue().isEmpty()) + if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) { return subscription; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java index a43474559d..20f123179f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.security.access; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanOperationParameter; import org.apache.qpid.server.management.MBeanOperation; import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; @@ -107,8 +106,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return UserManagement.TYPE; } - public boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")String password) + public boolean setPassword(String username, char[] password) { try { @@ -122,10 +120,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } } - public boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + public boolean setRights(String username, boolean read, boolean write, boolean admin) { if (_accessRights.get(username) == null) @@ -179,11 +174,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return true; } - public boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")String password, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) { if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) { @@ -195,7 +186,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return false; } - public boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username) + public boolean deleteUser(String username) { try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java index 6381213398..ce5e9fa4a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java @@ -45,7 +45,7 @@ public interface UserManagement */ @MBeanOperation(name = "setPassword", description = "Set password for user.") boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")String password); + @MBeanOperationParameter(name = "password", description = "Password")char[] password); /** * set rights for users with given details @@ -76,7 +76,7 @@ public interface UserManagement */ @MBeanOperation(name = "createUser", description = "Create new user from system.") boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")String password, + @MBeanOperationParameter(name = "password", description = "Password")char[] password, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 956db64d90..cd0a371b48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -176,7 +176,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { User user = _users.get(principal.getName()); @@ -187,13 +187,10 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase try { - - char[] passwd = convertPassword(password); - try { _userUpdate.lock(); - user.setPassword(passwd); + user.setPassword(password); try { @@ -215,7 +212,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } } - catch (UnsupportedEncodingException e) + catch (Exception e) { return false; } @@ -237,23 +234,14 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return passwd; } - public boolean createPrincipal(Principal principal, String password) + public boolean createPrincipal(Principal principal, char[] password) { if (_users.get(principal.getName()) != null) { return false; } - User user; - try - { - user = new User(principal.getName(), convertPassword(password)); - } - catch (UnsupportedEncodingException e) - { - _logger.warn("Unable to encode password:" + e); - return false; - } + User user = new User(principal.getName(), password); try { @@ -598,8 +586,13 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException { - Base64 b64 = new Base64(); - _encodedPassword = b64.encode(new String(_password).getBytes(DEFAULT_ENCODING)); + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte)c; + } + _encodedPassword = (new Base64()).encode(byteArray); } public boolean isModified() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 3f6794aaaf..90d08c963e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -151,12 +151,12 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase return passwd; } - public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { return false; // updates denied } - public boolean createPrincipal(Principal principal, String password) + public boolean createPrincipal(Principal principal, char[] password) { return false; // updates denied } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index 8073fcc3c6..494d8e0bf4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -65,7 +65,7 @@ public interface PrincipalDatabase * @return True if change was successful * @throws AccountNotFoundException If the given principal doesn't exist in the Database */ - boolean updatePassword(Principal principal, String password) + boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException; /** @@ -74,7 +74,7 @@ public interface PrincipalDatabase * @param password The password to set for the principal * @return True on a successful creation */ - boolean createPrincipal(Principal principal, String password); + boolean createPrincipal(Principal principal, char[] password); /** * Delete a principal diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index b1ac0e1f00..74c330f606 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -93,12 +93,12 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase } } - public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { return false; // updates denied } - public boolean createPrincipal(Principal principal, String password) + public boolean createPrincipal(Principal principal, char[] password) { return false; // updates denied } -- cgit v1.2.1 From a469da53c9de68e52794c47ef26d9d20b7fff934 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 20 Apr 2007 12:51:33 +0000 Subject: Copied some whitespace only differences from M2 to trunk. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530779 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 187 +++++++++++---------- 1 file changed, 99 insertions(+), 88 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index eac7ed21f2..931c15a664 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -1,44 +1,45 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.log4j; -import org.apache.log4j.helpers.OptionConverter; -import org.apache.log4j.helpers.CountingQuietWriter; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.spi.LoggingEvent; -import org.apache.qpid.framing.FieldTable; - +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Writer; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPOutputStream; -import java.text.SimpleDateFormat; -import java.io.IOException; -import java.io.Writer; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; + +import org.apache.log4j.helpers.CountingQuietWriter; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.spi.LoggingEvent; + +import org.apache.qpid.framing.FieldTable; /** *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either @@ -83,7 +84,7 @@ public class QpidCompositeRollingAppender extends FileAppender static final int BY_DATE = 2; static final int BY_COMPOSITE = 3; - //Not currently used + // Not currently used static final String S_BY_SIZE = "Size"; static final String S_BY_DATE = "Date"; static final String S_BY_COMPOSITE = "Composite"; @@ -146,7 +147,6 @@ public class QpidCompositeRollingAppender extends FileAppender /** FileName provided in configuration. Used for rolling properly */ protected String baseFileName; - /** Do we want to .gz our backup files. */ protected boolean compress = false; @@ -163,15 +163,13 @@ public class QpidCompositeRollingAppender extends FileAppender /** The default constructor does nothing. */ public QpidCompositeRollingAppender() - { - } + { } /** * Instantiate a CompositeRollingAppender and open the file designated by filename. The * opened filename will become the ouput destination for this appender. */ - public QpidCompositeRollingAppender(Layout layout, String filename, - String datePattern) throws IOException + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern) throws IOException { this(layout, filename, datePattern, true); } @@ -183,8 +181,7 @@ public class QpidCompositeRollingAppender extends FileAppender *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by * filename will be truncated before being opened. */ - public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) - throws IOException + public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) throws IOException { super(layout, filename, append); } @@ -193,8 +190,8 @@ public class QpidCompositeRollingAppender extends FileAppender * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename * will become the ouput destination for this appender. */ - public QpidCompositeRollingAppender(Layout layout, String filename, - String datePattern, boolean append) throws IOException + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern, boolean append) + throws IOException { super(layout, filename, append); this.datePattern = datePattern; @@ -305,7 +302,7 @@ public class QpidCompositeRollingAppender extends FileAppender qw = new CountingQuietWriter(writer, errorHandler); } - //Taken verbatum from DailyRollingFileAppender + // Taken verbatum from DailyRollingFileAppender int computeCheckPeriod() { RollingCalendar c = new RollingCalendar(); @@ -319,17 +316,18 @@ public class QpidCompositeRollingAppender extends FileAppender c.setType(i); Date next = new Date(c.getNextCheckMillis(epoch)); String r1 = sdf.format(next); - //LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); - if (r0 != null && r1 != null && !r0.equals(r1)) + // LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if ((r0 != null) && (r1 != null) && !r0.equals(r1)) { return i; } } } + return TOP_OF_TROUBLE; // Deliberately head for trouble... } - //Now for the new stuff + // Now for the new stuff /** * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked * first) or time (checked second) is need and then appends to the file last. @@ -351,7 +349,7 @@ public class QpidCompositeRollingAppender extends FileAppender if (rollSize) { - if ((fileName != null) && ((CountingQuietWriter) qw).getCount() >= maxFileSize) + if ((fileName != null) && (((CountingQuietWriter) qw).getCount() >= maxFileSize)) { rollOverSize(); } @@ -410,20 +408,24 @@ public class QpidCompositeRollingAppender extends FileAppender rollingStyle = style; switch (rollingStyle) { - case BY_SIZE: - rollDate = false; - rollSize = true; - break; - case BY_DATE: - rollDate = true; - rollSize = false; - break; - case BY_COMPOSITE: - rollDate = true; - rollSize = true; - break; - default: - errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); + + case BY_SIZE: + rollDate = false; + rollSize = true; + break; + + case BY_DATE: + rollDate = true; + rollSize = false; + break; + + case BY_COMPOSITE: + rollDate = true; + rollSize = true; + break; + + default: + errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); } } @@ -439,7 +441,7 @@ public class QpidCompositeRollingAppender extends FileAppender rollingStyle = BY_COMPOSITE; } } - */ + */ public boolean getStaticLogFileName() { return staticLogFileName; @@ -477,11 +479,10 @@ public class QpidCompositeRollingAppender extends FileAppender { executor = Executors.newFixedThreadPool(1); - compressor = new Compressor(); + compressor = new Compressor(); } } - public boolean getZeroBased() { return zeroBased; @@ -504,6 +505,7 @@ public class QpidCompositeRollingAppender extends FileAppender { td.mkdirs(); } + backupFilesToPath = path; } @@ -519,9 +521,10 @@ public class QpidCompositeRollingAppender extends FileAppender { curSizeRollBackups = -1; } + curTimeRollBackups = 0; - //part A starts here + // part A starts here String filter; if (staticLogFileName || !rollDate) { @@ -556,9 +559,9 @@ public class QpidCompositeRollingAppender extends FileAppender if (staticLogFileName) { int endLength = files[i].length() - index; - if (baseFileName.length() + endLength != files[i].length()) + if ((baseFileName.length() + endLength) != files[i].length()) { - //file is probably scheduledFilename + .x so I don't care + // file is probably scheduledFilename + .x so I don't care continue; } } @@ -574,18 +577,19 @@ public class QpidCompositeRollingAppender extends FileAppender } catch (Exception e) { - //this happens when file.log -> file.log.yyyy-mm-dd which is normal - //when staticLogFileName == false + // this happens when file.log -> file.log.yyyy-mm-dd which is normal + // when staticLogFileName == false LogLog.debug("Encountered a backup file not ending in .x " + files[i]); } } } + LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); - //part A ends here + // part A ends here - //part B not yet implemented + // part B not yet implemented - //part C + // part C if (staticLogFileName && rollDate) { File old = new File(baseFileName); @@ -600,8 +604,9 @@ public class QpidCompositeRollingAppender extends FileAppender } } } + LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); - //part C ends here + // part C ends here } @@ -612,29 +617,28 @@ public class QpidCompositeRollingAppender extends FileAppender public void activateOptions() { - //REMOVE removed rollDate from boolean to enable Alex's change + // REMOVE removed rollDate from boolean to enable Alex's change if (datePattern != null) { now.setTime(System.currentTimeMillis()); sdf = new SimpleDateFormat(datePattern); int type = computeCheckPeriod(); - //printPeriodicity(type); + // printPeriodicity(type); rc.setType(type); - //next line added as this removes the name check in rollOver + // next line added as this removes the name check in rollOver nextCheck = rc.getNextCheckMillis(now); } else { if (rollDate) { - LogLog.error("Either DatePattern or rollingStyle options are not set for [" + - name + "]."); + LogLog.error("Either DatePattern or rollingStyle options are not set for [" + name + "]."); } } existingInit(); - if (rollDate && fileName != null && scheduledFilename == null) + if (rollDate && (fileName != null) && (scheduledFilename == null)) { scheduledFilename = fileName + sdf.format(now); } @@ -662,7 +666,7 @@ public class QpidCompositeRollingAppender extends FileAppender this.closeFile(); // keep windows happy. - //delete the old stuff here + // delete the old stuff here if (staticLogFileName) { @@ -670,23 +674,25 @@ public class QpidCompositeRollingAppender extends FileAppender if (datePattern == null) { errorHandler.error("Missing DatePattern option in rollOver()."); + return; } - //is the new file name equivalent to the 'current' one - //something has gone wrong if we hit this -- we should only - //roll over if the new file will be different from the old + // is the new file name equivalent to the 'current' one + // something has gone wrong if we hit this -- we should only + // roll over if the new file will be different from the old String dateFormat = sdf.format(now); if (scheduledFilename.equals(fileName + dateFormat)) { errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); + return; } // close current file, and rename it to datedFilename this.closeFile(); - //we may have to roll over a large number of backups here + // we may have to roll over a large number of backups here String from, to; for (int i = 1; i <= curSizeRollBackups; i++) { @@ -709,9 +715,9 @@ public class QpidCompositeRollingAppender extends FileAppender { // This will also close the file. This is OK since multiple // close operations are safe. - curSizeRollBackups = 0; //We're cleared out the old date and are ready for the new + curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new - //new scheduled name + // new scheduled name scheduledFilename = fileName + sdf.format(now); this.setFile(baseFileName, false); } @@ -734,8 +740,10 @@ public class QpidCompositeRollingAppender extends FileAppender { LogLog.debug("Attempting to compress file with same output name."); } + return; } + File target = new File(to); if (target.exists()) { @@ -755,10 +763,10 @@ public class QpidCompositeRollingAppender extends FileAppender file.renameTo(target); } } + LogLog.debug(from + " -> " + to); } - protected void compress(String file) { File f = new File(file); @@ -773,6 +781,7 @@ public class QpidCompositeRollingAppender extends FileAppender { _compress.offer(new CompressJob(from, target)); } + startCompression(); } else @@ -805,7 +814,7 @@ public class QpidCompositeRollingAppender extends FileAppender *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} - * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is + * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is * renamed File.1 and closed.
      * * A new file is created to receive further log output. @@ -851,20 +860,20 @@ public class QpidCompositeRollingAppender extends FileAppender // Rename fileName to fileName.1 rollFile(fileName, fileName + ".1", compress); - } //REMOVE This code branching for Alexander Cerna's request + } // REMOVE This code branching for Alexander Cerna's request else if (countDirection == 0) { - //rollFile based on date pattern + // rollFile based on date pattern curSizeRollBackups++; now.setTime(System.currentTimeMillis()); scheduledFilename = fileName + sdf.format(now); rollFile(fileName, scheduledFilename, compress); } else - { //countDirection > 0 - if (curSizeRollBackups >= maxSizeRollBackups && maxSizeRollBackups > 0) + { // countDirection > 0 + if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) { - //delete the first and keep counting up. + // delete the first and keep counting up. int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; deleteFile(fileName + '.' + oldestFileIndex); } @@ -930,6 +939,7 @@ public class QpidCompositeRollingAppender extends FileAppender { out.write(buf, 0, len); } + in.close(); // Complete the GZIP file @@ -944,6 +954,7 @@ public class QpidCompositeRollingAppender extends FileAppender { target.delete(); } + rollFile(from.getPath(), to.getPath(), false); } } -- cgit v1.2.1 From 03aad71e252f89a0c9e4dbddb63b55ae9fe3e9cc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Apr 2007 15:00:06 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530830 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r530796 | ritchiem | 2007-04-20 14:23:17 +0100 (Fri, 20 Apr 2007) | 1 line QPID-468 Add Broker verison number to Listen print line in Main.java:367 ........ r530797 | ritchiem | 2007-04-20 14:24:43 +0100 (Fri, 20 Apr 2007) | 1 line Updated PrincipalDatabase verifyPassword to match rest of API and take a char[] ........ r530798 | ritchiem | 2007-04-20 14:25:50 +0100 (Fri, 20 Apr 2007) | 3 lines QPID-445 Added checks to ensure UserManagement MBean is only accessed by Admin users. Allow Qpid JMX Management console to manage access file. ........ r530800 | ritchiem | 2007-04-20 14:27:22 +0100 (Fri, 20 Apr 2007) | 1 line White space changes plus additional logging to aid in debugging ........ r530812 | ritchiem | 2007-04-20 14:59:27 +0100 (Fri, 20 Apr 2007) | 2 lines QPID-471 User list not populated. This was due to the fact that the 'View User' has been marked as an ACTION. Changing to an INFO made the console work just fine. ........ r530819 | ritchiem | 2007-04-20 15:08:13 +0100 (Fri, 20 Apr 2007) | 1 line QPID-468 Update to log4j.xml to ensure the new logger is at least at the info level. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530832 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 56 ++++++----- .../management/JMXManagedObjectRegistry.java | 104 +++++++++------------ .../management/MBeanInvocationHandlerImpl.java | 53 ++++++++++- .../server/management/ManagedObjectRegistry.java | 7 +- .../security/access/AMQUserManagementMBean.java | 25 ++++- .../server/security/access/UserManagement.java | 21 +++-- .../Base64MD5PasswordFilePrincipalDatabase.java | 26 ++---- .../PlainPasswordFilePrincipalDatabase.java | 20 +--- .../security/auth/database/PrincipalDatabase.java | 2 +- .../auth/database/PropertiesPrincipalDatabase.java | 12 +-- 10 files changed, 181 insertions(+), 145 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 14aa919356..1e5f56fe3a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -48,6 +48,7 @@ import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; import org.apache.qpid.AMQException; +import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; @@ -66,6 +67,7 @@ import org.apache.qpid.url.URLSyntaxException; public class Main { private static final Logger _logger = Logger.getLogger(Main.class); + public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; @@ -118,25 +120,25 @@ public class Main 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"); + 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"); + 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"); + 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"); + 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"); + 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); @@ -213,7 +215,7 @@ public class Main if (QpidHome == null) { - error = error + "\nNote: "+QPID_HOME+" is not set."; + error = error + "\nNote: " + QPID_HOME + " is not set."; } throw new InitException(error, null); @@ -239,10 +241,14 @@ public class Main ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); - _logger.info("Starting Qpid.AMQP broker"); + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + // that are causing the broker build to pick up the wrong properties file and hence say + // Starting Qpid Client + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); ConnectorConfiguration connectorConfig = - ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); @@ -293,7 +299,7 @@ public class Main } protected void setupVirtualHosts(String configFileParent, String configFilePath) - throws ConfigurationException, AMQException, URLSyntaxException + throws ConfigurationException, AMQException, URLSyntaxException { String configVar = "${conf}"; @@ -320,7 +326,7 @@ public class Main if (fileNames[each].endsWith(".xml")) { VirtualHostConfiguration vHostConfig = - new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); + new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); vHostConfig.performBindings(); } } @@ -367,7 +373,7 @@ public class Main } acceptor.bind(bindAddress, handler, sconfig); - _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); + _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } if (connectorConfig.enableSSL) @@ -376,11 +382,11 @@ public class Main try { acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); - _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); + _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); } catch (IOException e) { - _logger.error("Unable to listen on SSL port: " + e, e); + _brokerLogger.error("Unable to listen on SSL port: " + e, e); } } } @@ -434,7 +440,7 @@ public class Main 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"); + + "a non-negative integer. Using default of zero (no watching configured"); } if (logConfigFile.exists() && logConfigFile.canRead()) @@ -443,7 +449,7 @@ public class Main if (logWatchTime > 0) { System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " - + logWatchTime + " seconds"); + + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 38c9e4950a..a14d4214e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -83,7 +83,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } - public void start() + public void start() throws IOException { // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) @@ -97,76 +97,60 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", true); int port = appRegistry.getConfiguration().getInt("management.jmxport", 8999); - try + if (security) { - if (security) - { - // For SASL using JMXMP - _jmxURL = new JMXServiceURL("jmxmp", null, port); - - Map env = new HashMap(); - Map map = appRegistry.getDatabaseManager().getDatabases(); - PrincipalDatabase db = null; - - for (Map.Entry entry : map.entrySet()) - { - if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) - { - db = entry.getValue(); - break; - } - else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) - { - db = entry.getValue(); - } - } - - if (db instanceof Base64MD5PasswordFilePrincipalDatabase) - { - env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); - CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); - initialiser.initialise(db); - env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); - } - else if (db instanceof PlainPasswordFilePrincipalDatabase) - { - env.put("jmx.remote.profiles", "SASL/PLAIN"); - env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); - } + // For SASL using JMXMP + _jmxURL = new JMXServiceURL("jmxmp", null, port); - // Enable the SSL security and server authentication - /* - SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); - SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); - env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); - env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); - */ + Map env = new HashMap(); + Map map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = null; - try + for (Map.Entry entry : map.entrySet()) + { + if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) { - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - cs.start(); - _log.info("JMX: Starting JMXConnector server with SASL"); + db = entry.getValue(); + break; } - catch (java.net.MalformedURLException urlException) + else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) { - // When JMXMPConnector is not available - // java.net.MalformedURLException: Unsupported protocol: jmxmp - _log.info("JMX: Starting JMXConnector server"); - startJMXConnectorServer(port); + db = entry.getValue(); } } - else + + if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); + CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + } + else if (db instanceof PlainPasswordFilePrincipalDatabase) { - startJMXConnectorServer(port); + env.put("jmx.remote.profiles", "SASL/PLAIN"); + env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); } + + // Enable the SSL security and server authentication + /* + SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); + SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); + */ + + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + _log.warn("JMX: Started JMXConnector server with SASL"); + } - catch (Exception ex) + else { - _log.error("Error in initialising Managed Object Registry." + ex.getMessage()); - ex.printStackTrace(); + startJMXConnectorServer(port); + _log.warn("JMX: Started JMXConnector server with security disabled"); } } @@ -280,7 +264,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry String username = ncb.getDefaultName(); try { - authorized = _principalDatabase.verifyPassword(username, new String(pcb.getPassword())); + authorized = _principalDatabase.verifyPassword(username, pcb.getPassword()); } catch (AccountNotFoundException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index a79d993afc..7d25fb8c69 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -18,6 +18,7 @@ package org.apache.qpid.server.management; import org.apache.qpid.AMQException; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; import org.apache.log4j.Logger; import javax.management.remote.MBeanServerForwarder; @@ -122,8 +123,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler Principal principal = principals.iterator().next(); String identity = principal.getName(); + if (isAdminMethod(args)) + { + if (isAdmin(identity)) + { + return method.invoke(mbs, args); + } + else + { + throw new SecurityException("Access denied"); + } + } + // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAdmin(identity) || isAllowedToModify(identity)) + if (isAllowedToModify(identity)) { return method.invoke(mbs, args); } @@ -138,6 +151,41 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler throw new SecurityException("Access denied"); } + private boolean isAdminMethod(Object[] args) + { + if (args[0] instanceof ObjectName) + { + String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + return object.getCanonicalName().contains("UserManagement"); + } + else + { + return false; + } + } + + try + { + MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); + if (mbeanInfo != null) + { + return mbeanInfo.getClassName().equals("org.apache.qpid.server.security.access.AMQUserManagementMBean"); + } + } + catch (JMException ex) + { + return false; + } + } + + return false; + } + // Initialises the user roles public static void setAccessRights(Properties accessRights) { @@ -155,7 +203,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler private boolean isAllowedToModify(String userName) { - if (READWRITE.equals(_userRoles.getProperty(userName))) + if (ADMIN.equals(_userRoles.getProperty(userName)) + || READWRITE.equals(_userRoles.getProperty(userName))) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java index 5f9bc9ddad..d8d87ef881 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,6 +22,7 @@ package org.apache.qpid.server.management; import javax.management.JMException; import java.rmi.RemoteException; +import java.io.IOException; /** * Handles the registration (and unregistration and so on) of managed objects. @@ -37,7 +38,7 @@ import java.rmi.RemoteException; */ public interface ManagedObjectRegistry { - void start(); + void start() throws IOException; void registerObject(ManagedObject managedObject) throws JMException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java index 20f123179f..fbb80494c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -30,6 +30,7 @@ import org.apache.log4j.Logger; import org.apache.commons.configuration.ConfigurationException; import javax.management.JMException; +import javax.management.remote.JMXPrincipal; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; @@ -40,6 +41,7 @@ import javax.management.openmbean.OpenDataException; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.security.auth.login.AccountNotFoundException; +import javax.security.auth.Subject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -47,8 +49,11 @@ import java.io.FileOutputStream; import java.util.Properties; import java.util.List; import java.util.Enumeration; +import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import java.security.Principal; +import java.security.AccessControlContext; +import java.security.AccessController; /** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ @MBeanDescription("User Management Interface") @@ -250,8 +255,6 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana // Table of users // Username(string), Access rights Read,Write,Admin(bool,bool,bool) - reloadData(); - if (_userlistDataType == null) { _logger.warn("TabluarData not setup correctly"); @@ -411,7 +414,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana rights.renameTo(old); FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, ""); + _accessRights.store(output, "Last edited by user:" + getCurrentJMXUser()); output.close(); // Rename new file to main file @@ -434,6 +437,22 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } } + private String getCurrentJMXUser() + { + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + return "Unknown user principals were null"; + } + + Principal principal = principals.iterator().next(); + return principal.getName(); + } + /** * user=read user=write user=readwrite user=admin * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java index ce5e9fa4a7..ec7031534b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java @@ -28,6 +28,7 @@ import org.apache.qpid.AMQException; import javax.management.openmbean.TabularData; import javax.management.openmbean.CompositeData; import javax.management.JMException; +import javax.management.MBeanOperationInfo; import java.io.IOException; public interface UserManagement @@ -43,7 +44,8 @@ public interface UserManagement * * @return The result of the operation */ - @MBeanOperation(name = "setPassword", description = "Set password for user.") + @MBeanOperation(name = "setPassword", description = "Set password for user.", + impact = MBeanOperationInfo.ACTION) boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "password", description = "Password")char[] password); @@ -57,7 +59,8 @@ public interface UserManagement * * @return The result of the operation */ - @MBeanOperation(name = "setRights", description = "Set access rights for user.") + @MBeanOperation(name = "setRights", description = "Set access rights for user.", + impact = MBeanOperationInfo.ACTION) boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, @@ -74,7 +77,8 @@ public interface UserManagement * * @return The result of the operation */ - @MBeanOperation(name = "createUser", description = "Create new user from system.") + @MBeanOperation(name = "createUser", description = "Create new user from system.", + impact = MBeanOperationInfo.ACTION) boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "password", description = "Password")char[] password, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, @@ -88,7 +92,8 @@ public interface UserManagement * * @return The result of the operation */ - @MBeanOperation(name = "deleteUser", description = "Delete user from system.") + @MBeanOperation(name = "deleteUser", description = "Delete user from system.", + impact = MBeanOperationInfo.ACTION) boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); @@ -97,15 +102,17 @@ public interface UserManagement * * @return The result of the operation */ -// @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.") -// boolean reloadData(); + @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", + impact = MBeanOperationInfo.ACTION) + boolean reloadData(); /** * View users returns all the users that are currently available to the system. * * @return a table of users data (Username, read, write, admin) */ - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", + impact = MBeanOperationInfo.INFO) TabularData viewUsers(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index cd0a371b48..8ade3cdd98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -153,27 +153,19 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase * * @throws AccountNotFoundException if the principal cannot be found */ - public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException { - try - { - char[] pwd = lookupPassword(principal); - byte[] passwordBytes = password.getBytes(DEFAULT_ENCODING); + char[] pwd = lookupPassword(principal); - int index = 0; - boolean verified = true; + int index = 0; + boolean verified = true; - while (verified & index < passwordBytes.length) - { - verified = (pwd[index] == (char) passwordBytes[index]); - index++; - } - return verified; - } - catch (UnsupportedEncodingException e) + while (verified & index < password.length) { - return false; + verified = (pwd[index] == password[index]); + index++; } + return verified; } public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException @@ -590,7 +582,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase int index = 0; for (char c : _password) { - byteArray[index++] = (byte)c; + byteArray[index++] = (byte) c; } _encodedPassword = (new Base64()).encode(byteArray); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 90d08c963e..5170f6216c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -121,13 +121,13 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } - public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException { try { char[] pwd = lookupPassword(principal); - return compareCharArray(pwd, convertPassword(password)); + return compareCharArray(pwd, password); } catch (IOException e) { @@ -135,22 +135,6 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } - private char[] convertPassword(String password) throws UnsupportedEncodingException - { - byte[] passwdBytes = password.getBytes("utf-8"); - - char[] passwd = new char[passwdBytes.length]; - - int index = 0; - - for (byte b : passwdBytes) - { - passwd[index++] = (char) b; - } - - return passwd; - } - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { return false; // updates denied diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index 494d8e0bf4..a82f9ed40b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -55,7 +55,7 @@ public interface PrincipalDatabase * @return true if password is correct * @throws AccountNotFoundException if the principal cannot be found */ - boolean verifyPassword(String principal, String password) + boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index 74c330f606..49cd71e978 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -79,18 +79,12 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase } } - public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException { + //fixme this is not correct as toCharArray is not safe based on the type of string. char[] pwd = _users.getProperty(principal).toCharArray(); - try - { - return compareCharArray(pwd, convertPassword(password)); - } - catch (UnsupportedEncodingException e) - { - return false; - } + return compareCharArray(pwd, password); } public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException -- cgit v1.2.1 From 1edb77b98ecd6fc356fd5fc2e22afd470d7fbf2a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 24 Apr 2007 09:01:58 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-531832 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r530838 | ritchiem | 2007-04-20 17:03:10 +0100 (Fri, 20 Apr 2007) | 2 lines Added addition log when broker is ready to process. Updated HeapExhaustion - to use system.out.println so you can set amqj.logging.level=warn to speed up test. ........ r531437 | rgreig | 2007-04-23 12:23:39 +0100 (Mon, 23 Apr 2007) | 1 line QPID-394. Removed revision tags. ........ r531456 | bhupendrab | 2007-04-23 13:58:24 +0100 (Mon, 23 Apr 2007) | 1 line QPID-470 : Catching the security exception for users, which have no access to management console ........ r531458 | bhupendrab | 2007-04-23 14:13:28 +0100 (Mon, 23 Apr 2007) | 1 line QPID-445 : Fixed the ClassCastException ........ r531512 | ritchiem | 2007-04-23 16:52:43 +0100 (Mon, 23 Apr 2007) | 3 lines QPID-472 - Creation of TemporaryQueues will not guarantee unique queue names if created rapidly. Updated TemporaryQueueTest.java so that it checks Headers/Queue/Topic for unroutable/mandatory messages beig returned. ........ r531513 | ritchiem | 2007-04-23 16:54:15 +0100 (Mon, 23 Apr 2007) | 1 line QPID-436 - topic exchange doesn't obey the mandatory flag ........ r531515 | ritchiem | 2007-04-23 16:58:04 +0100 (Mon, 23 Apr 2007) | 2 lines Update to system test so that the run as part of the build process as they were not running. Change to AMQMessage to ensure that the TxAckTest passes. Was failing as the reference count was being changed out of the increment/decrementReference methods ........ r531517 | ritchiem | 2007-04-23 16:59:59 +0100 (Mon, 23 Apr 2007) | 1 line Comment updates on the origin of the tests ........ r531518 | ritchiem | 2007-04-23 17:02:41 +0100 (Mon, 23 Apr 2007) | 1 line White Space changes ........ r531524 | bhupendrab | 2007-04-23 17:28:00 +0100 (Mon, 23 Apr 2007) | 1 line QPID-445 ........ r531526 | ritchiem | 2007-04-23 17:38:24 +0100 (Mon, 23 Apr 2007) | 3 lines QPID-290 - Java broker does not honor maximum number of channels threshold Applied patch from Nuno Santos ........ r531527 | ritchiem | 2007-04-23 17:38:44 +0100 (Mon, 23 Apr 2007) | 1 line ResetMessageListenerTest - needs to have IMMEDIATE_PREFETCH = true. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@531842 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 10 +- .../qpid/server/exchange/DestWildExchange.java | 47 ++-- .../qpid/server/filter/ArithmeticExpression.java | 267 +++++++++++++-------- .../qpid/server/filter/BinaryExpression.java | 41 ++-- .../qpid/server/filter/BooleanExpression.java | 7 +- .../qpid/server/filter/ComparisonExpression.java | 131 +++++----- .../org/apache/qpid/server/filter/Expression.java | 7 +- .../apache/qpid/server/filter/LogicExpression.java | 104 ++++---- .../management/MBeanInvocationHandlerImpl.java | 50 +--- .../server/protocol/AMQMinaProtocolSession.java | 15 +- .../org/apache/qpid/server/queue/AMQMessage.java | 2 +- .../org/apache/qpid/server/queue/AMQQueue.java | 2 +- .../server/security/access/UserManagement.java | 4 +- 13 files changed, 377 insertions(+), 310 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 1e5f56fe3a..c345b43aeb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -373,6 +373,7 @@ public class Main } acceptor.bind(bindAddress, handler, sconfig); + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -381,14 +382,21 @@ public class Main AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); try { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); + } catch (IOException e) { _brokerLogger.error("Unable to listen on SSL port: " + e, e); } } + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 8a50e93bf9..605a4bcb61 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -57,19 +57,16 @@ public class DestWildExchange extends AbstractExchange private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); - /** - * DestWildExchangeMBean class implements the management interface for the - * Topic exchanges. - */ + /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */ @MBeanDescription("Management Bean for Topic Exchange") private final class DestWildExchangeMBean extends ExchangeMBean { // open mbean data types for representing exchange bindings - private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; - private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; + private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; + private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; private OpenType[] _bindingItemTypes = new OpenType[2]; - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; + private CompositeType _bindingDataType = null; + private TabularType _bindinglistDataType = null; private TabularDataSupport _bindingList = null; @MBeanConstructor("Creates an MBean for AMQ topic exchange") @@ -80,22 +77,18 @@ public class DestWildExchange extends AbstractExchange init(); } - /** - * initialises the OpenType objects. - */ + /** initialises the OpenType objects. */ private void init() throws OpenDataException { _bindingItemTypes[0] = SimpleType.STRING; _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindingItemNames, _bindingItemNames, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, _bindingItemIndexNames); } - /** - * returns exchange bindings in tabular form - */ + /** returns exchange bindings in tabular form */ public TabularData bindings() throws OpenDataException { _bindingList = new TabularDataSupport(_bindinglistDataType); @@ -122,7 +115,9 @@ public class DestWildExchange extends AbstractExchange { AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) + { throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } try { @@ -159,7 +154,7 @@ public class DestWildExchange extends AbstractExchange { queueList.add(queue); } - else if(_logger.isDebugEnabled()) + else if (_logger.isDebugEnabled()) { _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); } @@ -176,10 +171,18 @@ public class DestWildExchange extends AbstractExchange // TODO: add support for the immediate flag if (queues == null) { - _logger.warn("No queues found for routing key " + routingKey); - _logger.warn("Routing map contains: " + _routingKey2queues); - //todo Check for valid topic - mritchie - return; + if (info.isMandatory()) + { + String msg = "Topic " + routingKey + " is not known to " + this; + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn("No queues found for routing key " + routingKey); + _logger.warn("Routing map contains: " + _routingKey2queues); + //todo Check for valid topic - mritchie + return; + } } for (AMQQueue q : queues) @@ -245,7 +248,7 @@ public class DestWildExchange extends AbstractExchange } } - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws AMQException { try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index 1b3b116fd0..138d4155b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,16 +21,14 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // - import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; /** * An expression which performs an operation on two expression values - * - * @version $Revision$ */ -public abstract class ArithmeticExpression extends BinaryExpression { +public abstract class ArithmeticExpression extends BinaryExpression +{ protected static final int INTEGER = 1; protected static final int LONG = 2; @@ -39,156 +38,213 @@ public abstract class ArithmeticExpression extends BinaryExpression { * @param left * @param right */ - public ArithmeticExpression(Expression left, Expression right) { + public ArithmeticExpression(Expression left, Expression right) + { super(left, right); } - public static Expression createPlus(Expression left, Expression right) { - return new ArithmeticExpression(left, right) { - protected Object evaluate(Object lvalue, Object rvalue) { - if (lvalue instanceof String) { - String text = (String) lvalue; - String answer = text + rvalue; - return answer; + public static Expression createPlus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof String) + { + String text = (String) lvalue; + String answer = text + rvalue; + + return answer; + } + else if (lvalue instanceof Number) + { + return plus((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); } - else if (lvalue instanceof Number) { - return plus((Number) lvalue, asNumber(rvalue)); + + public String getExpressionSymbol() + { + return "+"; } - throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); - } + }; + } - public String getExpressionSymbol() + public static Expression createMinus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) { - return "+"; - } - }; - } + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return minus((Number) lvalue, asNumber(rvalue)); + } - public static Expression createMinus(Expression left, Expression right) { - return new ArithmeticExpression(left, right) { - protected Object evaluate(Object lvalue, Object rvalue) { - if (lvalue instanceof Number) { - return minus((Number) lvalue, asNumber(rvalue)); + throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); } - throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); - } - public String getExpressionSymbol() { - return "-"; - } - }; + public String getExpressionSymbol() + { + return "-"; + } + }; } - public static Expression createMultiply(Expression left, Expression right) { - return new ArithmeticExpression(left, right) { + public static Expression createMultiply(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return multiply((Number) lvalue, asNumber(rvalue)); + } - protected Object evaluate(Object lvalue, Object rvalue) { - if (lvalue instanceof Number) { - return multiply((Number) lvalue, asNumber(rvalue)); + throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); } - throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); - } - public String getExpressionSymbol() { - return "*"; - } - }; + public String getExpressionSymbol() + { + return "*"; + } + }; } - public static Expression createDivide(Expression left, Expression right) { - return new ArithmeticExpression(left, right) { + public static Expression createDivide(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { - protected Object evaluate(Object lvalue, Object rvalue) { - if (lvalue instanceof Number) { - return divide((Number) lvalue, asNumber(rvalue)); + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return divide((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); } - throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); - } - public String getExpressionSymbol() { - return "/"; - } - }; + public String getExpressionSymbol() + { + return "/"; + } + }; } - public static Expression createMod(Expression left, Expression right) { - return new ArithmeticExpression(left, right) { + public static Expression createMod(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return mod((Number) lvalue, asNumber(rvalue)); + } - protected Object evaluate(Object lvalue, Object rvalue) { - if (lvalue instanceof Number) { - return mod((Number) lvalue, asNumber(rvalue)); + throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); } - throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); - } - public String getExpressionSymbol() { - return "%"; - } - }; + public String getExpressionSymbol() + { + return "%"; + } + }; } - protected Number plus(Number left, Number right) { - switch (numberType(left, right)) { - case INTEGER: - return new Integer(left.intValue() + right.intValue()); - case LONG: - return new Long(left.longValue() + right.longValue()); - default: - return new Double(left.doubleValue() + right.doubleValue()); + protected Number plus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() + right.intValue()); + + case LONG: + return new Long(left.longValue() + right.longValue()); + + default: + return new Double(left.doubleValue() + right.doubleValue()); } } - protected Number minus(Number left, Number right) { - switch (numberType(left, right)) { - case INTEGER: - return new Integer(left.intValue() - right.intValue()); - case LONG: - return new Long(left.longValue() - right.longValue()); - default: - return new Double(left.doubleValue() - right.doubleValue()); + protected Number minus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() - right.intValue()); + + case LONG: + return new Long(left.longValue() - right.longValue()); + + default: + return new Double(left.doubleValue() - right.doubleValue()); } } - protected Number multiply(Number left, Number right) { - switch (numberType(left, right)) { - case INTEGER: - return new Integer(left.intValue() * right.intValue()); - case LONG: - return new Long(left.longValue() * right.longValue()); - default: - return new Double(left.doubleValue() * right.doubleValue()); + protected Number multiply(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() * right.intValue()); + + case LONG: + return new Long(left.longValue() * right.longValue()); + + default: + return new Double(left.doubleValue() * right.doubleValue()); } } - protected Number divide(Number left, Number right) { + protected Number divide(Number left, Number right) + { return new Double(left.doubleValue() / right.doubleValue()); } - protected Number mod(Number left, Number right) { + protected Number mod(Number left, Number right) + { return new Double(left.doubleValue() % right.doubleValue()); } - private int numberType(Number left, Number right) { - if (isDouble(left) || isDouble(right)) { + private int numberType(Number left, Number right) + { + if (isDouble(left) || isDouble(right)) + { return DOUBLE; } - else if (left instanceof Long || right instanceof Long) { + else if ((left instanceof Long) || (right instanceof Long)) + { return LONG; } - else { + else + { return INTEGER; } } - private boolean isDouble(Number n) { - return n instanceof Float || n instanceof Double; + private boolean isDouble(Number n) + { + return (n instanceof Float) || (n instanceof Double); } - protected Number asNumber(Object value) { - if (value instanceof Number) { + protected Number asNumber(Object value) + { + if (value instanceof Number) + { return (Number) value; } - else { + else + { throw new RuntimeException("Cannot convert value: " + value + " into a number"); } } @@ -196,22 +252,25 @@ public abstract class ArithmeticExpression extends BinaryExpression { public Object evaluate(AMQMessage message) throws AMQException { Object lvalue = left.evaluate(message); - if (lvalue == null) { + if (lvalue == null) + { return null; } + Object rvalue = right.evaluate(message); - if (rvalue == null) { + if (rvalue == null) + { return null; } + return evaluate(lvalue, rvalue); } - /** * @param lvalue * @param rvalue * @return */ - abstract protected Object evaluate(Object lvalue, Object rvalue); + protected abstract Object evaluate(Object lvalue, Object rvalue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java index 4256ab9189..1a1024bd2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,35 +21,35 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // - - /** * An expression which performs an operation on two expression values. - * - * @version $Revision$ */ -abstract public class BinaryExpression implements Expression { +public abstract class BinaryExpression implements Expression +{ protected Expression left; protected Expression right; - public BinaryExpression(Expression left, Expression right) { + public BinaryExpression(Expression left, Expression right) + { this.left = left; this.right = right; } - public Expression getLeft() { + public Expression getLeft() + { return left; } - public Expression getRight() { + public Expression getRight() + { return right; } - /** * @see java.lang.Object#toString() */ - public String toString() { + public String toString() + { return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; } @@ -57,7 +58,8 @@ abstract public class BinaryExpression implements Expression { * * @see java.lang.Object#hashCode() */ - public int hashCode() { + public int hashCode() + { return toString().hashCode(); } @@ -66,11 +68,14 @@ abstract public class BinaryExpression implements Expression { * * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object o) { + public boolean equals(Object o) + { - if (o == null || !this.getClass().equals(o.getClass())) { + if ((o == null) || !this.getClass().equals(o.getClass())) + { return false; } + return toString().equals(o.toString()); } @@ -81,20 +86,22 @@ abstract public class BinaryExpression implements Expression { * * @return */ - abstract public String getExpressionSymbol(); + public abstract String getExpressionSymbol(); /** * @param expression */ - public void setRight(Expression expression) { + public void setRight(Expression expression) + { right = expression; } /** * @param expression */ - public void setLeft(Expression expression) { + public void setLeft(Expression expression) + { left = expression; } - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index 122527d4f3..0d5c5009f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,18 +21,12 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // - import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; - - - /** * A BooleanExpression is an expression that always * produces a Boolean result. - * - * @version $Revision$ */ public interface BooleanExpression extends Expression { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index cedb8d7ca8..606a59e0fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -32,8 +33,6 @@ import org.apache.qpid.server.queue.AMQMessage; /** * A filter performing a comparison of two objects - * - * @version $Revision$ */ public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { @@ -153,7 +152,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { return Boolean.FALSE; - //throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); + // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); } return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; @@ -240,42 +239,42 @@ public abstract class ComparisonExpression extends BinaryExpression implements B private static BooleanExpression doCreateEqual(Expression left, Expression right) { return new ComparisonExpression(left, right) - { - - public Object evaluate(AMQMessage message) throws AMQException { - Object lv = left.evaluate(message); - Object rv = right.evaluate(message); - // Iff one of the values is null - if ((lv == null) ^ (rv == null)) + public Object evaluate(AMQMessage message) throws AMQException { + Object lv = left.evaluate(message); + Object rv = right.evaluate(message); + + // Iff one of the values is null + if ((lv == null) ^ (rv == null)) + { + return Boolean.FALSE; + } + + if ((lv == rv) || lv.equals(rv)) + { + return Boolean.TRUE; + } + + if ((lv instanceof Comparable) && (rv instanceof Comparable)) + { + return compare((Comparable) lv, (Comparable) rv); + } + return Boolean.FALSE; } - if ((lv == rv) || lv.equals(rv)) + protected boolean asBoolean(int answer) { - return Boolean.TRUE; + return answer == 0; } - if ((lv instanceof Comparable) && (rv instanceof Comparable)) + public String getExpressionSymbol() { - return compare((Comparable) lv, (Comparable) rv); + return "="; } - - return Boolean.FALSE; - } - - protected boolean asBoolean(int answer) - { - return answer == 0; - } - - public String getExpressionSymbol() - { - return "="; - } - }; + }; } public static BooleanExpression createGreaterThan(final Expression left, final Expression right) @@ -284,17 +283,17 @@ public abstract class ComparisonExpression extends BinaryExpression implements B checkLessThanOperand(right); return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) { - return answer > 0; - } + protected boolean asBoolean(int answer) + { + return answer > 0; + } - public String getExpressionSymbol() - { - return ">"; - } - }; + public String getExpressionSymbol() + { + return ">"; + } + }; } public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) @@ -303,17 +302,17 @@ public abstract class ComparisonExpression extends BinaryExpression implements B checkLessThanOperand(right); return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) { - return answer >= 0; - } + protected boolean asBoolean(int answer) + { + return answer >= 0; + } - public String getExpressionSymbol() - { - return ">="; - } - }; + public String getExpressionSymbol() + { + return ">="; + } + }; } public static BooleanExpression createLessThan(final Expression left, final Expression right) @@ -322,19 +321,19 @@ public abstract class ComparisonExpression extends BinaryExpression implements B checkLessThanOperand(right); return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) { - return answer < 0; - } - public String getExpressionSymbol() - { - return "<"; - } + protected boolean asBoolean(int answer) + { + return answer < 0; + } + + public String getExpressionSymbol() + { + return "<"; + } - }; + }; } public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) @@ -343,18 +342,18 @@ public abstract class ComparisonExpression extends BinaryExpression implements B checkLessThanOperand(right); return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) { - return answer <= 0; - } - public String getExpressionSymbol() - { - return "<="; - } - }; + protected boolean asBoolean(int answer) + { + return answer <= 0; + } + + public String getExpressionSymbol() + { + return "<="; + } + }; } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index 4a2130e767..cb40a32290 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -15,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.qpid.server.filter; // // Based on like named file from r450141 of the Apache ActiveMQ project @@ -24,11 +24,8 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; - /** * Represents an expression - * - * @version $Revision$ */ public interface Expression { @@ -37,5 +34,5 @@ public interface Expression * @return the value of this expression */ public Object evaluate(AMQMessage message) throws AMQException; - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index dea6092b8a..a90775a186 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,69 +26,86 @@ import org.apache.qpid.server.queue.AMQMessage; /** * A filter performing a comparison of two objects - * - * @version $Revision$ */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { - - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) { - - public Object evaluate(AMQMessage message) throws AMQException { - - Boolean lv = (Boolean) left.evaluate(message); - // Can we do an OR shortcut?? - if (lv !=null && lv.booleanValue()) { - return Boolean.TRUE; +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression +{ + + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new LogicExpression(lvalue, rvalue) + { + + public Object evaluate(AMQMessage message) throws AMQException + { + + Boolean lv = (Boolean) left.evaluate(message); + // Can we do an OR shortcut?? + if ((lv != null) && lv.booleanValue()) + { + return Boolean.TRUE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "OR"; } - - Boolean rv = (Boolean) right.evaluate(message); - return rv==null ? null : rv; - } - - public String getExpressionSymbol() { - return "OR"; - } - }; + }; } - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) { + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new LogicExpression(lvalue, rvalue) + { - public Object evaluate(AMQMessage message) throws AMQException { + public Object evaluate(AMQMessage message) throws AMQException + { - Boolean lv = (Boolean) left.evaluate(message); + Boolean lv = (Boolean) left.evaluate(message); - // Can we do an AND shortcut?? - if (lv == null) - return null; - if (!lv.booleanValue()) { - return Boolean.FALSE; - } + // Can we do an AND shortcut?? + if (lv == null) + { + return null; + } + + if (!lv.booleanValue()) + { + return Boolean.FALSE; + } + + Boolean rv = (Boolean) right.evaluate(message); - Boolean rv = (Boolean) right.evaluate(message); - return rv == null ? null : rv; - } + return (rv == null) ? null : rv; + } - public String getExpressionSymbol() { - return "AND"; - } - }; + public String getExpressionSymbol() + { + return "AND"; + } + }; } /** * @param left * @param right */ - public LogicExpression(BooleanExpression left, BooleanExpression right) { + public LogicExpression(BooleanExpression left, BooleanExpression right) + { super(left, right); } - abstract public Object evaluate(AMQMessage message) throws AMQException; + public abstract Object evaluate(AMQMessage message) throws AMQException; - public boolean matches(AMQMessage message) throws AMQException { + public boolean matches(AMQMessage message) throws AMQException + { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + + return (object != null) && (object == Boolean.TRUE); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 7d25fb8c69..3ab23e8b46 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -17,8 +17,7 @@ */ package org.apache.qpid.server.management; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.security.access.AMQUserManagementMBean; +import org.apache.qpid.server.security.access.UserManagement; import org.apache.log4j.Logger; import javax.management.remote.MBeanServerForwarder; @@ -37,12 +36,6 @@ import java.security.Principal; import java.security.AccessControlContext; import java.util.Set; import java.util.Properties; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentHashMap; -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.io.FileInputStream; /** * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements @@ -110,6 +103,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler // Restrict access to "createMBean" and "unregisterMBean" to any user if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) { + _logger.debug("User trying to create or unregister an MBean"); throw new SecurityException("Access denied"); } @@ -155,32 +149,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler { if (args[0] instanceof ObjectName) { - String mbeanMethod = (args.length > 1) ? (String) args[1] : null; - if (mbeanMethod == null) - { - if (args[0] instanceof ObjectName) - { - ObjectName object = (ObjectName) args[0]; - return object.getCanonicalName().contains("UserManagement"); - } - else - { - return false; - } - } - - try - { - MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); - if (mbeanInfo != null) - { - return mbeanInfo.getClassName().equals("org.apache.qpid.server.security.access.AMQUserManagementMBean"); - } - } - catch (JMException ex) - { - return false; - } + ObjectName object = (ObjectName) args[0]; + return UserManagement.TYPE.equals(object.getKeyProperty("type")); } return false; @@ -223,16 +193,16 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler private boolean isReadOnlyMethod(Method method, Object[] args) { String methodName = method.getName(); - if (methodName.equals("queryMBeans") || - methodName.equals("getDefaultDomain") || - methodName.equals("getMBeanInfo") || - methodName.equals("getAttribute") || - methodName.equals("getAttributes")) + if (methodName.startsWith("query") || methodName.startsWith("get")) { return true; } + else if (methodName.startsWith("set")) + { + return false; + } - if (args[0] instanceof ObjectName) + if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) { String mbeanMethod = (args.length > 1) ? (String) args[1] : null; if (mbeanMethod == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 2e62c2f1e4..3162efa183 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -463,7 +463,17 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, throw new AMQException("Session is marked awaiting channel close"); } - _channelMap.put(channelId, channel); + if (_channelMap.size() == _maxNoOfChannels) + { + String errorMessage = toString() + ": maximum number of channels has been reached (" + + _maxNoOfChannels + "); can't create channel"; + _logger.error(errorMessage); + throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); + } + else + { + _channelMap.put(channel.getChannelId(), channel); + } if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) { @@ -755,8 +765,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { return _authorizedID; } + public String getClientVersion() { - return _clientVersion == null ? null : _clientVersion.toString(); + return _clientVersion == null ? null : _clientVersion.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index e19038504f..955aaa6acb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -366,7 +366,7 @@ public class AMQMessage */ public AMQMessage takeReference() { - _referenceCount.incrementAndGet(); + incrementReference();// _referenceCount.incrementAndGet(); return this; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 65d5906d05..0adf6153f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -615,7 +615,7 @@ public class AMQQueue implements Managable, Comparable } catch (MessageCleanupException e) { - //Message was dequeued, but could notthen be deleted + //Message was dequeued, but could not then be deleted //though it is no longer referenced. This should be very //rare and can be detected and cleaned up on recovery or //done through some form of manual intervention. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java index ec7031534b..b8762aa43b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java @@ -63,7 +63,7 @@ public interface UserManagement impact = MBeanOperationInfo.ACTION) boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); /** @@ -82,7 +82,7 @@ public interface UserManagement boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "password", description = "Password")char[] password, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); /** -- cgit v1.2.1 From 977abc4f3ee3a4b9d34a325c9cfb6ea15bc5bf4e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 26 Apr 2007 15:28:48 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-532465,532467-532764 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r531859 | ritchiem | 2007-04-24 11:06:41 +0100 (Tue, 24 Apr 2007) | 1 line Defaulted the use of JMX SASL security to false. As this requries the jmxremote.jar from sun which is not Apache license friendly. ........ r531865 | ritchiem | 2007-04-24 11:24:51 +0100 (Tue, 24 Apr 2007) | 1 line Defaulted the use of management.security-enabled security to false. As this requires the jmxremote.jar from sun which is not Apache license friendly. ........ r531908 | bhupendrab | 2007-04-24 13:38:18 +0100 (Tue, 24 Apr 2007) | 1 line Management Console sasl changes ........ r531917 | bhupendrab | 2007-04-24 14:03:55 +0100 (Tue, 24 Apr 2007) | 1 line Added display of build and release versions in Help->About ........ r531937 | ritchiem | 2007-04-24 14:42:03 +0100 (Tue, 24 Apr 2007) | 1 line Reduced logging on requeue. ........ r531989 | bhupendrab | 2007-04-24 16:49:03 +0100 (Tue, 24 Apr 2007) | 1 line Added connection exception handling and refactored the action classes ........ r532002 | bhupendrab | 2007-04-24 17:35:43 +0100 (Tue, 24 Apr 2007) | 1 line Management Console SASL changes ........ r532372 | bhupendrab | 2007-04-25 15:46:03 +0100 (Wed, 25 Apr 2007) | 1 line Made the return type of getTestMessage() to a generic type for subclass to override. ........ r532728 | ritchiem | 2007-04-26 13:38:41 +0100 (Thu, 26 Apr 2007) | 3 lines QPID-292 - Authentication not handled correctly. Copied handling from SecureOkMethod handler. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@532779 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQChannel.java | 14 +++++--------- .../handler/ConnectionStartOkMethodHandler.java | 19 +++++++++++++++++-- .../server/management/JMXManagedObjectRegistry.java | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 97c95dae5e..918b5fc176 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -431,24 +431,20 @@ public class AMQChannel */ public void requeue() throws AMQException { - if (_log.isInfoEnabled()) - { - _log.info("Requeuing for " + toString()); - } - // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - if (_log.isDebugEnabled()) - { - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages."); - } // Deliver these messages out of the transaction as their delivery was never // part of the transaction only the receive. TransactionalContext deliveryContext = null; if (!messagesToBeDelivered.isEmpty()) { + if (_log.isInfoEnabled()) + { + _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + } + if (!(_txnContext instanceof NonTransactionalContext)) { // if (_nonTransactedContext == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 4734143497..29d6c26b66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -30,6 +30,7 @@ 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.framing.ConnectionCloseBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -93,10 +94,24 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< switch (authResult.status) { case ERROR: - throw new AMQException("Authentication failed"); + _logger.info("Authentication failed"); + stateManager.changeState(AMQState.CONNECTION_CLOSING); + // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) + // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. + // Be aware of possible changes to parameter order as versions change. + AMQFrame close = ConnectionCloseBody.createAMQFrame(0, + (byte) 8, (byte) 0, // AMQP version (major, minor) + ConnectionCloseBody.getClazz((byte) 8, (byte) 0), // classId + ConnectionCloseBody.getMethod((byte) 8, (byte) 0), // methodId + AMQConstant.NOT_ALLOWED.getCode(), // replyCode + AMQConstant.NOT_ALLOWED.getName()); // replyText + session.writeFrame(close); + disposeSaslServer(session); + break; + case SUCCESS: _logger.info("Connected as: " + ss.getAuthorizationID()); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index a14d4214e3..f277398b50 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -94,7 +94,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", true); + boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); int port = appRegistry.getConfiguration().getInt("management.jmxport", 8999); if (security) -- cgit v1.2.1 From 3fb59b5bfef97f2a46b5a47e5beaed547e1fc14c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Apr 2007 12:48:51 +0000 Subject: Merged revisions 533075-533079 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r533075 | ritchiem | 2007-04-27 13:27:19 +0100 (Fri, 27 Apr 2007) | 2 lines QPID-473 Base64MD5PrincipalDatabase doesn't check password changes were applied to disk before storing in memory Reversed the effects of the requested change if the changes cannot be persisted to disk ........ r533077 | ritchiem | 2007-04-27 13:29:52 +0100 (Fri, 27 Apr 2007) | 3 lines Bin Updates: Qpid-Run removed new bash 3.x feature += replaced with option="${value1} ${value2}" constructs to support older bash 2.x renamed passwd qpid-passwd and fixed classpath loading errors. Moved bdbbackup script to live with the bdb module. ........ r533078 | ritchiem | 2007-04-27 13:30:07 +0100 (Fri, 27 Apr 2007) | 1 line Updated PrincipalDatabase implementations to return empty strings rather than null. As this causes NPE on MC. ........ r533079 | ritchiem | 2007-04-27 13:31:03 +0100 (Fri, 27 Apr 2007) | 1 line Updated MLT to have variables that define the BROKER and VHOST used and White space ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@533083 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 22 +++++----------------- .../PlainPasswordFilePrincipalDatabase.java | 3 ++- .../auth/database/PropertiesPrincipalDatabase.java | 3 ++- 3 files changed, 9 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 8ade3cdd98..10adfdd9fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -182,6 +182,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase try { _userUpdate.lock(); + char[] orig = user.getPassword(); user.setPassword(password); try @@ -192,6 +193,8 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { _logger.error("Unable to save password file, password change for user'" + principal + "' will revert at restart"); + //revert the password change + user.setPassword(orig); return false; } return true; @@ -210,22 +213,6 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - private char[] convertPassword(String password) throws UnsupportedEncodingException - { - byte[] passwdBytes = password.getBytes(DEFAULT_ENCODING); - - char[] passwd = new char[passwdBytes.length]; - - int index = 0; - - for (byte b : passwdBytes) - { - passwd[index++] = (char) b; - } - - return passwd; - } - public boolean createPrincipal(Principal principal, char[] password) { if (_users.get(principal.getName()) != null) @@ -247,9 +234,10 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } catch (IOException e) { + //remove the use on failure. + _users.remove(user.getName()); return false; } - } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 5170f6216c..c49f4e2a33 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -39,6 +39,7 @@ import java.util.regex.Pattern; import java.util.Map; import java.util.HashMap; import java.util.List; +import java.util.LinkedList; import java.security.Principal; /** @@ -157,7 +158,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase public List getUsers() { - return null; //todo + return new LinkedList(); //todo } public Principal getUser(String username) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index 49cd71e978..73d58ca489 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -31,6 +31,7 @@ import java.util.Properties; import java.util.Map; import java.util.HashMap; import java.util.List; +import java.util.LinkedList; import java.security.Principal; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -142,7 +143,7 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase public List getUsers() { - return null; //todo + return new LinkedList(); //todo } public Principal getUser(String username) -- cgit v1.2.1 From 3f3a7f6af8d3ceb4b48fdea7605a57b5f7bff2ee Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 2 May 2007 16:47:36 +0000 Subject: Removed accidentally included copyright and author tags. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534539 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/filter/ArithmeticExpression.java | 1 - .../src/main/java/org/apache/qpid/server/filter/BinaryExpression.java | 1 - .../src/main/java/org/apache/qpid/server/filter/BooleanExpression.java | 1 - .../main/java/org/apache/qpid/server/filter/ComparisonExpression.java | 1 - .../broker/src/main/java/org/apache/qpid/server/filter/Expression.java | 1 - .../src/main/java/org/apache/qpid/server/filter/LogicExpression.java | 1 - 6 files changed, 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index 138d4155b1..fb5220f4da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java index 1a1024bd2b..024257bea9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index 0d5c5009f7..e28ff79820 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 606a59e0fa..72a9ef7969 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index cb40a32290..5f646c15db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index a90775a186..c8cbdb2125 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /** * * Licensed to the Apache Software Foundation (ASF) under one or more -- cgit v1.2.1 From 5338bcbb94ad3227b4689eacaec142945218eb1a Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Wed, 2 May 2007 16:49:03 +0000 Subject: I am commiting the patch supplied by Arnaud Simon. This patch contains support for dtx. Currently there is one test case failing. I will try to fix it, if not Arnuad will provide a patch soon git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534541 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 19 +- .../java/org/apache/qpid/server/AMQChannel.java | 14 +- .../configuration/VirtualHostConfiguration.java | 93 ++-- .../server/exception/CommandInvalidException.java | 59 +++ .../server/exception/InternalErrorException.java | 57 +++ .../qpid/server/exception/InvalidXidException.java | 72 +++ .../exception/MessageAlreadyStagedException.java | 58 +++ .../exception/MessageDoesntExistException.java | 58 +++ .../server/exception/NotPreparedException.java | 58 +++ .../exception/QueueAlreadyExistsException.java | 58 +++ .../exception/QueueDoesntExistException.java | 58 +++ .../qpid/server/exception/UnknownXidException.java | 72 +++ .../server/exchange/DefaultExchangeRegistry.java | 19 +- .../qpid/server/handler/ChannelOpenHandler.java | 3 +- .../qpid/server/handler/QueueDeclareHandler.java | 12 +- .../qpid/server/handler/QueueDeleteHandler.java | 12 +- .../server/messageStore/MemoryMessageStore.java | 169 +++++++ .../qpid/server/messageStore/MessageStore.java | 270 +++++++++++ .../qpid/server/messageStore/StorableMessage.java | 116 +++++ .../qpid/server/messageStore/StorableQueue.java | 75 +++ .../org/apache/qpid/server/queue/AMQMessage.java | 254 +++++++--- .../apache/qpid/server/queue/AMQMessageHandle.java | 3 + .../org/apache/qpid/server/queue/AMQQueue.java | 252 +++++++--- .../qpid/server/queue/InMemoryMessageHandle.java | 70 ++- .../qpid/server/queue/MessageHandleFactory.java | 8 +- .../apache/qpid/server/queue/QueueRegistry.java | 1 + .../qpid/server/queue/StorableMessageHandle.java | 215 +++++++++ .../server/queue/WeakReferenceMessageHandle.java | 6 + .../org/apache/qpid/server/txn/DequeueRecord.java | 59 +++ .../txn/DistributedTransactionalContext.java | 248 ++++++++++ .../org/apache/qpid/server/txn/EnqueueRecord.java | 79 ++++ .../qpid/server/txn/MemoryTransactionManager.java | 125 +++++ .../qpid/server/txn/NonTransactionalContext.java | 6 +- .../org/apache/qpid/server/txn/Transaction.java | 35 ++ .../apache/qpid/server/txn/TransactionManager.java | 215 +++++++++ .../apache/qpid/server/txn/TransactionRecord.java | 72 +++ .../java/org/apache/qpid/server/txn/XAFlag.java | 50 ++ .../java/org/apache/qpid/server/txn/XidImpl.java | 210 +++++++++ .../qpid/server/util/NullApplicationRegistry.java | 3 +- .../qpid/server/virtualhost/VirtualHost.java | 521 +++++++++++---------- 40 files changed, 3333 insertions(+), 451 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index d31359b019..ae1cf43f6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -58,8 +58,10 @@ import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.QueueAlreadyExistsException; /** * This MBean implements the broker management interface and exposes the @@ -100,7 +102,6 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param exchangeName * @param type * @param durable - * @param autoDelete * @throws JMException */ public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException @@ -158,7 +159,6 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param queueName * @param durable * @param owner - * @param autoDelete * @throws JMException */ public void createNewQueue(String queueName, String owner, boolean durable) throws JMException @@ -180,7 +180,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue); + try + { + _messageStore.createQueue(queue); + } catch (Exception e) + { + throw new JMException("problem creating queue " + queue.getName()); + } } Configuration virtualHostDefaultQueueConfiguration = @@ -222,10 +228,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.removeQueue(new AMQShortString(queueName)); - + _messageStore.destroyQueue(queue); } - catch (AMQException ex) + catch (Exception ex) { JMException jme = new JMException(ex.getMessage()); jme.initCause(ex); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 918b5fc176..9711bbf4d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -47,11 +47,9 @@ 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.queue.Subscription; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.txn.*; public class AMQChannel { @@ -93,6 +91,8 @@ public class AMQChannel private final MessageStore _messageStore; + private final TransactionManager _transactionManager; + private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); private final AtomicBoolean _suspended = new AtomicBoolean(false); @@ -116,7 +116,8 @@ public class AMQChannel //Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore, MessageRouter exchanges) + + public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, MessageStore messageStore, MessageRouter exchanges) throws AMQException { _session = session; @@ -125,6 +126,7 @@ public class AMQChannel _prefetch_HighWaterMark = DEFAULT_PREFETCH; _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; _messageStore = messageStore; + _transactionManager = transactionManager; _exchanges = exchanges; // by default the session is non-transactional _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); @@ -133,7 +135,7 @@ public class AMQChannel /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { - _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); + _txnContext = new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); } public boolean isTransactional() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 8573902af4..e337b26b33 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -36,8 +36,10 @@ import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.QueueAlreadyExistsException; public class VirtualHostConfiguration { @@ -48,7 +50,9 @@ public class VirtualHostConfiguration private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; - public VirtualHostConfiguration(String configFile) throws ConfigurationException + public VirtualHostConfiguration(String configFile) + throws + ConfigurationException { _logger.info("Loading Config file:" + configFile); @@ -57,24 +61,25 @@ public class VirtualHostConfiguration } - - private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException + private void configureVirtualHost(String virtualHostName, Configuration configuration) + throws + ConfigurationException, + AMQException { - _logger.debug("Loding configuration for virtaulhost: "+virtualHostName); + _logger.debug("Loding configuration for virtaulhost: " + virtualHostName); VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); - - if(virtualHost == null) + if (virtualHost == null) { throw new ConfigurationException("Unknown virtual host: " + virtualHostName); } List exchangeNames = configuration.getList("exchanges.exchange.name"); - for(Object exchangeNameObj : exchangeNames) + for (Object exchangeNameObj : exchangeNames) { String exchangeName = String.valueOf(exchangeNameObj); configureExchange(virtualHost, exchangeName, configuration); @@ -83,7 +88,7 @@ public class VirtualHostConfiguration List queueNames = configuration.getList("queues.queue.name"); - for(Object queueNameObj : queueNames) + for (Object queueNameObj : queueNames) { String queueName = String.valueOf(queueNameObj); configureQueue(virtualHost, queueName, configuration); @@ -91,12 +96,14 @@ public class VirtualHostConfiguration } - private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) throws AMQException + private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) + throws + AMQException { CompositeConfiguration exchangeConfiguration = new CompositeConfiguration(); - exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString)); + exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange." + exchangeNameString)); exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); @@ -110,18 +117,17 @@ public class VirtualHostConfiguration Exchange exchange; - synchronized (exchangeRegistry) { exchange = exchangeRegistry.getExchange(exchangeName); - if(exchange == null) + if (exchange == null) { - AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type","direct")); - boolean durable = exchangeConfiguration.getBoolean("durable",false); - boolean autodelete = exchangeConfiguration.getBoolean("autodelete",false); + AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type", "direct")); + boolean durable = exchangeConfiguration.getBoolean("durable", false); + boolean autodelete = exchangeConfiguration.getBoolean("autodelete", false); - Exchange newExchange = exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); + Exchange newExchange = exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); exchangeRegistry.registerExchange(newExchange); } @@ -149,11 +155,14 @@ public class VirtualHostConfiguration return queueConfiguration; } - private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException + private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) + throws + AMQException, + ConfigurationException { CompositeConfiguration queueConfiguration = new CompositeConfiguration(); - queueConfiguration.addConfiguration(configuration.subset("queues.queue."+ queueNameString)); + queueConfiguration.addConfiguration(configuration.subset("queues.queue." + queueNameString)); queueConfiguration.addConfiguration(configuration.subset("queues")); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); @@ -173,7 +182,7 @@ public class VirtualHostConfiguration { _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName()); - boolean durable = queueConfiguration.getBoolean("durable" ,false); + boolean durable = queueConfiguration.getBoolean("durable", false); boolean autodelete = queueConfiguration.getBoolean("autodelete", false); String owner = queueConfiguration.getString("owner", null); @@ -184,21 +193,32 @@ public class VirtualHostConfiguration if (queue.isDurable()) { - messageStore.createQueue(queue); + try + { + messageStore.createQueue(queue); + } catch (InternalErrorException e) + { + _logger.error("Problem when creating Queue '" + queueNameString + + "' on virtual host " + virtualHost.getName() + ", not creating."); + + } catch (QueueAlreadyExistsException e) + { + _logger.error("Queue '" + queueNameString + + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); + } } queueRegistry.registerQueue(queue); - } - else + } else { - _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating."); + _logger.info("Queue '" + queueNameString + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); } String exchangeName = queueConfiguration.getString("exchange", null); Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - if(exchange == null) + if (exchange == null) { exchange = virtualHost.getExchangeRegistry().getDefaultExchange(); } @@ -211,15 +231,15 @@ public class VirtualHostConfiguration synchronized (exchange) { List routingKeys = queueConfiguration.getList("routingKey"); - if(routingKeys == null || routingKeys.isEmpty()) + if (routingKeys == null || routingKeys.isEmpty()) { routingKeys = Collections.singletonList(queue.getName()); } - for(Object routingKeyNameObj : routingKeys) + for (Object routingKeyNameObj : routingKeys) { AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - + queue.bind(routingKey, null, exchange); @@ -227,31 +247,33 @@ public class VirtualHostConfiguration _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); } - if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) + if (exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) { - queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); + queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); } } } - Configurator.configure(queue, queueConfiguration); } - public void performBindings() throws AMQException, ConfigurationException + public void performBindings() + throws + AMQException, + ConfigurationException { List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); String defaultVirtualHostName = _config.getString("default"); - if(defaultVirtualHostName != null) + if (defaultVirtualHostName != null) { - ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); + ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); } _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); - for(Object nameObject : virtualHostNames) + for (Object nameObject : virtualHostNames) { String name = String.valueOf(nameObject); configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name)); @@ -265,5 +287,4 @@ public class VirtualHostConfiguration } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java new file mode 100644 index 0000000000..ae1b916144 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java @@ -0,0 +1,59 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 15:52:29 + */ +public class CommandInvalidException extends Exception +{ + /** + * Constructs a new CommandInvalidException with the specified detail message. + * + * @param message the detail message. + */ + public CommandInvalidException(String message) + { + super(message); + } + + /** + * Constructs a new CommandInvalidException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public CommandInvalidException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new CommandInvalidException with the specified cause. + * + * @param cause the cause + */ + public CommandInvalidException(Throwable cause) + { + super(cause); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java new file mode 100644 index 0000000000..f5fcfeee8f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java @@ -0,0 +1,57 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 14:41:53 + */ +public class InternalErrorException extends Exception +{ + /** + * Constructs a new InternalErrorException with the specified detail message. + * + * @param message the detail message. + */ + public InternalErrorException(String message) + { + super(message); + } + + /** + * Constructs a new InternalErrorException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public InternalErrorException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new InternalErrorException with the specified cause. + * + * @param cause the cause + */ + public InternalErrorException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java new file mode 100644 index 0000000000..3cae098403 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java @@ -0,0 +1,72 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 14:12:27 + */ +public class InvalidXidException extends Exception +{ + /** + * Constructs a newr InvalidXidException with a standard message + * + * @param xid The invalid xid. + */ + public InvalidXidException(Xid xid) + { + super("The Xid: " + xid + " is invalid"); + } + + /** + * Constructs a newr InvalidXidException with a cause + * + * @param xid The invalid xid. + * @param cause The casue for the xid to be invalid + */ + public InvalidXidException(Xid xid, Throwable cause) + { + super("The Xid: " + xid + " is invalid", cause); + } + + /** + * Constructs a newr InvalidXidException with a reason message + * + * @param reason The reason why the xid is invalid + * @param xid The invalid xid. + */ + public InvalidXidException(Xid xid, String reason) + { + super("The Xid: " + xid + " is invalid, The reason is: " + reason); + } + + /** + * Constructs a newr InvalidXidException with a reason message and cause + * + * @param reason The reason why the xid is invalid + * @param xid The invalid xid. + * @param cause The casue for the xid to be invalid + */ + public InvalidXidException(Xid xid, String reason, Throwable cause) + { + super("The Xid: " + xid + " is invalid, The reason is: " + reason, cause); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java new file mode 100644 index 0000000000..f95132a450 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 03-Apr-2007 + * Time: 09:46:31 + */ +public class MessageAlreadyStagedException extends Exception +{ + /** + * Constructs a new MessageAlreadyStagedException with the specified detail message. + * + * @param message the detail message. + */ + public MessageAlreadyStagedException(String message) + { + super(message); + } + + /** + * Constructs a new MessageAlreadyStagedException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public MessageAlreadyStagedException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new MessageAlreadyStagedException with the specified cause. + * + * @param cause the cause + */ + public MessageAlreadyStagedException(Throwable cause) + { + super(cause); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java new file mode 100644 index 0000000000..b8ffe91247 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 30-Mar-2007 + * Time: 10:52:29 + */ +public class MessageDoesntExistException extends Exception +{ + /** + * Constructs a new MessageDoesntExistException with the specified detail message. + * + * @param message the detail message. + */ + public MessageDoesntExistException(String message) + { + super(message); + } + + /** + * Constructs a new MessageDoesntExistException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public MessageDoesntExistException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new MessageDoesntExistException with the specified cause. + * + * @param cause the cause + */ + public MessageDoesntExistException(Throwable cause) + { + super(cause); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java new file mode 100644 index 0000000000..af8c7374bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 16:47:40 + */ +public class NotPreparedException extends Exception +{ + /** + * Constructs a new NotPreparedException with the specified detail message. + * + * @param message the detail message. + */ + public NotPreparedException(String message) + { + super(message); + } + + /** + * Constructs a new NotPreparedException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public NotPreparedException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new NotPreparedException with the specified cause. + * + * @param cause the cause + */ + public NotPreparedException(Throwable cause) + { + super(cause); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java new file mode 100644 index 0000000000..39751261e4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 30-Mar-2007 + * Time: 10:49:00 + */ +public class QueueAlreadyExistsException extends Exception +{ + /** + * Constructs a new QueueAlreadyExistsException with the specified detail message. + * + * @param message the detail message. + */ + public QueueAlreadyExistsException(String message) + { + super(message); + } + + /** + * Constructs a new QueueAlreadyExistsException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public QueueAlreadyExistsException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new QueueDoesntExistException with the specified cause. + * + * @param cause the cause + */ + public QueueAlreadyExistsException(Throwable cause) + { + super(cause); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java new file mode 100644 index 0000000000..88dea864a5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 17:38:24 + */ +public class QueueDoesntExistException extends Exception +{ + /** + * Constructs a new QueueDoesntExistException with the specified detail message. + * + * @param message the detail message. + */ + public QueueDoesntExistException(String message) + { + super(message); + } + + /** + * Constructs a new QueueDoesntExistException with the specified detail message and + * cause. + * + * @param message the detail message . + * @param cause the cause. + */ + public QueueDoesntExistException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new QueueDoesntExistException with the specified cause. + * + * @param cause the cause + */ + public QueueDoesntExistException(Throwable cause) + { + super(cause); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java new file mode 100644 index 0000000000..9c1a28413f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java @@ -0,0 +1,72 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.exception; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 15:45:06 + */ +public class UnknownXidException extends Exception +{ + /** + * Constructs a newr UnknownXidException with a standard message + * + * @param xid The unknown xid. + */ + public UnknownXidException(Xid xid) + { + super("The Xid: " + xid + " is unknown"); + } + + /** + * Constructs a newr UnknownXidException with a cause + * + * @param xid The unknown xid. + * @param cause The casue for the xid to be unknown + */ + public UnknownXidException(Xid xid, Throwable cause) + { + super("The Xid: " + xid + " is unknown", cause); + } + + /** + * Constructs a newr UnknownXidException with a reason message + * + * @param reason The reason why the xid is unknown + * @param xid The unknown xid. + */ + public UnknownXidException(Xid xid, String reason) + { + super("The Xid: " + xid + " is unknown, The reason is: " + reason); + } + + /** + * Constructs a newr UnknownXidException with a reason message and cause + * + * @param reason The reason why the xid is unknown + * @param xid The unknown xid. + * @param cause The casue for the xid to be unknown + */ + public UnknownXidException(Xid xid, String reason, Throwable cause) + { + super("The Xid: " + xid + " is unknown, The reason is: " + reason, cause); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 4774383642..9066af70d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -29,7 +29,8 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.exception.InternalErrorException; public class DefaultExchangeRegistry implements ExchangeRegistry { @@ -65,7 +66,13 @@ public class DefaultExchangeRegistry implements ExchangeRegistry _exchangeMap.put(exchange.getName(), exchange); if(exchange.isDurable()) { - getMessageStore().createExchange(exchange); + try + { + getMessageStore().createExchange(exchange); + } catch (InternalErrorException e) + { + throw new AMQException("problem registering excahgne " + exchange, e); + } } } @@ -87,7 +94,13 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { if(e.isDurable()) { - getMessageStore().removeExchange(e); + try + { + getMessageStore().removeExchange(e); + } catch (InternalErrorException e1) + { + throw new AMQException("Problem unregistering Exchange " + name, e1); + } } e.close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index 03fc7a3926..e4abae4f28 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -49,7 +49,8 @@ public class ChannelOpenHandler implements StateAwareMethodListener @@ -103,7 +105,13 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -107,7 +109,13 @@ public class QueueDeleteHandler implements StateAwareMethodListener getAllQueues() + throws + InternalErrorException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Collection getAllMessages(StorableQueue queue) + throws + InternalErrorException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getNewMessageId() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java new file mode 100644 index 0000000000..c4b1d3182f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java @@ -0,0 +1,270 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.commons.configuration.Configuration; + +import javax.transaction.xa.Xid; +import java.util.Collection; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 17:34:02 + */ +public interface MessageStore +{ + /** + * Create a new exchange + * + * @param exchange the exchange to be persisted + * @throws InternalErrorException If an error occurs + */ + public void createExchange(Exchange exchange) + throws + InternalErrorException; + + /** + * Remove an exchange + * @param exchange The exchange to be removed + * @throws InternalErrorException If an error occurs + */ + public void removeExchange(Exchange exchange) throws + InternalErrorException; + + /** + * Bind a queue with an exchange given a routing key + * + * @param exchange The exchange to bind the queue with + * @param routingKey The routing key + * @param queue The queue to be bound + * @param args Args + * @throws InternalErrorException If an error occurs + */ + public void bindQueue(Exchange exchange, + AMQShortString routingKey, + StorableQueue queue, FieldTable args) + throws + InternalErrorException; + + /** + * Unbind a queue from an exchange + * + * @param exchange The exchange the queue was bound to + * @param routingKey The routing queue + * @param queue The queue to unbind + * @param args args + * @throws InternalErrorException If an error occurs + */ + public void unbindQueue(Exchange exchange, + AMQShortString routingKey, + StorableQueue queue, FieldTable args) + throws + InternalErrorException; + + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param tm The transaction manager implementation + * @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 InternalErrorException If an error occurs that means the store is unable to configure itself + * @throws IllegalArgumentException If the configuration arguments are illegal + */ + void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) + throws + InternalErrorException, + IllegalArgumentException; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws InternalErrorException if close fails + */ + void close() + throws + InternalErrorException; + + /** + * Create a queue + * + * @param queue the queue to be created + * @throws InternalErrorException In case of internal message store problem + * @throws QueueAlreadyExistsException If the queue already exists in the store + */ + public void createQueue(StorableQueue queue) + throws + InternalErrorException, + QueueAlreadyExistsException; + + /** + * Destroy a queue + * + * @param queue The queue to be destroyed + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + */ + public void destroyQueue(StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException; + + /** + * Stage the message before effective enqueue + * + * @param m The message to stage + * @throws InternalErrorException In case of internal message store problem + * @throws MessageAlreadyStagedException If the message is already staged + */ + public void stage(StorableMessage m) + throws + InternalErrorException, + MessageAlreadyStagedException; + + + /** + * Append more data with a previously staged message + * + * @param m The message to which data must be appended + * @param data Data to happen to the message + * @param offset The number of bytes from the beginning of the payload + * @param size The number of bytes to be written + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message has not been staged + */ + public void appendContent(StorableMessage m, byte[] data, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Get the content of previously staged or enqueued message. + * The message headers are also set. + * + * @param m The message for which the content must be loaded + * @param offset The number of bytes from the beginning of the payload + * @param size The number of bytes to be loaded + * @return The message content + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist + */ + public byte[] loadContent(StorableMessage m, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Destroy a previously staged message + * + * @param m the message to be destroyed + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist in the store + */ + public void destroy(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Enqueue a message under the scope of the transaction branch + * identified by xid when specified. + *

      This operation is propagated to the queue and the message. + *

      A message that has been previously staged is assumed to have had + * its payload already added (see appendContent) + * + * @param xid The xid of the transaction branch under which the message must be enqueued. + *

      It he xid is null then the message is enqueued outside the scope of any transaction. + * @param m The message to be enqueued + * @param queue The queue into which the message must be enqueued + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + * @throws InvalidXidException The transaction branch is invalid + * @throws UnknownXidException The transaction branch is unknown + * @throws MessageDoesntExistException If the Message does not exist + */ + public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException; + + /** + * Dequeue a message under the scope of the transaction branch identified by xid + * if specified. + *

      This operation is propagated to the queue and the message. + * + * @param xid The xid of the transaction branch under which the message must be dequeued. + *

      It he xid is null then the message is dequeued outside the scope of any transaction. + * @param m The message to be dequeued + * @param queue The queue from which the message must be dequeued + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + * @throws InvalidXidException The transaction branch is invalid + * @throws UnknownXidException The transaction branch is unknown + */ + public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException; + + //========================================================= + // Recovery specific methods + //========================================================= + + /** + * List all the persistent queues + * + * @return All the persistent queues + * @throws InternalErrorException In case of internal message store problem + */ + public Collection getAllQueues() + throws + InternalErrorException; + + /** + * All enqueued messages of a given queue + * + * @param queue The queue where the message are retrieved from + * @return The list all enqueued messages of a given queue + * @throws InternalErrorException In case of internal message store problem + */ + public Collection getAllMessages(StorableQueue queue) + throws + InternalErrorException; + + /** + * Get a new message ID + * + * @return A new message ID + */ + public long getNewMessageId(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java new file mode 100644 index 0000000000..b228bb3027 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +/** + * A storable message can be persisted in the message store. + * + * Created by Arnaud Simon + * Date: 03-Apr-2007 + * Time: 08:56:48 + */ +public interface StorableMessage +{ + /** + * The message ID is used by the store to identify a message. + * + * @return The message identifier + */ + public long getMessageId(); + + /** + * Get the message header body that is saved when the message is staged. + * + * @return The message header body + */ + public byte[] getHeaderBody(); + + /** + * Get the message header body size in bytes. + * + * @return The message header body size + */ + public int getHeaderSize(); + + /** + * Get the message payload. This is required when the message is + * enqueued without any prior staging. + *

      When the message is staged, the payload can be partial or even empty. + * + * @return The message payload + */ + public byte[] getData(); + + /** + * Get the message payload size in bytes. + * + * @return The message payload size in bytes + */ + public int getPayloadSize(); + + /** + * Specify whether this message has been enqueued + * + * @return true if this message is enqueued, false otherwise + */ + public boolean isEnqueued(); + + /** + * This is called by the message store when this message is enqueued in the message store. + * + * @param queue The storable queue into which the message is enqueued + */ + public void enqueue(StorableQueue queue); + + /** + * This is called by the message store when this message is dequeued. + * + * @param queue The storable queue out of which the message is dequeued + */ + public void dequeue(StorableQueue queue); + + /** + * A message can be enqueued in several queues. + * The queue position represents the index of the provided queue within the ordered + * list of queues the message has been enqueued. + *

      For example: + *

      If the message is successively enqueued in queue Q1, Q2 and Q3 then + * the position of Q1 is 0, position of Q2 is 1 and position of Q3 is 2. + *

      If the message is dequeud form Q2 then position of Q1 is stil 0 but position + * of Q3 becomes 1. + * + * @param queue The storable queue for which the position should be determined + * + * @return The position of the specified storable queue + */ + public int getQueuePosition(StorableQueue queue); + + /** + * Indicates whether this message has been staged. + * + * @return True if the message has been staged, false otherwise + */ + public boolean isStaged(); + + /** + * Call by the message store when this message is staged. + */ + public void staged(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java new file mode 100644 index 0000000000..10a9a3b8b8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import org.apache.qpid.framing.AMQShortString; + +/** + * A storable queue can store storable messages and can be persisted in the store. + * Created by Arnaud Simon + * Date: 03-Apr-2007 + * Time: 08:52:18 + */ +public interface StorableQueue +{ + /** + * Get This queue unique id. + * + * @return The queue ID + */ + public int getQueueID(); + + /** + * Set the queue ID. + * + * @param id This queue ID + */ + public void setQueueID(int id); + + /** + * Get this queue owner. + * + * @return This queue owner + */ + public AMQShortString getOwner(); + + /** + * Get this queue name. + * + * @return the name of this queue + */ + public AMQShortString getName(); + + /** + * Signifies to this queue that a message is dequeued. + * This operation is called by the store. + * + * @param m The dequeued message + */ + public void dequeue(StorableMessage m); + + /** + * Signifies to this queue that a message is enqueued. + * This operation is called by the store. + * + * @param m The enqueued message + */ + public void enqueue(StorableMessage m); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 955aaa6acb..eefff090df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -25,38 +25,45 @@ import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.StorableQueue; /** Combines the information that make up a deliverable message into a more manageable form. */ import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -/** Combines the information that make up a deliverable message into a more manageable form. */ -public class AMQMessage +/** + * Combines the information that make up a deliverable message into a more manageable form. + */ +public class AMQMessage implements StorableMessage { private static final Logger _log = Logger.getLogger(AMQMessage.class); - /** Used in clustering */ + // The ordered list of queues into which this message is enqueued. + private List _queues = new LinkedList(); + // Indicates whether this message is staged + private boolean _isStaged = false; + + /** + * Used in clustering + */ private Set _tokens; - /** Only use in clustering - should ideally be removed? */ + /** + * Only use in clustering - should ideally be removed? + */ private AMQProtocolSession _publisher; private final Long _messageId; @@ -221,13 +228,14 @@ public class AMQMessage * @param messageId * @param store * @param factory - * * @throws AMQException */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) throws AMQException + public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) + throws + AMQException { _messageId = messageId; - _messageHandle = factory.createMessageHandle(messageId, store, true); + _messageHandle = factory.createMessageHandle(store, this, true); _txnContext = txnConext; _transientMessageData = null; } @@ -241,7 +249,9 @@ public class AMQMessage * @param contentHeader */ public AMQMessage(Long messageId, MessagePublishInfo info, - TransactionalContext txnContext, ContentHeaderBody contentHeader) throws AMQException + TransactionalContext txnContext, ContentHeaderBody contentHeader) + throws + AMQException { this(messageId, info, txnContext); setContentHeaderBody(contentHeader); @@ -256,14 +266,15 @@ public class AMQMessage * @param contentHeader * @param destinationQueues * @param contentBodies - * * @throws AMQException */ public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, MessageStore messageStore, StoreContext storeContext, - MessageHandleFactory messageHandleFactory) throws AMQException + MessageHandleFactory messageHandleFactory) + throws + AMQException { this(messageId, info, txnContext, contentHeader); _transientMessageData.setDestinationQueues(destinationQueues); @@ -274,7 +285,9 @@ public class AMQMessage } } - protected AMQMessage(AMQMessage msg) throws AMQException + protected AMQMessage(AMQMessage msg) + throws + AMQException { _messageId = msg._messageId; _messageHandle = msg._messageHandle; @@ -283,6 +296,98 @@ public class AMQMessage _transientMessageData = msg._transientMessageData; } + //======================================================================== + // Interface StorableMessage + //======================================================================== + + public long getMessageId() + { + return _messageId; + } + + public byte[] getHeaderBody() + { + byte[] result = null; + ContentHeaderBody headerBody; + ByteBuffer bufferedResult; + try + { + headerBody = _messageHandle.getContentHeaderBody(_txnContext.getStoreContext(), _messageId); + result = new byte[headerBody.getSize()]; + bufferedResult = ByteBuffer.wrap(result); + headerBody.writePayload(bufferedResult); + } catch (AMQException e) + { + _log.error("Error when getting message header", e); + } + return result; + } + + public int getHeaderSize() + { + int result = 0; + try + { + result = _messageHandle.getContentHeaderBody(_txnContext.getStoreContext(), _messageId).getSize(); + } catch (AMQException e) + { + _log.error("Error when getting message header size", e); + } + return result; + } + + public byte[] getData() + { + return _messageHandle.getMessagePayload(); + } + + public int getPayloadSize() + { + return _messageHandle.getMessagePayload().length; + } + + public boolean isEnqueued() + { + return _queues.size() > 0; + } + + public void enqueue(StorableQueue queue) + { + _queues.add(queue); + if (_log.isDebugEnabled()) + { + _log.debug("enqueued"); + } + } + + public void dequeue(StorableQueue queue) + { + _queues.remove(queue); + if (_log.isDebugEnabled()) + { + _log.debug("dequeued"); + } + } + + public int getQueuePosition(StorableQueue queue) + { + if (_log.isDebugEnabled()) + { + _log.debug("The queue position is " + _queues.indexOf(queue)); + } + return _queues.indexOf(queue); + } + + public boolean isStaged() + { + return _isStaged; + } + + public void staged() + { + _isStaged = true; + } + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) { return new BodyFrameIterator(protocolSession, channel); @@ -293,32 +398,36 @@ public class AMQMessage return new BodyContentIterator(); } - public ContentHeaderBody getContentHeaderBody() throws AMQException + public ContentHeaderBody getContentHeaderBody() + throws + AMQException { if (_transientMessageData != null) { return _transientMessageData.getContentHeaderBody(); - } - else + } else { return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); } } public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - throws AMQException + throws + AMQException { _transientMessageData.setContentHeaderBody(contentHeaderBody); } - public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) throws AMQException + public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) + throws + AMQException { final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(_messageId, store, persistent); - if (persistent) - { + _messageHandle = factory.createMessageHandle(store, this, persistent); + //if (persistent) + // { _txnContext.beginTranIfNecessary(); - } + // } // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store @@ -334,7 +443,9 @@ public class AMQMessage } } - public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException + public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) + throws + AMQException { _transientMessageData.addBodyLength(contentChunk.getSize()); final boolean allContentReceived = isAllContentReceived(); @@ -343,22 +454,19 @@ public class AMQMessage { deliver(storeContext); return true; - } - else + } else { return false; } } - public boolean isAllContentReceived() throws AMQException + public boolean isAllContentReceived() + throws + AMQException { return _transientMessageData.isAllContentReceived(); } - public long getMessageId() - { - return _messageId; - } /** * Creates a long-lived reference to this message, and increments the count of such references, as an atomic @@ -366,11 +474,13 @@ public class AMQMessage */ public AMQMessage takeReference() { - incrementReference();// _referenceCount.incrementAndGet(); + _referenceCount.incrementAndGet(); return this; } - /** Threadsafe. Increment the reference count on the message. */ + /** + * Threadsafe. Increment the reference count on the message. + */ protected void incrementReference() { _referenceCount.incrementAndGet(); @@ -385,11 +495,12 @@ public class AMQMessage * message store. * * @param storeContext - * * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that * failed */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException + public void decrementReference(StoreContext storeContext) + throws + MessageCleanupException { int count = _referenceCount.decrementAndGet(); @@ -419,8 +530,7 @@ public class AMQMessage incrementReference(); throw new MessageCleanupException(_messageId, e); } - } - else + } else { if (_log.isDebugEnabled()) { @@ -497,8 +607,7 @@ public class AMQMessage if (taken.getAndSet(true)) { return true; - } - else + } else { _takenMap.put(queue, taken); _takenBySubcriptionMap.put(queue, sub); @@ -524,8 +633,7 @@ public class AMQMessage if (taken == null) { taken = new AtomicBoolean(false); - } - else + } else { taken.set(false); } @@ -546,8 +654,7 @@ public class AMQMessage if (_tokens.contains(token)) { return true; - } - else + } else { _tokens.add(token); return false; @@ -560,26 +667,30 @@ public class AMQMessage * 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 + public void enqueue(AMQQueue queue) + throws + AMQException { _transientMessageData.addDestinationQueue(queue); } - public void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException + public void dequeue(StoreContext storeContext, AMQQueue queue) + throws + AMQException { _messageHandle.dequeue(storeContext, _messageId, queue); } - public boolean isPersistent() throws AMQException + public boolean isPersistent() + throws + AMQException { if (_transientMessageData != null) { return _transientMessageData.isPersistent(); - } - else + } else { return _messageHandle.isPersistent(getStoreContext(), _messageId); } @@ -591,7 +702,9 @@ public class AMQMessage * @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 + public void checkDeliveredToConsumer() + throws + NoConsumersException { if (_immediate && !_deliveredToConsumer) @@ -600,14 +713,15 @@ public class AMQMessage } } - public MessagePublishInfo getMessagePublishInfo() throws AMQException + public MessagePublishInfo getMessagePublishInfo() + throws + AMQException { MessagePublishInfo pb; if (_transientMessageData != null) { pb = _transientMessageData.getMessagePublishInfo(); - } - else + } else { pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); } @@ -630,13 +744,17 @@ public class AMQMessage } - /** Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). */ + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + */ public void setDeliveredToConsumer() { _deliveredToConsumer = true; } - private void deliver(StoreContext storeContext) throws AMQException + private void deliver(StoreContext storeContext) + throws + AMQException { // we get a reference to the destination queues now so that we can clear the // transient message data as quickly as possible @@ -650,7 +768,7 @@ public class AMQMessage // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, _transientMessageData.getMessagePublishInfo(), - _transientMessageData.getContentHeaderBody()); + _transientMessageData.getContentHeaderBody()); // we then allow the transactional context to do something with the message content // now that it has all been received, before we attempt delivery @@ -867,7 +985,9 @@ public class AMQMessage } - public void restoreTransientMessageData() throws AMQException + public void restoreTransientMessageData() + throws + AMQException { TransientMessageData transientMessageData = new TransientMessageData(); transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); @@ -889,7 +1009,7 @@ public class AMQMessage // _taken + " by :" + _takenBySubcription; return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + - _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } public Subscription getDeliveredSubscription(AMQQueue queue) @@ -911,8 +1031,7 @@ public class AMQMessage } _rejectedBy.add(subscription); - } - else + } else { _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); } @@ -925,8 +1044,7 @@ public class AMQMessage if (rejected) // We have subscriptions that rejected this message { return _rejectedBy.contains(subscription); - } - else // This messasge hasn't been rejected yet. + } else // This messasge hasn't been rejected yet. { return rejected; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index ede55b3bbf..296e61bfa9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -76,4 +76,7 @@ public interface AMQMessageHandle void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; long getArrivalTime(); + + // added by Arnaud + byte[] getMessagePayload(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 0adf6153f8..fa3b34a634 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.queue; import java.text.MessageFormat; import java.util.List; +import java.util.Hashtable; +import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -36,6 +38,9 @@ import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.StorableQueue; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -47,9 +52,10 @@ import org.apache.qpid.server.virtualhost.VirtualHost; * 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, Comparable +public class AMQQueue implements Managable, Comparable, StorableQueue { + public static int s_queueID =0; public static final class ExistingExclusiveSubscription extends AMQException { @@ -76,15 +82,27 @@ public class AMQQueue implements Managable, Comparable private final AMQShortString _name; - /** null means shared */ + // The queueu ID + int _queueId; + // The list of enqueued messages. + Hashtable _messages = new Hashtable(); + + + /** + * null means shared + */ private final AMQShortString _owner; private final boolean _durable; - /** If true, this queue is deleted when the last subscriber is removed */ + /** + * If true, this queue is deleted when the last subscriber is removed + */ private final boolean _autoDelete; - /** Holds subscribers to the queue. */ + /** + * Holds subscribers to the queue. + */ private final SubscriptionSet _subscribers; private final SubscriptionFactory _subscriptionFactory; @@ -97,13 +115,19 @@ public class AMQQueue implements Managable, Comparable private List _deleteTaskList = new CopyOnWriteArrayList(); - /** Manages message delivery. */ + /** + * Manages message delivery. + */ private final DeliveryManager _deliveryMgr; - /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ + /** + * 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 */ + /** + * Executor on which asynchronous delivery will be carriedout where required + */ private final Executor _asyncDelivery; private final AMQQueueMBean _managedObject; @@ -111,27 +135,39 @@ public class AMQQueue implements Managable, Comparable private final VirtualHost _virtualHost; - /** max allowed size(KB) of a single message */ + /** + * max allowed size(KB) of a single message + */ @Configured(path = "maximumMessageSize", defaultValue = "0") public long _maximumMessageSize; - /** max allowed number of messages on a queue. */ + /** + * max allowed number of messages on a queue. + */ @Configured(path = "maximumMessageCount", defaultValue = "0") public long _maximumMessageCount; - /** max queue depth for the queue */ + /** + * max queue depth for the queue + */ @Configured(path = "maximumQueueDepth", defaultValue = "0") public long _maximumQueueDepth; - /** maximum message age before alerts occur */ + /** + * maximum message age before alerts occur + */ @Configured(path = "maximumMessageAge", defaultValue = "0") public long _maximumMessageAge; - /** the minimum interval between sending out consequetive alerts of the same type */ + /** + * the minimum interval between sending out consequetive alerts of the same type + */ @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") public long _minimumAlertRepeatGap; - /** total messages received by the queue since startup. */ + /** + * total messages received by the queue since startup. + */ public AtomicLong _totalMessagesReceived = new AtomicLong(); public int compareTo(Object o) @@ -141,26 +177,29 @@ public class AMQQueue implements Managable, Comparable public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException + throws + AMQException { this(name, durable, owner, autoDelete, virtualHost, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionSet(), new SubscriptionImpl.Factory()); + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionSet(), new SubscriptionImpl.Factory()); } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, SubscriptionSet subscribers) - throws AMQException + throws + AMQException { this(name, durable, owner, autoDelete, virtualHost, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) - throws AMQException + throws + AMQException { if (name == null) { @@ -183,9 +222,12 @@ public class AMQQueue implements Managable, Comparable _subscribers = subscribers; _subscriptionFactory = subscriptionFactory; _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); + _queueId = s_queueID++; } - private AMQQueueMBean createMBean() throws AMQException + private AMQQueueMBean createMBean() + throws + AMQException { try { @@ -222,13 +264,17 @@ public class AMQQueue implements Managable, Comparable return _autoDelete; } - /** @return no of messages(undelivered) on the queue. */ + /** + * @return no of messages(undelivered) on the queue. + */ public int getMessageCount() { return _deliveryMgr.getQueueMessageCount(); } - /** @return List of messages(undelivered) on the queue. */ + /** + * @return List of messages(undelivered) on the queue. + */ public List getMessagesOnTheQueue() { return _deliveryMgr.getMessages(); @@ -239,7 +285,6 @@ public class AMQQueue implements Managable, Comparable * * @param fromMessageId * @param toMessageId - * * @return List of messages */ public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) @@ -254,7 +299,6 @@ public class AMQQueue implements Managable, Comparable /** * @param messageId - * * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. */ public AMQMessage getMessageOnTheQueue(long messageId) @@ -321,7 +365,9 @@ public class AMQQueue implements Managable, Comparable _deliveryMgr.processAsync(_asyncDelivery); } - /** @return MBean object associated with this Queue */ + /** + * @return MBean object associated with this Queue + */ public ManagedObject getManagedObject() { return _managedObject; @@ -379,34 +425,58 @@ public class AMQQueue implements Managable, Comparable } - /** Removes the AMQMessage from the top of the queue. */ - public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException + /** + * Removes the AMQMessage from the top of the queue. + */ + public synchronized void deleteMessageFromTop(StoreContext storeContext) + throws + AMQException { _deliveryMgr.removeAMessageFromTop(storeContext); } - /** removes all the messages from the queue. */ - public synchronized long clearQueue(StoreContext storeContext) throws AMQException + /** + * removes all the messages from the queue. + */ + public synchronized long clearQueue(StoreContext storeContext) + throws + AMQException { return _deliveryMgr.clearAllMessages(storeContext); } - public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException + public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + throws + AMQException { exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + try + { + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + } catch (InternalErrorException e) + { + throw new AMQException("Problem binding queue ", e); + } } _bindings.addBinding(routingKey, arguments, exchange); } - public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException + public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + throws + AMQException { exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + try + { + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + } catch (InternalErrorException e) + { + throw new AMQException("problem unbinding queue", e); + } } _bindings.remove(routingKey, arguments, exchange); } @@ -414,7 +484,8 @@ public class AMQQueue implements Managable, Comparable public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal, boolean exclusive) - throws AMQException + throws + AMQException { if (incrementSubscriberCount() > 1) { @@ -422,15 +493,13 @@ public class AMQQueue implements Managable, Comparable { decrementSubscriberCount(); throw EXISTING_EXCLUSIVE; - } - else if (exclusive) + } else if (exclusive) { decrementSubscriberCount(); throw EXISTING_SUBSCRIPTION; } - } - else if (exclusive) + } else if (exclusive) { setExclusive(true); } @@ -438,11 +507,11 @@ public class AMQQueue implements Managable, Comparable if (_logger.isDebugEnabled()) { _logger.debug(MessageFormat.format("Registering protocol session {0} with channel {1} and " + - "consumer tag {2} with {3}", ps, channel, consumerTag, this)); + "consumer tag {2} with {3}", ps, channel, consumerTag, this)); } Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, - filters, noLocal, this); + filters, noLocal, this); if (subscription.filtersMessages()) { @@ -477,22 +546,24 @@ public class AMQQueue implements Managable, Comparable } - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) + throws + AMQException { if (_logger.isDebugEnabled()) { _logger.debug(MessageFormat.format("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, - this)); + this)); } Subscription removedSubscription; if ((removedSubscription = _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, - ps, - consumerTag))) - == null) + 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); + " and protocol session key " + ps.getKey() + " not registered with queue " + this); } removedSubscription.close(); @@ -524,26 +595,28 @@ public class AMQQueue implements Managable, Comparable } - public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException + public int delete(boolean checkUnused, boolean checkEmpty) + throws + AMQException { if (checkUnused && !_subscribers.isEmpty()) { _logger.info("Will not delete " + this + " as it is in use."); return 0; - } - else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) + } else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) { _logger.info("Will not delete " + this + " as it is not empty."); return 0; - } - else + } else { delete(); return _deliveryMgr.getQueueMessageCount(); } } - public void delete() throws AMQException + public void delete() + throws + AMQException { if (!_deleted.getAndSet(true)) { @@ -559,7 +632,9 @@ public class AMQQueue implements Managable, Comparable } } - protected void autodelete() throws AMQException + protected void autodelete() + throws + AMQException { if (_logger.isDebugEnabled()) { @@ -568,7 +643,9 @@ public class AMQQueue implements Managable, Comparable delete(); } - public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException + public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) + throws + AMQException { //fixme not sure what this is doing. should we be passing deliverFirst through here? // This code is not used so when it is perhaps it should @@ -591,7 +668,9 @@ public class AMQQueue implements Managable, Comparable // return _deliveryMgr; // } - public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException + public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) + throws + AMQException { _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); try @@ -607,7 +686,9 @@ public class AMQQueue implements Managable, Comparable } } - void dequeue(StoreContext storeContext, AMQMessage msg) throws FailedDequeueException + void dequeue(StoreContext storeContext, AMQMessage msg) + throws + FailedDequeueException { try { @@ -637,7 +718,9 @@ public class AMQQueue implements Managable, Comparable return _subscribers; } - protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException + protected void updateReceivedMessageCount(AMQMessage msg) + throws + AMQException { if (!msg.isRedelivered()) { @@ -680,7 +763,9 @@ public class AMQQueue implements Managable, Comparable return "Queue(" + _name + ")@" + System.identityHashCode(this); } - public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException + public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) + throws + AMQException { return _deliveryMgr.performGet(session, channel, acks); } @@ -697,7 +782,9 @@ public class AMQQueue implements Managable, Comparable public static interface Task { - public void doTask(AMQQueue queue) throws AMQException; + public void doTask(AMQQueue queue) + throws + AMQException; } public void addQueueDeleteTask(Task task) @@ -729,4 +816,53 @@ public class AMQQueue implements Managable, Comparable { _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, msg); } + + //======================================================================== + // Interface StorableQueue + //======================================================================== + + public int getQueueID() + { + return _queueId; + } + + public void setQueueID(int id) + { + _queueId = id; + } + + public void dequeue(StorableMessage m) + { + _messages.remove(m.getMessageId()); + } + + public void enqueue(StorableMessage m) + { + _messages.put(m.getMessageId(), m); + } + + //======================================================================== + // Used by the Store + //======================================================================== + + /** + * Get the list of enqueud messages + * + * @return The list of enqueud messages + */ + public Collection getAllEnqueuedMessages() + { + return _messages.values(); + } + + /** + * Get the enqueued message identified by messageID + * + * @param messageId the id of the enqueued message to recover + * @return The enqueued message with the specified id + */ + public StorableMessage getEnqueuedMessage(long messageId) + { + return _messages.get(messageId); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 630186991b..1d9f56669e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import java.util.LinkedList; import java.util.List; +import java.nio.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -46,11 +47,18 @@ public class InMemoryMessageHandle implements AMQMessageHandle private long _arrivalTime; + // the message payload + private byte[] _payload; + // a buffer to write the payload + ByteBuffer _buffer; + public InMemoryMessageHandle() { } - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) + throws + AMQException { return _contentHeaderBody; } @@ -60,28 +68,36 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _contentBodies.size(); } - public long getBodySize(StoreContext context, Long messageId) throws AMQException + public long getBodySize(StoreContext context, Long messageId) + throws + AMQException { return getContentHeaderBody(context, messageId).bodySize; } - public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, 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)); + (_contentBodies.size() - 1)); } return _contentBodies.get(index); } public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) - throws AMQException + throws + AMQException { _contentBodies.add(contentBody); } - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) + throws + AMQException { return _messagePublishInfo; } @@ -97,40 +113,50 @@ public class InMemoryMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(StoreContext context, Long messageId) throws AMQException + public boolean isPersistent(StoreContext context, Long messageId) + throws + AMQException { //todo remove literal values to a constant file such as AMQConstants in common ContentHeaderBody chb = getContentHeaderBody(context, messageId); return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; } /** * This is called when all the content has been received. + * * @param messagePublishInfo * @param contentHeaderBody * @throws AMQException */ public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) - throws AMQException + throws + AMQException { _messagePublishInfo = messagePublishInfo; _contentHeaderBody = contentHeaderBody; _arrivalTime = System.currentTimeMillis(); } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + public void removeMessage(StoreContext storeContext, Long messageId) + throws + AMQException { // NO OP } - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) + throws + AMQException { // NO OP } - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) + throws + AMQException { // NO OP } @@ -140,4 +166,24 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _arrivalTime; } + + // added by Arnaud + public byte[] getMessagePayload() + { + if (_payload == null) + { + int bodySize = (int) _contentHeaderBody.bodySize; + _buffer = ByteBuffer.allocate(bodySize); + _payload = new byte[bodySize]; + for (ContentChunk contentBody : _contentBodies) + { + int chunkSize = contentBody.getSize(); + byte[] chunk = new byte[chunkSize]; + contentBody.getData().get(chunk); + _buffer.put(chunk); + } + _buffer.get(_payload); + } + return _payload; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java index 94ab935115..69aaffa907 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -20,7 +20,8 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.StorableMessage; /** * Constructs a message handle based on the publish body, the content header and the queue to which the message @@ -31,12 +32,13 @@ import org.apache.qpid.server.store.MessageStore; public class MessageHandleFactory { - public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) + public AMQMessageHandle createMessageHandle(MessageStore store, StorableMessage m, boolean persistent) { // just hardcoded for now if (persistent) { - return new WeakReferenceMessageHandle(store); + // return new WeakReferenceMessageHandle(store); + return new StorableMessageHandle(store, m); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index 3b1b5acf3c..ed2101fd75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.messageStore.StorableQueue; public interface QueueRegistry diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java new file mode 100644 index 0000000000..5978e3b10d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java @@ -0,0 +1,215 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import javax.transaction.xa.Xid; +import java.util.List; +import java.util.LinkedList; +import java.nio.ByteBuffer; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 14:26:34 + */ +public class StorableMessageHandle implements AMQMessageHandle +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(StorableMessageHandle.class); + + //======================================================================== + // Instance Fields + //======================================================================== + // the message store + final private MessageStore _messageStore; + // A reference on the message itself + final private StorableMessage _message; + // the message payload + private byte[] _payload; + // a buffer to write the payload + ByteBuffer _buffer; + // the ContentHeaderBody + private ContentHeaderBody _contentHeaderBody; + // the arrival time + private long _arrivalTime; + // Specify if this messag is redelivered + private boolean _redelivered; + // MessagePublishInfo + private MessagePublishInfo _messagePublishInfo; + // list of chunks + private List _chunks = new LinkedList(); + + //======================================================================== + // Constructors + //======================================================================== + + public StorableMessageHandle(MessageStore messageStore, StorableMessage message) + { + _messageStore = messageStore; + _message = message; + } + + //======================================================================== + // Interface AMQMessageHandle + //======================================================================== + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) + throws + AMQException + { + return _contentHeaderBody; + } + + public int getBodyCount(StoreContext context, Long messageId) + throws + AMQException + { + return _chunks.size(); + } + + public long getBodySize(StoreContext context, Long messageId) + throws + AMQException + { + return _payload.length; + } + + public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) + throws + IllegalArgumentException, + AMQException + { + return _chunks.get(index); + } + + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) + throws + AMQException + { + _chunks.add(contentBody); + // if rquired this message can be added to the store + //_messageStore.appendContent(_message, _payload, 0, 10); + + } + + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) + throws + AMQException + { + return _messagePublishInfo; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public boolean isPersistent(StoreContext context, Long messageId) + throws + AMQException + { + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } + + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, + MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws + AMQException + { + _contentHeaderBody = contentHeaderBody; + _arrivalTime = System.currentTimeMillis(); + _messagePublishInfo = messagePublishInfo; + } + + public void removeMessage(StoreContext storeContext, Long messageId) + throws + AMQException + { + // This is already handled by the store but we can possibly do: + // _messageStore.destroy(_message); + } + + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) + throws + AMQException + { + try + { + _messageStore.enqueue((Xid) storeContext.getPayload(), _message, queue); + } catch (Exception e) + { + throw new AMQException("PRoblem during message enqueue", e); + } + } + + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) + throws + AMQException + { + try + { + _messageStore.dequeue((Xid) storeContext.getPayload(), _message, queue); + } catch (Exception e) + { + throw new AMQException("PRoblem during message dequeue", e); + } + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public byte[] getMessagePayload() + { + if (_payload == null) + { + int bodySize = (int) _contentHeaderBody.bodySize; + _buffer = ByteBuffer.allocate(bodySize); + _payload = new byte[bodySize]; + for (ContentChunk contentBody : _chunks) + { + int chunkSize = contentBody.getSize(); + byte[] chunk = new byte[chunkSize]; + contentBody.getData().get(chunk); + _buffer.put(chunk); + } + _buffer.get(_payload); + } + return _payload; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 373a64e2eb..64fb6c15d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -224,4 +224,10 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return _arrivalTime; } + + // added by Arnaud + public byte[] getMessagePayload() + { + return new byte[0]; //To change body of implemented methods use File | Settings | File Templates. + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java new file mode 100644 index 0000000000..0d25ab0e32 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java @@ -0,0 +1,59 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.exception.*; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 17:13:07 + */ +public class DequeueRecord implements TransactionRecord +{ + + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + // do nothing + } + + public void rollback(MessageStore store) + throws + InternalErrorException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void prepare(MessageStore store) + throws + InternalErrorException + { + //To change body of implemented methods use File | Settings | File Templates. + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java new file mode 100644 index 0000000000..eff623ca7c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java @@ -0,0 +1,248 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.InvalidXidException; +import org.apache.log4j.Logger; + +import javax.transaction.xa.Xid; +import java.util.List; +import java.util.LinkedList; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 15:58:07 + */ +public class DistributedTransactionalContext implements TransactionalContext +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(DistributedTransactionalContext.class); + + //======================================================================== + // Instance Fields + //======================================================================== + // the message store + final private MessageStore _messageStore; + // The transaction manager + final private TransactionManager _transactionManager; + // the store context + final private StoreContext _storeContext; + // the returned messages + final private List _returnMessages; + // for generating xids + private byte[] _txId = ("txid").getBytes(); + private int _count = 0; + + public DistributedTransactionalContext(TransactionManager transactionManager, MessageStore messageStore, StoreContext storeContext, + List returnMessages) + { + _messageStore = messageStore; + _storeContext = storeContext; + _returnMessages = returnMessages; + _transactionManager = transactionManager; + } + + public void beginTranIfNecessary() + throws + AMQException + { + // begin the transaction and pass the XID through the context + Xid xid = new XidImpl(("branch" + _count++).getBytes(), 1, _txId); + try + { + _transactionManager.begin(xid); + _storeContext.setPayload(xid); + } catch (Exception e) + { + throw new AMQException("Problem during transaction begin", e); + } + } + + public void commit() + throws + AMQException + { + try + { + _transactionManager.commit_one_phase((Xid) _storeContext.getPayload()); + } catch (Exception e) + { + throw new AMQException("Problem during transaction commit", e); + } + } + + public void rollback() + throws + AMQException + { + try + { + _transactionManager.rollback((Xid) _storeContext.getPayload()); + } catch (Exception e) + { + throw new AMQException("Problem during transaction rollback", e); + } + } + + public void messageFullyReceived(boolean persistent) + throws + AMQException + { + // The message is now fully received, we can stage it before enqueued if necessary + } + + public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) + throws + AMQException + { + try + { + //The message has been delivered to the queues + message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); + // add a record in the transaction + _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new EnqueueRecord(_storeContext, message, queue, deliverFirst)); + } catch (Exception e) + { + throw new AMQException("Problem during transaction rollback", e); + } + } + + public void acknowledgeMessage(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 + { + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + message.message.getMessageId()); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + dequeue(message); + 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) + { + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + msg.message.getMessageId()); + } + //Message has been ack so discard it. This will dequeue and decrement the reference. + dequeue(msg); + } + } + } else + { + UnacknowledgedMessage msg; + msg = unacknowledgedMessageMap.remove(deliveryTag); + + if (msg == null) + { + _log.info("Single ack on delivery tag " + deliveryTag); + throw new AMQException("Single ack on delivery tag " + deliveryTag); + } + + if (_log.isDebugEnabled()) + { + _log.debug("Discarding message: " + msg.message.getMessageId()); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + dequeue(msg); + + if (_log.isDebugEnabled()) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + + msg.message.getMessageId()); + } + } + } + + private void dequeue(UnacknowledgedMessage message) + throws + AMQException + { + // Dequeue the message from the strore + message.discard(_storeContext); + // Add a record + try + { + _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new DequeueRecord()); + } catch (Exception e) + { + throw new AMQException("Problem during message dequeue", e); + } + } + + + public void messageProcessed(AMQProtocolSession protocolSession) + throws + AMQException + { + // The message has been sent + } + + public StoreContext getStoreContext() + { + return _storeContext; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java new file mode 100644 index 0000000000..cdf209fb12 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java @@ -0,0 +1,79 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.AMQException; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 17:01:06 + */ +public class EnqueueRecord implements TransactionRecord +{ + private final StoreContext _storeContext; + private final AMQMessage _msg; + private final AMQQueue _queue; + private final boolean _first; + + EnqueueRecord(StoreContext storeContext, AMQMessage msg, AMQQueue q, boolean firsr) + { + _storeContext = storeContext; + _msg = msg; + _queue = q; + _first = firsr; + } + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + try + { + _queue.process(_storeContext, _msg, _first); + } catch (AMQException e) + { + throw new InternalErrorException(e); + } + } + + public void rollback(MessageStore store) + throws + InternalErrorException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void prepare(MessageStore store) + throws + InternalErrorException + { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java new file mode 100644 index 0000000000..a132bcefe6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java @@ -0,0 +1,125 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.exception.*; + +import javax.transaction.xa.Xid; +import java.util.Set; + +/** + * Created by Arnaud Simon + * Date: 02-May-2007 + * Time: 08:41:33 + */ +public class MemoryTransactionManager implements TransactionManager +{ + + public XAFlag begin(Xid xid) + throws + InternalErrorException, + InvalidXidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public XAFlag prepare(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public XAFlag rollback(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public XAFlag commit(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException, + NotPreparedException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public XAFlag commit_one_phase(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void forget(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setTimeout(Xid xid, long timeout) + throws + InternalErrorException, + UnknownXidException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public long getTimeout(Xid xid) + throws + InternalErrorException, + UnknownXidException + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public Set recover(boolean startscan, boolean endscan) + throws + InternalErrorException, + CommandInvalidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void HeuristicOutcome(Xid xid) + throws + UnknownXidException, + InternalErrorException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Transaction getTransaction(Xid xid) + throws + UnknownXidException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 181dfa3a80..857fb350a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -31,7 +31,7 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.store.StoreContext; /** @author Apache Software Foundation */ @@ -74,7 +74,7 @@ public class NonTransactionalContext implements TransactionalContext { if (!_inTran) { - _messageStore.beginTran(_storeContext); + // _messageStore.beginTran(_storeContext); _inTran = true; } } @@ -212,7 +212,7 @@ public class NonTransactionalContext implements TransactionalContext { if (persistent) { - _messageStore.commitTran(_storeContext); + // _messageStore.commitTran(_storeContext); _inTran = false; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java new file mode 100644 index 0000000000..cd2f619f7e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 14:08:39 + */ +public interface Transaction +{ + + /** + * Add an abstract record to this tx. + * + * @param record The record to be added + */ + public void addRecord(TransactionRecord record); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java new file mode 100644 index 0000000000..8047236985 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.exception.*; + +import javax.transaction.xa.Xid; +import java.util.Set; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 13:29:31 + */ +public interface TransactionManager +{ + /** + * Begin a transaction branch identified by Xid + * + * @param xid The xid of the branch to begin + * @return
        + *
      • XAFlag.ok: Normal execution. + *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspecified reason. + *
      + * @throws InternalErrorException In case of internal problem + * @throws InvalidXidException The Xid is invalid + */ + public XAFlag begin(Xid xid) + throws + InternalErrorException, + InvalidXidException; + + /** + * Prepare the transaction branch identified by Xid + * + * @param xid The xid of the branch to prepare + * @return
        + *
      • XAFlag.ok: Normal execution. + *
      • XAFlag.rdonly: The transaction branch was read-only and has been committed. + *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspeci?ed reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Prepare has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public XAFlag prepare(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException; + + /** + * Rollback the transaction branch identified by Xid + * + * @param xid The xid of the branch to rollback + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      • XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Rollback has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public XAFlag rollback(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException; + + /** + * Commit the transaction branch identified by Xid + * + * @param xid The xid of the branch to commit + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Commit has been call in an improper context + * @throws UnknownXidException The Xid is unknown + * @throws NotPreparedException The branch was not prepared prior to commit + */ + public XAFlag commit(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException, + NotPreparedException; + + /** + * One phase commit the transaction branch identified by Xid + * + * @param xid The xid of the branch to one phase commit + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      • XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Commit has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public XAFlag commit_one_phase(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException; + + /** + * Forget about the transaction branch identified by Xid + * + * @param xid The xid of the branch to forget + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Forget has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public void forget(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException; + + /** + * Set the transaction branch timeout value in seconds + * + * @param xid The xid of the branch to set timeout + * @param timeout Timeout value in seconds + * @throws InternalErrorException In case of internal problem + * @throws UnknownXidException The Xid is unknown + */ + public void setTimeout(Xid xid, long timeout) + throws + InternalErrorException, + UnknownXidException; + + /** + * Get the transaction branch timeout + * + * @param xid The xid of the branch to get the timeout from + * @return The timeout associated with the branch identified with xid + * @throws InternalErrorException In case of internal problem + * @throws UnknownXidException The Xid is unknown + */ + public long getTimeout(Xid xid) + throws + InternalErrorException, + UnknownXidException; + + /** + * Get a set of Xids the RM has prepared or heuristically completed + * + * @param startscan Indicates that recovery scan should start + * @param endscan Indicates that the recovery scan should end after returning the Xids + * @return Set of Xids the RM has prepared or heuristically completed + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Recover has been call in an improper context + */ + public Set recover(boolean startscan, boolean endscan) + throws + InternalErrorException, + CommandInvalidException; + + + /** + * An error happened (for example the channel has been abruptly closed) + * with this Xid, TM must make a heuristical decision. + * + * @param xid The Xid of the transaction branch to be heuristically completed + * @throws UnknownXidException The Xid is unknown + * @throws InternalErrorException In case of internal problem + */ + public void HeuristicOutcome(Xid xid) + throws + UnknownXidException, + InternalErrorException; + + /** + * Get the Transaction corresponding to the provided Xid + * @param xid The Xid of the transaction to ger + * @return The transaction with the provided Xid + * @throws UnknownXidException The Xid is unknown + */ + public Transaction getTransaction(Xid xid) + throws + UnknownXidException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java new file mode 100644 index 0000000000..3f6f1d6b8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.messageStore.MessageStore; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 25-Apr-2007 + * Time: 14:12:17 + */ +public interface TransactionRecord +{ + /** + * Commit this record. + * + * @param store the store to be used during commit + * @param xid the xid of the tx branch + * @throws org.apache.qpid.server.exception.InternalErrorException in case of internal problem + * @throws org.apache.qpid.server.exception.QueueDoesntExistException the queue does not exist + * @throws org.apache.qpid.server.exception.InvalidXidException the xid is invalid + * @throws org.apache.qpid.server.exception.UnknownXidException the xid is unknonw + * @throws org.apache.qpid.server.exception.MessageDoesntExistException the message does not exist + */ + public abstract void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException; + + /** + * rollback this record + * + * @param store the store to be used + * @throws InternalErrorException In case of internal error + */ + public abstract void rollback(MessageStore store) + throws + InternalErrorException; + + /** + * Prepare this record + * + * @param store the store to be used + * @throws InternalErrorException In case of internal error + */ + public abstract void prepare(MessageStore store) + throws + InternalErrorException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java new file mode 100644 index 0000000000..8214ab7dac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java @@ -0,0 +1,50 @@ +package org.apache.qpid.server.txn; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 14:57:01 + */ +public enum XAFlag +{ + rbrollback(1, "XA-RBROLLBACK", "The rollback was caused by an unspecified reason"), + rbtimeout(2, "XA-RBTIMEOUT", "The transaction branch took too long"), + heurhaz(3, "XA-HEURHAZ", "The transaction branch may have been heuristically completed"), + heurcom(4, "XA-HEURCOM", "The transaction branch has been heuristically committed"), + heurrb(5, "XA-HEURRB", "The transaction branch has been heuristically rolled back"), + heurmix(6, "XA-HEURMIX", "The transaction branch has been heuristically committed and rolled back"), + rdonly(7, "XA-RDONLY", "The transaction branch was read-only and has been committed"), + ok(8, "XA-OK", "Normal execution"); + + private final int _code; + + private final String _name; + + private final String _description; + + XAFlag(int code, String name, String description) + { + _code = code; + _name = name; + _description = description; + } + + //============================================== + // Getter methods + //============================================== + + public int getCode() + { + return _code; + } + + public String getName() + { + return _name; + } + + public String getDescription() + { + return _description; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java new file mode 100644 index 0000000000..91db1d97c0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java @@ -0,0 +1,210 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 03-Apr-2007 + * Time: 20:32:55 + */ +public class XidImpl implements Xid +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(XidImpl.class); + + //======================================================================== + // Instance Fields + //======================================================================== + + //the transaction branch identifier part of XID as an array of bytes + private byte[] m_branchQualifier; + + // the format identifier part of the XID. + private int m_formatID; + + // the global transaction identifier part of XID as an array of bytes. + private byte[] m_globalTransactionID; + + //======================================================================== + // Constructor(s) + //======================================================================== + + /** + * Create new Xid. + */ + public XidImpl() + { + + } + + /** + * Create new XidImpl from an existing Xid. + *

      + * This is usually called when an application server provides some implementation + * of the Xid interface and we need to cast this into our own XidImpl. + * + * @param xid the xid to cloning + */ + public XidImpl(Xid xid) + { + if (_log.isDebugEnabled()) + { + _log.debug("Cloning Xid"); + } + m_branchQualifier = xid.getBranchQualifier(); + m_formatID = xid.getFormatId(); + m_globalTransactionID = xid.getGlobalTransactionId(); + } + + /** + * Create a new Xid. + * + * @param branchQualifier The transaction branch identifier part of XID as an array of bytes. + * @param format The format identifier part of the XID. + * @param globalTransactionID The global transaction identifier part of XID as an array of bytes. + */ + public XidImpl(byte[] branchQualifier, int format, byte[] globalTransactionID) + { + if (_log.isDebugEnabled()) + { + _log.debug("creating Xid"); + } + m_branchQualifier = branchQualifier; + m_formatID = format; + m_globalTransactionID = globalTransactionID; + } + +//======================================================================== + + // Xid interface implementation + //======================================================================== + /** + * Format identifier. O means the OSI CCR format. + * + * @return Global transaction identifier. + */ + public byte[] getGlobalTransactionId() + { + return m_globalTransactionID; + } + + /** + * Obtain the transaction branch identifier part of XID as an array of bytes. + * + * @return Branch identifier part of XID. + */ + public byte[] getBranchQualifier() + { + return m_branchQualifier; + } + + /** + * Obtain the format identifier part of the XID. + * + * @return Format identifier. O means the OSI CCR format. + */ + public int getFormatId() + { + return m_formatID; + } + +//======================================================================== +// Object operations +//======================================================================== + + /** + * Indicates whether some other Xid is "equal to" this one. + *

      + * Two Xids are equal if and only if their three elementary parts are equal + * + * @param o the object to compare this XidImpl against. + * @return code>true if the XidImpl are equal; false otherwise. + */ + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (o instanceof XidImpl) + { + XidImpl other = (XidImpl) o; + if (m_formatID == other.getFormatId()) + { + if (m_branchQualifier.length == other.getBranchQualifier().length) + { + for (int i = 0; i < m_branchQualifier.length; i++) + { + if (m_branchQualifier[i] != other.getBranchQualifier()[i]) + { + return false; + } + } + + if (m_globalTransactionID.length == other.getGlobalTransactionId().length) + { + for (int i = 0; i < m_globalTransactionID.length; i++) + { + if (m_globalTransactionID[i] != other.getGlobalTransactionId()[i]) + { + return false; + } + } + // everithing is equal + return true; + } + } + } + } + return false; + } + + /** + * Returns a hash code for this Xid. + *

      + * As this object is used as a key entry in a hashMap it is necessary to provide an implementation + * of hashcode in order to fulfill the following aspect of the general contract of + * {@link Object#hashCode()} that is: + *

        + *
      • If two objects are equal according to the equals(Object) + * method, then calling the hashCode method on each of + * the two objects must produce the same integer result. + *
      + *

      + * The hash code for a + * XidImpl object is computed as + *

      +     *  hashcode( globalTransactionID ) + hashcode( branchQualifier ) + formatID
      +     * 
      + * + * @return a hash code value for this object. + */ + public int hashCode() + { + return (new String(m_globalTransactionID)).hashCode() + (new String(m_branchQualifier)).hashCode() + m_formatID; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 150b98b424..f7c578d9a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -59,7 +59,8 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { - _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); + _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.MemoryMessageStore"); + _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.MemoryTransactionManager"); Properties users = new Properties(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index b5c59dbbb7..7e329a5274 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,249 +1,272 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - - private final String _name; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - - } // End of MBean class - - - public VirtualHost(String name, MessageStore store) throws Exception - { - this(name, null, store); - } - - public VirtualHost(String name, Configuration hostConfig) throws Exception - { - this(name, hostConfig, null); - } - - private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception - { - _name = name; - - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - _exchangeRegistry.initialise(); - - _logger.warn("VirtualHost authentication Managers require spec change to be operational."); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - - _accessManager = new AccessManagerImpl(name, hostConfig); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - } - - private void initialiseMessageStore(Configuration config) throws Exception - { - String messageStoreClass = config.getString("store.class"); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - _messageStore.configure(this, "store", config); - } - - - public T getConfiguredObject(Class instanceType, Configuration config) - { - T instance; - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); - } - Configurator.configure(instance); - - return instance; - } - - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - if (_messageStore != null) - { - _messageStore.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.messageStore.MessageStore; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + private TransactionManager _transactionManager; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private AccessManager _accessManager; + + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, null, store); + } + + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + // This isn't needed to be registered + //_virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(this); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseTransactionManager(hostConfig); + initialiseMessageStore(hostConfig); + } + + _exchangeRegistry.initialise(); + + _logger.warn("VirtualHost authentication Managers require spec change to be operational."); + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = new AccessManagerImpl(name, hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(this, _transactionManager, "store", config); + } + + private void initialiseTransactionManager(Configuration config) throws Exception + { + String transactionManagerClass = config.getString("txn.class"); + Class clazz = Class.forName(transactionManagerClass); + Object o = clazz.newInstance(); + + if (!(o instanceof TransactionManager)) + { + throw new ClassCastException("Transaction Manager class must implement " + TransactionManager.class + ". Class " + clazz + + " does not."); + } + _transactionManager = (TransactionManager) o; + } + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public TransactionManager getTransactionManager() + { + return _transactionManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public AccessManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} -- cgit v1.2.1 From 05f831392baff1b6a442384de9ff3d937e175287 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 May 2007 13:41:35 +0000 Subject: Merged revisions 533704-533720,533722-533763,533766-533818,533820-533839,533841-533859,533862-534112,534114-534117 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r533704 | bhupendrab | 2007-04-30 12:37:59 +0100 (Mon, 30 Apr 2007) | 1 line Added time-out for secure server connection. ........ r534036 | ritchiem | 2007-05-01 13:28:03 +0100 (Tue, 01 May 2007) | 1 line QPID-461 Update to CommitRollbackTest. Ensuring messages received have the correct redelivered value, regardless of order. Different test case also was problematic. ........ r534117 | ritchiem | 2007-05-01 16:22:17 +0100 (Tue, 01 May 2007) | 4 lines Comments and Test changes VirtualHost Added comments HeapExhaustion - Updated to send transient messages. QpidClientConnection - Allowed specification of type of message to send. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534856 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHost.java | 263 +++++++++++++++++++++ 1 file changed, 263 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 7e329a5274..15edb2289f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,3 +1,4 @@ +<<<<<<< .working /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -270,3 +271,265 @@ public class VirtualHost implements Accessable return _virtualHostMBean; } } +======= +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private AccessManager _accessManager; + + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + /** + * Used for testing only + * @param name + * @param store + * @throws Exception + */ + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, null, store); + } + + /** + * Normal Constructor + * @param name + * @param hostConfig + * @throws Exception + */ + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + // This isn't needed to be registered + //_virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(this); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + _exchangeRegistry.initialise(); + + _logger.warn("VirtualHost authentication Managers require spec change to be operational."); + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = new AccessManagerImpl(name, hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(this, "store", config); + } + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public AccessManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} +>>>>>>> .merge-right.r534117 -- cgit v1.2.1 From 8a1ee495d1c6c26fee7310b117eed401c9121362 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 May 2007 13:47:43 +0000 Subject: Merged revisions 534473-534477,534479-534763 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r534473 | bhupendrab | 2007-05-02 15:19:52 +0100 (Wed, 02 May 2007) | 2 lines Exchange MBeans updated - init method moved to super class. Exception handling of management console updated for SecurityException. ........ r534763 | bhupendrab | 2007-05-03 10:35:11 +0100 (Thu, 03 May 2007) | 1 line Management console users list display is updated. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534859 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/AbstractExchange.java | 29 ++++++++++++++++++++++ .../qpid/server/exchange/DestNameExchange.java | 21 ---------------- .../qpid/server/exchange/DestWildExchange.java | 19 -------------- .../qpid/server/exchange/FanoutExchange.java | 21 ---------------- .../qpid/server/exchange/HeadersExchange.java | 15 +++++------ .../security/access/AMQUserManagementMBean.java | 2 +- 6 files changed, 36 insertions(+), 71 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index ff120e6a92..868ac31a54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -23,6 +23,13 @@ package org.apache.qpid.server.exchange; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.ArrayType; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -60,11 +67,33 @@ public abstract class AbstractExchange implements Exchange, Managable */ protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange { + // open mbean data types for representing exchange bindings + protected String[] _bindingItemNames; + protected String[] _bindingItemIndexNames; + protected OpenType[] _bindingItemTypes; + protected CompositeType _bindingDataType; + protected TabularType _bindinglistDataType; + protected TabularDataSupport _bindingList; + public ExchangeMBean() throws NotCompliantMBeanException { super(ManagedExchange.class, ManagedExchange.TYPE); } + protected void init() throws OpenDataException + { + _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[2]; + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + public ManagedObject getParentObject() { return _virtualHost.getManagedObject(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index de3905268e..ab103fbd2a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -64,14 +64,6 @@ public class DestNameExchange extends AbstractExchange @MBeanDescription("Management Bean for Direct Exchange") private final class DestNameExchangeMBean extends ExchangeMBean { - // open mbean data types for representing exchange bindings - private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; - private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; - 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 JMException { @@ -80,19 +72,6 @@ public class DestNameExchange extends AbstractExchange init(); } - /** - * initialises the OpenType objects. - */ - private void init() throws OpenDataException - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - public TabularData bindings() throws OpenDataException { Map> bindings = _index.getBindingsMap(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 605a4bcb61..386cfd2349 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -61,14 +61,6 @@ public class DestWildExchange extends AbstractExchange @MBeanDescription("Management Bean for Topic Exchange") private final class DestWildExchangeMBean extends ExchangeMBean { - // open mbean data types for representing exchange bindings - private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; - private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; - 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 JMException { @@ -77,17 +69,6 @@ public class DestWildExchange extends AbstractExchange init(); } - /** initialises the OpenType objects. */ - private void init() throws OpenDataException - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - /** returns exchange bindings in tabular form */ public TabularData bindings() throws OpenDataException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 095fd2b7e9..b3690d3e10 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -41,14 +41,6 @@ public class FanoutExchange extends AbstractExchange @MBeanDescription("Management Bean for Fanout Exchange") private final class FanoutExchangeMBean extends ExchangeMBean { - // open mbean data types for representing exchange bindings - private String[] _bindingItemNames = {"Routing Key", "Queue Names"}; - private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; - private OpenType[] _bindingItemTypes = new OpenType[2]; - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; - private TabularDataSupport _bindingList = null; - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") public FanoutExchangeMBean() throws JMException { @@ -57,19 +49,6 @@ public class FanoutExchange extends AbstractExchange init(); } - /** - * initialises the OpenType objects. - */ - private void init() throws OpenDataException - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Routing key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - public TabularData bindings() throws OpenDataException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 204e2f9f93..b4b2bc20bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -90,14 +90,6 @@ public class HeadersExchange extends AbstractExchange @MBeanDescription("Management Bean for Headers Exchange") private final class HeadersExchangeMBean extends ExchangeMBean { - // open mbean data types for representing exchange bindings - private String[] _bindingItemNames = {"S.No.", "Queue Name", "Header Bindings"}; - private String[] _bindingItemIndexNames = {_bindingItemNames[0]}; - private OpenType[] _bindingItemTypes = new OpenType[3]; - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; - private TabularDataSupport _bindingList = null; - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") public HeadersExchangeMBean() throws JMException { @@ -105,11 +97,16 @@ public class HeadersExchange extends AbstractExchange _exchangeType = "headers"; init(); } + /** * initialises the OpenType objects. */ - private void init() throws OpenDataException + protected void init() throws OpenDataException { + _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[3]; _bindingItemTypes[0] = SimpleType.INTEGER; _bindingItemTypes[1] = SimpleType.STRING; _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java index fbb80494c1..155afa961e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -72,7 +72,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana static TabularType _userlistDataType; // Datatype for representing User Lists static CompositeType _userDataType; // Composite type for representing User - static String[] _userItemNames = {"Username", "Read", "Write", "Admin"}; + static String[] _userItemNames = {"Username", "read", "write", "admin"}; static { -- cgit v1.2.1 From 1402635a77ae14a0f595c6452630ac66b957315c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 May 2007 14:23:11 +0000 Subject: Error during merge. SVN reported a conflict but didn't when editing the conflict it didn't see any.... it was wrong.. or rather I should have checked the file. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534883 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHost.java | 265 +-------------------- 1 file changed, 1 insertion(+), 264 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 15edb2289f..af0f5e534e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,4 +1,3 @@ -<<<<<<< .working /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -270,266 +269,4 @@ public class VirtualHost implements Accessable { return _virtualHostMBean; } -} -======= -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - - private final String _name; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - - } // End of MBean class - - /** - * Used for testing only - * @param name - * @param store - * @throws Exception - */ - public VirtualHost(String name, MessageStore store) throws Exception - { - this(name, null, store); - } - - /** - * Normal Constructor - * @param name - * @param hostConfig - * @throws Exception - */ - public VirtualHost(String name, Configuration hostConfig) throws Exception - { - this(name, hostConfig, null); - } - - private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception - { - _name = name; - - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - _exchangeRegistry.initialise(); - - _logger.warn("VirtualHost authentication Managers require spec change to be operational."); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - - _accessManager = new AccessManagerImpl(name, hostConfig); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - } - - private void initialiseMessageStore(Configuration config) throws Exception - { - String messageStoreClass = config.getString("store.class"); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - _messageStore.configure(this, "store", config); - } - - - public T getConfiguredObject(Class instanceType, Configuration config) - { - T instance; - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); - } - Configurator.configure(instance); - - return instance; - } - - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - if (_messageStore != null) - { - _messageStore.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } -} ->>>>>>> .merge-right.r534117 +} \ No newline at end of file -- cgit v1.2.1 From f255f2afe5d386deec361fcc4978b60c2322f790 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 May 2007 14:25:36 +0000 Subject: Remerged comment changes from r534117 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534888 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/virtualhost/VirtualHost.java | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index af0f5e534e..19e732d5a5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -110,12 +110,27 @@ public class VirtualHost implements Accessable } // End of MBean class - + /** + * Used for testing only + * + * @param name + * @param store + * + * @throws Exception + */ public VirtualHost(String name, MessageStore store) throws Exception { this(name, null, store); } + /** + * Normal Constructor + * + * @param name + * @param hostConfig + * + * @throws Exception + */ public VirtualHost(String name, Configuration hostConfig) throws Exception { this(name, hostConfig, null); @@ -174,9 +189,9 @@ public class VirtualHost implements Accessable _messageStore.configure(this, _transactionManager, "store", config); } - private void initialiseTransactionManager(Configuration config) throws Exception + private void initialiseTransactionManager(Configuration config) throws Exception { - String transactionManagerClass = config.getString("txn.class"); + String transactionManagerClass = config.getString("txn.class"); Class clazz = Class.forName(transactionManagerClass); Object o = clazz.newInstance(); -- cgit v1.2.1 From 29c7ff71a3f4116b1df17261a496e5c9e273cdae Mon Sep 17 00:00:00 2001 From: Tejeswar Das Date: Thu, 3 May 2007 18:04:14 +0000 Subject: Added newline at the end git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534948 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 19e732d5a5..e855a2da91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -284,4 +284,5 @@ public class VirtualHost implements Accessable { return _virtualHostMBean; } -} \ No newline at end of file +} + -- cgit v1.2.1 From ab8d563c9ac1f7f82a4b417ca02b210d2e51245a Mon Sep 17 00:00:00 2001 From: Tejeswar Das Date: Thu, 3 May 2007 19:17:04 +0000 Subject: git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534964 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e855a2da91..6638689299 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -284,5 +284,5 @@ public class VirtualHost implements Accessable { return _virtualHostMBean; } -} - +} + -- cgit v1.2.1 From d4b3506f2133f3520ce3cf6e058d7e5863c0e807 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 9 May 2007 08:48:18 +0000 Subject: Patch from Arnaud Simon (asimon@redhat.com) to fix tests broken by earlier changes. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536458 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 6 +- .../java/org/apache/qpid/server/AMQChannel.java | 197 +++++++++--------- .../server/messageStore/MemoryMessageStore.java | 148 +++++++++++-- .../org/apache/qpid/server/queue/AMQMessage.java | 8 +- .../qpid/server/queue/StorableMessageHandle.java | 13 +- .../org/apache/qpid/server/txn/DequeueRecord.java | 2 +- .../txn/DistributedTransactionalContext.java | 45 ++-- .../qpid/server/txn/MemoryDequeueRecord.java | 82 ++++++++ .../qpid/server/txn/MemoryEnqueueRecord.java | 82 ++++++++ .../apache/qpid/server/txn/MemoryTransaction.java | 158 ++++++++++++++ .../qpid/server/txn/MemoryTransactionManager.java | 228 ++++++++++++++++++++- .../qpid/server/txn/NonTransactionalContext.java | 1 + .../org/apache/qpid/server/txn/Transaction.java | 16 +- .../apache/qpid/server/txn/TransactionManager.java | 13 ++ 14 files changed, 847 insertions(+), 152 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index ae1cf43f6c..40462cf2bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -228,10 +228,14 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.destroyQueue(queue); + if( queue.isDurable() ) + { + _messageStore.destroyQueue(queue); + } } catch (Exception ex) { + ex.printStackTrace(); JMException jme = new JMException(ex.getMessage()); jme.initCause(ex); throw new MBeanException(jme, "Error in deleting queue " + queueName); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 9711bbf4d2..6dd80b3bfa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -73,10 +73,14 @@ public class AMQChannel */ 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 */ + /** + * 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. */ + /** + * This tag is unique per subscription to a queue. The server returns this in response to a basic.consume request. + */ private int _consumerTag; /** @@ -86,7 +90,9 @@ public class AMQChannel */ private AMQMessage _currentMessage; - /** Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */ + /** + * Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. + */ private final Map _consumerTag2QueueMap = new HashMap(); private final MessageStore _messageStore; @@ -118,7 +124,8 @@ public class AMQChannel public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, MessageStore messageStore, MessageRouter exchanges) - throws AMQException + throws + AMQException { _session = session; _channelId = channelId; @@ -132,7 +139,9 @@ public class AMQChannel _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } - /** Sets this channel to be part of a local transaction */ + /** + * Sets this channel to be part of a local transaction + */ public void setLocalTransactional() { _txnContext = new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); @@ -193,23 +202,25 @@ public class AMQChannel } - public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) throws AMQException + public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) + throws + AMQException { _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, - _txnContext); + _txnContext); _currentMessage.setPublisher(publisher); } public void publishContentHeader(ContentHeaderBody contentHeaderBody) - throws AMQException + throws + AMQException { if (_currentMessage == null) { throw new AMQException("Received content header without previously receiving a BasicPublish frame"); - } - else + } else { if (_log.isTraceEnabled()) { @@ -228,7 +239,8 @@ public class AMQChannel } public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) - throws AMQException + throws + AMQException { if (_currentMessage == null) { @@ -261,7 +273,9 @@ public class AMQChannel } } - protected void routeCurrentMessage() throws AMQException + protected void routeCurrentMessage() + throws + AMQException { try { @@ -294,14 +308,15 @@ public class AMQChannel * @param exclusive Flag requesting exclusive access to the queue * @param acks Are acks enabled for this subscriber * @param filters Filters to apply to this 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 AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) + throws + AMQException, + ConsumerTagNotUniqueException { if (tag == null) { @@ -318,28 +333,11 @@ public class AMQChannel } - public void unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException + public void unsubscribeConsumer(AMQProtocolSession session, final AMQShortString consumerTag) + throws + AMQException { - if (_log.isDebugEnabled()) - { - _log.debug("Unacked Map Dump size:" + _unacknowledgedMessageMap.size()); - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - _log.debug(message); - - return true; - } - - public void visitComplete() - { - } - }); - } - - AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); + final AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); if (q != null) { q.unregisterProtocolSession(session, _channelId, consumerTag); @@ -350,25 +348,27 @@ public class AMQChannel * Called from the protocol session to close this channel and clean up. T * * @param session The session to close - * * @throws AMQException if there is an error during closure */ - public void close(AMQProtocolSession session) throws AMQException + public void close(AMQProtocolSession session) + throws + AMQException { _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); } - private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException + private void unsubscribeAllConsumers(AMQProtocolSession session) + throws + AMQException { if (_log.isInfoEnabled()) { if (!_consumerTag2QueueMap.isEmpty()) { _log.info("Unsubscribing all consumers on channel " + toString()); - } - else + } else { _log.info("No consumers to unsubscribe on channel " + toString()); } @@ -400,13 +400,12 @@ public class AMQChannel if (queue == null) { _log.debug("Adding unacked message with a null queue:" + message.debugIdentity()); - } - else + } else { if (_log.isDebugEnabled()) { _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag + - ") with a queue(" + queue + ") for " + consumerTag); + ") with a queue(" + queue + ") for " + consumerTag); } } } @@ -431,7 +430,9 @@ public class AMQChannel * * @throws org.apache.qpid.AMQException if the requeue fails */ - public void requeue() throws AMQException + 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(); @@ -452,12 +453,11 @@ public class AMQChannel // if (_nonTransactedContext == null) { _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } - else + } else { deliveryContext = _txnContext; } @@ -489,10 +489,11 @@ public class AMQChannel * Requeue a single message * * @param deliveryTag The message to requeue - * * @throws AMQException If something goes wrong. */ - public void requeue(long deliveryTag) throws AMQException + public void requeue(long deliveryTag) + throws + AMQException { UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); @@ -516,12 +517,11 @@ public class AMQChannel // if (_nonTransactedContext == null) { _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } - else + } else { deliveryContext = _txnContext; } @@ -532,19 +532,17 @@ public class AMQChannel deliveryContext.deliver(unacked.message, unacked.queue, true); //Deliver increments the message count but we have already deliverted this once so don't increment it again // this was because deliver did an increment changed this. - } - else + } else { _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() + "):" + deliveryTag + - " but no queue defined and no DeadLetter queue so DROPPING message."); + " but no queue defined and no DeadLetter queue so DROPPING message."); // _log.error("Requested requeue of message:" + deliveryTag + // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); // // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); // } - } - else + } else { _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); @@ -554,10 +552,12 @@ public class AMQChannel { int count = 0; - public boolean callback(UnacknowledgedMessage message) throws AMQException + public boolean callback(UnacknowledgedMessage message) + throws + AMQException { _log.debug((count++) + ": (" + message.message.debugIdentity() + ")" + - "[" + message.deliveryTag + "]"); + "[" + message.deliveryTag + "]"); return false; // Continue } @@ -577,10 +577,11 @@ public class AMQChannel * Called to resend all outstanding unacknowledged messages to this same channel. * * @param requeue Are the messages to be requeued or dropped. - * * @throws AMQException When something goes wrong. */ - public void resend(final boolean requeue) throws AMQException + public void resend(final boolean requeue) + throws + AMQException { final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); @@ -595,7 +596,9 @@ public class AMQChannel // and those that don't to be requeued. _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - public boolean callback(UnacknowledgedMessage message) throws AMQException + public boolean callback(UnacknowledgedMessage message) + throws + AMQException { AMQShortString consumerTag = message.consumerTag; AMQMessage msg = message.message; @@ -606,13 +609,11 @@ public class AMQChannel if (_consumerTag2QueueMap.containsKey(consumerTag)) { msgToResend.add(message); - } - else // consumer has gone + } else // consumer has gone { msgToRequeue.add(message); } - } - else + } else { // Message has no consumer tag, so was "delivered" to a GET // or consumer no longer registered @@ -622,13 +623,11 @@ public class AMQChannel if (requeue) { msgToRequeue.add(message); - } - else + } else { _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); } - } - else + } else { _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } @@ -649,8 +648,7 @@ public class AMQChannel if (!msgToResend.isEmpty()) { _log.info("Preparing (" + msgToResend.size() + ") message to resend."); - } - else + } else { _log.info("No message to resend."); } @@ -699,8 +697,7 @@ public class AMQChannel } //move this message to requeue msgToRequeue.add(message); - } - else + } else { if (_log.isDebugEnabled()) { @@ -710,8 +707,7 @@ public class AMQChannel _unacknowledgedMessageMap.remove(message.deliveryTag); } } // sync(sub.getSendLock) - } - else + } else { if (_log.isInfoEnabled()) @@ -740,12 +736,11 @@ public class AMQChannel if (_nonTransactedContext == null) { _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } - else + } else { deliveryContext = _txnContext; } @@ -768,14 +763,17 @@ public class AMQChannel * 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 + public void queueDeleted(final AMQQueue queue) + throws + AMQException { _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - public boolean callback(UnacknowledgedMessage message) throws AMQException + public boolean callback(UnacknowledgedMessage message) + throws + AMQException { if (message.queue == queue) { @@ -787,7 +785,7 @@ public class AMQChannel catch (AMQException e) { _log.error("Error decrementing ref count on message " + message.message.getMessageId() + ": " + - e, e); + e, e); } } return false; @@ -805,10 +803,11 @@ public class AMQChannel * @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 + public void acknowledgeMessage(long deliveryTag, boolean multiple) + throws + AMQException { synchronized (_unacknowledgedMessageMap.getLock()) { @@ -842,7 +841,7 @@ public class AMQChannel boolean suspend; suspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark) - || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); + || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); setSuspended(suspend); } @@ -868,8 +867,7 @@ public class AMQChannel { q.deliverAsync(); } - } - else + } else { _log.debug("Suspending channel " + this); } @@ -881,16 +879,20 @@ public class AMQChannel return _suspended.get(); } - public void commit() throws AMQException + public void commit() + throws + AMQException { if (!isTransactional()) { throw new AMQException("Fatal error: commit called on non-transactional channel"); } - _txnContext.commit(); + _txnContext.commit(); } - public void rollback() throws AMQException + public void rollback() + throws + AMQException { _txnContext.rollback(); } @@ -919,14 +921,16 @@ public class AMQChannel return _storeContext; } - public void processReturns(AMQProtocolSession session) throws AMQException + public void processReturns(AMQProtocolSession session) + throws + AMQException { for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); session.getProtocolOutputConverter().writeReturn(message, _channelId, - bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); + bouncedMessage.getReplyCode().getCode(), + new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); } @@ -937,8 +941,7 @@ public class AMQChannel if (isSuspended()) { return true; - } - else + } else { boolean willSuspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() + 1 > _prefetch_HighWaterMark); if (!willSuspend) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java index 581bca2efe..a027b90743 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java @@ -19,49 +19,75 @@ package org.apache.qpid.server.messageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.txn.TransactionRecord; +import org.apache.qpid.server.txn.MemoryEnqueueRecord; +import org.apache.qpid.server.txn.MemoryDequeueRecord; import org.apache.qpid.server.exception.*; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; import javax.transaction.xa.Xid; -import java.util.Collection; +import java.util.*; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; /** + * This a simple in-memory implementation of a message store i.e. nothing is persisted + *

      * Created by Arnaud Simon * Date: 26-Apr-2007 * Time: 08:23:45 */ -public class MemoryMessageStore implements MessageStore +public class MemoryMessageStore implements MessageStore { + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); + + // The table of message with its corresponding stream containing the message body + private Map _stagedMessages; + // The queue/messages association + private Map> _queueMap; + // the message ID + private long _messageID = 0; + // The transaction manager + private TransactionManager _txm; + + //======================================================================== + // Interface MessageStore + //======================================================================== public void removeExchange(Exchange exchange) throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // do nothing this is inmemory } public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException + throws + InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // do nothing this is inmemory } public void createExchange(Exchange exchange) throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // do nothing this is inmemory } public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // do nothing this is inmemory } public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) @@ -69,14 +95,21 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, IllegalArgumentException { - //To change body of implemented methods use File | Settings | File Templates. + _log.info("Configuring memory message store"); + // Initialise the maps + _stagedMessages = new HashMap(); + _queueMap = new HashMap>(); + _txm = tm; + _txm.configure(this, "txn", config); } public void close() throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + _log.info("Closing memory message store"); + _stagedMessages.clear(); + _queueMap.clear(); } public void createQueue(StorableQueue queue) @@ -84,7 +117,12 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, QueueAlreadyExistsException { - //To change body of implemented methods use File | Settings | File Templates. + if (_queueMap.containsKey(queue)) + { + throw new QueueAlreadyExistsException("queue " + queue + " already exists"); + } + // add this queue into the map + _queueMap.put(queue, new LinkedList()); } public void destroyQueue(StorableQueue queue) @@ -92,7 +130,12 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, QueueDoesntExistException { - //To change body of implemented methods use File | Settings | File Templates. + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " does not exist"); + } + // remove this queue from the map + _queueMap.remove(queue); } public void stage(StorableMessage m) @@ -100,7 +143,12 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, MessageAlreadyStagedException { - //To change body of implemented methods use File | Settings | File Templates. + if (_stagedMessages.containsKey(m)) + { + throw new MessageAlreadyStagedException("message " + m + " already staged"); + } + _stagedMessages.put(m, new ByteArrayOutputStream()); + m.staged(); } public void appendContent(StorableMessage m, byte[] data, int offset, int size) @@ -108,7 +156,11 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, MessageDoesntExistException { - //To change body of implemented methods use File | Settings | File Templates. + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + _stagedMessages.get(m).write(data, offset, size); } public byte[] loadContent(StorableMessage m, int offset, int size) @@ -116,7 +168,15 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, MessageDoesntExistException { - return new byte[0]; //To change body of implemented methods use File | Settings | File Templates. + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + byte[] result = new byte[size]; + ByteBuffer buf = ByteBuffer.allocate(size); + buf.put(_stagedMessages.get(m).toByteArray(), offset, size); + buf.get(result); + return result; } public void destroy(StorableMessage m) @@ -124,7 +184,11 @@ public class MemoryMessageStore implements MessageStore InternalErrorException, MessageDoesntExistException { - //To change body of implemented methods use File | Settings | File Templates. + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + _stagedMessages.remove(m); } public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) @@ -135,7 +199,31 @@ public class MemoryMessageStore implements MessageStore UnknownXidException, MessageDoesntExistException { - //To change body of implemented methods use File | Settings | File Templates. + if (xid != null) + { + // this is a tx operation + TransactionRecord enqueueRecord = new MemoryEnqueueRecord(m, queue); + _txm.getTransaction(xid).addRecord(enqueueRecord); + } else + { + if (!_stagedMessages.containsKey(m)) + { + try + { + stage(m); + } catch (MessageAlreadyStagedException e) + { + throw new InternalErrorException(e); + } + appendContent(m, m.getData(), 0, m.getPayloadSize()); + } + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " dos not exist"); + } + _queueMap.get(queue).add(m); + m.enqueue(queue); + } } public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) @@ -145,25 +233,43 @@ public class MemoryMessageStore implements MessageStore InvalidXidException, UnknownXidException { - //To change body of implemented methods use File | Settings | File Templates. + if (xid != null) + { + // this is a tx operation + TransactionRecord dequeueRecord = new MemoryDequeueRecord(m, queue); + _txm.getTransaction(xid).addRecord(dequeueRecord); + } else + { + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " dos not exist"); + } + m.dequeue(queue); + _queueMap.get(queue).remove(m); + if (!m.isEnqueued()) + { + // we can delete this message + _stagedMessages.remove(m); + } + } } public Collection getAllQueues() throws InternalErrorException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return _queueMap.keySet(); } public Collection getAllMessages(StorableQueue queue) throws InternalErrorException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return _queueMap.get(queue); } public long getNewMessageId() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return _messageID++; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index eefff090df..32c6eb2c9b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -432,10 +432,10 @@ public class AMQMessage implements StorableMessage // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store - for (AMQQueue q : _transientMessageData.getDestinationQueues()) - { - _messageHandle.enqueue(storeContext, _messageId, q); - } + // for (AMQQueue q : _transientMessageData.getDestinationQueues()) + // { + // _messageHandle.enqueue(storeContext, _messageId, q); + // } if (_transientMessageData.getContentHeaderBody().bodySize == 0) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java index 5978e3b10d..5539627820 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java @@ -169,7 +169,10 @@ public class StorableMessageHandle implements AMQMessageHandle { try { - _messageStore.enqueue((Xid) storeContext.getPayload(), _message, queue); + if (queue.isDurable()) + { + _messageStore.enqueue((Xid) storeContext.getPayload(), _message, queue); + } } catch (Exception e) { throw new AMQException("PRoblem during message enqueue", e); @@ -182,7 +185,10 @@ public class StorableMessageHandle implements AMQMessageHandle { try { - _messageStore.dequeue((Xid) storeContext.getPayload(), _message, queue); + if (queue.isDurable()) + { + _messageStore.dequeue((Xid) storeContext.getPayload(), _message, queue); + } } catch (Exception e) { throw new AMQException("PRoblem during message dequeue", e); @@ -199,8 +205,8 @@ public class StorableMessageHandle implements AMQMessageHandle if (_payload == null) { int bodySize = (int) _contentHeaderBody.bodySize; - _buffer = ByteBuffer.allocate(bodySize); _payload = new byte[bodySize]; + _buffer = ByteBuffer.wrap(_payload); for (ContentChunk contentBody : _chunks) { int chunkSize = contentBody.getSize(); @@ -208,7 +214,6 @@ public class StorableMessageHandle implements AMQMessageHandle contentBody.getData().get(chunk); _buffer.put(chunk); } - _buffer.get(_payload); } return _payload; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java index 0d25ab0e32..d899bb972c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java @@ -39,7 +39,7 @@ public class DequeueRecord implements TransactionRecord UnknownXidException, MessageDoesntExistException { - // do nothing + // nothing } public void rollback(MessageStore store) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java index eff623ca7c..05756a8c23 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java @@ -46,7 +46,8 @@ public class DistributedTransactionalContext implements TransactionalContext //======================================================================== // The logger for this class private static final Logger _log = Logger.getLogger(DistributedTransactionalContext.class); - + private static final Object _lockXID = new Object(); + private static int _count = 0; //======================================================================== // Instance Fields //======================================================================== @@ -60,7 +61,6 @@ public class DistributedTransactionalContext implements TransactionalContext final private List _returnMessages; // for generating xids private byte[] _txId = ("txid").getBytes(); - private int _count = 0; public DistributedTransactionalContext(TransactionManager transactionManager, MessageStore messageStore, StoreContext storeContext, List returnMessages) @@ -75,15 +75,21 @@ public class DistributedTransactionalContext implements TransactionalContext throws AMQException { - // begin the transaction and pass the XID through the context - Xid xid = new XidImpl(("branch" + _count++).getBytes(), 1, _txId); - try + if (_storeContext.getPayload() == null) { - _transactionManager.begin(xid); - _storeContext.setPayload(xid); - } catch (Exception e) - { - throw new AMQException("Problem during transaction begin", e); + synchronized (_lockXID) + { + // begin the transaction and pass the XID through the context + Xid xid = new XidImpl(("branch" + _count++).getBytes(), 1, _txId); + try + { + _transactionManager.begin(xid); + _storeContext.setPayload(xid); + } catch (Exception e) + { + throw new AMQException("Problem during transaction begin", e); + } + } } } @@ -93,11 +99,18 @@ public class DistributedTransactionalContext implements TransactionalContext { try { - _transactionManager.commit_one_phase((Xid) _storeContext.getPayload()); + if (_storeContext.getPayload() != null) + { + _transactionManager.commit_one_phase((Xid) _storeContext.getPayload()); + } } catch (Exception e) { throw new AMQException("Problem during transaction commit", e); } + finally + { + _storeContext.setPayload(null); + } } public void rollback() @@ -106,11 +119,18 @@ public class DistributedTransactionalContext implements TransactionalContext { try { - _transactionManager.rollback((Xid) _storeContext.getPayload()); + if (_storeContext.getPayload() != null) + { + _transactionManager.rollback((Xid) _storeContext.getPayload()); + } } catch (Exception e) { throw new AMQException("Problem during transaction rollback", e); } + finally + { + _storeContext.setPayload(null); + } } public void messageFullyReceived(boolean persistent) @@ -142,6 +162,7 @@ public class DistributedTransactionalContext implements TransactionalContext throws AMQException { + beginTranIfNecessary(); if (multiple) { if (deliveryTag == 0) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java new file mode 100644 index 0000000000..abbd2ad923 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java @@ -0,0 +1,82 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.exception.*; +import org.apache.log4j.Logger; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 03-May-2007 + * Time: 13:59:47 + */ +public class MemoryDequeueRecord implements TransactionRecord +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryDequeueRecord.class); + // the queue + StorableQueue _queue; + // the message + StorableMessage _message; + + //======================================================================== + // Constructor + //======================================================================== + public MemoryDequeueRecord( StorableMessage m, StorableQueue queue) + { + _queue = queue; + _message = m; + } + + //======================================================================== + // Interface TransactionRecord + //======================================================================== + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + store.dequeue(null, _message, _queue); + } + + public void rollback(MessageStore store) + throws + InternalErrorException + { + // do nothing + } + + public void prepare(MessageStore store) + throws + InternalErrorException + { + // do nothing + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java new file mode 100644 index 0000000000..159a5a471c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java @@ -0,0 +1,82 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.exception.*; +import org.apache.log4j.Logger; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 03-May-2007 + * Time: 14:00:04 + */ +public class MemoryEnqueueRecord implements TransactionRecord +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryDequeueRecord.class); + + // the queue + StorableQueue _queue; + // the message + StorableMessage _message; + + //======================================================================== + // Constructor + //======================================================================== + public MemoryEnqueueRecord(StorableMessage m, StorableQueue queue) + { + _queue = queue; + _message = m; + } + //======================================================================== + // Interface TransactionRecord + //======================================================================== + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + store.enqueue(null, _message, _queue); + } + + public void rollback(MessageStore store) + throws + InternalErrorException + { + // do nothing + } + + public void prepare(MessageStore store) + throws + InternalErrorException + { + // do nothing + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java new file mode 100644 index 0000000000..4cd52b1a72 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java @@ -0,0 +1,158 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; + +import java.util.List; +import java.util.LinkedList; + +/** + * Created by Arnaud Simon + * Date: 03-May-2007 + * Time: 14:30:41 + */ +public class MemoryTransaction implements Transaction +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryTransaction.class); + + //======================================================================== + // Instance Fields + //======================================================================== + // Indicates whether this transaction is prepared + private boolean _prepared = false; + // Indicates that this transaction has heuristically rolled back + private boolean _heurRollBack = false; + // The list of Abstract records associated with this tx + private List _records = new LinkedList(); + // The date when this tx has been created. + private long _dateCreated; + // The timeout in seconds + private long _timeout; + + //========================================================= + // Constructors + //========================================================= + /** + * Create a transaction that wraps a BDB tx and set the creation date. + * + */ + public MemoryTransaction() + { + _dateCreated = System.currentTimeMillis(); + } + + //========================================================= + // Getter and Setter methods + //========================================================= + /** + * Notify that this tx has been prepared + */ + public void prepare() + { + _prepared = true; + } + + /** + * Specify whether this transaction is prepared + * + * @return true if this transaction is prepared, false otherwise + */ + public boolean isPrepared() + { + return _prepared; + } + + /** + * Notify that this tx has been heuristically rolled back + */ + public void heurRollback() + { + _heurRollBack = true; + } + + /** + * Specify whether this transaction has been heuristically rolled back + * + * @return true if this transaction has been heuristically rolled back , false otherwise + */ + public boolean isHeurRollback() + { + return _heurRollBack; + } + + /** + * Add an abstract record to this tx. + * + * @param record The record to be added + */ + public void addRecord(TransactionRecord record) + { + _records.add(record); + } + + /** + * Get the list of records associated with this tx. + * + * @return The list of records associated with this tx. + */ + public List getrecords() + { + return _records; + } + + /** + * Set this tx timeout + * + * @param timeout This tx timeout in seconds + */ + public void setTimeout(long timeout) + { + _timeout = timeout; + } + + /** + * Get this tx timeout + * + * @return This tx timeout in seconds + */ + public long getTimeout() + { + return _timeout; + } + + /** + * Specify whether this tx has expired + * + * @return true if this tx has expired, false otherwise + */ + public boolean hasExpired() + { + long currentDate = System.currentTimeMillis(); + boolean result = currentDate - _dateCreated > _timeout * 1000; + if (_log.isDebugEnabled()) + { + _log.debug("transaction has expired"); + } + return result; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java index a132bcefe6..e740ff9c30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java @@ -18,9 +18,13 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; import javax.transaction.xa.Xid; import java.util.Set; +import java.util.HashMap; /** * Created by Arnaud Simon @@ -29,13 +33,65 @@ import java.util.Set; */ public class MemoryTransactionManager implements TransactionManager { + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryTransactionManager.class); + + private static final String ENVIRONMENT_TX_TIMEOUT = "environment-tx-timeout"; + + //======================================================================== + // Instance Fields + //======================================================================== + // The underlying BDB message store + private MessageStore _messagStore; + // A map of XID/BDBtx + private HashMap _xidMap; + // A map of in-doubt txs + private HashMap _indoubtXidMap; + + // A default tx timeout in sec + private int _defaultTimeout; // set to 10s if not specified in the config + + //======================================================================== + // Interface TransactionManager + //======================================================================== + public void configure(MessageStore messageStroe, String base, Configuration config) + { + _messagStore = messageStroe; + if (config != null) + { + _defaultTimeout = config.getInt(base + "." + ENVIRONMENT_TX_TIMEOUT, 10); + } else + { + _defaultTimeout = 10; + } + _log.info("Using transaction timeout of " + _defaultTimeout + " s"); + _xidMap = new HashMap(); + _indoubtXidMap = new HashMap(); + } public XAFlag begin(Xid xid) throws InternalErrorException, InvalidXidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + if (xid == null) + { + throw new InvalidXidException(xid, "null xid"); + } + if (_xidMap.containsKey(xid)) + { + throw new InvalidXidException(xid, "Xid already exist"); + } + MemoryTransaction tx = new MemoryTransaction(); + tx.setTimeout(_defaultTimeout); + _xidMap.put(xid, tx); + return XAFlag.ok; + } } public XAFlag prepare(Xid xid) @@ -44,7 +100,35 @@ public class MemoryTransactionManager implements TransactionManager CommandInvalidException, UnknownXidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + // get the transaction + MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); + XAFlag result = XAFlag.ok; + if (tx.hasExpired()) + { + result = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + if (tx.isPrepared()) + { + throw new CommandInvalidException("TransactionImpl is already prepared"); + } + if (tx.getrecords().size() == 0) + { + // the tx was read only (no work has been done) + _xidMap.remove(xid); + result = XAFlag.rdonly; + } else + { + // we need to persist the tx records + tx.prepare(); + } + } + return result; + } } public XAFlag rollback(Xid xid) @@ -53,7 +137,28 @@ public class MemoryTransactionManager implements TransactionManager CommandInvalidException, UnknownXidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + // get the transaction + MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); + XAFlag flag = XAFlag.ok; + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else + { + for (TransactionRecord record : tx.getrecords()) + { + record.rollback(_messagStore); + } + _xidMap.remove(xid); + } + if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + } + return flag; + } } public XAFlag commit(Xid xid) @@ -63,7 +168,44 @@ public class MemoryTransactionManager implements TransactionManager UnknownXidException, NotPreparedException { - return null; //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + // get the transaction + MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); + XAFlag flag = XAFlag.ok; + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + if (!tx.isPrepared()) + { + throw new NotPreparedException("TransactionImpl is not prepared"); + } + for (TransactionRecord record : tx.getrecords()) + { + try + { + record.commit(_messagStore, xid); + } catch (InvalidXidException e) + { + throw new UnknownXidException(xid, e); + } catch (Exception e) + { + // this should not happen as the queue and the message must exist + _log.error("Error when committing distributed transaction heurmix mode returned: " + xid); + flag = XAFlag.heurmix; + } + } + _xidMap.remove(xid); + } + return flag; + } } public XAFlag commit_one_phase(Xid xid) @@ -72,7 +214,47 @@ public class MemoryTransactionManager implements TransactionManager CommandInvalidException, UnknownXidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + XAFlag flag = XAFlag.ok; + MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + // we need to prepare the tx + tx.prepare(); + try + { + for (TransactionRecord record : tx.getrecords()) + { + try + { + record.commit(_messagStore, xid); + } catch (InvalidXidException e) + { + throw new UnknownXidException(xid, e); + } catch (Exception e) + { + // this should not happen as the queue and the message must exist + _log.error("Error when committing transaction heurmix mode returned: " + xid); + flag = XAFlag.heurmix; + } + } + } + finally + { + _xidMap.remove(xid); + } + } + return flag; + } } public void forget(Xid xid) @@ -81,7 +263,10 @@ public class MemoryTransactionManager implements TransactionManager CommandInvalidException, UnknownXidException { - //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + _xidMap.remove(xid); + } } public void setTimeout(Xid xid, long timeout) @@ -89,7 +274,8 @@ public class MemoryTransactionManager implements TransactionManager InternalErrorException, UnknownXidException { - //To change body of implemented methods use File | Settings | File Templates. + Transaction tx = getTransaction(xid); + tx.setTimeout(timeout); } public long getTimeout(Xid xid) @@ -97,7 +283,8 @@ public class MemoryTransactionManager implements TransactionManager InternalErrorException, UnknownXidException { - return 0; //To change body of implemented methods use File | Settings | File Templates. + Transaction tx = getTransaction(xid); + return tx.getTimeout(); } public Set recover(boolean startscan, boolean endscan) @@ -105,7 +292,7 @@ public class MemoryTransactionManager implements TransactionManager InternalErrorException, CommandInvalidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return _indoubtXidMap.keySet(); } public void HeuristicOutcome(Xid xid) @@ -113,13 +300,32 @@ public class MemoryTransactionManager implements TransactionManager UnknownXidException, InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + synchronized (xid) + { + MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); + if (!tx.isPrepared()) + { + // heuristically rollback this tx + for (TransactionRecord record : tx.getrecords()) + { + record.rollback(_messagStore); + } + tx.heurRollback(); + } + // add this branch in the list of indoubt tx + _indoubtXidMap.put(xid, tx); + } } public Transaction getTransaction(Xid xid) throws UnknownXidException { - return null; //To change body of implemented methods use File | Settings | File Templates. + Transaction tx = _xidMap.get(xid); + if (tx == null) + { + throw new UnknownXidException(xid); + } + return tx; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 857fb350a0..496c94dae9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -93,6 +93,7 @@ public class NonTransactionalContext implements TransactionalContext { try { + message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); queue.process(_storeContext, message, deliverFirst); //following check implements the functionality //required by the 'immediate' flag: diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java index cd2f619f7e..2dc6ec2b77 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java @@ -26,10 +26,24 @@ package org.apache.qpid.server.txn; public interface Transaction { - /** + /** * Add an abstract record to this tx. * * @param record The record to be added */ public void addRecord(TransactionRecord record); + + /** + * Set this tx timeout + * + * @param timeout This tx timeout in seconds + */ + public void setTimeout(long timeout); + + /** + * Get this tx timeout + * + * @return This tx timeout in seconds + */ + public long getTimeout(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java index 8047236985..bcbf2c9de4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java @@ -19,6 +19,8 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.commons.configuration.Configuration; import javax.transaction.xa.Xid; import java.util.Set; @@ -30,6 +32,17 @@ import java.util.Set; */ public interface TransactionManager { + + /** + * Configure this TM with the Message store implementation + * + * @param base The base element identifier from which all configuration items are relative. For example, if the base + * element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object + * @param messageStroe the message store associated with the TM + */ + public void configure(MessageStore messageStroe, String base, Configuration config); + /** * Begin a transaction branch identified by Xid * -- cgit v1.2.1 From 29f2cfe7529b2242e13257bd80649ee5b989ddb6 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 9 May 2007 13:47:00 +0000 Subject: Applied patch from Arnaud Simon (asimon@redhat.com) to add back the AckTest and get it working again. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536528 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/messageStore/MemoryMessageStore.java | 550 ++++++++++----------- 1 file changed, 275 insertions(+), 275 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java index a027b90743..38fd9daa39 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java @@ -1,275 +1,275 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.txn.TransactionRecord; -import org.apache.qpid.server.txn.MemoryEnqueueRecord; -import org.apache.qpid.server.txn.MemoryDequeueRecord; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; - -import javax.transaction.xa.Xid; -import java.util.*; -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; - -/** - * This a simple in-memory implementation of a message store i.e. nothing is persisted - *

      - * Created by Arnaud Simon - * Date: 26-Apr-2007 - * Time: 08:23:45 - */ -public class MemoryMessageStore implements MessageStore -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); - - // The table of message with its corresponding stream containing the message body - private Map _stagedMessages; - // The queue/messages association - private Map> _queueMap; - // the message ID - private long _messageID = 0; - // The transaction manager - private TransactionManager _txm; - - //======================================================================== - // Interface MessageStore - //======================================================================== - - public void removeExchange(Exchange exchange) - throws - InternalErrorException - { - // do nothing this is inmemory - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException - { - // do nothing this is inmemory - } - - public void createExchange(Exchange exchange) - throws - InternalErrorException - { - // do nothing this is inmemory - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException - { - // do nothing this is inmemory - } - - public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws - InternalErrorException, - IllegalArgumentException - { - _log.info("Configuring memory message store"); - // Initialise the maps - _stagedMessages = new HashMap(); - _queueMap = new HashMap>(); - _txm = tm; - _txm.configure(this, "txn", config); - } - - public void close() - throws - InternalErrorException - { - _log.info("Closing memory message store"); - _stagedMessages.clear(); - _queueMap.clear(); - } - - public void createQueue(StorableQueue queue) - throws - InternalErrorException, - QueueAlreadyExistsException - { - if (_queueMap.containsKey(queue)) - { - throw new QueueAlreadyExistsException("queue " + queue + " already exists"); - } - // add this queue into the map - _queueMap.put(queue, new LinkedList()); - } - - public void destroyQueue(StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException - { - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " does not exist"); - } - // remove this queue from the map - _queueMap.remove(queue); - } - - public void stage(StorableMessage m) - throws - InternalErrorException, - MessageAlreadyStagedException - { - if (_stagedMessages.containsKey(m)) - { - throw new MessageAlreadyStagedException("message " + m + " already staged"); - } - _stagedMessages.put(m, new ByteArrayOutputStream()); - m.staged(); - } - - public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - _stagedMessages.get(m).write(data, offset, size); - } - - public byte[] loadContent(StorableMessage m, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - byte[] result = new byte[size]; - ByteBuffer buf = ByteBuffer.allocate(size); - buf.put(_stagedMessages.get(m).toByteArray(), offset, size); - buf.get(result); - return result; - } - - public void destroy(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - _stagedMessages.remove(m); - } - - public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - if (xid != null) - { - // this is a tx operation - TransactionRecord enqueueRecord = new MemoryEnqueueRecord(m, queue); - _txm.getTransaction(xid).addRecord(enqueueRecord); - } else - { - if (!_stagedMessages.containsKey(m)) - { - try - { - stage(m); - } catch (MessageAlreadyStagedException e) - { - throw new InternalErrorException(e); - } - appendContent(m, m.getData(), 0, m.getPayloadSize()); - } - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " dos not exist"); - } - _queueMap.get(queue).add(m); - m.enqueue(queue); - } - } - - public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException - { - if (xid != null) - { - // this is a tx operation - TransactionRecord dequeueRecord = new MemoryDequeueRecord(m, queue); - _txm.getTransaction(xid).addRecord(dequeueRecord); - } else - { - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " dos not exist"); - } - m.dequeue(queue); - _queueMap.get(queue).remove(m); - if (!m.isEnqueued()) - { - // we can delete this message - _stagedMessages.remove(m); - } - } - } - - public Collection getAllQueues() - throws - InternalErrorException - { - return _queueMap.keySet(); - } - - public Collection getAllMessages(StorableQueue queue) - throws - InternalErrorException - { - return _queueMap.get(queue); - } - - public long getNewMessageId() - { - return _messageID++; - } -} +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.txn.TransactionRecord; +import org.apache.qpid.server.txn.MemoryEnqueueRecord; +import org.apache.qpid.server.txn.MemoryDequeueRecord; +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; + +import javax.transaction.xa.Xid; +import java.util.*; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +/** + * This a simple in-memory implementation of a message store i.e. nothing is persisted + *

      + * Created by Arnaud Simon + * Date: 26-Apr-2007 + * Time: 08:23:45 + */ +public class MemoryMessageStore implements MessageStore +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); + + // The table of message with its corresponding stream containing the message body + private Map _stagedMessages; + // The queue/messages association + protected Map> _queueMap; + // the message ID + private long _messageID = 0; + // The transaction manager + private TransactionManager _txm; + + //======================================================================== + // Interface MessageStore + //======================================================================== + + public void removeExchange(Exchange exchange) + throws + InternalErrorException + { + // do nothing this is inmemory + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) + throws + InternalErrorException + { + // do nothing this is inmemory + } + + public void createExchange(Exchange exchange) + throws + InternalErrorException + { + // do nothing this is inmemory + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) + throws + InternalErrorException + { + // do nothing this is inmemory + } + + public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) + throws + InternalErrorException, + IllegalArgumentException + { + _log.info("Configuring memory message store"); + // Initialise the maps + _stagedMessages = new HashMap(); + _queueMap = new HashMap>(); + _txm = tm; + _txm.configure(this, "txn", config); + } + + public void close() + throws + InternalErrorException + { + _log.info("Closing memory message store"); + _stagedMessages.clear(); + _queueMap.clear(); + } + + public void createQueue(StorableQueue queue) + throws + InternalErrorException, + QueueAlreadyExistsException + { + if (_queueMap.containsKey(queue)) + { + throw new QueueAlreadyExistsException("queue " + queue + " already exists"); + } + // add this queue into the map + _queueMap.put(queue, new LinkedList()); + } + + public void destroyQueue(StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException + { + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " does not exist"); + } + // remove this queue from the map + _queueMap.remove(queue); + } + + public void stage(StorableMessage m) + throws + InternalErrorException, + MessageAlreadyStagedException + { + if (_stagedMessages.containsKey(m)) + { + throw new MessageAlreadyStagedException("message " + m + " already staged"); + } + _stagedMessages.put(m, new ByteArrayOutputStream()); + m.staged(); + } + + public void appendContent(StorableMessage m, byte[] data, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException + { + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + _stagedMessages.get(m).write(data, offset, size); + } + + public byte[] loadContent(StorableMessage m, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException + { + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + byte[] result = new byte[size]; + ByteBuffer buf = ByteBuffer.allocate(size); + buf.put(_stagedMessages.get(m).toByteArray(), offset, size); + buf.get(result); + return result; + } + + public void destroy(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException + { + if (!_stagedMessages.containsKey(m)) + { + throw new MessageDoesntExistException("message " + m + " has not been staged"); + } + _stagedMessages.remove(m); + } + + public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + if (xid != null) + { + // this is a tx operation + TransactionRecord enqueueRecord = new MemoryEnqueueRecord(m, queue); + _txm.getTransaction(xid).addRecord(enqueueRecord); + } else + { + if (!_stagedMessages.containsKey(m)) + { + try + { + stage(m); + } catch (MessageAlreadyStagedException e) + { + throw new InternalErrorException(e); + } + appendContent(m, m.getData(), 0, m.getPayloadSize()); + } + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " dos not exist"); + } + _queueMap.get(queue).add(m); + m.enqueue(queue); + } + } + + public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException + { + if (xid != null) + { + // this is a tx operation + TransactionRecord dequeueRecord = new MemoryDequeueRecord(m, queue); + _txm.getTransaction(xid).addRecord(dequeueRecord); + } else + { + if (!_queueMap.containsKey(queue)) + { + throw new QueueDoesntExistException("queue " + queue + " dos not exist"); + } + m.dequeue(queue); + _queueMap.get(queue).remove(m); + if (!m.isEnqueued()) + { + // we can delete this message + _stagedMessages.remove(m); + } + } + } + + public Collection getAllQueues() + throws + InternalErrorException + { + return _queueMap.keySet(); + } + + public Collection getAllMessages(StorableQueue queue) + throws + InternalErrorException + { + return _queueMap.get(queue); + } + + public long getNewMessageId() + { + return _messageID++; + } +} -- cgit v1.2.1 From 59fcffb8aac5234521f4ae98cfa16970c061109c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 9 May 2007 15:06:06 +0000 Subject: Merged revisions 536008 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r536008 | rgodfrey | 2007-05-07 23:19:59 +0100 (Mon, 07 May 2007) | 1 line QPID-480 : Avoid deadlock on UnacknowledgedMessageMap and ConcurrentSelectorDeliveryManager ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536556 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 6dd80b3bfa..4361194dc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -817,13 +817,14 @@ public class AMQChannel } _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); - checkSuspension(); + if (_log.isDebugEnabled()) { _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size()); } } + checkSuspension(); } /** -- cgit v1.2.1 From a9be5411186e3ee0f14372de828e455c15ac7e83 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 9 May 2007 15:15:58 +0000 Subject: Merged revisions 536480 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r536480 | rgodfrey | 2007-05-09 11:24:13 +0100 (Wed, 09 May 2007) | 1 line QPID-482 : Small performance enhancements ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536560 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 7 +++ .../amqp0_8/ProtocolOutputConverterImpl.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 9 ++-- .../org/apache/qpid/server/queue/AMQMessage.java | 28 +++-------- .../apache/qpid/server/queue/SubscriptionImpl.java | 58 +++++++++++----------- .../apache/qpid/server/state/AMQStateManager.java | 4 -- 6 files changed, 50 insertions(+), 58 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 4361194dc3..6cf9fe6bf7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -121,6 +121,7 @@ public class AMQChannel //Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; + private boolean _closing; public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, MessageStore messageStore, MessageRouter exchanges) @@ -354,6 +355,7 @@ public class AMQChannel throws AMQException { + _closing = true; _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); @@ -966,4 +968,9 @@ public class AMQChannel { return _txnContext; } + + public boolean isClosing() + { + return _closing; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index bd5bb632fe..28b2489142 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -77,7 +77,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter final AMQMessageHandle messageHandle = message.getMessageHandle(); final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); + final Long messageId = message.getMessageId(); final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 3162efa183..d430f1af94 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -432,15 +432,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public AMQChannel getChannel(int channelId) throws AMQException { - if (channelAwaitingClosure(channelId)) + final AMQChannel channel = ((channelId & CHANNEL_CACHE_SIZE) == channelId) + ? _cachedChannels[channelId] + : _channelMap.get(channelId); + if (channel == null || channel.isClosing()) { return null; } else { - return ((channelId & CHANNEL_CACHE_SIZE) == channelId) - ? _cachedChannels[channelId] - : _channelMap.get(channelId); + return channel; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 32c6eb2c9b..282569eed5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -214,10 +214,6 @@ public class AMQMessage implements StorableMessage // _taken = new AtomicBoolean(false); - if (_log.isDebugEnabled()) - { - _log.debug("Message(" + System.identityHashCode(this) + ") created (" + debugIdentity() + ")"); - } } /** @@ -484,10 +480,10 @@ public class AMQMessage implements StorableMessage protected void incrementReference() { _referenceCount.incrementAndGet(); - if (_log.isDebugEnabled()) - { - _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - } +// if (_log.isDebugEnabled()) +// { +// _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); +// } } /** @@ -512,10 +508,10 @@ public class AMQMessage implements StorableMessage { try { - if (_log.isDebugEnabled()) - { - _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - } +// if (_log.isDebugEnabled()) +// { +// _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); +// } // must check if the handle is null since there may be cases where we decide to throw away a message // and the handle has not yet been constructed @@ -532,14 +528,6 @@ public class AMQMessage implements StorableMessage } } else { - if (_log.isDebugEnabled()) - { - _log.debug("Decremented ref count is now " + count + " for message id " + debugIdentity() + "\n" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 5)); - if (count < 0) - { - Thread.dumpStack(); - } - } if (count < 0) { throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index 3bce950ba9..c496996002 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -322,17 +322,17 @@ public class SubscriptionImpl implements Subscription public boolean isSuspended() { - if (_suspensionlogger.isInfoEnabled()) - { - if (channel.isSuspended()) - { - _suspensionlogger.info("Subscription(" + debugIdentity() + ") channel's is susupended"); - } - if (_sendLock.get()) - { - _suspensionlogger.info("Subscription(" + debugIdentity() + ") has sendLock set so closing."); - } - } +// if (_suspensionlogger.isInfoEnabled()) +// { +// if (channel.isSuspended()) +// { +// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") channel's is susupended"); +// } +// if (_sendLock.get()) +// { +// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") has sendLock set so closing."); +// } +// } return channel.isSuspended() || _sendLock.get(); } @@ -381,11 +381,11 @@ public class SubscriptionImpl implements Subscription { if (localInstance == msgInstance || localInstance.equals(msgInstance)) { - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + - msg.debugIdentity() + ")"); - } +// if (_logger.isTraceEnabled()) +// { +// _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + +// msg.debugIdentity() + ")"); +// } return false; } } @@ -399,11 +399,11 @@ public class SubscriptionImpl implements Subscription msgInstance = publisher.getClientIdentifier(); if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) { - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + - msg.debugIdentity() + ")"); - } +// if (_logger.isTraceEnabled()) +// { +// _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + +// msg.debugIdentity() + ")"); +// } return false; } } @@ -431,18 +431,18 @@ public class SubscriptionImpl implements Subscription { if (_filters != null) { - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + debugIdentity() + ") has filters."); - } +// if (_logger.isTraceEnabled()) +// { +// _logger.trace("(" + debugIdentity() + ") has filters."); +// } return _filters.allAllow(msg); } else { - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + debugIdentity() + ") has no filters"); - } +// if (_logger.isTraceEnabled()) +// { +// _logger.trace("(" + debugIdentity() + ") has no filters"); +// } return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index d12f5cd084..50129ec274 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -241,10 +241,6 @@ public class AMQStateManager implements AMQMethodListener 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); -- cgit v1.2.1 From 6166e60244233eb113f55f13ad3fa714c019fea5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 9 May 2007 15:33:17 +0000 Subject: Merged revisions 536506 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r536506 | ritchiem | 2007-05-09 13:32:27 +0100 (Wed, 09 May 2007) | 10 lines QPID-25 TimeToLive Basic implementation. Messages are not automatically purged rather they are checked as they are selected for delivery. If they have expired they are dequeued. AMQChannel - Update to call setExpiration on the message so the time can be adjusted if client & broker clocks are out of sync. AMQMessage - Caches the _expiration time for internal use, adjusted for broker time. This leaves message headers unchanged so receiving client can see actual value requested by producer. ConcurrentSelectorDeliveryManager - Updated to check for expired messages when getNextMessage is called. Immediate messages are NOT expired. Subscription - Added method to getChannel that this Subscription is attatched to so we can retrieve the StoreContext for dequeue-ing the message. TimeToLiveTest - Test of Time to live. Sends 50 msgs. 1 non-timed 48 1 second and 1 non-timed ensure only 2 msgs come back after 2 seconds ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536567 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 2 + .../org/apache/qpid/server/queue/AMQMessage.java | 63 ++++++++++++++++++++-- .../queue/ConcurrentSelectorDeliveryManager.java | 17 ++++-- .../org/apache/qpid/server/queue/Subscription.java | 3 ++ .../apache/qpid/server/queue/SubscriptionImpl.java | 4 ++ 5 files changed, 81 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 6cf9fe6bf7..1cd098a64f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -228,6 +228,8 @@ public class AMQChannel _log.trace(debugIdentity() + "Content header received on channel " + _channelId); } _currentMessage.setContentHeaderBody(contentHeaderBody); + _currentMessage.setExpiration(); + routeCurrentMessage(); _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 282569eed5..6ffe1af018 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; @@ -34,6 +35,7 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.messageStore.StorableMessage; import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; /** Combines the information that make up a deliverable message into a more manageable form. */ @@ -100,12 +102,42 @@ public class AMQMessage implements StorableMessage private final int hashcode = System.identityHashCode(this); + private long _expiration; public String debugIdentity() { return "(HC:" + hashcode + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; } + public void setExpiration() + { + long expiration = ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); + long timestamp = ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); + + if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false)) + { + _expiration = expiration; + } + else + { + // Update TTL to be in broker time. + if (expiration != 0L) + { + if (timestamp != 0L) + { + //todo perhaps use arrival time + long diff = (System.currentTimeMillis() - timestamp); + + if (diff > 1000L || diff < 1000L) + { + _expiration = expiration + diff; + } + } + } + } + + } + /** * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory * therefore is memory-efficient. @@ -212,8 +244,6 @@ public class AMQMessage implements StorableMessage _immediate = info.isImmediate(); _transientMessageData.setMessagePublishInfo(info); -// _taken = new AtomicBoolean(false); - } /** @@ -731,10 +761,35 @@ public class AMQMessage implements StorableMessage return _messageHandle.getArrivalTime(); } - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @param storecontext + * @param queue + * + * @return true if the message has expire + * + * @throws AMQException */ + public boolean expired(StoreContext storecontext, AMQQueue queue) throws AMQException + { + //note: If the storecontext isn't need then we can remove the getChannel() from Subscription. + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + if (now > _expiration) + { + dequeue(storecontext, queue); + return true; + } + } + + return false; + } + + /** Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). */ public void setDeliveredToConsumer() { _deliveredToConsumer = true; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 1f92cee1df..bdc2189676 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -434,13 +434,19 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return count; } - /** This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. */ + /** + * This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. + * + * @return the next message or null + * + * @throws org.apache.qpid.AMQException + */ private AMQMessage getNextMessage() throws AMQException { return getNextMessage(_messages, null); } - private AMQMessage getNextMessage(Queue messages, Subscription sub) + private AMQMessage getNextMessage(Queue messages, Subscription sub) throws AMQException { AMQMessage message = messages.peek(); @@ -449,9 +455,11 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager && ( ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) || sub == null) - && message.taken(_queue, sub)) + && (message.taken(_queue, sub) // Message not taken by another consumer ... unless it is expired + || (sub == null || message.expired(sub.getChannel().getStoreContext(), _queue))) // Message not expired + ) { - //remove the already taken message + //remove the already taken message or expired AMQMessage removed = messages.poll(); assert removed == message; @@ -466,6 +474,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // try the next message message = messages.peek(); } + return message; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java index e6d5d0c88d..77688f19be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import java.util.Queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.AMQChannel; public interface Subscription { @@ -57,4 +58,6 @@ public interface Subscription void addToResendQueue(AMQMessage msg); Object getSendLock(); + + AMQChannel getChannel(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index c496996002..a7be9f2ad2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -668,5 +668,9 @@ public class SubscriptionImpl implements Subscription return _sendLock; } + public AMQChannel getChannel() + { + return channel; + } } -- cgit v1.2.1 From 297cbc84e777d48c2111baa688ba46383c068067 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Thu, 17 May 2007 15:32:18 +0000 Subject: Merged revisions 538084-538097,538099-538108,538110-538906,538908-538912 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r538084 | ritchiem | 2007-05-15 09:02:42 +0100 (Tue, 15 May 2007) | 1 line QPID-466 Removed Unsupported exception from setIntProperty with STRICT_AMQP set ........ r538240 | ritchiem | 2007-05-15 17:19:01 +0100 (Tue, 15 May 2007) | 6 lines QPID-3 Topic Matching with tests A simple naive approach. Similar to C++ to be included for M2. More elaborate pre-evaluated version will have to wait. Once benchmarks have been performed we can evaluate performance advantages if any of that approach. ........ r538882 | ritchiem | 2007-05-17 13:12:34 +0100 (Thu, 17 May 2007) | 3 lines Fix for broken CSDM message purging routine that was causing python test_get to fail. Replaced long while control with a method call that is easier to understand and has more comments. ........ r538912 | ritchiem | 2007-05-17 14:26:25 +0100 (Thu, 17 May 2007) | 2 lines Fixed failing python tests. The rather annoying way we unsubscribe subscribers by creating new ones was causing a problem as the closing channel had been closed before the unsubscribe call. Java now passes all python tests ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@538968 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 388 ++++++++++----------- .../qpid/server/exchange/DestWildExchange.java | 189 +++++++++- .../queue/ConcurrentSelectorDeliveryManager.java | 56 ++- 3 files changed, 418 insertions(+), 215 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1cd098a64f..1de4d16ad4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentBody; @@ -42,12 +43,12 @@ 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.exchange.NoRouteException; +import org.apache.qpid.server.messageStore.MessageStore; 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.queue.Subscription; -import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.*; @@ -59,7 +60,7 @@ public class AMQChannel private final int _channelId; - //private boolean _transactional; + // private boolean _transactional; private long _prefetch_HighWaterMark; @@ -119,14 +120,12 @@ public class AMQChannel private Set _browsedAcks = new HashSet(); - //Why do we need this reference ? - ritchiem + // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; private boolean _closing; - - public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, MessageStore messageStore, MessageRouter exchanges) - throws - AMQException + public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, + MessageStore messageStore, MessageRouter exchanges) throws AMQException { _session = session; _channelId = channelId; @@ -145,7 +144,8 @@ public class AMQChannel */ public void setLocalTransactional() { - _txnContext = new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); + _txnContext = + new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); } public boolean isTransactional() @@ -176,7 +176,6 @@ public class AMQChannel return _prefetchSize; } - public void setPrefetchSize(long prefetchSize) { _prefetchSize = prefetchSize; @@ -202,31 +201,26 @@ public class AMQChannel _prefetch_HighWaterMark = prefetchCount; } - - public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) - throws - AMQException + public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) throws AMQException { - - _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, - _txnContext); + _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); _currentMessage.setPublisher(publisher); } - public void publishContentHeader(ContentHeaderBody contentHeaderBody) - throws - AMQException + public void publishContentHeader(ContentHeaderBody contentHeaderBody) throws AMQException { if (_currentMessage == null) { throw new AMQException("Received content header without previously receiving a BasicPublish frame"); - } else + } + else { if (_log.isTraceEnabled()) { _log.trace(debugIdentity() + "Content header received on channel " + _channelId); } + _currentMessage.setContentHeaderBody(contentHeaderBody); _currentMessage.setExpiration(); @@ -241,9 +235,7 @@ public class AMQChannel } } - public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) - throws - AMQException + public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException { if (_currentMessage == null) { @@ -254,12 +246,15 @@ public class AMQChannel { _log.trace(debugIdentity() + "Content body received on channel " + _channelId); } + try { // returns true iff the message was delivered (i.e. if all data was // received - if (_currentMessage.addContentBodyFrame(_storeContext, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk(contentBody))) + if (_currentMessage.addContentBodyFrame(_storeContext, + protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk( + contentBody))) { // callback to allow the context to do any post message processing // primary use is to allow message return processing in the non-tx case @@ -276,9 +271,7 @@ public class AMQChannel } } - protected void routeCurrentMessage() - throws - AMQException + protected void routeCurrentMessage() throws AMQException { try { @@ -316,15 +309,13 @@ public class AMQChannel * @throws AMQException if something goes wrong */ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) - throws - AMQException, - ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { tag = new AMQShortString("sgen_" + getNextConsumerTag()); } + if (_consumerTag2QueueMap.containsKey(tag)) { throw new ConsumerTagNotUniqueException(); @@ -332,13 +323,11 @@ public class AMQChannel queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive); _consumerTag2QueueMap.put(tag, queue); + return tag; } - - public void unsubscribeConsumer(AMQProtocolSession session, final AMQShortString consumerTag) - throws - AMQException + public void unsubscribeConsumer(AMQProtocolSession session, final AMQShortString consumerTag) throws AMQException { final AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); if (q != null) @@ -353,38 +342,44 @@ public class AMQChannel * @param session The session to close * @throws AMQException if there is an error during closure */ - public void close(AMQProtocolSession session) - throws - AMQException + public void close(AMQProtocolSession session) throws AMQException { - _closing = true; _txnContext.rollback(); unsubscribeAllConsumers(session); requeue(); + + setClosing(true); + } + + private void setClosing(boolean closing) + { + _closing = closing; } - private void unsubscribeAllConsumers(AMQProtocolSession session) - throws - AMQException + private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException { if (_log.isInfoEnabled()) { if (!_consumerTag2QueueMap.isEmpty()) { _log.info("Unsubscribing all consumers on channel " + toString()); - } else + } + else { _log.info("No consumers to unsubscribe on channel " + toString()); } } + for (Map.Entry me : _consumerTag2QueueMap.entrySet()) { if (_log.isInfoEnabled()) { _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); } + me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); } + _consumerTag2QueueMap.clear(); } @@ -404,12 +399,13 @@ public class AMQChannel if (queue == null) { _log.debug("Adding unacked message with a null queue:" + message.debugIdentity()); - } else + } + else { if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag + - ") with a queue(" + queue + ") for " + consumerTag); + _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag + + ") with a queue(" + queue + ") for " + consumerTag); } } } @@ -434,9 +430,7 @@ public class AMQChannel * * @throws org.apache.qpid.AMQException if the requeue fails */ - public void requeue() - throws - AMQException + 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(); @@ -454,20 +448,20 @@ public class AMQChannel if (!(_txnContext instanceof NonTransactionalContext)) { -// if (_nonTransactedContext == null) + // if (_nonTransactedContext == null) { - _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } else + } + else { deliveryContext = _txnContext; } } - for (UnacknowledgedMessage unacked : messagesToBeDelivered) { if (unacked.queue != null) @@ -483,7 +477,7 @@ public class AMQChannel // Should we allow access To the DM to directy deliver the message? // As we don't need to check for Consumers or worry about incrementing the message count? -// unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); + // unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); } } @@ -495,9 +489,7 @@ public class AMQChannel * @param deliveryTag The message to requeue * @throws AMQException If something goes wrong. */ - public void requeue(long deliveryTag) - throws - AMQException + public void requeue(long deliveryTag) throws AMQException { UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); @@ -518,74 +510,71 @@ public class AMQChannel TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { -// if (_nonTransactedContext == null) + // if (_nonTransactedContext == null) { - _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } else + } + else { deliveryContext = _txnContext; } if (unacked.queue != null) { - //Redeliver the messages to the front of the queue + // Redeliver the messages to the front of the queue deliveryContext.deliver(unacked.message, unacked.queue, true); - //Deliver increments the message count but we have already deliverted this once so don't increment it again + // Deliver increments the message count but we have already deliverted this once so don't increment it again // this was because deliver did an increment changed this. - } else - { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() + "):" + deliveryTag + - " but no queue defined and no DeadLetter queue so DROPPING message."); -// _log.error("Requested requeue of message:" + deliveryTag + -// " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); -// -// deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); -// } - } else + else + { + _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() + + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); + // _log.error("Requested requeue of message:" + deliveryTag + + // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); + // + // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); + // + } + } + else { - _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); + _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + + _unacknowledgedMessageMap.size()); if (_log.isDebugEnabled()) { _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - int count = 0; - - public boolean callback(UnacknowledgedMessage message) - throws - AMQException { - _log.debug((count++) + ": (" + message.message.debugIdentity() + ")" + - "[" + message.deliveryTag + "]"); - return false; // Continue - } + int count = 0; - public void visitComplete() - { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug( + (count++) + ": (" + message.message.debugIdentity() + ")" + "[" + message.deliveryTag + "]"); - } - }); + return false; // Continue + } + + public void visitComplete() + { } + }); } } - } - /** * Called to resend all outstanding unacknowledged messages to this same channel. * * @param requeue Are the messages to be requeued or dropped. * @throws AMQException When something goes wrong. */ - public void resend(final boolean requeue) - throws - AMQException + public void resend(final boolean requeue) throws AMQException { final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); @@ -599,52 +588,53 @@ public class AMQChannel // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) - throws - AMQException { - AMQShortString consumerTag = message.consumerTag; - AMQMessage msg = message.message; - msg.setRedelivered(true); - if (consumerTag != null) + public boolean callback(UnacknowledgedMessage message) throws AMQException { - // Consumer exists - if (_consumerTag2QueueMap.containsKey(consumerTag)) - { - msgToResend.add(message); - } else // consumer has gone + AMQShortString consumerTag = message.consumerTag; + AMQMessage msg = message.message; + msg.setRedelivered(true); + if (consumerTag != null) { - msgToRequeue.add(message); + // Consumer exists + if (_consumerTag2QueueMap.containsKey(consumerTag)) + { + msgToResend.add(message); + } + else // consumer has gone + { + msgToRequeue.add(message); + } } - } else - { - // Message has no consumer tag, so was "delivered" to a GET - // or consumer no longer registered - // cannot resend, so re-queue. - if (message.queue != null) + else { - if (requeue) + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (message.queue != null) { - msgToRequeue.add(message); - } else + if (requeue) + { + msgToRequeue.add(message); + } + else + { + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + } + } + else { - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } - } else - { - _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } - } - // false means continue processing - return false; - } + // false means continue processing + return false; + } - public void visitComplete() - { - } - }); + public void visitComplete() + { } + }); // Process Messages to Resend if (_log.isInfoEnabled()) @@ -652,11 +642,13 @@ public class AMQChannel if (!msgToResend.isEmpty()) { _log.info("Preparing (" + msgToResend.size() + ") message to resend."); - } else + } + else { _log.info("No message to resend."); } } + for (UnacknowledgedMessage message : msgToResend) { AMQMessage msg = message.message; @@ -665,22 +657,21 @@ public class AMQChannel // If the client has requested the messages be resent then it is // their responsibility to ensure that thay are capable of receiving them // i.e. The channel hasn't been server side suspended. -// if (isSuspended()) -// { -// _log.info("Channel is suspended so requeuing"); -// //move this message to requeue -// msgToRequeue.add(message); -// } -// else -// { - //release to allow it to be delivered + // if (isSuspended()) + // { + // _log.info("Channel is suspended so requeuing"); + // //move this message to requeue + // msgToRequeue.add(message); + // } + // else + // { + // release to allow it to be delivered msg.release(message.queue); // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. msg.setRedelivered(true); - Subscription sub = msg.getDeliveredSubscription(message.queue); if (sub != null) @@ -697,32 +688,38 @@ public class AMQChannel { if (_log.isDebugEnabled()) { - _log.debug("Subscription(" + System.identityHashCode(sub) + ") closed during resend so requeuing message"); + _log.debug("Subscription(" + System.identityHashCode(sub) + + ") closed during resend so requeuing message"); } - //move this message to requeue + // move this message to requeue msgToRequeue.add(message); - } else + } + else { if (_log.isDebugEnabled()) { - _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" + System.identityHashCode(sub)); + _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" + + System.identityHashCode(sub)); } + sub.addToResendQueue(msg); _unacknowledgedMessageMap.remove(message.deliveryTag); } } // sync(sub.getSendLock) - } else + } + else { if (_log.isInfoEnabled()) { - _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + ")to prevent loss"); + _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + + ")to prevent loss"); } - //move this message to requeue + // move this message to requeue msgToRequeue.add(message); } } // for all messages -// } else !isSuspend + // } else !isSuspend if (_log.isInfoEnabled()) { @@ -739,12 +736,13 @@ public class AMQChannel { if (_nonTransactedContext == null) { - _nonTransactedContext = new NonTransactionalContext(_messageStore, _storeContext, this, - _returnMessages, _browsedAcks); + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; - } else + } + else { deliveryContext = _txnContext; } @@ -769,36 +767,32 @@ public class AMQChannel * @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 + public void queueDeleted(final AMQQueue queue) throws AMQException { _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) - throws - AMQException { - if (message.queue == queue) + public boolean callback(UnacknowledgedMessage message) throws AMQException { - try - { - message.discard(_storeContext); - message.queue = null; - } - catch (AMQException e) + if (message.queue == queue) { - _log.error("Error decrementing ref count on message " + message.message.getMessageId() + ": " + - e, e); + try + { + message.discard(_storeContext); + message.queue = null; + } + catch (AMQException e) + { + _log.error( + "Error decrementing ref count on message " + message.message.getMessageId() + ": " + e, e); + } } + + return false; } - return false; - } - public void visitComplete() - { - } - }); + public void visitComplete() + { } + }); } /** @@ -809,9 +803,7 @@ public class AMQChannel * 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 + public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { synchronized (_unacknowledgedMessageMap.getLock()) { @@ -828,6 +820,7 @@ public class AMQChannel } } + checkSuspension(); } @@ -845,8 +838,9 @@ public class AMQChannel { boolean suspend; - suspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark) - || ((_prefetchSize != 0) && _prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()); + suspend = + ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) + || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); setSuspended(suspend); } @@ -867,12 +861,13 @@ public class AMQChannel if (wasSuspended) { _log.debug("Unsuspending channel " + this); - //may need to deliver queued messages + // may need to deliver queued messages for (AMQQueue q : _consumerTag2QueueMap.values()) { q.deliverAsync(); } - } else + } + else { _log.debug("Suspending channel " + this); } @@ -884,20 +879,17 @@ public class AMQChannel return _suspended.get(); } - public void commit() - throws - AMQException + public void commit() throws AMQException { if (!isTransactional()) { throw new AMQException("Fatal error: commit called on non-transactional channel"); } - _txnContext.commit(); + + _txnContext.commit(); } - public void rollback() - throws - AMQException + public void rollback() throws AMQException { _txnContext.rollback(); } @@ -908,6 +900,7 @@ public class AMQChannel sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(isTransactional()); sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); sb.append("/").append(_prefetch_HighWaterMark); + return sb.toString(); } @@ -926,41 +919,40 @@ public class AMQChannel return _storeContext; } - public void processReturns(AMQProtocolSession session) - throws - AMQException + public void processReturns(AMQProtocolSession session) throws AMQException { for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); - session.getProtocolOutputConverter().writeReturn(message, _channelId, - bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); + session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), + new AMQShortString(bouncedMessage.getMessage())); } + _returnMessages.clear(); } - public boolean wouldSuspend(AMQMessage msg) { if (isSuspended()) { return true; - } else + } + else { - boolean willSuspend = ((_prefetch_HighWaterMark != 0) && _unacknowledgedMessageMap.size() + 1 > _prefetch_HighWaterMark); + boolean willSuspend = + ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); if (!willSuspend) { final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); - willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < msg.getSize() + unackedSize); + willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < (msg.getSize() + unackedSize)); } - if (willSuspend) { setSuspended(true); } + return willSuspend; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 386cfd2349..e9c5b0024c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.exchange; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.StringTokenizer; +import java.util.LinkedList; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -56,6 +58,10 @@ public class DestWildExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(DestWildExchange.class); private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); + // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); + private static final String TOPIC_SEPARATOR = "."; + private static final String AMQP_STAR = "*"; + private static final String AMQP_HASH = "#"; /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */ @MBeanDescription("Management Bean for Topic Exchange") @@ -78,7 +84,7 @@ public class DestWildExchange extends AbstractExchange AMQShortString key = entry.getKey(); List queueList = new ArrayList(); - List queues = entry.getValue(); + List queues = getMatchedQueues(key); for (AMQQueue q : queues) { queueList.add(q.getName().toString()); @@ -118,10 +124,13 @@ public class DestWildExchange extends AbstractExchange return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; } - public synchronized void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; - assert routingKey != null; + assert rKey != null; + + AMQShortString routingKey = normalize(rKey); + _logger.debug("Registering queue " + queue.getName() + " with routing key " + routingKey); // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition List queueList = _routingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList()); @@ -142,15 +151,67 @@ public class DestWildExchange extends AbstractExchange } + private AMQShortString normalize(AMQShortString routingKey) + { + StringTokenizer routingTokens = new StringTokenizer(routingKey.toString(), TOPIC_SEPARATOR); + List _subscription = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + _subscription.add(routingTokens.nextToken()); + } + + int size = _subscription.size(); + + for (int index = 0; index < size; index++) + { + //if there are more levels + if (index + 1 < size) + { + if (_subscription.get(index).equals(AMQP_HASH)) + { + if (_subscription.get(index + 1).equals(AMQP_HASH)) + { + // we don't need #.# delete this one + _subscription.remove(index); + size--; + //redo this normalisation + index--; + } + + if (_subscription.get(index + 1).equals(AMQP_STAR)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + _subscription.add(index + 1, _subscription.remove(index)); + } + } + }//if we have more levels + } + + StringBuilder sb = new StringBuilder(); + + for (String s : _subscription) + { + sb.append(s); + sb.append(TOPIC_SEPARATOR); + } + + sb.deleteCharAt(sb.length() - 1); + + return new AMQShortString(sb.toString()); + } + public void route(AMQMessage payload) throws AMQException { MessagePublishInfo info = payload.getMessagePublishInfo(); - final AMQShortString routingKey = info.getRoutingKey(); - List queues = _routingKey2queues.get(routingKey); + final AMQShortString routingKey = normalize(info.getRoutingKey()); + + List queues = getMatchedQueues(routingKey); // if we have no registered queues we have nothing to do // TODO: add support for the immediate flag - if (queues == null) + if (queues == null || queues.size() == 0) { if (info.isMandatory()) { @@ -177,14 +238,14 @@ public class DestWildExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { - List queues = _routingKey2queues.get(routingKey); + List queues = _routingKey2queues.get(normalize(routingKey)); return queues != null && queues.contains(queue); } public boolean isBound(AMQShortString routingKey) throws AMQException { - List queues = _routingKey2queues.get(routingKey); + List queues = _routingKey2queues.get(normalize(routingKey)); return queues != null && !queues.isEmpty(); } @@ -205,10 +266,12 @@ public class DestWildExchange extends AbstractExchange return !_routingKey2queues.isEmpty(); } - public synchronized void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException { assert queue != null; - assert routingKey != null; + assert rKey != null; + + AMQShortString routingKey = normalize(rKey); List queues = _routingKey2queues.get(routingKey); if (queues == null) @@ -241,4 +304,110 @@ public class DestWildExchange extends AbstractExchange throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); } } + + + private List getMatchedQueues(AMQShortString routingKey) + { + List list = new LinkedList(); + StringTokenizer routingTokens = new StringTokenizer(routingKey.toString(), TOPIC_SEPARATOR); + + ArrayList routingkeyList = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + String next = routingTokens.nextToken(); + if (next.equals(AMQP_HASH) && routingkeyList.get(routingkeyList.size() - 1).equals(AMQP_HASH)) + { + continue; + } + + routingkeyList.add(next); + } + + for (AMQShortString queue : _routingKey2queues.keySet()) + { + StringTokenizer queTok = new StringTokenizer(queue.toString(), TOPIC_SEPARATOR); + + ArrayList queueList = new ArrayList(); + + while (queTok.hasMoreTokens()) + { + queueList.add(queTok.nextToken()); + } + + + int depth = 0; + boolean matching = true; + boolean done = false; + int routingskip = 0; + int queueskip = 0; + + while (matching && !done) + { + if (queueList.size() == depth + queueskip || routingkeyList.size() == depth + routingskip) + { + done = true; + + // if it was the routing key that ran out of digits + if (routingkeyList.size() == depth + routingskip) + { + if (queueList.size() > (depth + queueskip)) + { // a hash and it is the last entry + matching = queueList.get(depth + queueskip).equals(AMQP_HASH) && queueList.size() == depth + queueskip + 1; + } + } + else if (routingkeyList.size() > depth + routingskip) + { + // There is still more routing key to check + matching = false; + } + + + continue; + } + + // if the values on the two topics don't match + if (!queueList.get(depth + queueskip).equals(routingkeyList.get(depth + routingskip))) + { + if (queueList.get(depth + queueskip).equals(AMQP_STAR)) + { + depth++; + + continue; + } + else if (queueList.get(depth + queueskip).equals(AMQP_HASH)) + { + // Is this a # at the end + if (queueList.size() == depth + queueskip + 1) + { + done = true; + continue; + } + + // otherwise # in the middle + while (routingkeyList.size() > depth + routingskip) + { + if (routingkeyList.get(depth + routingskip).equals(queueList.get(depth + queueskip + 1))) + { + queueskip++; + depth++; + break; + } + routingskip++; + } + continue; + } + matching = false; + } + depth++; + } + + if (matching) + { + list.addAll(_routingKey2queues.get(queue)); + } + } + + return list; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index bdc2189676..0fb5e6d88a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -451,13 +451,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager AMQMessage message = messages.peek(); //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) - while (message != null - && ( - ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) - || sub == null) - && (message.taken(_queue, sub) // Message not taken by another consumer ... unless it is expired - || (sub == null || message.expired(sub.getChannel().getStoreContext(), _queue))) // Message not expired - ) + while (purgeMessage(message, sub)) { //remove the already taken message or expired AMQMessage removed = messages.poll(); @@ -478,6 +472,54 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return message; } + /** + * + * @param message + * @param sub + * @return + * @throws AMQException + */ + private boolean purgeMessage(AMQMessage message, Subscription sub) throws AMQException + { + //Original.. complicated while loop control +// (message != null +// && ( +// ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) +// || sub == null) +// && message.taken(_queue, sub)); + + boolean purge = false; + + // if the message is null then don't purge as we have no messagse. + if (message != null) + { + // if we have a subscriber perform message checks + if (sub != null) + { + // Check that the message hasn't expired. + if (message.expired(sub.getChannel().getStoreContext(), _queue)) + { + return true; + } + + // if we have a queue browser(we don't purge) so check mark the message as taken + purge = ((!sub.isBrowser() || message.isTaken(_queue))); + } + else + { + // if there is no subscription we are doing + // a get or purging so mark message as taken. + message.isTaken(_queue); + // and then ensure that it gets purged + purge = true; + } + } + + // if we are purging then ensure we mark this message taken for the current subscriber + // the current subscriber may be null in the case of a get or a purge but this is ok. + return purge && message.taken(_queue, sub); + } + public void sendNextMessage(Subscription sub, AMQQueue queue)//Queue messageQueue) { -- cgit v1.2.1 From d99f53fb5ef7970a63e150af0a22347c42767dd5 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Mon, 21 May 2007 11:26:55 +0000 Subject: Merged revisions 540107 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r540107 | rupertlssmith | 2007-05-21 11:57:30 +0100 (Mon, 21 May 2007) | 1 line Documented all exception. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540119 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/RequiredDeliveryException.java | 22 ++-- .../server/exchange/ExchangeInUseException.java | 18 ++- .../qpid/server/exchange/NoRouteException.java | 14 ++- .../protocol/AMQNoMethodHandlerException.java | 16 ++- .../protocol/UnknnownMessageTypeException.java | 17 ++- .../org/apache/qpid/server/queue/AMQQueue.java | 136 ++++++++++++--------- .../qpid/server/queue/FailedDequeueException.java | 17 ++- .../qpid/server/queue/MessageCleanupException.java | 21 +++- .../qpid/server/queue/NoConsumersException.java | 15 ++- .../apache/qpid/server/state/AMQStateManager.java | 40 +++--- .../state/IllegalStateTransitionException.java | 12 +- 11 files changed, 218 insertions(+), 110 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index ff933d3c0b..d61bb8916a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -25,9 +25,17 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.queue.AMQMessage; /** - * Signals that a required delivery could not be made. This could be bacuse of - * the immediate flag being set and the queue having no consumers, or the mandatory - * flag being set and the exchange having no valid bindings. + * 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. + * + *

      The failed message is associated with this error condition, by taking a reference to it. This enables the + * correct compensating action to be taken against the message, for example, bouncing it back to the sender. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      Associate the failed message with the error condition. {@link AMQMessage} + *
      */ public abstract class RequiredDeliveryException extends AMQException { @@ -40,10 +48,10 @@ public abstract class RequiredDeliveryException extends AMQException // Increment the reference as this message is in the routing phase // and so will have the ref decremented as routing fails. // we need to keep this message around so we can return it in the - // handler. So increment here. - _amqMessage = payload.takeReference(); - - //payload.incrementReference(); + // handler. So increment here. + _amqMessage = payload.takeReference(); + + // payload.incrementReference(); } public AMQMessage getAMQMessage() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java index 6b2891c573..c77f114428 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,6 +22,20 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +/** + * ExchangeInUseRegistry indicates that an exchange cannot be unregistered because it is currently being used. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to unregister exchange that is in use. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo This exception is not used. However, it is part of the ExchangeRegistry interface, and looks like code is + * going to need to be added to throw/deal with this. Alternatively ExchangeResitries may be able to handle the + * issue internally. + */ public class ExchangeInUseException extends AMQException { public ExchangeInUseException(String exchangeName) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index c972b9d078..1d6ab3842d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -25,8 +25,14 @@ import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; /** - * Thrown by an exchange if there is no way to route a message with the - * mandatory flag set. + * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message + * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report + * this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      */ public class NoRouteException extends RequiredDeliveryException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java index 16d74b6fc0..a7599a3e0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -20,13 +20,25 @@ */ package org.apache.qpid.server.protocol; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.AMQException; +/** + * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to handle an AMQP method. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a + * Runtime. + */ public class AMQNoMethodHandlerException extends AMQException { - public AMQNoMethodHandlerException(AMQMethodEvent evt) { super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java index 45d09e8f3e..6e72aa062f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -20,14 +20,27 @@ */ package org.apache.qpid.server.protocol; -import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; +/** + * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to cast a frame to its expected type. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would + * be better just to leave that as a ClassCastException. However, check the framing layer catches this error + * first. + */ public class UnknnownMessageTypeException extends AMQException { public UnknnownMessageTypeException(AMQDataBlock message) { super("Unknown message type: " + message.getClass().getName() + ": " + message); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index fa3b34a634..a17cbb87ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicLong; import javax.management.JMException; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; @@ -54,7 +55,19 @@ import org.apache.qpid.server.virtualhost.VirtualHost; */ public class AMQQueue implements Managable, Comparable, StorableQueue { - + /** + * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create a subscription, because an exclusive subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ public static int s_queueID =0; public static final class ExistingExclusiveSubscription extends AMQException { @@ -65,19 +78,27 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } } + /** + * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create an exclusize subscription, as a subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ public static final class ExistingSubscriptionPreventsExclusive extends AMQException { - public ExistingSubscriptionPreventsExclusive() { super(""); } } - private static final ExistingExclusiveSubscription EXISTING_EXCLUSIVE = new ExistingExclusiveSubscription(); - private static final ExistingSubscriptionPreventsExclusive EXISTING_SUBSCRIPTION = new ExistingSubscriptionPreventsExclusive(); - - private static final Logger _logger = Logger.getLogger(AMQQueue.class); private final AMQShortString _name; @@ -134,7 +155,6 @@ public class AMQQueue implements Managable, Comparable, StorableQueue private final VirtualHost _virtualHost; - /** * max allowed size(KB) of a single message */ @@ -175,40 +195,34 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return _name.compareTo(((AMQQueue) o).getName()); } - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, VirtualHost virtualHost) - throws - AMQException + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException { - this(name, durable, owner, autoDelete, virtualHost, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionSet(), new SubscriptionImpl.Factory()); + this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), + new SubscriptionSet(), new SubscriptionImpl.Factory()); } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, VirtualHost virtualHost, - SubscriptionSet subscribers) - throws - AMQException + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, + VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException { - this(name, durable, owner, autoDelete, virtualHost, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); + this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, + new SubscriptionImpl.Factory()); } - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, - boolean autoDelete, VirtualHost virtualHost, - Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) - throws - AMQException + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, + VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, + SubscriptionFactory subscriptionFactory) throws AMQException { if (name == null) { throw new IllegalArgumentException("Queue name must not be null"); } + if (virtualHost == null) { throw new IllegalArgumentException("Virtual Host must not be null"); } + _name = name; _durable = durable; _owner = owner; @@ -304,10 +318,11 @@ public class AMQQueue implements Managable, Comparable, StorableQueue public AMQMessage getMessageOnTheQueue(long messageId) { List list = getMessagesOnTheQueue(messageId, messageId); - if (list == null || list.size() == 0) + if ((list == null) || (list.size() == 0)) { return null; } + return list.get(0); } @@ -324,7 +339,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue * @param storeContext */ public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) + StoreContext storeContext) { // prepare the delivery manager for moving messages by stopping the async delivery and creating a lock AMQQueue anotherQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); @@ -460,6 +475,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue throw new AMQException("Problem binding queue ", e); } } + _bindings.addBinding(routingKey, arguments, exchange); } @@ -478,25 +494,23 @@ public class AMQQueue implements Managable, Comparable, StorableQueue throw new AMQException("problem unbinding queue", e); } } + _bindings.remove(routingKey, arguments, exchange); } - public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) - throws - AMQException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (incrementSubscriberCount() > 1) { if (isExclusive()) { decrementSubscriberCount(); - throw EXISTING_EXCLUSIVE; + throw new ExistingExclusiveSubscription(); } else if (exclusive) { decrementSubscriberCount(); - throw EXISTING_SUBSCRIPTION; + throw new ExistingSubscriptionPreventsExclusive(); } } else if (exclusive) @@ -506,12 +520,13 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (_logger.isDebugEnabled()) { - _logger.debug(MessageFormat.format("Registering protocol session {0} with channel {1} and " + - "consumer tag {2} with {3}", ps, channel, consumerTag, this)); + _logger.debug(MessageFormat.format( + "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, - filters, noLocal, this); + Subscription subscription = + _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); if (subscription.filtersMessages()) { @@ -524,7 +539,6 @@ public class AMQQueue implements Managable, Comparable, StorableQueue _subscribers.addSubscriber(subscription); } - private boolean isExclusive() { return _isExclusive.get(); @@ -545,25 +559,25 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return _subscriberCount.decrementAndGet(); } - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException { if (_logger.isDebugEnabled()) { - _logger.debug(MessageFormat.format("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, - this)); + _logger.debug(MessageFormat.format( + "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))) + + 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); + throw new AMQException("Protocol session with channel " + channel + " and consumer tag " + consumerTag + + " and protocol session key " + ps.getKey() + " not registered with queue " + this); } removedSubscription.close(); @@ -577,6 +591,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue { _logger.info("Auto-deleteing queue:" + this); } + 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 @@ -594,7 +609,6 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return !_deliveryMgr.hasQueuedMessages(); } - public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException @@ -602,14 +616,17 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (checkUnused && !_subscribers.isEmpty()) { _logger.info("Will not delete " + this + " as it is in use."); + return 0; } else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) { _logger.info("Will not delete " + this + " as it is not empty."); + return 0; } else { delete(); + return _deliveryMgr.getQueueMessageCount(); } } @@ -628,6 +645,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue { task.doTask(this); } + _deleteTaskList.clear(); } } @@ -640,6 +658,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue { _logger.debug(MessageFormat.format("autodeleting {0}", this)); } + delete(); } @@ -647,7 +666,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue throws AMQException { - //fixme not sure what this is doing. should we be passing deliverFirst through here? + // fixme not sure what this is doing. should we be passing deliverFirst through here? // This code is not used so when it is perhaps it should _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); try @@ -663,10 +682,10 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } } -// public DeliveryManager getDeliveryManager() -// { -// return _deliveryMgr; -// } + // public DeliveryManager getDeliveryManager() + // { + // return _deliveryMgr; + // } public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws @@ -696,10 +715,10 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } catch (MessageCleanupException e) { - //Message was dequeued, but could not then be deleted - //though it is no longer referenced. This should be very - //rare and can be detected and cleaned up on recovery or - //done through some form of manual intervention. + // Message was dequeued, but could not then be deleted + // though it is no longer referenced. This should be very + // rare and can be detected and cleaned up on recovery or + // done through some form of manual intervention. _logger.error(e, e); } catch (AMQException e) @@ -743,7 +762,8 @@ public class AMQQueue implements Managable, Comparable, StorableQueue { return true; } - if (o == null || getClass() != o.getClass()) + + if ((o == null) || (getClass() != o.getClass())) { return false; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java index b74c49e6e1..6466e81dd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,7 +23,18 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; /** - * Signals that the dequeue of a message from a queue failed + * Signals that the dequeue of a message from a queue failed. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Indicates the a message could not be dequeued from a queue. + *
      + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Happens as a consequence of a message store failure, or reference counting error. Both of which migh become + * runtime exceptions, as unrecoverable conditions? In which case this one might be dropped too. */ public class FailedDequeueException extends AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java index 1e7e6f03d2..090096d3c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,8 +23,20 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; /** - * Signals that the removal of a message once its refcount reached - * zero failed. + * MessageCleanupException represents the failure to perform reference counting on messages correctly. This should not + * happen, but there may be programming errors giving race conditions that cause the reference counting to go wrong. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Signals that the reference count of a message has gone below zero. + *
      Indicates that a message store has lost a message which is still referenced. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo The race conditions leading to this error should be cleaned up, and a runtime exception used instead. If the + * message store loses messages, then something is seriously wrong and it would be sensible to terminate the + * broker. This may be disguising out of memory errors. */ public class MessageCleanupException extends AMQException { @@ -32,6 +44,7 @@ public class MessageCleanupException extends AMQException { super("Failed to cleanup message with id " + messageId, e); } + public MessageCleanupException(String message) { super(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java index c63490f019..d6fd1eec89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,9 +24,14 @@ 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. + * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate + * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is + * always used to report this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      */ public class NoConsumersException extends RequiredDeliveryException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 50129ec274..f96900d0a9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.BasicAckBody; @@ -35,6 +36,7 @@ import org.apache.qpid.framing.BasicGetBody; import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.BasicQosBody; import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.BasicRejectBody; import org.apache.qpid.framing.ChannelCloseBody; import org.apache.qpid.framing.ChannelCloseOkBody; import org.apache.qpid.framing.ChannelFlowBody; @@ -55,7 +57,6 @@ import org.apache.qpid.framing.QueuePurgeBody; import org.apache.qpid.framing.TxCommitBody; import org.apache.qpid.framing.TxRollbackBody; import org.apache.qpid.framing.TxSelectBody; -import org.apache.qpid.framing.BasicRejectBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.handler.BasicAckMethodHandler; @@ -65,6 +66,7 @@ import org.apache.qpid.server.handler.BasicGetMethodHandler; import org.apache.qpid.server.handler.BasicPublishMethodHandler; import org.apache.qpid.server.handler.BasicQosHandler; import org.apache.qpid.server.handler.BasicRecoverMethodHandler; +import org.apache.qpid.server.handler.BasicRejectMethodHandler; import org.apache.qpid.server.handler.ChannelCloseHandler; import org.apache.qpid.server.handler.ChannelCloseOkHandler; import org.apache.qpid.server.handler.ChannelFlowHandler; @@ -83,9 +85,8 @@ import org.apache.qpid.server.handler.QueueDeclareHandler; import org.apache.qpid.server.handler.QueueDeleteHandler; import org.apache.qpid.server.handler.QueuePurgeHandler; import org.apache.qpid.server.handler.TxCommitHandler; -import org.apache.qpid.server.handler.BasicRejectMethodHandler; -import org.apache.qpid.server.handler.TxSelectHandler; import org.apache.qpid.server.handler.TxRollbackHandler; +import org.apache.qpid.server.handler.TxSelectHandler; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -107,18 +108,18 @@ public class AMQStateManager implements AMQMethodListener * AMQFrame. */ private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = - new EnumMap, StateAwareMethodListener>>(AMQState.class); - + new EnumMap, StateAwareMethodListener>>( + AMQState.class); private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) { this(AMQState.CONNECTION_NOT_STARTED, true, virtualHostRegistry, protocolSession); } - protected AMQStateManager(AMQState initial, boolean register, VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) + protected AMQStateManager(AMQState initial, boolean register, VirtualHostRegistry virtualHostRegistry, + AMQProtocolSession protocolSession) { _virtualHostRegistry = virtualHostRegistry; _protocolSession = protocolSession; @@ -220,37 +221,38 @@ public class AMQStateManager implements AMQMethodListener checkChannel(evt, _protocolSession); handler.methodReceived(this, evt); + return true; } + return false; } private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) - throws AMQException + throws AMQException { - if (evt.getChannelId() != 0 - && !(evt.getMethod() instanceof ChannelOpenBody) - && (protocolSession.getChannel(evt.getChannelId()) == null) - && !protocolSession.channelAwaitingClosure(evt.getChannelId())) + if ((evt.getChannelId() != 0) && !(evt.getMethod() instanceof ChannelOpenBody) + && (protocolSession.getChannel(evt.getChannelId()) == null) + && !protocolSession.channelAwaitingClosure(evt.getChannelId())) { throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); } } protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, - B frame) - throws IllegalStateTransitionException + B frame) + // throws IllegalStateTransitionException { - final Map, StateAwareMethodListener> - classToHandlerMap = _state2HandlersMap.get(currentState); + final Map, StateAwareMethodListener> classToHandlerMap = + _state2HandlersMap.get(currentState); - final StateAwareMethodListener handler = classToHandlerMap == null - ? null - : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); + final StateAwareMethodListener handler = + (classToHandlerMap == null) ? null : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); if (handler == null) { _logger.debug("No state transition handler defined for receiving frame " + frame); + return null; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java index 2d7cc27a85..cec67a8a6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,6 +22,11 @@ package org.apache.qpid.server.state; import org.apache.qpid.AMQException; +/** + * @todo Not an AMQP exception as no status code. + * + * @todo Not used! Delete. + */ public class IllegalStateTransitionException extends AMQException { private AMQState _originalState; @@ -30,8 +35,7 @@ public class IllegalStateTransitionException extends AMQException public IllegalStateTransitionException(AMQState originalState, Class frame) { - super("No valid state transition defined for receiving frame " + frame + - " from state " + originalState); + super("No valid state transition defined for receiving frame " + frame + " from state " + originalState); _originalState = originalState; _frame = frame; } -- cgit v1.2.1 From eaa113f7b7640bddf8328f3e8cc24ce72fb9b52c Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Mon, 21 May 2007 15:11:23 +0000 Subject: Refactored exceptions to have single constructors and made room for wrapped causes. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540165 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 6 +- .../qpid/server/ConsumerTagNotUniqueException.java | 20 +- .../qpid/server/RequiredDeliveryException.java | 4 +- .../server/ack/UnacknowledgedMessageMapImpl.java | 4 +- .../server/exchange/DefaultExchangeFactory.java | 6 +- .../server/exchange/DefaultExchangeRegistry.java | 8 +- .../qpid/server/exchange/DestNameExchange.java | 8 +- .../qpid/server/exchange/DestWildExchange.java | 12 +- .../server/exchange/ExchangeInUseException.java | 4 +- .../qpid/server/exchange/FanoutExchange.java | 8 +- .../qpid/server/exchange/HeadersExchange.java | 4 +- .../qpid/server/exchange/NoRouteException.java | 4 +- .../server/handler/BasicConsumeMethodHandler.java | 6 +- .../handler/ConnectionSecureOkMethodHandler.java | 2 +- .../handler/ConnectionStartOkMethodHandler.java | 2 +- .../qpid/server/handler/ExchangeBoundHandler.java | 2 +- .../server/handler/ExchangeDeclareHandler.java | 2 +- .../qpid/server/handler/QueueDeclareHandler.java | 2 +- .../qpid/server/handler/QueueDeleteHandler.java | 2 +- .../server/management/DefaultManagedObject.java | 4 +- .../server/protocol/AMQMinaProtocolSession.java | 14 +- .../protocol/AMQNoMethodHandlerException.java | 4 +- .../protocol/UnknnownMessageTypeException.java | 4 +- .../org/apache/qpid/server/queue/AMQMessage.java | 559 ++++++++++----------- .../org/apache/qpid/server/queue/AMQQueue.java | 157 ++---- .../ExistingExclusiveSubscriptionException.java | 22 + ...tingSubscriptionPreventsExclusiveException.java | 22 + .../qpid/server/queue/FailedDequeueException.java | 9 +- .../qpid/server/queue/MessageCleanupException.java | 9 +- .../qpid/server/queue/NoConsumersException.java | 4 +- .../qpid/server/queue/StorableMessageHandle.java | 4 +- .../apache/qpid/server/queue/SubscriptionImpl.java | 2 +- .../state/IllegalStateTransitionException.java | 52 -- .../txn/DistributedTransactionalContext.java | 14 +- .../qpid/server/txn/LocalTransactionalContext.java | 2 +- .../qpid/server/txn/NonTransactionalContext.java | 6 +- 36 files changed, 455 insertions(+), 539 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1de4d16ad4..5de59f47a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -212,7 +212,7 @@ public class AMQChannel { if (_currentMessage == null) { - throw new AMQException("Received content header without previously receiving a BasicPublish frame"); + throw new AMQException(null, "Received content header without previously receiving a BasicPublish frame", null); } else { @@ -239,7 +239,7 @@ public class AMQChannel { if (_currentMessage == null) { - throw new AMQException("Received content body without previously receiving a JmsPublishBody"); + throw new AMQException(null, "Received content body without previously receiving a JmsPublishBody", null); } if (_log.isTraceEnabled()) @@ -883,7 +883,7 @@ public class AMQChannel { if (!isTransactional()) { - throw new AMQException("Fatal error: commit called on non-transactional channel"); + throw new AMQException(null, "Fatal error: commit called on non-transactional channel", null); } _txnContext.commit(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java index 9a98af5689..3253650d14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,6 +20,16 @@ */ package org.apache.qpid.server; -public class ConsumerTagNotUniqueException extends Exception -{ -} +/** + * ConsumerTagNotUniqueException indicates that a client has attempted to connect with a consumer tag that is already + * used. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents error when clients connects with a non-unique tag. + *
      + * + * @todo Consider replacing with an AMQNotAllowedException, as this is the status code returned when this happens. + */ +public class ConsumerTagNotUniqueException extends Exception +{ } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index d61bb8916a..37c5f38ea3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -41,9 +41,9 @@ public abstract class RequiredDeliveryException extends AMQException { private final AMQMessage _amqMessage; - public RequiredDeliveryException(String message, AMQMessage payload) + public RequiredDeliveryException(String message, AMQMessage payload, Throwable cause) { - super(message); + super(null, message, cause); // Increment the reference as this message is in the routing phase // and so will have the ref decremented as routing fails. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 30bbdea2ef..1604d94539 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -181,8 +181,8 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap 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()); + throw new AMQException(null, "UnacknowledgedMessageMap is out of order:" + unacked.getKey() + + " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString(), null); } it.remove(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index c349b44d6d..39a5bba8b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -55,7 +55,7 @@ public class DefaultExchangeFactory implements ExchangeFactory if (exchClass == null) { - throw new AMQUnknownExchangeType("Unknown exchange type: " + type); + throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null); } try { @@ -65,11 +65,11 @@ public class DefaultExchangeFactory implements ExchangeFactory } catch (InstantiationException e) { - throw new AMQException("Unable to create exchange: " + e, e); + throw new AMQException(null, "Unable to create exchange: " + e, e); } catch (IllegalAccessException e) { - throw new AMQException("Unable to create exchange: " + e, e); + throw new AMQException(null, "Unable to create exchange: " + e, e); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 9066af70d9..f3bdecc32e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -71,7 +71,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry getMessageStore().createExchange(exchange); } catch (InternalErrorException e) { - throw new AMQException("problem registering excahgne " + exchange, e); + throw new AMQException(null, "problem registering excahgne " + exchange, e); } } } @@ -99,14 +99,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry getMessageStore().removeExchange(e); } catch (InternalErrorException e1) { - throw new AMQException("Problem unregistering Exchange " + name, e1); + throw new AMQException(null, "Problem unregistering Exchange " + name, e1); } } e.close(); } else { - throw new AMQException("Unknown exchange " + name); + throw new AMQException(null, "Unknown exchange " + name, null); } } @@ -138,7 +138,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry // TODO: check where the exchange is validated if (exch == null) { - throw new AMQException("Exchange '" + exchange + "' does not exist"); + throw new AMQException(null, "Exchange '" + exchange + "' does not exist", null); } exch.route(payload); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index ab103fbd2a..01242f90de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -126,7 +126,7 @@ public class DestNameExchange extends AbstractExchange catch (JMException ex) { _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex); } } @@ -156,8 +156,8 @@ public class DestNameExchange extends AbstractExchange 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"); + throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that routing key", null); } } @@ -171,7 +171,7 @@ public class DestNameExchange extends AbstractExchange String msg = "Routing key " + routingKey + " is not known to " + this; if (info.isMandatory()) { - throw new NoRouteException(msg, payload); + throw new NoRouteException(msg, payload, null); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index e9c5b0024c..25ec0c3a2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -216,7 +216,7 @@ public class DestWildExchange extends AbstractExchange if (info.isMandatory()) { String msg = "Topic " + routingKey + " is not known to " + this; - throw new NoRouteException(msg, payload); + throw new NoRouteException(msg, payload, null); } else { @@ -276,15 +276,15 @@ public class DestWildExchange extends AbstractExchange 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"); + throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that routing key", null); } boolean removedQ = queues.remove(queue); if (!removedQ) { - throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey); + throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey, null); } if (queues.isEmpty()) { @@ -301,7 +301,7 @@ public class DestWildExchange extends AbstractExchange catch (JMException ex) { _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); + throw new AMQException(null, "Exception occured in creating the topic exchenge mbean", ex); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java index c77f114428..07550dd808 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -38,8 +38,8 @@ import org.apache.qpid.AMQException; */ public class ExchangeInUseException extends AMQException { - public ExchangeInUseException(String exchangeName) + public ExchangeInUseException(String exchangeName, Throwable cause) { - super("Exchange " + exchangeName + " is currently in use"); + super(null, "Exchange " + exchangeName + " is currently in use", cause); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index b3690d3e10..28d4b19f2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -98,7 +98,7 @@ public class FanoutExchange extends AbstractExchange catch (JMException ex) { _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex); } } @@ -129,8 +129,8 @@ public class FanoutExchange extends AbstractExchange if (!_queues.remove(queue)) { - throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + - ". "); + throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + + ". ", null); } } @@ -143,7 +143,7 @@ public class FanoutExchange extends AbstractExchange String msg = "No queues bound to " + this; if (publishInfo.isMandatory()) { - throw new NoRouteException(msg, payload); + throw new NoRouteException(msg, payload, null); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index b4b2bc20bc..8205924207 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -231,7 +231,7 @@ public class HeadersExchange extends AbstractExchange if (payload.getMessagePublishInfo().isMandatory()) { - throw new NoRouteException(msg, payload); + throw new NoRouteException(msg, payload, null); } else { @@ -284,7 +284,7 @@ public class HeadersExchange extends AbstractExchange catch (JMException ex) { _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); + throw new AMQException(null, "Exception occured in creating the HeadersExchangeMBean", ex); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index 1d6ab3842d..c787103c00 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -36,9 +36,9 @@ import org.apache.qpid.server.queue.AMQMessage; */ public class NoRouteException extends RequiredDeliveryException { - public NoRouteException(String msg, AMQMessage message) + public NoRouteException(String msg, AMQMessage message, Throwable cause) { - super(msg, message); + super(msg, message, cause); } public AMQConstant getReplyCode() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 56eae279dc..9346eecbb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -33,6 +33,8 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.ExistingExclusiveSubscriptionException; +import org.apache.qpid.server.queue.ExistingSubscriptionPreventsExclusiveException; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -146,14 +148,14 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener evt) + public AMQNoMethodHandlerException(AMQMethodEvent evt, Throwable cause) { - super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + super(null, "AMQMethodEvent " + evt + " was not processed by any listener on Broker.", cause); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java index 6e72aa062f..d053884e69 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -39,8 +39,8 @@ import org.apache.qpid.framing.AMQDataBlock; */ public class UnknnownMessageTypeException extends AMQException { - public UnknnownMessageTypeException(AMQDataBlock message) + public UnknnownMessageTypeException(AMQDataBlock message, Throwable cause) { - super("Unknown message type: " + message.getClass().getName() + ": " + message); + super(null, "Unknown message type: " + message.getClass().getName() + ": " + message, cause); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 6ffe1af018..95f75fdb36 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,31 +20,33 @@ */ package org.apache.qpid.server.queue; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + + +/** Combines the information that make up a deliverable message into a more manageable form. */ + +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.messageStore.StorableMessage; import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.registry.ApplicationRegistry; - -/** Combines the information that make up a deliverable message into a more manageable form. */ - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; - -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TransactionalContext; /** * Combines the information that make up a deliverable message into a more manageable form. @@ -56,7 +58,7 @@ public class AMQMessage implements StorableMessage // The ordered list of queues into which this message is enqueued. private List _queues = new LinkedList(); // Indicates whether this message is staged - private boolean _isStaged = false; + private boolean _isStaged = false; /** * Used in clustering @@ -89,18 +91,15 @@ public class AMQMessage implements StorableMessage */ private boolean _immediate; - // private Subscription _takenBySubcription; - // private AtomicBoolean _taken = new AtomicBoolean(false); + // private Subscription _takenBySubcription; + // private AtomicBoolean _taken = new AtomicBoolean(false); private TransientMessageData _transientMessageData = new TransientMessageData(); - private Set _rejectedBy = null; - private Map _takenMap = new HashMap(); private Map _takenBySubcriptionMap = new HashMap(); - private final int hashcode = System.identityHashCode(this); private long _expiration; @@ -111,8 +110,10 @@ public class AMQMessage implements StorableMessage public void setExpiration() { - long expiration = ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); - long timestamp = ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); + long expiration = + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); + long timestamp = + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false)) { @@ -125,10 +126,10 @@ public class AMQMessage implements StorableMessage { if (timestamp != 0L) { - //todo perhaps use arrival time + // todo perhaps use arrival time long diff = (System.currentTimeMillis() - timestamp); - if (diff > 1000L || diff < 1000L) + if ((diff > 1000L) || (diff < 1000L)) { _expiration = expiration + diff; } @@ -159,11 +160,12 @@ public class AMQMessage implements StorableMessage { try { - return _index < _messageHandle.getBodyCount(getStoreContext(), _messageId) - 1; + return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); } catch (AMQException e) { _log.error("Unable to get body count: " + e, e); + return false; } } @@ -173,7 +175,10 @@ public class AMQMessage implements StorableMessage try { - AMQBody cb = getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index)); + AMQBody cb = + getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), + _messageId, ++_index)); + return new AMQFrame(_channel, cb); } catch (AMQException e) @@ -209,11 +214,12 @@ public class AMQMessage implements StorableMessage { try { - return _index < _messageHandle.getBodyCount(getStoreContext(), _messageId) - 1; + return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); } catch (AMQException e) { _log.error("Error getting body count: " + e, e); + return false; } } @@ -236,8 +242,7 @@ public class AMQMessage implements StorableMessage } } - public AMQMessage(Long messageId, MessagePublishInfo info, - TransactionalContext txnContext) + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext) { _messageId = messageId; _txnContext = txnContext; @@ -257,8 +262,7 @@ public class AMQMessage implements StorableMessage * @throws AMQException */ public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws - AMQException + throws AMQException { _messageId = messageId; _messageHandle = factory.createMessageHandle(store, this, true); @@ -274,10 +278,8 @@ public class AMQMessage implements StorableMessage * @param txnContext * @param contentHeader */ - public AMQMessage(Long messageId, MessagePublishInfo info, - TransactionalContext txnContext, ContentHeaderBody contentHeader) - throws - AMQException + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, + ContentHeaderBody contentHeader) throws AMQException { this(messageId, info, txnContext); setContentHeaderBody(contentHeader); @@ -294,13 +296,9 @@ public class AMQMessage implements StorableMessage * @param contentBodies * @throws AMQException */ - public AMQMessage(Long messageId, MessagePublishInfo info, - TransactionalContext txnContext, - ContentHeaderBody contentHeader, List destinationQueues, - List contentBodies, MessageStore messageStore, StoreContext storeContext, - MessageHandleFactory messageHandleFactory) - throws - AMQException + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, + ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, + MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException { this(messageId, info, txnContext, contentHeader); _transientMessageData.setDestinationQueues(destinationQueues); @@ -311,9 +309,7 @@ public class AMQMessage implements StorableMessage } } - protected AMQMessage(AMQMessage msg) - throws - AMQException + protected AMQMessage(AMQMessage msg) throws AMQException { _messageId = msg._messageId; _messageHandle = msg._messageHandle; @@ -322,9 +318,9 @@ public class AMQMessage implements StorableMessage _transientMessageData = msg._transientMessageData; } - //======================================================================== + // ======================================================================== // Interface StorableMessage - //======================================================================== + // ======================================================================== public long getMessageId() { @@ -342,10 +338,12 @@ public class AMQMessage implements StorableMessage result = new byte[headerBody.getSize()]; bufferedResult = ByteBuffer.wrap(result); headerBody.writePayload(bufferedResult); - } catch (AMQException e) + } + catch (AMQException e) { _log.error("Error when getting message header", e); } + return result; } @@ -355,10 +353,12 @@ public class AMQMessage implements StorableMessage try { result = _messageHandle.getContentHeaderBody(_txnContext.getStoreContext(), _messageId).getSize(); - } catch (AMQException e) + } + catch (AMQException e) { _log.error("Error when getting message header size", e); } + return result; } @@ -372,7 +372,7 @@ public class AMQMessage implements StorableMessage return _messageHandle.getMessagePayload().length; } - public boolean isEnqueued() + public boolean isEnqueued() { return _queues.size() > 0; } @@ -401,6 +401,7 @@ public class AMQMessage implements StorableMessage { _log.debug("The queue position is " + _queues.indexOf(queue)); } + return _queues.indexOf(queue); } @@ -424,44 +425,40 @@ public class AMQMessage implements StorableMessage return new BodyContentIterator(); } - public ContentHeaderBody getContentHeaderBody() - throws - AMQException + public ContentHeaderBody getContentHeaderBody() throws AMQException { if (_transientMessageData != null) { return _transientMessageData.getContentHeaderBody(); - } else + } + else { return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); } } - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - throws - AMQException + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException { _transientMessageData.setContentHeaderBody(contentHeaderBody); } public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) - throws - AMQException + throws AMQException { final boolean persistent = isPersistent(); _messageHandle = factory.createMessageHandle(store, this, persistent); - //if (persistent) - // { - _txnContext.beginTranIfNecessary(); - // } + // if (persistent) + // { + _txnContext.beginTranIfNecessary(); + // } // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store - // for (AMQQueue q : _transientMessageData.getDestinationQueues()) - // { - // _messageHandle.enqueue(storeContext, _messageId, q); - // } + // for (AMQQueue q : _transientMessageData.getDestinationQueues()) + // { + // _messageHandle.enqueue(storeContext, _messageId, q); + // } if (_transientMessageData.getContentHeaderBody().bodySize == 0) { @@ -469,9 +466,7 @@ public class AMQMessage implements StorableMessage } } - public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) - throws - AMQException + public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException { _transientMessageData.addBodyLength(contentChunk.getSize()); final boolean allContentReceived = isAllContentReceived(); @@ -479,21 +474,20 @@ public class AMQMessage implements StorableMessage if (allContentReceived) { deliver(storeContext); + return true; - } else + } + else { return false; } } - public boolean isAllContentReceived() - throws - AMQException + public boolean isAllContentReceived() throws AMQException { return _transientMessageData.isAllContentReceived(); } - /** * Creates a long-lived reference to this message, and increments the count of such references, as an atomic * operation. @@ -501,6 +495,7 @@ public class AMQMessage implements StorableMessage public AMQMessage takeReference() { _referenceCount.incrementAndGet(); + return this; } @@ -510,10 +505,10 @@ public class AMQMessage implements StorableMessage protected void incrementReference() { _referenceCount.incrementAndGet(); -// if (_log.isDebugEnabled()) -// { -// _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); -// } + // if (_log.isDebugEnabled()) + // { + // _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); + // } } /** @@ -524,9 +519,7 @@ public class AMQMessage implements StorableMessage * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that * failed */ - public void decrementReference(StoreContext storeContext) - throws - MessageCleanupException + public void decrementReference(StoreContext storeContext) throws MessageCleanupException { int count = _referenceCount.decrementAndGet(); @@ -538,10 +531,10 @@ public class AMQMessage implements StorableMessage { try { -// if (_log.isDebugEnabled()) -// { -// _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); -// } + // if (_log.isDebugEnabled()) + // { + // _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); + // } // must check if the handle is null since there may be cases where we decide to throw away a message // and the handle has not yet been constructed @@ -552,15 +545,17 @@ public class AMQMessage implements StorableMessage } catch (AMQException e) { - //to maintain consistency, we revert the count + // to maintain consistency, we revert the count incrementReference(); - throw new MessageCleanupException(_messageId, e); + throw new MessageCleanupException("Failed to cleanup message with id " + _messageId, e); } - } else + } + else { if (count < 0) { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0."); + throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0.", + null); } } } @@ -587,7 +582,7 @@ public class AMQMessage implements StorableMessage public boolean isTaken(AMQQueue queue) { - //return _taken.get(); + // return _taken.get(); synchronized (this) { @@ -604,15 +599,15 @@ public class AMQMessage implements StorableMessage public boolean taken(AMQQueue queue, Subscription sub) { -// if (_taken.getAndSet(true)) -// { -// return true; -// } -// else -// { -// _takenBySubcription = sub; -// return false; -// } + // if (_taken.getAndSet(true)) + // { + // return true; + // } + // else + // { + // _takenBySubcription = sub; + // return false; + // } synchronized (this) { @@ -625,10 +620,12 @@ public class AMQMessage implements StorableMessage if (taken.getAndSet(true)) { return true; - } else + } + else { _takenMap.put(queue, taken); _takenBySubcriptionMap.put(queue, sub); + return false; } } @@ -641,9 +638,8 @@ public class AMQMessage implements StorableMessage _log.trace("Releasing Message:" + debugIdentity()); } -// _taken.set(false); -// _takenBySubcription = null; - + // _taken.set(false); + // _takenBySubcription = null; synchronized (this) { @@ -651,7 +647,8 @@ public class AMQMessage implements StorableMessage if (taken == null) { taken = new AtomicBoolean(false); - } else + } + else { taken.set(false); } @@ -672,9 +669,11 @@ public class AMQMessage implements StorableMessage if (_tokens.contains(token)) { return true; - } else + } + else { _tokens.add(token); + return false; } } @@ -687,28 +686,23 @@ public class AMQMessage implements StorableMessage * @param queue the queue * @throws org.apache.qpid.AMQException if there is an error enqueuing the message */ - public void enqueue(AMQQueue queue) - throws - AMQException + public void enqueue(AMQQueue queue) throws AMQException { _transientMessageData.addDestinationQueue(queue); } - public void dequeue(StoreContext storeContext, AMQQueue queue) - throws - AMQException + public void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException { _messageHandle.dequeue(storeContext, _messageId, queue); } - public boolean isPersistent() - throws - AMQException + public boolean isPersistent() throws AMQException { if (_transientMessageData != null) { return _transientMessageData.isPersistent(); - } else + } + else { return _messageHandle.isPersistent(getStoreContext(), _messageId); } @@ -720,29 +714,27 @@ public class AMQMessage implements StorableMessage * @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 + public void checkDeliveredToConsumer() throws NoConsumersException { if (_immediate && !_deliveredToConsumer) { - throw new NoConsumersException(this); + throw new NoConsumersException(this, null); } } - public MessagePublishInfo getMessagePublishInfo() - throws - AMQException + public MessagePublishInfo getMessagePublishInfo() throws AMQException { MessagePublishInfo pb; if (_transientMessageData != null) { pb = _transientMessageData.getMessagePublishInfo(); - } else + } + else { pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); } + return pb; } @@ -773,7 +765,7 @@ public class AMQMessage implements StorableMessage */ public boolean expired(StoreContext storecontext, AMQQueue queue) throws AMQException { - //note: If the storecontext isn't need then we can remove the getChannel() from Subscription. + // note: If the storecontext isn't need then we can remove the getChannel() from Subscription. if (_expiration != 0L) { @@ -782,6 +774,7 @@ public class AMQMessage implements StorableMessage if (now > _expiration) { dequeue(storecontext, queue); + return true; } } @@ -795,9 +788,7 @@ public class AMQMessage implements StorableMessage _deliveredToConsumer = true; } - private void deliver(StoreContext storeContext) - throws - AMQException + private void deliver(StoreContext storeContext) throws AMQException { // we get a reference to the destination queues now so that we can clear the // transient message data as quickly as possible @@ -806,12 +797,13 @@ public class AMQMessage implements StorableMessage { _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues); } + try { // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, _transientMessageData.getMessagePublishInfo(), - _transientMessageData.getContentHeaderBody()); + _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, + _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); // we then allow the transactional context to do something with the message content // now that it has all been received, before we attempt delivery @@ -821,9 +813,9 @@ public class AMQMessage implements StorableMessage for (AMQQueue q : destinationQueues) { - //Increment the references to this message for each queue delivery. + // Increment the references to this message for each queue delivery. incrementReference(); - //normal deliver so add this message at the end. + // normal deliver so add this message at the end. _txnContext.deliver(this, q, false); } } @@ -835,182 +827,181 @@ public class AMQMessage implements StorableMessage } } -/* - public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - ByteBuffer deliver = createEncodedDeliverFrame(protocolSession, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); - if (bodyCount == 0) + /* + public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); + ByteBuffer deliver = createEncodedDeliverFrame(protocolSession, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); + + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); + if (bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + protocolSession.writeFrame(compositeBlock); + } + else + { + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + protocolSession.writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for (int i = 1; i < bodyCount; i++) + { + cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); + protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + - protocolSession.writeFrame(compositeBlock); } - else + + public void writeGetOk(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) throws AMQException { + ByteBuffer deliver = createEncodedGetOkFrame(protocolSession, channelId, deliveryTag, queueSize); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); + final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); + if (bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + protocolSession.writeFrame(compositeBlock); + } + else + { + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + protocolSession.writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for (int i = 1; i < bodyCount; i++) + { + cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); + protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } - AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); - // - // Now start writing out the other content bodies - // - for (int i = 1; i < bodyCount; i++) - { - cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); - protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } } - } + private ByteBuffer createEncodedDeliverFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + MessagePublishInfo pb = getMessagePublishInfo(); + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), (byte) 0, consumerTag, + deliveryTag, pb.getExchange(), _messageHandle.isRedelivered(), + pb.getRoutingKey()); + ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? + deliverFrame.writePayload(buf); + buf.flip(); + return buf; + } - public void writeGetOk(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) throws AMQException - { - ByteBuffer deliver = createEncodedGetOkFrame(protocolSession, channelId, deliveryTag, queueSize); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); + private ByteBuffer createEncodedGetOkFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + MessagePublishInfo pb = getMessagePublishInfo(); + AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, + protocolSession.getProtocolMajorVersion(), + protocolSession.getProtocolMinorVersion(), + deliveryTag, pb.getExchange(), + queueSize, + _messageHandle.isRedelivered(), + pb.getRoutingKey()); + ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? + getOkFrame.writePayload(buf); + buf.flip(); + return buf; + } - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); - if (bodyCount == 0) + private ByteBuffer createEncodedReturnFrame(AMQProtocolSession protocolSession, int channelId, int replyCode, AMQShortString replyText) throws AMQException { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - protocolSession.writeFrame(compositeBlock); + AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, + protocolSession.getProtocolMajorVersion(), + protocolSession.getProtocolMinorVersion(), + getMessagePublishInfo().getExchange(), + replyCode, replyText, + getMessagePublishInfo().getRoutingKey()); + ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? + returnFrame.writePayload(buf); + buf.flip(); + return buf; } - else + + public void writeReturn(AMQProtocolSession protocolSession, int channelId, int replyCode, AMQShortString replyText) + throws AMQException { + ByteBuffer returnFrame = createEncodedReturnFrame(protocolSession, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); + Iterator bodyFrameIterator = getBodyFrameIterator(protocolSession, 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. // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); + 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 // - for (int i = 1; i < bodyCount; i++) + while (bodyFrameIterator.hasNext()) { - cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); - protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + protocolSession.writeFrame(bodyFrameIterator.next()); } - - } - - - } - - - private ByteBuffer createEncodedDeliverFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - MessagePublishInfo pb = getMessagePublishInfo(); - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), (byte) 0, consumerTag, - deliveryTag, pb.getExchange(), _messageHandle.isRedelivered(), - pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; - } - - private ByteBuffer createEncodedGetOkFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - MessagePublishInfo pb = getMessagePublishInfo(); - AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - deliveryTag, pb.getExchange(), - queueSize, - _messageHandle.isRedelivered(), - pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? - getOkFrame.writePayload(buf); - buf.flip(); - return buf; - } - - private ByteBuffer createEncodedReturnFrame(AMQProtocolSession protocolSession, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - getMessagePublishInfo().getExchange(), - replyCode, replyText, - getMessagePublishInfo().getRoutingKey()); - 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, AMQShortString replyText) - throws AMQException - { - ByteBuffer returnFrame = createEncodedReturnFrame(protocolSession, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - Iterator bodyFrameIterator = getBodyFrameIterator(protocolSession, 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()); - } - } -*/ + */ public AMQMessageHandle getMessageHandle() { return _messageHandle; } - public long getSize() { try @@ -1022,15 +1013,13 @@ public class AMQMessage implements StorableMessage catch (AMQException e) { _log.error(e.toString(), e); + return 0; } } - - public void restoreTransientMessageData() - throws - AMQException + public void restoreTransientMessageData() throws AMQException { TransientMessageData transientMessageData = new TransientMessageData(); transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); @@ -1039,25 +1028,23 @@ public class AMQMessage implements StorableMessage _transientMessageData = transientMessageData; } - public void clearTransientMessageData() { _transientMessageData = null; } - public String toString() { -// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + -// _taken + " by :" + _takenBySubcription; + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + - _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } public Subscription getDeliveredSubscription(AMQQueue queue) { -// return _takenBySubcription; + // return _takenBySubcription; synchronized (this) { return _takenBySubcriptionMap.get(queue); @@ -1074,7 +1061,8 @@ public class AMQMessage implements StorableMessage } _rejectedBy.add(subscription); - } else + } + else { _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); } @@ -1084,10 +1072,11 @@ public class AMQMessage implements StorableMessage { boolean rejected = _rejectedBy != null; - if (rejected) // We have subscriptions that rejected this message + if (rejected) // We have subscriptions that rejected this message { return _rejectedBy.contains(subscription); - } else // This messasge hasn't been rejected yet. + } + else // This messasge hasn't been rejected yet. { return rejected; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index a17cbb87ff..a803ef1227 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,9 +21,9 @@ package org.apache.qpid.server.queue; import java.text.MessageFormat; -import java.util.List; -import java.util.Hashtable; import java.util.Collection; +import java.util.Hashtable; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,11 +40,11 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.StorableQueue; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.StorableQueue; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -55,49 +55,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; */ public class AMQQueue implements Managable, Comparable, StorableQueue { - /** - * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create a subscription, because an exclusive subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - public static int s_queueID =0; - public static final class ExistingExclusiveSubscription extends AMQException - { - - public ExistingExclusiveSubscription() - { - super(""); - } - } - - /** - * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create an exclusize subscription, as a subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - public static final class ExistingSubscriptionPreventsExclusive extends AMQException - { - public ExistingSubscriptionPreventsExclusive() - { - super(""); - } - } + public static int s_queueID = 0; private static final Logger _logger = Logger.getLogger(AMQQueue.class); @@ -108,7 +66,6 @@ public class AMQQueue implements Managable, Comparable, StorableQueue // The list of enqueued messages. Hashtable _messages = new Hashtable(); - /** * null means shared */ @@ -236,12 +193,10 @@ public class AMQQueue implements Managable, Comparable, StorableQueue _subscribers = subscribers; _subscriptionFactory = subscriptionFactory; _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); - _queueId = s_queueID++; + _queueId = s_queueID++; } - private AMQQueueMBean createMBean() - throws - AMQException + private AMQQueueMBean createMBean() throws AMQException { try { @@ -249,7 +204,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } catch (JMException ex) { - throw new AMQException("AMQQueue MBean creation has failed ", ex); + throw new AMQException(null, "AMQQueue MBean creation has failed ", ex); } } @@ -443,9 +398,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue /** * Removes the AMQMessage from the top of the queue. */ - public synchronized void deleteMessageFromTop(StoreContext storeContext) - throws - AMQException + public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException { _deliveryMgr.removeAMessageFromTop(storeContext); } @@ -453,16 +406,12 @@ public class AMQQueue implements Managable, Comparable, StorableQueue /** * removes all the messages from the queue. */ - public synchronized long clearQueue(StoreContext storeContext) - throws - AMQException + public synchronized long clearQueue(StoreContext storeContext) throws AMQException { return _deliveryMgr.clearAllMessages(storeContext); } - public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - throws - AMQException + public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException { exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) @@ -470,18 +419,17 @@ public class AMQQueue implements Managable, Comparable, StorableQueue try { _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); - } catch (InternalErrorException e) + } + catch (InternalErrorException e) { - throw new AMQException("Problem binding queue ", e); + throw new AMQException(null, "Problem binding queue ", e); } } _bindings.addBinding(routingKey, arguments, exchange); } - public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - throws - AMQException + public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException { exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) @@ -489,9 +437,10 @@ public class AMQQueue implements Managable, Comparable, StorableQueue try { _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); - } catch (InternalErrorException e) + } + catch (InternalErrorException e) { - throw new AMQException("problem unbinding queue", e); + throw new AMQException(null, "problem unbinding queue", e); } } @@ -506,14 +455,16 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (isExclusive()) { decrementSubscriberCount(); - throw new ExistingExclusiveSubscription(); - } else if (exclusive) + throw new ExistingExclusiveSubscriptionException(); + } + else if (exclusive) { decrementSubscriberCount(); - throw new ExistingSubscriptionPreventsExclusive(); + throw new ExistingSubscriptionPreventsExclusiveException(); } - } else if (exclusive) + } + else if (exclusive) { setExclusive(true); } @@ -559,9 +510,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return _subscriberCount.decrementAndGet(); } - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) - throws - AMQException + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException { if (_logger.isDebugEnabled()) { @@ -576,8 +525,8 @@ public class AMQQueue implements Managable, Comparable, StorableQueue _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); + throw new AMQException(null, "Protocol session with channel " + channel + " and consumer tag " + consumerTag + + " and protocol session key " + ps.getKey() + " not registered with queue " + this, null); } removedSubscription.close(); @@ -609,21 +558,21 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return !_deliveryMgr.hasQueuedMessages(); } - public int delete(boolean checkUnused, boolean checkEmpty) - throws - AMQException + public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException { if (checkUnused && !_subscribers.isEmpty()) { _logger.info("Will not delete " + this + " as it is in use."); return 0; - } else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) + } + else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) { _logger.info("Will not delete " + this + " as it is not empty."); return 0; - } else + } + else { delete(); @@ -631,9 +580,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } } - public void delete() - throws - AMQException + public void delete() throws AMQException { if (!_deleted.getAndSet(true)) { @@ -650,9 +597,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } } - protected void autodelete() - throws - AMQException + protected void autodelete() throws AMQException { if (_logger.isDebugEnabled()) { @@ -662,9 +607,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue delete(); } - public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) - throws - AMQException + public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { // fixme not sure what this is doing. should we be passing deliverFirst through here? // This code is not used so when it is perhaps it should @@ -687,9 +630,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue // return _deliveryMgr; // } - public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) - throws - AMQException + public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); try @@ -705,9 +646,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } } - void dequeue(StoreContext storeContext, AMQMessage msg) - throws - FailedDequeueException + void dequeue(StoreContext storeContext, AMQMessage msg) throws FailedDequeueException { try { @@ -737,9 +676,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return _subscribers; } - protected void updateReceivedMessageCount(AMQMessage msg) - throws - AMQException + protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException { if (!msg.isRedelivered()) { @@ -752,7 +689,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } catch (JMException e) { - throw new AMQException("Unable to get notification from manage queue: " + e, e); + throw new AMQException(null, "Unable to get notification from manage queue: " + e, e); } } @@ -783,9 +720,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue return "Queue(" + _name + ")@" + System.identityHashCode(this); } - public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) - throws - AMQException + public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException { return _deliveryMgr.performGet(session, channel, acks); } @@ -802,9 +737,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue public static interface Task { - public void doTask(AMQQueue queue) - throws - AMQException; + public void doTask(AMQQueue queue) throws AMQException; } public void addQueueDeleteTask(Task task) @@ -837,9 +770,9 @@ public class AMQQueue implements Managable, Comparable, StorableQueue _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, msg); } - //======================================================================== + // ======================================================================== // Interface StorableQueue - //======================================================================== + // ======================================================================== public int getQueueID() { @@ -861,9 +794,9 @@ public class AMQQueue implements Managable, Comparable, StorableQueue _messages.put(m.getMessageId(), m); } - //======================================================================== + // ======================================================================== // Used by the Store - //======================================================================== + // ======================================================================== /** * Get the list of enqueud messages diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java new file mode 100644 index 0000000000..a5ff9e6326 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java @@ -0,0 +1,22 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * ExistingExclusiveSubscriptionException signals a failure to create a subscription, because an exclusive subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create a subscription, because an exclusive subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + */ +public final class ExistingExclusiveSubscriptionException extends AMQException +{ + public ExistingExclusiveSubscriptionException() + { + super(null, "", null); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java new file mode 100644 index 0000000000..a13686eb56 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java @@ -0,0 +1,22 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * ExistingSubscriptionPreventsExclusiveException signals a failure to create an exclusize subscription, as a subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create an exclusize subscription, as a subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + */ +public final class ExistingSubscriptionPreventsExclusiveException extends AMQException +{ + public ExistingSubscriptionPreventsExclusiveException() + { + super(null, "", null); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java index 6466e81dd2..d5c34152a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java @@ -38,13 +38,8 @@ import org.apache.qpid.AMQException; */ public class FailedDequeueException extends AMQException { - public FailedDequeueException(String queue) + public FailedDequeueException(String queue, Throwable cause) { - super("Failed to dequeue message from " + queue); - } - - public FailedDequeueException(String queue, AMQException e) - { - super("Failed to dequeue message from " + queue, e); + super(null, "Failed to dequeue message from " + queue, cause); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java index 090096d3c3..2fdd2791b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java @@ -40,13 +40,8 @@ import org.apache.qpid.AMQException; */ public class MessageCleanupException extends AMQException { - public MessageCleanupException(long messageId, AMQException e) + public MessageCleanupException(String message, Throwable cause) { - super("Failed to cleanup message with id " + messageId, e); - } - - public MessageCleanupException(String message) - { - super(message); + super(null, message, cause); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java index d6fd1eec89..afcdf062de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -35,9 +35,9 @@ import org.apache.qpid.server.RequiredDeliveryException; */ public class NoConsumersException extends RequiredDeliveryException { - public NoConsumersException(AMQMessage message) + public NoConsumersException(AMQMessage message, Throwable cause) { - super("Immediate delivery is not possible.", message); + super("Immediate delivery is not possible.", message, cause); } public AMQConstant getReplyCode() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java index 5539627820..560549c126 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java @@ -175,7 +175,7 @@ public class StorableMessageHandle implements AMQMessageHandle } } catch (Exception e) { - throw new AMQException("PRoblem during message enqueue", e); + throw new AMQException(null, "PRoblem during message enqueue", e); } } @@ -191,7 +191,7 @@ public class StorableMessageHandle implements AMQMessageHandle } } catch (Exception e) { - throw new AMQException("PRoblem during message dequeue", e); + throw new AMQException(null, "PRoblem during message dequeue", e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index a7be9f2ad2..1cebf08fa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -108,7 +108,7 @@ public class SubscriptionImpl implements Subscription AMQChannel channel = protocolSession.getChannel(channelId); if (channel == null) { - throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); + throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session", null); } this.channel = channel; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java deleted file mode 100644 index cec67a8a6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -/** - * @todo Not an AMQP exception as no status code. - * - * @todo Not used! Delete. - */ -public class IllegalStateTransitionException extends AMQException -{ - private AMQState _originalState; - - private Class _frame; - - public IllegalStateTransitionException(AMQState originalState, Class frame) - { - super("No valid state transition defined for receiving frame " + frame + " from state " + originalState); - _originalState = originalState; - _frame = frame; - } - - public AMQState getOriginalState() - { - return _originalState; - } - - public Class getFrameClass() - { - return _frame; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java index 05756a8c23..6c001485b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java @@ -87,7 +87,7 @@ public class DistributedTransactionalContext implements TransactionalContext _storeContext.setPayload(xid); } catch (Exception e) { - throw new AMQException("Problem during transaction begin", e); + throw new AMQException(null, "Problem during transaction begin", e); } } } @@ -105,7 +105,7 @@ public class DistributedTransactionalContext implements TransactionalContext } } catch (Exception e) { - throw new AMQException("Problem during transaction commit", e); + throw new AMQException(null, "Problem during transaction commit", e); } finally { @@ -125,7 +125,7 @@ public class DistributedTransactionalContext implements TransactionalContext } } catch (Exception e) { - throw new AMQException("Problem during transaction rollback", e); + throw new AMQException(null, "Problem during transaction rollback", e); } finally { @@ -152,7 +152,7 @@ public class DistributedTransactionalContext implements TransactionalContext _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new EnqueueRecord(_storeContext, message, queue, deliverFirst)); } catch (Exception e) { - throw new AMQException("Problem during transaction rollback", e); + throw new AMQException(null, "Problem during transaction rollback", e); } } @@ -196,7 +196,7 @@ public class DistributedTransactionalContext implements TransactionalContext { if (!unacknowledgedMessageMap.contains(deliveryTag)) { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + throw new AMQException(null, "Multiple ack on delivery tag " + deliveryTag + " not known for channel", null); } LinkedList acked = new LinkedList(); @@ -219,7 +219,7 @@ public class DistributedTransactionalContext implements TransactionalContext if (msg == null) { _log.info("Single ack on delivery tag " + deliveryTag); - throw new AMQException("Single ack on delivery tag " + deliveryTag); + throw new AMQException(null, "Single ack on delivery tag " + deliveryTag, null); } if (_log.isDebugEnabled()) @@ -250,7 +250,7 @@ public class DistributedTransactionalContext implements TransactionalContext _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new DequeueRecord()); } catch (Exception e) { - throw new AMQException("Problem during message dequeue", e); + throw new AMQException(null, "Problem during message dequeue", e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 6d776eec0f..93459beb45 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -126,7 +126,7 @@ public class LocalTransactionalContext implements TransactionalContext { if (!unacknowledgedMessageMap.contains(deliveryTag)) { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); + throw new AMQException(null, "Ack with delivery tag " + deliveryTag + " not known for channel", null); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 496c94dae9..addb0c791f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -149,7 +149,7 @@ public class NonTransactionalContext implements TransactionalContext { if (!unacknowledgedMessageMap.contains(deliveryTag)) { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + throw new AMQException(null, "Multiple ack on delivery tag " + deliveryTag + " not known for channel", null); } LinkedList acked = new LinkedList(); @@ -182,8 +182,8 @@ public class NonTransactionalContext implements TransactionalContext { _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()); + throw new AMQException(null, "Single ack on delivery tag " + deliveryTag + " not known for channel:" + + _channel.getChannelId(), null); } if (!_browsedAcks.contains(deliveryTag)) -- cgit v1.2.1 From 3cc70a8be2f499ca9a20661f798453cee9f37aa8 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Mon, 21 May 2007 16:34:03 +0000 Subject: Documented remaining exceptions. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540198 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/exception/CommandInvalidException.java | 39 +++--- .../server/exception/InternalErrorException.java | 25 +++- .../qpid/server/exception/InvalidXidException.java | 20 ++- .../exception/MessageAlreadyStagedException.java | 12 +- .../exception/MessageDoesntExistException.java | 18 ++- .../server/exception/NotPreparedException.java | 21 ++- .../exception/QueueAlreadyExistsException.java | 17 ++- .../exception/QueueDoesntExistException.java | 19 ++- .../qpid/server/exception/UnknownXidException.java | 23 +++- .../server/messageStore/MemoryMessageStore.java | 133 ++++++++---------- .../org/apache/qpid/server/txn/EnqueueRecord.java | 37 ++--- .../qpid/server/txn/MemoryTransactionManager.java | 152 ++++++++++----------- 12 files changed, 277 insertions(+), 239 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java index ae1b916144..2b5fbf9795 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,22 +18,16 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 15:52:29 + * CommandInvalidException indicates that an innapropriate request has been made to a transaction manager. For example, + * calling prepare on an already prepared transaction. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents an error due to an innapropriate request to a transction manager. + *
      */ public class CommandInvalidException extends Exception { - /** - * Constructs a new CommandInvalidException with the specified detail message. - * - * @param message the detail message. - */ - public CommandInvalidException(String message) - { - super(message); - } - /** * Constructs a new CommandInvalidException with the specified detail message and * cause. @@ -46,14 +40,27 @@ public class CommandInvalidException extends Exception super(message, cause); } + /** + * Constructs a new CommandInvalidException with the specified detail message. + * + * @param message the detail message. + * + * @deprected + */ + public CommandInvalidException(String message) + { + super(message); + } + /** * Constructs a new CommandInvalidException with the specified cause. * * @param cause the cause + * + * @deprected */ public CommandInvalidException(Throwable cause) { super(cause); } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java index f5fcfeee8f..60e1514d2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,15 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 14:41:53 + * General purpose exception for non-specifc error cases. Do not use. + * + * @deprected Far too broad to be a checked exception. Will be abused as a "don't know what to do with it" exception + * when Runtimes should be used. If this has a specific meaning within transaction managers, it should + * be renamed to something like TxManagerException, for example. At the moment, transaction managers are not + * catching this exception and taking some action, so it is clear that it is being used for errors that are + * not recoverable/handleable from; use runtimes. So far, it is only caught to be rethrown as AMQException, + * which is the other catch-all exception case to be eliminated. There are sequences in the code where + * AMQException is caught and rethrown as InternalErrorException, which is cause and rethrown as AMQException. */ public class InternalErrorException extends Exception { @@ -28,6 +34,8 @@ public class InternalErrorException extends Exception * Constructs a new InternalErrorException with the specified detail message. * * @param message the detail message. + * + * @deprected */ public InternalErrorException(String message) { @@ -50,8 +58,11 @@ public class InternalErrorException extends Exception * Constructs a new InternalErrorException with the specified cause. * * @param cause the cause + * + * @deprected */ - public InternalErrorException(Throwable cause) { + public InternalErrorException(Throwable cause) + { super(cause); } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java index 3cae098403..277614afff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,9 +20,13 @@ package org.apache.qpid.server.exception; import javax.transaction.xa.Xid; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 14:12:27 + * InvalidXidException indicates that an Xid under which to conduct a transaction is invalid. This may be because it + * has an incorrect format, is null, or a transcaction with the same Xid is already running. + * + *

      + * + *
      CRC Card
      Responsibilities Collaborations + *
      Represents an invalid Xid for a transaction. + *
      */ public class InvalidXidException extends Exception { @@ -30,6 +34,8 @@ public class InvalidXidException extends Exception * Constructs a newr InvalidXidException with a standard message * * @param xid The invalid xid. + * + * @deprected */ public InvalidXidException(Xid xid) { @@ -41,6 +47,8 @@ public class InvalidXidException extends Exception * * @param xid The invalid xid. * @param cause The casue for the xid to be invalid + * + * @deprected */ public InvalidXidException(Xid xid, Throwable cause) { @@ -64,6 +72,8 @@ public class InvalidXidException extends Exception * @param reason The reason why the xid is invalid * @param xid The invalid xid. * @param cause The casue for the xid to be invalid + * + * @deprected */ public InvalidXidException(Xid xid, String reason, Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java index f95132a450..336f5fdf64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,7 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 03-Apr-2007 - * Time: 09:46:31 + * @todo Need to understand what message staging is to document properly. */ public class MessageAlreadyStagedException extends Exception { @@ -40,6 +38,8 @@ public class MessageAlreadyStagedException extends Exception * * @param message the detail message . * @param cause the cause. + * + * @deprected */ public MessageAlreadyStagedException(String message, Throwable cause) { @@ -50,6 +50,8 @@ public class MessageAlreadyStagedException extends Exception * Constructs a new MessageAlreadyStagedException with the specified cause. * * @param cause the cause + * + * @deprected */ public MessageAlreadyStagedException(Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java index b8ffe91247..544d669d4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,13 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 30-Mar-2007 - * Time: 10:52:29 + * MessageDoesntExistException indicates that a message store cannot find a message looked up by its id. This may + * indicate message loss. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure of message store to find a message. + *
      */ public class MessageDoesntExistException extends Exception { @@ -40,6 +44,8 @@ public class MessageDoesntExistException extends Exception * * @param message the detail message . * @param cause the cause. + * + * @deprected */ public MessageDoesntExistException(String message, Throwable cause) { @@ -50,6 +56,8 @@ public class MessageDoesntExistException extends Exception * Constructs a new MessageDoesntExistException with the specified cause. * * @param cause the cause + * + * @deprected */ public MessageDoesntExistException(Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java index af8c7374bf..ab288748f5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,14 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 16:47:40 + * NotPreparedException indicates a failure to commit a transaction that has not been prepared. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to commit an unprepared transaction. + *
      + * + * @todo There is already a CommandInvalidException which would seem to cover this too. Use it instead? */ public class NotPreparedException extends Exception { @@ -40,6 +45,8 @@ public class NotPreparedException extends Exception * * @param message the detail message . * @param cause the cause. + * + * @deprecated */ public NotPreparedException(String message, Throwable cause) { @@ -50,9 +57,11 @@ public class NotPreparedException extends Exception * Constructs a new NotPreparedException with the specified cause. * * @param cause the cause + * + * @deprected */ public NotPreparedException(Throwable cause) { super(cause); } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java index 39751261e4..3635d2c19d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,12 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 30-Mar-2007 - * Time: 10:49:00 + * QueueAlreadyExistsException inidicates failure of a message store to create a queue that already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to create a queue that already exists. + *
      */ public class QueueAlreadyExistsException extends Exception { @@ -40,6 +43,8 @@ public class QueueAlreadyExistsException extends Exception * * @param message the detail message . * @param cause the cause. + * + * @deprecated */ public QueueAlreadyExistsException(String message, Throwable cause) { @@ -50,6 +55,8 @@ public class QueueAlreadyExistsException extends Exception * Constructs a new QueueDoesntExistException with the specified cause. * * @param cause the cause + * + * @deprecated */ public QueueAlreadyExistsException(Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java index 88dea864a5..d05c152228 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,9 +18,12 @@ package org.apache.qpid.server.exception; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 17:38:24 + * MessageDoesntExistException indicates that a message store cannot find a queue. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to find a queue on a message store. + *
      */ public class QueueDoesntExistException extends Exception { @@ -40,6 +43,8 @@ public class QueueDoesntExistException extends Exception * * @param message the detail message . * @param cause the cause. + * + * @deprecated */ public QueueDoesntExistException(String message, Throwable cause) { @@ -50,9 +55,11 @@ public class QueueDoesntExistException extends Exception * Constructs a new QueueDoesntExistException with the specified cause. * * @param cause the cause + * + * @deprecated */ public QueueDoesntExistException(Throwable cause) { super(cause); } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java index 9c1a28413f..b8a8de90a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,9 +20,16 @@ package org.apache.qpid.server.exception; import javax.transaction.xa.Xid; /** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 15:45:06 + * UnknownXidException indicates that an Xid under which a transactional operation is to be run is not known. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure of a transaction manager to recognize an Xid. + *
      + * + * @todo Already have an InvalidXidException, this might be splitting things too far? There are cases where invalid is + * caught and rethrown as unknown. What is unknown specifically used for that invalid is not? For example, when + * recovering, is it important to distinguish between invalid and unknown? */ public class UnknownXidException extends Exception { @@ -30,6 +37,8 @@ public class UnknownXidException extends Exception * Constructs a newr UnknownXidException with a standard message * * @param xid The unknown xid. + * + * @deprecated */ public UnknownXidException(Xid xid) { @@ -41,6 +50,8 @@ public class UnknownXidException extends Exception * * @param xid The unknown xid. * @param cause The casue for the xid to be unknown + * + * @deprecated */ public UnknownXidException(Xid xid, Throwable cause) { @@ -52,6 +63,8 @@ public class UnknownXidException extends Exception * * @param reason The reason why the xid is unknown * @param xid The unknown xid. + * + * @deprecated */ public UnknownXidException(Xid xid, String reason) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java index 38fd9daa39..2bcebe0fa7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -17,22 +17,25 @@ */ package org.apache.qpid.server.messageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.txn.TransactionRecord; -import org.apache.qpid.server.txn.MemoryEnqueueRecord; -import org.apache.qpid.server.txn.MemoryDequeueRecord; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.*; + +import javax.transaction.xa.Xid; + import org.apache.commons.configuration.Configuration; + import org.apache.log4j.Logger; -import javax.transaction.xa.Xid; -import java.util.*; -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.txn.MemoryDequeueRecord; +import org.apache.qpid.server.txn.MemoryEnqueueRecord; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.txn.TransactionRecord; +import org.apache.qpid.server.virtualhost.VirtualHost; /** * This a simple in-memory implementation of a message store i.e. nothing is persisted @@ -43,9 +46,9 @@ import java.nio.ByteBuffer; */ public class MemoryMessageStore implements MessageStore { - //======================================================================== + // ======================================================================== // Static Constants - //======================================================================== + // ======================================================================== // The logger for this class private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -58,42 +61,34 @@ public class MemoryMessageStore implements MessageStore // The transaction manager private TransactionManager _txm; - //======================================================================== + // ======================================================================== // Interface MessageStore - //======================================================================== + // ======================================================================== - public void removeExchange(Exchange exchange) - throws - InternalErrorException + public void removeExchange(Exchange exchange) throws InternalErrorException { - // do nothing this is inmemory + // do nothing this is inmemory } public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException + throws InternalErrorException { // do nothing this is inmemory } - public void createExchange(Exchange exchange) - throws - InternalErrorException + public void createExchange(Exchange exchange) throws InternalErrorException { // do nothing this is inmemory } public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException + throws InternalErrorException { // do nothing this is inmemory } public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws - InternalErrorException, - IllegalArgumentException + throws InternalErrorException, IllegalArgumentException { _log.info("Configuring memory message store"); // Initialise the maps @@ -103,19 +98,14 @@ public class MemoryMessageStore implements MessageStore _txm.configure(this, "txn", config); } - public void close() - throws - InternalErrorException + public void close() throws InternalErrorException { _log.info("Closing memory message store"); _stagedMessages.clear(); _queueMap.clear(); } - public void createQueue(StorableQueue queue) - throws - InternalErrorException, - QueueAlreadyExistsException + public void createQueue(StorableQueue queue) throws InternalErrorException, QueueAlreadyExistsException { if (_queueMap.containsKey(queue)) { @@ -125,10 +115,7 @@ public class MemoryMessageStore implements MessageStore _queueMap.put(queue, new LinkedList()); } - public void destroyQueue(StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException + public void destroyQueue(StorableQueue queue) throws InternalErrorException, QueueDoesntExistException { if (!_queueMap.containsKey(queue)) { @@ -138,65 +125,56 @@ public class MemoryMessageStore implements MessageStore _queueMap.remove(queue); } - public void stage(StorableMessage m) - throws - InternalErrorException, - MessageAlreadyStagedException + public void stage(StorableMessage m) throws InternalErrorException, MessageAlreadyStagedException { if (_stagedMessages.containsKey(m)) { throw new MessageAlreadyStagedException("message " + m + " already staged"); } + _stagedMessages.put(m, new ByteArrayOutputStream()); m.staged(); } public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException + throws InternalErrorException, MessageDoesntExistException { if (!_stagedMessages.containsKey(m)) { throw new MessageDoesntExistException("message " + m + " has not been staged"); } + _stagedMessages.get(m).write(data, offset, size); } public byte[] loadContent(StorableMessage m, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException + throws InternalErrorException, MessageDoesntExistException { if (!_stagedMessages.containsKey(m)) { throw new MessageDoesntExistException("message " + m + " has not been staged"); } + byte[] result = new byte[size]; ByteBuffer buf = ByteBuffer.allocate(size); buf.put(_stagedMessages.get(m).toByteArray(), offset, size); buf.get(result); + return result; } - public void destroy(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException + public void destroy(StorableMessage m) throws InternalErrorException, MessageDoesntExistException { if (!_stagedMessages.containsKey(m)) { throw new MessageDoesntExistException("message " + m + " has not been staged"); } + _stagedMessages.remove(m); } public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, + throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException, MessageDoesntExistException { if (xid != null) @@ -204,46 +182,49 @@ public class MemoryMessageStore implements MessageStore // this is a tx operation TransactionRecord enqueueRecord = new MemoryEnqueueRecord(m, queue); _txm.getTransaction(xid).addRecord(enqueueRecord); - } else + } + else { if (!_stagedMessages.containsKey(m)) { try { stage(m); - } catch (MessageAlreadyStagedException e) + } + catch (MessageAlreadyStagedException e) { - throw new InternalErrorException(e); + throw new InternalErrorException(e.getMessage(), e); } + appendContent(m, m.getData(), 0, m.getPayloadSize()); } + if (!_queueMap.containsKey(queue)) { throw new QueueDoesntExistException("queue " + queue + " dos not exist"); } + _queueMap.get(queue).add(m); m.enqueue(queue); } } public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException + throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException { if (xid != null) { // this is a tx operation TransactionRecord dequeueRecord = new MemoryDequeueRecord(m, queue); _txm.getTransaction(xid).addRecord(dequeueRecord); - } else + } + else { if (!_queueMap.containsKey(queue)) { throw new QueueDoesntExistException("queue " + queue + " dos not exist"); } + m.dequeue(queue); _queueMap.get(queue).remove(m); if (!m.isEnqueued()) @@ -254,16 +235,12 @@ public class MemoryMessageStore implements MessageStore } } - public Collection getAllQueues() - throws - InternalErrorException + public Collection getAllQueues() throws InternalErrorException { return _queueMap.keySet(); } - public Collection getAllMessages(StorableQueue queue) - throws - InternalErrorException + public Collection getAllMessages(StorableQueue queue) throws InternalErrorException { return _queueMap.get(queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java index cdf209fb12..6770d8a8dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -17,14 +17,14 @@ */ package org.apache.qpid.server.txn; -import org.apache.qpid.server.messageStore.MessageStore; +import javax.transaction.xa.Xid; + +import org.apache.qpid.AMQException; import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.AMQException; - -import javax.transaction.xa.Xid; +import org.apache.qpid.server.store.StoreContext; /** * Created by Arnaud Simon @@ -47,33 +47,26 @@ public class EnqueueRecord implements TransactionRecord } public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, + throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException, MessageDoesntExistException { try { _queue.process(_storeContext, _msg, _first); - } catch (AMQException e) + } + catch (AMQException e) { - throw new InternalErrorException(e); + throw new InternalErrorException(e.getMessage(), e); } } - public void rollback(MessageStore store) - throws - InternalErrorException + public void rollback(MessageStore store) throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // To change body of implemented methods use File | Settings | File Templates. } - public void prepare(MessageStore store) - throws - InternalErrorException + public void prepare(MessageStore store) throws InternalErrorException { - //To change body of implemented methods use File | Settings | File Templates. + // To change body of implemented methods use File | Settings | File Templates. } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java index e740ff9c30..a361f85e2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -17,14 +17,17 @@ */ package org.apache.qpid.server.txn; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.messageStore.MessageStore; +import java.util.HashMap; +import java.util.Set; + +import javax.transaction.xa.Xid; + import org.apache.commons.configuration.Configuration; + import org.apache.log4j.Logger; -import javax.transaction.xa.Xid; -import java.util.Set; -import java.util.HashMap; +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.messageStore.MessageStore; /** * Created by Arnaud Simon @@ -33,17 +36,17 @@ import java.util.HashMap; */ public class MemoryTransactionManager implements TransactionManager { - //======================================================================== + // ======================================================================== // Static Constants - //======================================================================== + // ======================================================================== // The logger for this class private static final Logger _log = Logger.getLogger(MemoryTransactionManager.class); private static final String ENVIRONMENT_TX_TIMEOUT = "environment-tx-timeout"; - //======================================================================== + // ======================================================================== // Instance Fields - //======================================================================== + // ======================================================================== // The underlying BDB message store private MessageStore _messagStore; // A map of XID/BDBtx @@ -52,30 +55,29 @@ public class MemoryTransactionManager implements TransactionManager private HashMap _indoubtXidMap; // A default tx timeout in sec - private int _defaultTimeout; // set to 10s if not specified in the config + private int _defaultTimeout; // set to 10s if not specified in the config - //======================================================================== + // ======================================================================== // Interface TransactionManager - //======================================================================== + // ======================================================================== public void configure(MessageStore messageStroe, String base, Configuration config) { _messagStore = messageStroe; if (config != null) { _defaultTimeout = config.getInt(base + "." + ENVIRONMENT_TX_TIMEOUT, 10); - } else + } + else { _defaultTimeout = 10; } + _log.info("Using transaction timeout of " + _defaultTimeout + " s"); _xidMap = new HashMap(); _indoubtXidMap = new HashMap(); } - public XAFlag begin(Xid xid) - throws - InternalErrorException, - InvalidXidException + public XAFlag begin(Xid xid) throws InternalErrorException, InvalidXidException { synchronized (xid) { @@ -83,22 +85,21 @@ public class MemoryTransactionManager implements TransactionManager { throw new InvalidXidException(xid, "null xid"); } + if (_xidMap.containsKey(xid)) { throw new InvalidXidException(xid, "Xid already exist"); } + MemoryTransaction tx = new MemoryTransaction(); tx.setTimeout(_defaultTimeout); _xidMap.put(xid, tx); + return XAFlag.ok; } } - public XAFlag prepare(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException + public XAFlag prepare(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException { synchronized (xid) { @@ -110,32 +111,32 @@ public class MemoryTransactionManager implements TransactionManager result = XAFlag.rbtimeout; // rollback this tx branch rollback(xid); - } else + } + else { if (tx.isPrepared()) { - throw new CommandInvalidException("TransactionImpl is already prepared"); + throw new CommandInvalidException("TransactionImpl is already prepared", null); } + if (tx.getrecords().size() == 0) { // the tx was read only (no work has been done) _xidMap.remove(xid); result = XAFlag.rdonly; - } else + } + else { // we need to persist the tx records tx.prepare(); } } + return result; } } - public XAFlag rollback(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException + public XAFlag rollback(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException { synchronized (xid) { @@ -145,28 +146,28 @@ public class MemoryTransactionManager implements TransactionManager if (tx.isHeurRollback()) { flag = XAFlag.heurrb; - } else + } + else { for (TransactionRecord record : tx.getrecords()) { record.rollback(_messagStore); } + _xidMap.remove(xid); } + if (tx.hasExpired()) { flag = XAFlag.rbtimeout; } + return flag; } } public XAFlag commit(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException, - NotPreparedException + throws InternalErrorException, CommandInvalidException, UnknownXidException, NotPreparedException { synchronized (xid) { @@ -176,43 +177,46 @@ public class MemoryTransactionManager implements TransactionManager if (tx.isHeurRollback()) { flag = XAFlag.heurrb; - } else if (tx.hasExpired()) + } + else if (tx.hasExpired()) { flag = XAFlag.rbtimeout; // rollback this tx branch rollback(xid); - } else + } + else { if (!tx.isPrepared()) { throw new NotPreparedException("TransactionImpl is not prepared"); } + for (TransactionRecord record : tx.getrecords()) { try { record.commit(_messagStore, xid); - } catch (InvalidXidException e) + } + catch (InvalidXidException e) { - throw new UnknownXidException(xid, e); - } catch (Exception e) + throw new UnknownXidException(xid, e.getMessage(), e); + } + catch (Exception e) { // this should not happen as the queue and the message must exist _log.error("Error when committing distributed transaction heurmix mode returned: " + xid); flag = XAFlag.heurmix; } } + _xidMap.remove(xid); } + return flag; } } - public XAFlag commit_one_phase(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException + public XAFlag commit_one_phase(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException { synchronized (xid) { @@ -221,12 +225,14 @@ public class MemoryTransactionManager implements TransactionManager if (tx.isHeurRollback()) { flag = XAFlag.heurrb; - } else if (tx.hasExpired()) + } + else if (tx.hasExpired()) { flag = XAFlag.rbtimeout; // rollback this tx branch rollback(xid); - } else + } + else { // we need to prepare the tx tx.prepare(); @@ -237,31 +243,30 @@ public class MemoryTransactionManager implements TransactionManager try { record.commit(_messagStore, xid); - } catch (InvalidXidException e) + } + catch (InvalidXidException e) { - throw new UnknownXidException(xid, e); - } catch (Exception e) + throw new UnknownXidException(xid, e.getMessage(), e); + } + catch (Exception e) { // this should not happen as the queue and the message must exist _log.error("Error when committing transaction heurmix mode returned: " + xid); flag = XAFlag.heurmix; } } - } + } finally { _xidMap.remove(xid); } } + return flag; } } - public void forget(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException + public void forget(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException { synchronized (xid) { @@ -269,36 +274,25 @@ public class MemoryTransactionManager implements TransactionManager } } - public void setTimeout(Xid xid, long timeout) - throws - InternalErrorException, - UnknownXidException + public void setTimeout(Xid xid, long timeout) throws InternalErrorException, UnknownXidException { Transaction tx = getTransaction(xid); tx.setTimeout(timeout); } - public long getTimeout(Xid xid) - throws - InternalErrorException, - UnknownXidException + public long getTimeout(Xid xid) throws InternalErrorException, UnknownXidException { Transaction tx = getTransaction(xid); + return tx.getTimeout(); } - public Set recover(boolean startscan, boolean endscan) - throws - InternalErrorException, - CommandInvalidException + public Set recover(boolean startscan, boolean endscan) throws InternalErrorException, CommandInvalidException { return _indoubtXidMap.keySet(); } - public void HeuristicOutcome(Xid xid) - throws - UnknownXidException, - InternalErrorException + public void HeuristicOutcome(Xid xid) throws UnknownXidException, InternalErrorException { synchronized (xid) { @@ -310,6 +304,7 @@ public class MemoryTransactionManager implements TransactionManager { record.rollback(_messagStore); } + tx.heurRollback(); } // add this branch in the list of indoubt tx @@ -317,15 +312,14 @@ public class MemoryTransactionManager implements TransactionManager } } - public Transaction getTransaction(Xid xid) - throws - UnknownXidException + public Transaction getTransaction(Xid xid) throws UnknownXidException { Transaction tx = _xidMap.get(xid); if (tx == null) { - throw new UnknownXidException(xid); + throw new UnknownXidException(xid, "", null); } + return tx; } } -- cgit v1.2.1 From 6526e1eb68ec1ec85f59d39d113491aa4294cb3b Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Tue, 22 May 2007 08:49:53 +0000 Subject: Patch from Arnaud Simon (asimon@redhat.com) in connection with QPID-496. This adds a JDBC based message store implementation. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540493 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 2 +- .../apache/qpid/server/messageStore/JDBCStore.java | 1759 ++++++++++++++++++++ .../server/messageStore/MemoryMessageStore.java | 21 + .../qpid/server/messageStore/MessageStore.java | 570 ++++--- .../org/apache/qpid/server/messageStore/Pool.java | 135 ++ .../qpid/server/queue/StorableMessageHandle.java | 87 +- .../apache/qpid/server/txn/JDBCAbstractRecord.java | 93 ++ .../apache/qpid/server/txn/JDBCDequeueRecord.java | 85 + .../apache/qpid/server/txn/JDBCEnqueueRecord.java | 106 ++ .../apache/qpid/server/txn/JDBCTransaction.java | 196 +++ .../qpid/server/txn/JDBCTransactionManager.java | 554 ++++++ .../qpid/server/txn/NonTransactionalContext.java | 5 +- .../qpid/server/util/NullApplicationRegistry.java | 7 +- 13 files changed, 3344 insertions(+), 276 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 5de59f47a3..43a04dbfa1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -473,7 +473,7 @@ public class AMQChannel unacked.message.setRedelivered(true); // Deliver Message - deliveryContext.deliver(unacked.message, unacked.queue, false); + deliveryContext.deliver(unacked.message, unacked.queue, true); // Should we allow access To the DM to directy deliver the message? // As we don't need to check for Consumers or worry about incrementing the message count? diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java new file mode 100644 index 0000000000..44de0d3d98 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java @@ -0,0 +1,1759 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.txn.*; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +import javax.transaction.xa.Xid; +import java.util.Collection; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.sql.*; + +/** + * Created by Arnaud Simon + * Date: 15-May-2007 + * Time: 09:59:12 + */ +public class JDBCStore implements MessageStore +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCStore.class); + // the database connection pool + public static ConnectionPool _connectionPool = null; + // the prepared statements + //==== IMPORTANT: remember to update if we add more prepared statements! + private static final int CREATE_EXCHANGE = 0; + private static final int DELETE_EXCHANGE = 1; + private static final int BIND_QUEUE = 2; + private static final int UNBIND_QUEUE = 3; + private static final int CREATE_QUEUE = 4; + private static final int DELETE_QUEUE = 5; + private static final int STAGE_MESSAGE = 6; + private static final int UPDATE_MESSAGE_PAYLOAD = 7; + private static final int SELECT_MESSAGE_PAYLOAD = 8; + private static final int DELETE_MESSAGE = 9; + private static final int ENQUEUE = 10; + private static final int DEQUEUE = 11; + private static final int GET_ALL_QUEUES = 12; + private static final int GET_ALL_MESSAGES = 13; + private static final int SAVE_RECORD = 14; + private static final int SAVE_XID = 15; + private static final int DELETE_RECORD = 16; + private static final int DELETE_XID = 17; + private static final int UPDATE_QMR = 18; + private static final int GET_CONTENT_HEADER = 19; + private static final int GET_MESSAGE_INFO = 20; + //==== size: + private static final int STATEMENT_SIZE = 21; + //======================================================================== + // field properties + //======================================================================== + //The default URL + protected String _connectionURL = "jdbc:derby:derbyDB;create=true"; + // The default driver + private String _driver = "org.apache.derby.jdbc.EmbeddedDriver"; + // The pool max size + private int _maxSize = 40; + // The tables + // the table containing the messages + private String _tableNameMessage = "MessageTable"; + private String _tableNameQueue = "QueueTable"; + private String _tableNameQueueMessageRelation = "QeueMessageRelation"; + private String _tableNameExchange = "Exchange"; + private String _tableNameExchangeQueueRelation = "ExchangeQueueRelation"; + private String _tableNameTransaction = "TransactionTable"; + private String _tableNameRecord = "RecordTable"; + + // The transaction maanger + private JDBCTransactionManager _tm; + // the message ID + private long _messageID = 0; + // the virtual host + private VirtualHost _virtualHost; + // indicate whether this store is recovering + private boolean _recovering = false; + // the recovered queues + private HashMap _queueMap; + + //======================================================================== + // Interface MessageStore + //======================================================================== + public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) + throws + InternalErrorException, + IllegalArgumentException + { + _log.info("Configuring Derby message store"); + // the virtual host + _virtualHost = virtualHost; + // Specify that the tables must be dropped. + // If true then this means that recovery is not possible. + boolean dropTables = true; + if (config != null) + { + dropTables = config.getBoolean(base + "dropTables", false); + _driver = config.getString(base + "driver", _driver); + _connectionURL = config.getString(base + "connectionURL", _connectionURL); + _maxSize = config.getInt(base + "connectionPoolSize", 20); + } + if (dropTables) + { + _log.info("Dropping table of Derby message store"); + } + if (!setupStore(dropTables)) + { + _log.error("Error configuration of Derby store failed"); + throw new InternalErrorException("Error configuration of Derby store failed"); + } + // recovery + _recovering = true; + _queueMap = recover(); //==> recover the queues and the messages + // recreate the excahnges and bind the queues + recoverExchanges(_queueMap); + _recovering = false; + _tm = (JDBCTransactionManager) tm; + _tm.configure(this, "txn", config); + _queueMap.clear(); + _queueMap = null; + } + + public void close() + throws + InternalErrorException + { + // nothing has to be done + } + + public void createExchange(Exchange exchange) + throws + InternalErrorException + { + if (!_recovering) + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[CREATE_EXCHANGE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameExchange + + " (Name,Type) VALUES (?,?)"); + connection.getStatements()[CREATE_EXCHANGE] = pstmt; + } + pstmt.setString(1, exchange.getName().asString()); + pstmt.setString(2, exchange.getType().asString()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot create Exchange: " + exchange); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot create Exchange: " + exchange); + } + } + } + } + } + + public void removeExchange(Exchange exchange) + throws + InternalErrorException + { + if (!_recovering) + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[DELETE_EXCHANGE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameExchange + + " WHERE Name = ?"); + connection.getStatements()[DELETE_EXCHANGE] = pstmt; + } + pstmt.setString(1, exchange.getName().asString()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot remove Exchange: " + exchange); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot remove Exchange: " + exchange); + } + } + } + } + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) + throws + InternalErrorException + { + if (!_recovering) + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[BIND_QUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameExchangeQueueRelation + + " (QueueID,Name,RoutingKey,fieldTable) VALUES (?,?,?,?)"); + connection.getStatements()[BIND_QUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.setString(2, exchange.getName().asString()); + pstmt.setString(3, routingKey.asString()); + if (args != null) + { + pstmt.setBytes(4, args.getDataAsBytes()); + } else + { + pstmt.setBytes(4, null); + } + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot create Exchange: " + exchange); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot create Exchange: " + exchange); + } + } + } + } + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) + throws + InternalErrorException + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[UNBIND_QUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameExchangeQueueRelation + + " WHERE QueueID = ? AND NAME = ? AND RoutingKey = ?"); + connection.getStatements()[UNBIND_QUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.setString(2, exchange.getName().asString()); + pstmt.setString(3, routingKey.asString()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot remove Exchange: " + exchange); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot remove Exchange: " + exchange); + } + } + } + } + + public void createQueue(StorableQueue queue) + throws + InternalErrorException, + QueueAlreadyExistsException + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[CREATE_QUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameQueue + + " (QueueID,Name,Owner) VALUES (?,?,?)"); + connection.getStatements()[CREATE_QUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.setString(2, queue.getName().asString()); + if (queue.getOwner() != null) + { + pstmt.setString(3, queue.getOwner().asString()); + } else + { + pstmt.setString(3, null); + } + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot create Queue: " + queue); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot create Queue: " + queue); + } + } + } + } + + public void destroyQueue(StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[DELETE_QUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameQueue + + " WHERE QueueID = ?"); + connection.getStatements()[DELETE_QUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot remove Queue: " + queue); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot remove Queue: " + queue); + } + } + } + } + + public void stage(StorableMessage m) + throws + InternalErrorException, + MessageAlreadyStagedException + { + if (m.isStaged() || m.isEnqueued()) + { + _log.error("Message with Id " + m.getMessageId() + " is already staged"); + throw new MessageAlreadyStagedException("Message eith Id " + m.getMessageId() + " is already staged"); + } + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + stage(connection, m); + } catch (Exception e) + { + throw new InternalErrorException("Cannot stage Message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot stage Message: " + m); + } + } + } + } + + public void appendContent(StorableMessage m, byte[] data, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException + { + // The message must have been staged + if (!m.isStaged()) + { + _log.error("Cannot append content of message Id " + + m.getMessageId() + " as it has not been staged"); + throw new MessageDoesntExistException("Cannot append content of message Id " + + m.getMessageId() + " as it has not been staged"); + } + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + appendContent(connection, m, data, offset, size); + } catch (Exception e) + { + throw new InternalErrorException("Cannot stage Message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot stage Message: " + m); + } + } + } + } + + public byte[] loadContent(StorableMessage m, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException + { + MyConnection connection = null; + try + { + byte[] result; + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[SELECT_MESSAGE_PAYLOAD]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT Payload FROM " + _tableNameMessage + + " WHERE MessageID = ? "); + connection.getStatements()[SELECT_MESSAGE_PAYLOAD] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + ResultSet rs = pstmt.executeQuery(); + if (!rs.next()) + { + throw new MessageDoesntExistException("Cannot load content of message Id " + + m.getMessageId() + " as it has not been found"); + } + Blob myBlob = rs.getBlob(1); + + if (myBlob.length() > 0) + { + if (size == 0) + { + result = myBlob.getBytes(offset, (int) myBlob.length()); + } else + { + result = myBlob.getBytes(offset, size); + } + } else + { + throw new MessageDoesntExistException("Cannot load content of message Id " + + m.getMessageId() + " as it has not been found"); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot load Message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot load Message: " + m); + } + } + } + } + + public void destroy(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + destroy(connection, m); + } catch (Exception e) + { + throw new InternalErrorException("Cannot destroy message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot destroy message: " + m); + } + } + } + } + + public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + MyConnection connection = null; + // Get the current tx + JDBCTransaction tx = getTx(xid); + // If this operation is transacted then we need to add a record + if (tx != null && !tx.isPrepared()) + { + // add an enqueue record + tx.addRecord(new JDBCEnqueueRecord(m, queue)); + } else + { + try + { + if (tx != null) + { + connection = tx.getConnection(); + } else + { + connection = (MyConnection) _connectionPool.acquireInstance(); + } + if (!m.isStaged() && !m.isEnqueued()) + { + //This is the first time this message is enqueued and it has not been staged. + stage(connection, m); + appendContent(connection, m, m.getData(), 0, m.getData().length); + } + PreparedStatement pstmt = connection.getStatements()[ENQUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameQueueMessageRelation + + " (QueueID,MessageID,Prepared) VALUES (?,?,0)"); + connection.getStatements()[ENQUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.setLong(2, m.getMessageId()); + pstmt.executeUpdate(); + m.enqueue(queue); + queue.enqueue(m); + } catch (Exception e) + { + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + } finally + { + if (tx == null && connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + } + } + } + } + } + + public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException + { + MyConnection connection = null; + // Get the current tx + JDBCTransaction tx = getTx(xid); + // If this operation is transacted then we need to add a record + if (tx != null && !tx.isPrepared()) + { + // add an dequeue record + tx.addRecord(new JDBCDequeueRecord(m, queue)); + } else + { + try + { + if (tx != null) + { + connection = tx.getConnection(); + } else + { + connection = (MyConnection) _connectionPool.acquireInstance(); + } + PreparedStatement pstmt = connection.getStatements()[DEQUEUE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameQueueMessageRelation + + " WHERE QueueID = ? AND MessageID = ?"); + connection.getStatements()[DEQUEUE] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + pstmt.setLong(2, m.getMessageId()); + pstmt.executeUpdate(); + m.dequeue(queue); + if (!m.isEnqueued()) + { + // delete this message from persistence store + destroy(connection, m); + } + queue.dequeue(m); + } catch (Exception e) + { + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + } finally + { + if (tx == null && connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + } + } + } + } + } + + public Collection getAllQueues() + throws + InternalErrorException + { + MyConnection connection = null; + List result = new ArrayList(); + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[GET_ALL_QUEUES]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT * FROM " + _tableNameQueue); + connection.getStatements()[GET_ALL_QUEUES] = pstmt; + } + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + //the queue owner may be null + AMQShortString queueOwner = null; + if (rs.getString(3) != null) + { + queueOwner = new AMQShortString(rs.getString(3)); + } + result.add(new AMQQueue(new AMQShortString(rs.getString(2)), true, queueOwner, + false, _virtualHost)); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot get all queues"); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot get all queues"); + } + } + } + } + + public Collection getAllMessages(StorableQueue queue) + throws + InternalErrorException + { + MyConnection connection = null; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + return getAllMessages(connection, queue); + } catch (Exception e) + { + throw new InternalErrorException("Cannot get all queues"); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot get all queues"); + } + } + } + } + + public HashMap getAllInddoubt() + throws + InternalErrorException + { + MyConnection connection = null; + HashMap result = new HashMap(); + try + { + TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); + MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); + // re-create all the tx + connection = (MyConnection) _connectionPool.acquireInstance(); + Statement stmt = connection.getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameTransaction); + JDBCTransaction foundTx; + Xid foundXid; + long foundXIDID; + while (rs.next()) + { + // set the XID_ID + foundXIDID = rs.getLong(1); + if (foundXIDID > JDBCTransaction._xidId) + { + JDBCTransaction._xidId = foundXIDID; + } + foundTx = new JDBCTransaction(); + foundXid = new XidImpl(rs.getBlob(3).getBytes(1, (int) rs.getBlob(3).length()), + rs.getInt(2), rs.getBlob(4).getBytes(1, (int) rs.getBlob(4).length())); + // get all the records + Statement stmtr = connection.getConnection().createStatement(); + ResultSet rsr = stmtr.executeQuery("SELECT * FROM " + _tableNameRecord + + " WHERE XID_ID = " + rs.getLong(1)); + int foundType; + AMQQueue foundQueue; + StorableMessage foundMessage; + TransactionRecord foundRecord; + while (rsr.next()) + { + // those messages were not recovered before so they need to be recreated + foundType = rsr.getInt(2); + foundQueue = _queueMap.get(new Integer(rsr.getInt(4))); + foundMessage = new AMQMessage(rs.getLong(3), this, messageHandleFactory, txnContext); + if (foundType == JDBCAbstractRecord.TYPE_DEQUEUE) + { + foundRecord = new JDBCDequeueRecord(foundMessage, foundQueue); + } else + { + foundRecord = new JDBCEnqueueRecord(foundMessage, foundQueue); + } + foundTx.addRecord(foundRecord); + } + rsr.close(); + // add this tx to the map + result.put(foundXid, foundTx); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot recover: ", e); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot recover: ", e); + } + } + } + } + + + public long getNewMessageId() + { + return _messageID++; + } + + //======================================================================== + // Public methods + //======================================================================== + + public MyConnection getConnection() + throws + Exception + { + return (MyConnection) _connectionPool.acquireInstance(); + } + + public void commitConnection(MyConnection connection) + throws + InternalErrorException + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot commit connection ="); + } + } + + public void rollbackConnection(MyConnection connection) + throws + InternalErrorException + { + try + { + connection.getConnection().rollback(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to rollback this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot rollback connection"); + } + } + + public void appendContent(MyConnection connection, StorableMessage m, byte[] data, int offset, int size) + throws + SQLException, + MessageDoesntExistException + { + PreparedStatement pstmt = connection.getStatements()[SELECT_MESSAGE_PAYLOAD]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT Payload FROM " + _tableNameMessage + + " WHERE MessageID = ? "); + connection.getStatements()[SELECT_MESSAGE_PAYLOAD] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + ResultSet rs = pstmt.executeQuery(); + if (!rs.next()) + { + throw new MessageDoesntExistException("Cannot append content of message Id " + + m.getMessageId() + " as it has not been found"); + } + Blob myBlob = rs.getBlob(1); + byte[] oldPayload; + if (myBlob != null && myBlob.length() > 0) + { + oldPayload = myBlob.getBytes(1, (int) myBlob.length()); + } else + { + oldPayload = new byte[0]; + } + rs.close(); + byte[] newPayload = new byte[oldPayload.length + size]; + ByteBuffer buffer = ByteBuffer.wrap(newPayload); + buffer.put(oldPayload); + buffer.put(data, offset, size); + PreparedStatement pstmtUpdate = connection.getStatements()[UPDATE_MESSAGE_PAYLOAD]; + if (pstmtUpdate == null) + { + pstmtUpdate = connection.getConnection().prepareStatement("UPDATE " + _tableNameMessage + + " SET Payload = ? WHERE MessageID = ?"); + connection.getStatements()[UPDATE_MESSAGE_PAYLOAD] = pstmtUpdate; + } + pstmtUpdate.setBytes(1, newPayload); + pstmtUpdate.setLong(2, m.getMessageId()); + pstmtUpdate.executeUpdate(); + } + + public void stage(MyConnection connection, StorableMessage m) + throws + Exception + { + PreparedStatement pstmt = connection.getStatements()[STAGE_MESSAGE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameMessage + + " (MessageID,Header,ExchangeName,RoutingKey,Mandatory,Is_Immediate) VALUES (?,?,?,?,?,?)"); + connection.getStatements()[STAGE_MESSAGE] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + pstmt.setBytes(2, m.getHeaderBody()); + pstmt.setString(3, ((AMQMessage) m).getMessagePublishInfo().getExchange().asString()); + pstmt.setString(4, ((AMQMessage) m).getMessagePublishInfo().getRoutingKey().asString()); + pstmt.setBoolean(5, ((AMQMessage) m).getMessagePublishInfo().isMandatory()); + pstmt.setBoolean(6, ((AMQMessage) m).getMessagePublishInfo().isImmediate()); + pstmt.executeUpdate(); + m.staged(); + } + + public void saveRecord(MyConnection connection, JDBCTransaction tx, JDBCAbstractRecord record) + throws + InternalErrorException + { + try + { + PreparedStatement pstmt = connection.getStatements()[SAVE_RECORD]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameRecord + + " (XID_ID,Type,MessageID,QueueID) VALUES (?,?,?,?)"); + connection.getStatements()[SAVE_RECORD] = pstmt; + } + pstmt.setLong(1, tx.getXidID()); + pstmt.setInt(2, record.getType()); + pstmt.setLong(3, record.getMessageID()); + pstmt.setLong(4, record.getQueueID()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot save record: " + record); + } + } + + public void saveXID(MyConnection connection, JDBCTransaction tx, Xid xid) + throws + InternalErrorException + { + try + { + PreparedStatement pstmt = connection.getStatements()[SAVE_XID]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameTransaction + + " (XID_ID,FormatId, BranchQualifier,GlobalTransactionId) VALUES (?,?,?,?)"); + connection.getStatements()[SAVE_XID] = pstmt; + } + pstmt.setLong(1, tx.getXidID()); + pstmt.setInt(2, xid.getFormatId()); + pstmt.setBytes(3, xid.getBranchQualifier()); + pstmt.setBytes(4, xid.getGlobalTransactionId()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot save xid: " + xid); + } + } + + public void deleteRecords(MyConnection connection, JDBCTransaction tx) + throws + InternalErrorException + { + try + { + PreparedStatement pstmt = connection.getStatements()[DELETE_RECORD]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameRecord + + " WHERE XID_ID = ?"); + connection.getStatements()[DELETE_RECORD] = pstmt; + } + pstmt.setLong(1, tx.getXidID()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot delete record: " + tx.getXidID()); + } + } + + public void deleteXID(MyConnection connection, JDBCTransaction tx) + throws + InternalErrorException + { + try + { + PreparedStatement pstmt = connection.getStatements()[DELETE_XID]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameTransaction + + " WHERE XID_ID = ?"); + connection.getStatements()[DELETE_XID] = pstmt; + } + pstmt.setLong(1, tx.getXidID()); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot delete xid: " + tx.getXidID()); + } + } + + public void prepareDequeu(Xid xid, StorableMessage m, StorableQueue queue) + throws + UnknownXidException, + InternalErrorException + { + JDBCTransaction tx = getTx(xid); + if (tx == null) + { + throw new UnknownXidException(xid); + } + updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 1); + + } + + public void rollbackDequeu(Xid xid, StorableMessage m, StorableQueue queue) + throws + UnknownXidException, + InternalErrorException + { + JDBCTransaction tx = getTx(xid); + if (tx == null) + { + throw new UnknownXidException(xid); + } + updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 0); + } + + //======================================================================== + // Private methods + //======================================================================== + + + private void updateQueueMessageRelation(MyConnection connection, + int queueID, long messageId, int prepared) + throws + InternalErrorException + { + try + { + PreparedStatement pstmt = connection.getStatements()[UPDATE_QMR]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("UPDATE " + _tableNameQueueMessageRelation + + " SET Prepared = ? WHERE MessageID = ? AND QueueID = ?"); + connection.getStatements()[UPDATE_QMR] = pstmt; + } + pstmt.setInt(1, prepared); + pstmt.setLong(2, messageId); + pstmt.setInt(3, queueID); + pstmt.executeUpdate(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot update QMR", e); + } + + } + + public MessagePublishInfo getMessagePublishInfo(StorableMessage m) + throws + InternalErrorException + { + MyConnection connection = null; + MessagePublishInfo result; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[GET_MESSAGE_INFO]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT ExchangeName, RoutingKey," + + " Mandatory, Is_Immediate from " + _tableNameMessage + + " WHERE MessageID = ?"); + connection.getStatements()[GET_MESSAGE_INFO] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + final AMQShortString exchange = new AMQShortString(rs.getString(1)); + final AMQShortString routingKey = new AMQShortString(rs.getString(2)); + final boolean mandatory = rs.getBoolean(3); + final boolean immediate = rs.getBoolean(4); + result = new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public boolean isImmediate() + { + return immediate; + } + + public boolean isMandatory() + { + return mandatory; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + }; + } else + { + throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); + } + } + } + } + + public ContentHeaderBody getContentHeaderBody(StorableMessage m) + throws + InternalErrorException + { + MyConnection connection = null; + ContentHeaderBody result; + try + { + connection = (MyConnection) _connectionPool.acquireInstance(); + PreparedStatement pstmt = connection.getStatements()[GET_CONTENT_HEADER]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT Header from " + _tableNameMessage + + " WHERE MessageID = ?"); + connection.getStatements()[GET_CONTENT_HEADER] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + result = new ContentHeaderBody(ByteBuffer.wrap(rs.getBlob(1).getBytes(1, (int) rs.getBlob(1).length())), 0); + } else + { + throw new InternalErrorException("Cannot get Content Header of message: " + m); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot get Content Header of message: " + m); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot get Content Header of message: " + m); + } + } + } + } + + private List getAllMessages(MyConnection connection, StorableQueue queue) + throws + SQLException, + AMQException + { + List result = new ArrayList(); + TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); + MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); + PreparedStatement pstmt = connection.getStatements()[GET_ALL_MESSAGES]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("SELECT " + _tableNameMessage + ".MessageID, Header FROM " + + _tableNameMessage + + " INNER JOIN " + + _tableNameQueueMessageRelation + + " ON " + + _tableNameMessage + ".MessageID = " + _tableNameQueueMessageRelation + ".MessageID" + + " WHERE " + + _tableNameQueueMessageRelation + ".QueueID = ?" + + " AND " + + _tableNameQueueMessageRelation + ".Prepared = 0"); + connection.getStatements()[GET_ALL_MESSAGES] = pstmt; + } + pstmt.setInt(1, queue.getQueueID()); + ResultSet rs = pstmt.executeQuery(); + AMQMessage foundMessage; + // ContentHeaderBody hb; + while (rs.next()) + { + foundMessage = new AMQMessage(rs.getLong(1), this, messageHandleFactory, txnContext); + result.add(foundMessage); + } + rs.close(); + return result; + } + + private HashMap recover() + throws + InternalErrorException + { + MyConnection connection = null; + HashMap result = new HashMap(); + try + { + // re-create all the queues + connection = (MyConnection) _connectionPool.acquireInstance(); + Statement stmt = connection.getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameQueue); + AMQQueue foundQueue; + List foundMessages; + StoreContext context = new StoreContext(); + while (rs.next()) + { + AMQShortString owner = null; + if (rs.getString(3) != null) + { + owner = new AMQShortString(rs.getString(3)); + } + foundQueue = new AMQQueue(new AMQShortString(rs.getString(2)), + true, owner, false, _virtualHost); + // get all the Messages of that queue + foundMessages = getAllMessages(connection, foundQueue); + // enqueue those messages + if (_log.isDebugEnabled()) + { + _log.debug("Recovering " + foundMessages.size() + " messages for queue " + foundQueue.getName()); + } + for (StorableMessage foundMessage : foundMessages) + { + foundMessage.staged(); + foundMessage.enqueue(foundQueue); + foundQueue.enqueue(foundMessage); + foundQueue.process(context, (AMQMessage) foundMessage, false); + } + // add the queue in the result map + result.put(foundQueue.getQueueID(), foundQueue); + // add it in the registry + _virtualHost.getQueueRegistry().registerQueue(foundQueue); + } + rs.close(); + return result; + } catch (Exception e) + { + throw new InternalErrorException("Cannot recover: ", e); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot recover: ", e); + } + } + } + } + + private void recoverExchanges(HashMap queueMap) + throws + InternalErrorException + { + MyConnection connection = null; + try + { + // re-create all the exchanges + connection = (MyConnection) _connectionPool.acquireInstance(); + Statement stmt = connection.getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameExchange); + Exchange foundExchange; + AMQQueue foundQueue; + while (rs.next()) + { + foundExchange = _virtualHost.getExchangeFactory().createExchange( + new AMQShortString(rs.getString(1)), new AMQShortString(rs.getString(2)), true, false, 0); + // get all the bindings + Statement stmtb = connection.getConnection().createStatement(); + ResultSet rsb = stmtb.executeQuery("SELECT * FROM " + _tableNameExchangeQueueRelation + + " WHERE Name = '" + rs.getString(1) + "'"); + while (rsb.next()) + { + foundQueue = queueMap.get(new Integer(rsb.getInt(1))); + if (foundQueue != null) + { + // the field table + FieldTable ft = null; + if (rsb.getBlob(4) != null) + { + long length = rsb.getBlob(4).length(); + ByteBuffer buffer = ByteBuffer.wrap(rsb.getBlob(4).getBytes(1, (int) length)); + ft = new FieldTable(buffer, length); + } + foundQueue.bind(new AMQShortString(rsb.getString(3)), ft, foundExchange); + } + } + rsb.close(); + // register this exchange + _virtualHost.getExchangeRegistry().registerExchange(foundExchange); + } + rs.close(); + } catch (Exception e) + { + throw new InternalErrorException("Cannot recover: ", e); + } finally + { + if (connection != null) + { + try + { + connection.getConnection().commit(); + _connectionPool.releaseInstance(connection); + } catch (SQLException e) + { + // we did not manage to commit this connection + // it is better to release it + _connectionPool.releaseDeadInstance(); + throw new InternalErrorException("Cannot recover: ", e); + } + } + } + } + + private void destroy(MyConnection connection, StorableMessage m) + throws + SQLException + { + PreparedStatement pstmt = connection.getStatements()[DELETE_MESSAGE]; + if (pstmt == null) + { + pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameMessage + + " WHERE MessageID = ?"); + connection.getStatements()[DELETE_MESSAGE] = pstmt; + } + pstmt.setLong(1, m.getMessageId()); + pstmt.executeUpdate(); + } + + private JDBCTransaction getTx(Xid xid) + throws + UnknownXidException + { + JDBCTransaction tx = null; + if (xid != null) + { + tx = _tm.getTransaction(xid); + } + return tx; + } + + /** + * setupConnections - Initialize the connections + * + * @return true if ok + */ + private synchronized boolean setupConnections() + { + try + { + if (_connectionPool == null) + { + // In an embedded environment, loading the driver also starts Derby. + Class.forName(_driver).newInstance(); + _connectionPool = new ConnectionPool(_maxSize); + } + } + catch (Exception e) + { + _log.warn("Setup connections trouble", e); + return false; + } + return true; + } + + /** + * Try to create the connection and table. + * If this fails, then we will exit. + */ + protected synchronized boolean setupStore(boolean dropTables) + { + if (!setupConnections()) + { + return false; + } + MyConnection myconnection = null; + try + { + myconnection = (MyConnection) _connectionPool.acquireInstance(); + Statement stmt = myconnection._connection.createStatement(); + /* + * TODO Need some management interface to delete the table! + */ + if (dropTables) + { + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameMessage); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // don't want to print error - chances are it + // just reports that the table does not exist + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameQueue); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameQueueMessageRelation); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameExchange); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameExchangeQueueRelation); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameRecord); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + try + { + stmt.executeUpdate("DROP TABLE " + _tableNameTransaction); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + } + } + // create the table for messages + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameMessage + " (MessageID FLOAT NOT NULL, Header BLOB," + + " Payload BLOB, ExchangeName VARCHAR(1024), RoutingKey VARCHAR(1024)," + + " Mandatory INTEGER, Is_Immediate INTEGER, PRIMARY KEY(MessageID))"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + // create the table for queues + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameQueue + " (QueueID INTEGER NOT NULL, " + + "Name VARCHAR(1024) NOT NULL, Owner VARCHAR(1024), PRIMARY KEY(QueueID))"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + //ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + // create the table for queue to message mapping + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameQueueMessageRelation + " (QueueID INTEGER NOT NULL, " + + "MessageID FLOAT NOT NULL, Prepared INTEGER)"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + //ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameExchange + " (Name VARCHAR(1024) NOT NULL, " + + "Type VARCHAR(1024) NOT NULL, PRIMARY KEY(Name))"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + //ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameExchangeQueueRelation + " (QueueID INTEGER NOT NULL, " + + "Name VARCHAR(1024) NOT NULL, RoutingKey VARCHAR(1024), FieldTable BLOB )"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + //ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameRecord + " (XID_ID FLOAT, Type INTEGER, MessageID FLOAT, " + + "QueueID INTEGER, PRIMARY KEY(Type, MessageID, QueueID))"); + // we could alter the table with QueueID as foreign key + myconnection._connection.commit(); + } + catch (SQLException ex) + { + //ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + try + { + stmt.executeUpdate("CREATE TABLE " + _tableNameTransaction + " (XID_ID FLOAT, FormatId INTEGER, " + + "BranchQualifier BLOB, GlobalTransactionId BLOB, PRIMARY KEY(XID_ID))"); + myconnection._connection.commit(); + } + catch (SQLException ex) + { + // ex.printStackTrace(); + // assume this is reporting that the table already exists: + } + } + catch (Throwable e) + { + _log.warn("Setup Store trouble: ", e); + return false; + } + finally + { + if (myconnection != null) + { + _connectionPool.releaseInstance(myconnection); + } + } + return true; + } + //======================================================================================== + //============== the connection pool ===================================================== + //======================================================================================== + + private class ConnectionPool extends Pool + { + + /** + * Create a pool of specified size. Negative or null pool sizes are + * disallowed. + * + * @param poolSize The size of the pool to create. Should be 1 or + * greater. + * @throws Exception If the pool size is less than 1. + */ + public ConnectionPool(int poolSize) + throws + Exception + { + super(poolSize); + } + + /** + * @return An instance of the pooled object. + * @throws Exception In case of internal error. + */ + protected MyConnection createInstance() + throws + Exception + { + try + { + // standard way to obtain a Connection object is to call the method DriverManager.getConnection, + // which takes a String containing a connection URL (uniform resource locator). + Connection conn = DriverManager.getConnection(_connectionURL); + //conn.setAutoCommit(true); + PreparedStatement[] st = new PreparedStatement[STATEMENT_SIZE]; + for (int j = 0; j < STATEMENT_SIZE; j++) + { + st[j] = null; + } + return new MyConnection(conn, st); + } + catch (SQLException e) + { + throw new Exception("sqlException when creating connection to " + _connectionURL, e); + } + } + } + + public class MyConnection + { + // the connection + private Connection _connection = null; + // its associated prepared statements + private PreparedStatement[] _preparedStatements = null; + + MyConnection(Connection con, PreparedStatement[] st) + { + _connection = con; + _preparedStatements = st; + } + + public Connection getConnection() + { + return _connection; + } + + public PreparedStatement[] getStatements() + { + return _preparedStatements; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java index 2bcebe0fa7..8954ffc4d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java @@ -29,6 +29,8 @@ import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.exception.*; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.txn.MemoryDequeueRecord; @@ -249,4 +251,23 @@ public class MemoryMessageStore implements MessageStore { return _messageID++; } + + + public ContentHeaderBody getContentHeaderBody(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException + { + // do nothing this is only used during recovery + return null; + } + + public MessagePublishInfo getMessagePublishInfo(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException + { + // do nothing this is only used during recovery + return null; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java index c4b1d3182f..913f3ed9c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java @@ -1,270 +1,300 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.commons.configuration.Configuration; - -import javax.transaction.xa.Xid; -import java.util.Collection; - -/** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 17:34:02 - */ -public interface MessageStore -{ - /** - * Create a new exchange - * - * @param exchange the exchange to be persisted - * @throws InternalErrorException If an error occurs - */ - public void createExchange(Exchange exchange) - throws - InternalErrorException; - - /** - * Remove an exchange - * @param exchange The exchange to be removed - * @throws InternalErrorException If an error occurs - */ - public void removeExchange(Exchange exchange) throws - InternalErrorException; - - /** - * Bind a queue with an exchange given a routing key - * - * @param exchange The exchange to bind the queue with - * @param routingKey The routing key - * @param queue The queue to be bound - * @param args Args - * @throws InternalErrorException If an error occurs - */ - public void bindQueue(Exchange exchange, - AMQShortString routingKey, - StorableQueue queue, FieldTable args) - throws - InternalErrorException; - - /** - * Unbind a queue from an exchange - * - * @param exchange The exchange the queue was bound to - * @param routingKey The routing queue - * @param queue The queue to unbind - * @param args args - * @throws InternalErrorException If an error occurs - */ - public void unbindQueue(Exchange exchange, - AMQShortString routingKey, - StorableQueue queue, FieldTable args) - throws - InternalErrorException; - - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param tm The transaction manager implementation - * @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 InternalErrorException If an error occurs that means the store is unable to configure itself - * @throws IllegalArgumentException If the configuration arguments are illegal - */ - void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws - InternalErrorException, - IllegalArgumentException; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws InternalErrorException if close fails - */ - void close() - throws - InternalErrorException; - - /** - * Create a queue - * - * @param queue the queue to be created - * @throws InternalErrorException In case of internal message store problem - * @throws QueueAlreadyExistsException If the queue already exists in the store - */ - public void createQueue(StorableQueue queue) - throws - InternalErrorException, - QueueAlreadyExistsException; - - /** - * Destroy a queue - * - * @param queue The queue to be destroyed - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - */ - public void destroyQueue(StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException; - - /** - * Stage the message before effective enqueue - * - * @param m The message to stage - * @throws InternalErrorException In case of internal message store problem - * @throws MessageAlreadyStagedException If the message is already staged - */ - public void stage(StorableMessage m) - throws - InternalErrorException, - MessageAlreadyStagedException; - - - /** - * Append more data with a previously staged message - * - * @param m The message to which data must be appended - * @param data Data to happen to the message - * @param offset The number of bytes from the beginning of the payload - * @param size The number of bytes to be written - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message has not been staged - */ - public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Get the content of previously staged or enqueued message. - * The message headers are also set. - * - * @param m The message for which the content must be loaded - * @param offset The number of bytes from the beginning of the payload - * @param size The number of bytes to be loaded - * @return The message content - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist - */ - public byte[] loadContent(StorableMessage m, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Destroy a previously staged message - * - * @param m the message to be destroyed - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist in the store - */ - public void destroy(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Enqueue a message under the scope of the transaction branch - * identified by xid when specified. - *

      This operation is propagated to the queue and the message. - *

      A message that has been previously staged is assumed to have had - * its payload already added (see appendContent) - * - * @param xid The xid of the transaction branch under which the message must be enqueued. - *

      It he xid is null then the message is enqueued outside the scope of any transaction. - * @param m The message to be enqueued - * @param queue The queue into which the message must be enqueued - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - * @throws InvalidXidException The transaction branch is invalid - * @throws UnknownXidException The transaction branch is unknown - * @throws MessageDoesntExistException If the Message does not exist - */ - public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException; - - /** - * Dequeue a message under the scope of the transaction branch identified by xid - * if specified. - *

      This operation is propagated to the queue and the message. - * - * @param xid The xid of the transaction branch under which the message must be dequeued. - *

      It he xid is null then the message is dequeued outside the scope of any transaction. - * @param m The message to be dequeued - * @param queue The queue from which the message must be dequeued - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - * @throws InvalidXidException The transaction branch is invalid - * @throws UnknownXidException The transaction branch is unknown - */ - public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException; - - //========================================================= - // Recovery specific methods - //========================================================= - - /** - * List all the persistent queues - * - * @return All the persistent queues - * @throws InternalErrorException In case of internal message store problem - */ - public Collection getAllQueues() - throws - InternalErrorException; - - /** - * All enqueued messages of a given queue - * - * @param queue The queue where the message are retrieved from - * @return The list all enqueued messages of a given queue - * @throws InternalErrorException In case of internal message store problem - */ - public Collection getAllMessages(StorableQueue queue) - throws - InternalErrorException; - - /** - * Get a new message ID - * - * @return A new message ID - */ - public long getNewMessageId(); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import org.apache.qpid.server.exception.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.commons.configuration.Configuration; + +import javax.transaction.xa.Xid; +import java.util.Collection; + +/** + * Created by Arnaud Simon + * Date: 29-Mar-2007 + * Time: 17:34:02 + */ +public interface MessageStore +{ + /** + * Create a new exchange + * + * @param exchange the exchange to be persisted + * @throws InternalErrorException If an error occurs + */ + public void createExchange(Exchange exchange) + throws + InternalErrorException; + + /** + * Remove an exchange + * + * @param exchange The exchange to be removed + * @throws InternalErrorException If an error occurs + */ + public void removeExchange(Exchange exchange) + throws + InternalErrorException; + + /** + * Bind a queue with an exchange given a routing key + * + * @param exchange The exchange to bind the queue with + * @param routingKey The routing key + * @param queue The queue to be bound + * @param args Args + * @throws InternalErrorException If an error occurs + */ + public void bindQueue(Exchange exchange, + AMQShortString routingKey, + StorableQueue queue, FieldTable args) + throws + InternalErrorException; + + /** + * Unbind a queue from an exchange + * + * @param exchange The exchange the queue was bound to + * @param routingKey The routing queue + * @param queue The queue to unbind + * @param args args + * @throws InternalErrorException If an error occurs + */ + public void unbindQueue(Exchange exchange, + AMQShortString routingKey, + StorableQueue queue, FieldTable args) + throws + InternalErrorException; + + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param tm The transaction manager implementation + * @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 InternalErrorException If an error occurs that means the store is unable to configure itself + * @throws IllegalArgumentException If the configuration arguments are illegal + */ + void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) + throws + InternalErrorException, + IllegalArgumentException; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws InternalErrorException if close fails + */ + void close() + throws + InternalErrorException; + + /** + * Create a queue + * + * @param queue the queue to be created + * @throws InternalErrorException In case of internal message store problem + * @throws QueueAlreadyExistsException If the queue already exists in the store + */ + public void createQueue(StorableQueue queue) + throws + InternalErrorException, + QueueAlreadyExistsException; + + /** + * Destroy a queue + * + * @param queue The queue to be destroyed + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + */ + public void destroyQueue(StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException; + + /** + * Stage the message before effective enqueue + * + * @param m The message to stage + * @throws InternalErrorException In case of internal message store problem + * @throws MessageAlreadyStagedException If the message is already staged + */ + public void stage(StorableMessage m) + throws + InternalErrorException, + MessageAlreadyStagedException; + + + /** + * Append more data with a previously staged message + * + * @param m The message to which data must be appended + * @param data Data to happen to the message + * @param offset The number of bytes from the beginning of the payload + * @param size The number of bytes to be written + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message has not been staged + */ + public void appendContent(StorableMessage m, byte[] data, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Get the content of previously staged or enqueued message. + * The message headers are also set. + * + * @param m The message for which the content must be loaded + * @param offset The number of bytes from the beginning of the payload + * @param size The number of bytes to be loaded + * @return The message content + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist + */ + public byte[] loadContent(StorableMessage m, int offset, int size) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Get the content header of this message + * + * @param m The message + * @return The message content + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist + */ + public ContentHeaderBody getContentHeaderBody(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Get the MessagePublishInfo of this message + * + * @param m The message + * @return The message content + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist + */ + public MessagePublishInfo getMessagePublishInfo(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Destroy a previously staged message + * + * @param m the message to be destroyed + * @throws InternalErrorException In case of internal message store problem + * @throws MessageDoesntExistException If the message does not exist in the store + */ + public void destroy(StorableMessage m) + throws + InternalErrorException, + MessageDoesntExistException; + + /** + * Enqueue a message under the scope of the transaction branch + * identified by xid when specified. + *

      This operation is propagated to the queue and the message. + *

      A message that has been previously staged is assumed to have had + * its payload already added (see appendContent) + * + * @param xid The xid of the transaction branch under which the message must be enqueued. + *

      It he xid is null then the message is enqueued outside the scope of any transaction. + * @param m The message to be enqueued + * @param queue The queue into which the message must be enqueued + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + * @throws InvalidXidException The transaction branch is invalid + * @throws UnknownXidException The transaction branch is unknown + * @throws MessageDoesntExistException If the Message does not exist + */ + public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException; + + /** + * Dequeue a message under the scope of the transaction branch identified by xid + * if specified. + *

      This operation is propagated to the queue and the message. + * + * @param xid The xid of the transaction branch under which the message must be dequeued. + *

      It he xid is null then the message is dequeued outside the scope of any transaction. + * @param m The message to be dequeued + * @param queue The queue from which the message must be dequeued + * @throws InternalErrorException In case of internal message store problem + * @throws QueueDoesntExistException If the queue does not exist in the store + * @throws InvalidXidException The transaction branch is invalid + * @throws UnknownXidException The transaction branch is unknown + */ + public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException; + + //========================================================= + // Recovery specific methods + //========================================================= + + /** + * List all the persistent queues + * + * @return All the persistent queues + * @throws InternalErrorException In case of internal message store problem + */ + public Collection getAllQueues() + throws + InternalErrorException; + + /** + * All enqueued messages of a given queue + * + * @param queue The queue where the message are retrieved from + * @return The list all enqueued messages of a given queue + * @throws InternalErrorException In case of internal message store problem + */ + public Collection getAllMessages(StorableQueue queue) + throws + InternalErrorException; + + /** + * Get a new message ID + * + * @return A new message ID + */ + public long getNewMessageId(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java new file mode 100644 index 0000000000..49af218b7a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java @@ -0,0 +1,135 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.messageStore; + +import java.util.ArrayList; + +/** + * Created by Arnaud Simon + * Date: 15-May-2007 + * Time: 10:11:49 + */ +public abstract class Pool +{ + // The maximum size of the pool. + private int _maxPoolSize = -1; + // The current size of the pool. + private int _currentPoolSize = 0; + // The pool objects. + private volatile ArrayList _poolObjects = new ArrayList(); + //The current number of created instances. + private int _instanceCount = 0; + + /** + * Create a pool of specified size. Negative or null pool sizes are + * disallowed. + * + * @param poolSize The size of the pool to create. Should be 1 or + * greater. + * @throws Exception If the pool size is less than 1. + */ + public Pool(int poolSize) throws Exception + { + if (poolSize <= 0) + { + throw new Exception("pool size is less than 1: " + poolSize); + } + _maxPoolSize = poolSize; + } + + /** + * Return the maximum size of this pool. + * + * @return The maximum size of this pool. + */ + public final int maxSize() + { + return _maxPoolSize; + } + + /** + * Return the current number of created instances. + * + * @return The current number of created instances in this pool. + */ + public final int numberOfInstances() + { + return _instanceCount; + } + + /** + * Extending classes MUST define how to create an instance of the object + * that they pool. + * + * @return An instance of the pooled object. + * @throws Exception In case of internal error. + */ + abstract protected Object createInstance() throws Exception; + + /** + * Remove the next available object from the pool or wait for one to become + * available. + * + * @return The next available instance. + * @throws Exception If the call is interrupted + */ + public final synchronized Object acquireInstance() throws Exception + { + while (_currentPoolSize == _maxPoolSize) + { + try + { + this.wait(); + } + catch (InterruptedException e) + { + throw new Exception("pool wait threw interrupted exception", e); + } + } + if (_poolObjects.size() == 0) + { + _poolObjects.add(createInstance()); + _instanceCount++; + } + _currentPoolSize++; + return _poolObjects.remove(0); + } + + /** + * Return an object back into this pool. + * + * @param object The returning object. + */ + public synchronized void releaseInstance(Object object) + { + _poolObjects.add(object); + _currentPoolSize--; + this.notify(); + } + + /** + * Return a dead object back into this pool. + * + */ + public synchronized void releaseDeadInstance() + { + _instanceCount--; + _currentPoolSize--; + this.notify(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java index 560549c126..47126f4b68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java @@ -5,9 +5,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,7 +24,11 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.JDBCStore; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.MessageDoesntExistException; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.log4j.Logger; import javax.transaction.xa.Xid; @@ -65,7 +69,7 @@ public class StorableMessageHandle implements AMQMessageHandle // MessagePublishInfo private MessagePublishInfo _messagePublishInfo; // list of chunks - private List _chunks = new LinkedList(); + private List _chunks; //======================================================================== // Constructors @@ -84,6 +88,17 @@ public class StorableMessageHandle implements AMQMessageHandle throws AMQException { + if (_contentHeaderBody == null) + { + // load it from the store + try + { + _contentHeaderBody = _messageStore.getContentHeaderBody(_message); + } catch (Exception e) + { + throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); + } + } return _contentHeaderBody; } @@ -91,6 +106,17 @@ public class StorableMessageHandle implements AMQMessageHandle throws AMQException { + if (_chunks == null ) + { + if(_message.isStaged() ) + { + loadChunks(); + } + else + { + return 0; + } + } return _chunks.size(); } @@ -106,13 +132,57 @@ public class StorableMessageHandle implements AMQMessageHandle IllegalArgumentException, AMQException { + if (_chunks == null) + { + loadChunks(); + } return _chunks.get(index); } + private void loadChunks() + throws + AMQException + { + try + { + _chunks = new LinkedList(); + byte[] underlying = _messageStore.loadContent(_message, 1, 0); + final int size = underlying.length; + final org.apache.mina.common.ByteBuffer data = + org.apache.mina.common.ByteBuffer.wrap(underlying); + ContentChunk cb = new ContentChunk() + { + + public int getSize() + { + return size; + } + + public org.apache.mina.common.ByteBuffer getData() + { + return data; + } + + public void reduceToFit() + { + + } + }; + _chunks.add(cb); + } catch (Exception e) + { + throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); + } + } + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException { + if (_chunks == null) + { + _chunks = new LinkedList(); + } _chunks.add(contentBody); // if rquired this message can be added to the store //_messageStore.appendContent(_message, _payload, 0, 10); @@ -123,6 +193,17 @@ public class StorableMessageHandle implements AMQMessageHandle throws AMQException { + if (_messagePublishInfo == null) + { + // read it from the store + try + { + _messagePublishInfo = _messageStore.getMessagePublishInfo(_message); + } catch (Exception e) + { + throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); + } + } return _messagePublishInfo; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java new file mode 100644 index 0000000000..cc0cc7140b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java @@ -0,0 +1,93 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.UnknownXidException; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 16-May-2007 + * Time: 15:15:18 + */ +public abstract class JDBCAbstractRecord implements TransactionRecord +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCEnqueueRecord.class); + // The record types + static public final int TYPE_DEQUEUE = 1; + static public final int TYPE_ENQUEUE = 2; + + // the queue + StorableQueue _queue; + // the message + StorableMessage _message; + + //======================================================================== + // Constructor + //======================================================================== + public JDBCAbstractRecord(StorableMessage m, StorableQueue queue) + { + _queue = queue; + _message = m; + } + + public abstract int getType(); + public long getMessageID() + { + return _message.getMessageId(); + } + + public int getQueueID() + { + return _queue.getQueueID(); + } + + public void rollback(MessageStore store) + throws + InternalErrorException + { + + } + + public void prepare(MessageStore store) + throws + InternalErrorException + { + } + + + public abstract void rollback(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException; + + public abstract void prepare(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java new file mode 100644 index 0000000000..c18a6a7fcf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java @@ -0,0 +1,85 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.JDBCStore; +import org.apache.qpid.server.exception.*; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 16-May-2007 + * Time: 14:50:34 + */ +public class JDBCDequeueRecord extends JDBCAbstractRecord +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCDequeueRecord.class); + + //======================================================================== + // Constructor + //======================================================================== + public JDBCDequeueRecord( StorableMessage m, StorableQueue queue) + { + super(m, queue); + } + + //======================================================================== + // Interface TransactionRecord + //======================================================================== + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + store.dequeue(xid, _message, _queue); + } + + public void rollback(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException + { + ((JDBCStore) store).rollbackDequeu(xid, _message, _queue); + } + + public void prepare(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException + { + ((JDBCStore) store).prepareDequeu(xid, _message, _queue); + } + + public int getType() + { + return TYPE_DEQUEUE; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java new file mode 100644 index 0000000000..4a4a23153e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java @@ -0,0 +1,106 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.messageStore.StorableQueue; +import org.apache.qpid.server.messageStore.StorableMessage; +import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.JDBCStore; +import org.apache.qpid.server.exception.*; + +import javax.transaction.xa.Xid; + +/** + * Created by Arnaud Simon + * Date: 16-May-2007 + * Time: 14:50:20 + */ +public class JDBCEnqueueRecord extends JDBCAbstractRecord +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCEnqueueRecord.class); + + //======================================================================== + // Constructor + //======================================================================== + public JDBCEnqueueRecord(StorableMessage m, StorableQueue queue) + { + super(m, queue); + } + + //======================================================================== + // Interface TransactionRecord + //======================================================================== + + public void commit(MessageStore store, Xid xid) + throws + InternalErrorException, + QueueDoesntExistException, + InvalidXidException, + UnknownXidException, + MessageDoesntExistException + { + store.enqueue(xid, _message, _queue); + } + + public void rollback(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException + { + if (!_message.isEnqueued()) + { + // try to delete the message + try + { + store.destroy(_message); + } catch (Exception e) + { + throw new InternalErrorException("Problem when destoying message ", e); + } + } + } + + public void prepare(MessageStore store, Xid xid) + throws + InternalErrorException, + UnknownXidException + { + try + { + if (!_message.isEnqueued() && !_message.isStaged()) + { + store.stage(_message); + store.appendContent(_message, _message.getData(), 0, _message.getData().length); + } + } + catch (Exception e) + { + throw new InternalErrorException("Problem when persisting message ", e); + } + } + + public int getType() + { + return TYPE_ENQUEUE; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java new file mode 100644 index 0000000000..cc35b50cc8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java @@ -0,0 +1,196 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.messageStore.JDBCStore; + +import java.util.List; +import java.util.LinkedList; + +/** + * Created by Arnaud Simon + * Date: 16-May-2007 + * Time: 14:09:35 + */ +public class JDBCTransaction implements Transaction +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCTransaction.class); + public static long _xidId = 0; + //======================================================================== + // Instance Fields + //======================================================================== + // the associated connection + private JDBCStore.MyConnection _connection; + // Indicates whether this transaction is prepared + private boolean _prepared = false; + // Indicates that this transaction has heuristically rolled back + private boolean _heurRollBack = false; + // The list of records associated with this tx + private List _records = new LinkedList(); + // The date when this tx has been created. + private long _dateCreated; + // The timeout in seconds + private long _timeout; + // this instance xid id used as primary key + private long _thisxidId; + + //========================================================= + // Constructors + //========================================================= + + /** + * Create a transaction + * + */ + public JDBCTransaction() + { + _dateCreated = System.currentTimeMillis(); + _thisxidId = _xidId++; + } + + //========================================================= + // Getter and Setter methods + //========================================================= + + /** + * Notify that this tx has been prepared + */ + public void prepare() + { + _prepared = true; + } + + /** + * Specify whether this transaction is prepared + * + * @return true if this transaction is prepared, false otherwise + */ + public boolean isPrepared() + { + return _prepared; + } + + /** + * Notify that this tx has been heuristically rolled back + */ + public void heurRollback() + { + _heurRollBack = true; + } + + /** + * Specify whether this transaction has been heuristically rolled back + * + * @return true if this transaction has been heuristically rolled back , false otherwise + */ + public boolean isHeurRollback() + { + return _heurRollBack; + } + + /** + * Add an abstract record to this tx. + * + * @param record The record to be added + */ + public void addRecord(TransactionRecord record) + { + _records.add(record); + } + + /** + * Get the list of records associated with this tx. + * + * @return The list of records associated with this tx. + */ + public List getrecords() + { + return _records; + } + + /** + * Set this tx timeout + * + * @param timeout This tx timeout in seconds + */ + public void setTimeout(long timeout) + { + _timeout = timeout; + } + + /** + * Get this tx timeout + * + * @return This tx timeout in seconds + */ + public long getTimeout() + { + return _timeout; + } + + /** + * Specify whether this tx has expired + * + * @return true if this tx has expired, false otherwise + */ + public boolean hasExpired() + { + long currentDate = System.currentTimeMillis(); + boolean result = currentDate - _dateCreated > _timeout * 1000; + if (_log.isDebugEnabled() && result) + { + _log.debug("transaction has expired"); + } + return result; + } + + /** + * Get the JDBC connection + * @return The JDBC connection + */ + public JDBCStore.MyConnection getConnection() + { + return _connection; + } + + /** + * Set the JDBC connection + * + * @param connection The new JDBC connection + */ + public void setConnection(JDBCStore.MyConnection connection) + { + _connection = connection; + } + + /** + * This tx xid id used as primary key + * + * @return this tx xid id + */ + public long getXidID() + { + return _thisxidId; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java new file mode 100644 index 0000000000..e60fb89bf7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java @@ -0,0 +1,554 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.server.messageStore.MessageStore; +import org.apache.qpid.server.messageStore.JDBCStore; +import org.apache.qpid.server.exception.*; +import org.apache.commons.configuration.Configuration; + +import javax.transaction.xa.Xid; +import java.util.HashMap; +import java.util.Set; + + +/** + * Created by Arnaud Simon + * Date: 16-May-2007 + * Time: 14:05:45 + */ +public class JDBCTransactionManager implements TransactionManager +{ + //======================================================================== + // Static Constants + //======================================================================== + // The logger for this class + private static final Logger _log = Logger.getLogger(JDBCTransactionManager.class); + + private static final String ENVIRONMENT_TX_TIMEOUT = "environment-tx-timeout"; + + //======================================================================== + // Instance Fields + //======================================================================== + // The underlying jdbc message store + private JDBCStore _messagStore; + + // A map of XID/x + private HashMap _xidMap; + + // A map of in-doubt txs + private HashMap _indoubtXidMap; + + // A default tx timeout in sec + private int _defaultTimeout; // set to 10s if not specified in the config + + //=================================== + //=== Configuartion + //=================================== + + /** + * Configure this TM with the Message store implementation + * + * @param base The base element identifier from which all configuration items are relative. For example, if the base + * element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object + * @param messageStroe the message store associated with the TM + */ + public void configure(MessageStore messageStroe, String base, Configuration config) + { + _messagStore = (JDBCStore) messageStroe; + if (config != null) + { + _defaultTimeout = config.getInt(base + "." + ENVIRONMENT_TX_TIMEOUT, 120); + } else + { + _defaultTimeout = 120; + } + _log.info("Using transaction timeout of " + _defaultTimeout + " s"); + // get the list of in-doubt transactions + try + { + _indoubtXidMap = _messagStore.getAllInddoubt(); + _xidMap = _indoubtXidMap; + } catch (Exception e) + { + _log.fatal("Cannot recover in-doubt transactions", e); + } + } + + //=================================== + //=== TransactionManager interface + //=================================== + + /** + * Begin a transaction branch identified by Xid + * + * @param xid The xid of the branch to begin + * @return
        + *
      • XAFlag.ok: Normal execution. + *
      + * @throws InternalErrorException In case of internal problem + * @throws InvalidXidException The Xid is invalid + */ + public synchronized XAFlag begin(Xid xid) + throws + InternalErrorException, + InvalidXidException + { + if (xid == null) + { + throw new InvalidXidException(xid, "null xid"); + } + if (_xidMap.containsKey(xid)) + { + throw new InvalidXidException(xid, "Xid already exist"); + } + Transaction tx = new JDBCTransaction(); + tx.setTimeout(_defaultTimeout); + _xidMap.put(xid, tx); + return XAFlag.ok; + } + + /** + * Prepare the transaction branch identified by Xid + * + * @param xid The xid of the branch to prepare + * @return
        + *
      • XAFlag.ok: Normal execution. + *
      • XAFlag.rdonly: The transaction branch was read-only and has been committed. + *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspecied reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Prepare has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public synchronized XAFlag prepare(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + // get the transaction + JDBCTransaction tx = getTransaction(xid); + XAFlag result = XAFlag.ok; + if (tx.isHeurRollback()) + { + result = XAFlag.rdonly; + } else if (tx.hasExpired()) + { + result = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + if (tx.isPrepared()) + { + throw new CommandInvalidException("TransactionImpl is already prepared"); + } + if (tx.getrecords().size() == 0) + { + // the tx was read only (no work has been done) + _xidMap.remove(xid); + result = XAFlag.rdonly; + } else + { + try + { + JDBCStore.MyConnection con = _messagStore.getConnection(); + tx.setConnection(con); + // save the xid + _messagStore.saveXID(con, tx, xid); + for (TransactionRecord record : tx.getrecords()) + { + if (record instanceof JDBCAbstractRecord) + { + ((JDBCAbstractRecord) record).prepare(_messagStore, xid); + _messagStore.saveRecord(con, tx, (JDBCAbstractRecord) record); + } else + { + record.prepare(_messagStore); + } + } + _messagStore.commitConnection(con); + tx.setConnection(null); + } catch (Exception e) + { + _log.error("Cannot prepare tx: " + xid); + throw new InternalErrorException("Cannot prepare tx: " + xid); + } + tx.prepare(); + } + } + return result; + } + + /** + * Rollback the transaction branch identified by Xid + * + * @param xid The xid of the branch to rollback + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • NOT SUPPORTED XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      • NOT SUPPORTED XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Rollback has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public synchronized XAFlag rollback(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + // get the transaction + JDBCTransaction tx = getTransaction(xid); + XAFlag flag = XAFlag.ok; + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else + { + try + { + JDBCStore.MyConnection con = _messagStore.getConnection(); + tx.setConnection(con); + for (TransactionRecord record : tx.getrecords()) + { + if (record instanceof JDBCAbstractRecord) + { + ((JDBCAbstractRecord) record).rollback(_messagStore, xid); + } else + { + record.rollback(_messagStore); + } + } + if (tx.isPrepared()) + { + _messagStore.deleteRecords(con, tx); + _messagStore.deleteXID(con, tx); + _messagStore.commitConnection(con); + } + _messagStore.commitConnection(con); + tx.setConnection(null); + } + catch (Exception e) + { + // this should not happen + _log.error("Error when rolling back distributed transaction: " + xid); + throw new InternalErrorException("Error when rolling back distributed transaction: " + xid, e); + } + removeTransaction(xid); + } + if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + } + return flag; + } + + /** + * Commit the transaction branch identified by Xid + * + * @param xid The xid of the branch to commit + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the specied transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Commit has been call in an improper context + * @throws UnknownXidException The Xid is unknown + * @throws org.apache.qpid.server.exception.NotPreparedException + * The branch was not prepared prior to commit + */ + public synchronized XAFlag commit(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException, + NotPreparedException + { + // get the transaction + JDBCTransaction tx = getTransaction(xid); + XAFlag flag = XAFlag.ok; + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + if (!tx.isPrepared()) + { + throw new NotPreparedException("TransactionImpl is not prepared"); + } + try + { + JDBCStore.MyConnection con = _messagStore.getConnection(); + tx.setConnection(con); + for (TransactionRecord record : tx.getrecords()) + { + try + { + record.commit(_messagStore, xid); + } catch (InvalidXidException e) + { + throw new UnknownXidException(xid, e); + } catch (Exception e) + { + // this should not happen as the queue and the message must exist + _log.error("Error when committing distributed transaction heurmix mode returned: " + xid); + flag = XAFlag.heurmix; + } + } + _messagStore.deleteRecords(con, tx); + _messagStore.deleteXID(con, tx); + _messagStore.commitConnection(con); + tx.setConnection(null); + } catch (Exception e) + { + // this should not happen + _log.error("Error when committing distributed transaction heurrb mode returned: " + xid); + throw new InternalErrorException("Error when committing distributed transaction: " + xid, e); + } + removeTransaction(xid); + } + return flag; + } + + /** + * One phase commit the transaction branch identified by Xid + * + * @param xid The xid of the branch to one phase commit + * @return
        + *
      • XAFlag.ok: Normal execution, + *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. + *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. + *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. + *
      • NOT SUPPORTED XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. + *
      • NOT SUPPORTED XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. + *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. + *
      + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Commit has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public synchronized XAFlag commit_one_phase(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + XAFlag flag = XAFlag.ok; + JDBCTransaction tx = getTransaction(xid); + if (tx.isHeurRollback()) + { + flag = XAFlag.heurrb; + } else if (tx.hasExpired()) + { + flag = XAFlag.rbtimeout; + // rollback this tx branch + rollback(xid); + } else + { + try + { + // we do not need to prepare the tx + tx.prepare(); + JDBCStore.MyConnection con = _messagStore.getConnection(); + tx.setConnection(con); + for (TransactionRecord record : tx.getrecords()) + { + try + { + record.commit(_messagStore, xid); + } catch (InvalidXidException e) + { + throw new UnknownXidException(xid, e); + } catch (Exception e) + { + // this should not happen as the queue and the message must exist + _log.error("Error when committing transaction heurmix mode returned: " + xid); + flag = XAFlag.heurmix; + } + } + _messagStore.commitConnection(con); + tx.setConnection(null); + } catch (Exception e) + { + e.printStackTrace(); + throw new InternalErrorException("cannot commit transaxtion with xid " + xid + " " + e, e); + } + finally + { + removeTransaction(xid); + } + } + return flag; + } + + /** + * Forget about the transaction branch identified by Xid + * + * @param xid The xid of the branch to forget + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Forget has been call in an improper context + * @throws UnknownXidException The Xid is unknown + */ + public void forget(Xid xid) + throws + InternalErrorException, + CommandInvalidException, + UnknownXidException + { + synchronized (xid) + { + getTransaction(xid); + removeTransaction(xid); + } + } + + /** + * Set the transaction branch timeout value in seconds + * + * @param xid The xid of the branch to set timeout + * @param timeout Timeout value in seconds + * @throws InternalErrorException In case of internal problem + * @throws UnknownXidException The Xid is unknown + */ + public void setTimeout(Xid xid, long timeout) + throws + InternalErrorException, + UnknownXidException + { + JDBCTransaction tx = getTransaction(xid); + tx.setTimeout(timeout); + } + + /** + * Get the transaction branch timeout + * + * @param xid The xid of the branch to get the timeout from + * @return The timeout associated with the branch identified with xid + * @throws InternalErrorException In case of internal problem + * @throws UnknownXidException The Xid is unknown + */ + public long getTimeout(Xid xid) + throws + InternalErrorException, + UnknownXidException + { + JDBCTransaction tx = getTransaction(xid); + return tx.getTimeout(); + } + + /** + * Get a set of Xids the RM has prepared or heuristically completed + * + * @param startscan Indicates that recovery scan should start + * @param endscan Indicates that the recovery scan should end after returning the Xids + * @return Set of Xids the RM has prepared or heuristically completed + * @throws InternalErrorException In case of internal problem + * @throws CommandInvalidException Recover has been call in an improper context + */ + public Set recover(boolean startscan, boolean endscan) + throws + InternalErrorException, + CommandInvalidException + { + return _indoubtXidMap.keySet(); + } + + /** + * An error happened (for example the channel has been abruptly closed) + * with this Xid, TM must make a heuristical decision. + * + * @param xid The Xid of the transaction branch to be heuristically completed + * @throws UnknownXidException The Xid is unknown + * @throws InternalErrorException In case of internal problem + */ + public void HeuristicOutcome(Xid xid) + throws + UnknownXidException, + InternalErrorException + { + synchronized (xid) + { + JDBCTransaction tx = getTransaction(xid); + if (!tx.isPrepared()) + { + // heuristically rollback this tx + for (TransactionRecord record : tx.getrecords()) + { + record.rollback(_messagStore); + } + tx.heurRollback(); + } + // add this branch in the list of indoubt tx + _indoubtXidMap.put(xid, tx); + } + } + + + public JDBCTransaction getTransaction(Xid xid) + throws + UnknownXidException + { + Transaction tx = _xidMap.get(xid); + if (tx == null) + { + throw new UnknownXidException(xid); + } + return (JDBCTransaction) tx; + } + + //========================================================================== + //== Methods for Message Store + //========================================================================== + + /** + * Get the default tx timeout in seconds + * + * @return the default tx timeout in seconds + */ + public int getDefaultTimeout() + { + return _defaultTimeout; + } + //========================================================================== + //== Private Methods + //========================================================================== + + private void removeTransaction(Xid xid) + { + _xidMap.remove(xid); + _indoubtXidMap.remove(xid); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index addb0c791f..8becaf52b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -93,7 +93,10 @@ public class NonTransactionalContext implements TransactionalContext { try { - message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); + if( ! deliverFirst ) + { + message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); + } queue.process(_storeContext, message, deliverFirst); //following check implements the functionality //required by the 'immediate' flag: diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index f7c578d9a0..12b2a4f7a8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -57,10 +57,14 @@ public class NullApplicationRegistry extends ApplicationRegistry super(new MapConfiguration(new HashMap())); } - public void initialise() throws Exception + public void initialise() + throws + Exception { _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.MemoryMessageStore"); _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.MemoryTransactionManager"); + // _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.JDBCStore"); + // _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.JDBCTransactionManager"); Properties users = new Properties(); @@ -121,3 +125,4 @@ public class NullApplicationRegistry extends ApplicationRegistry } + -- cgit v1.2.1 From b699d6aa15aba59a9c6ae1651ff7be1f3bf577e8 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Tue, 22 May 2007 13:45:50 +0000 Subject: Eliminated catch/rethrow where underlying cause was discarded. All causes now wrapped. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540584 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 31 ++++----- .../apache/qpid/server/messageStore/JDBCStore.java | 76 +++++++++++----------- .../ConfigurationFilePrincipalDatabaseManager.java | 30 +++++---- .../qpid/server/txn/JDBCTransactionManager.java | 2 +- 4 files changed, 71 insertions(+), 68 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 40462cf2bf..f2cc6e8bca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -48,6 +48,8 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.QueueAlreadyExistsException; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -56,12 +58,10 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; /** * This MBean implements the broker management interface and exposes the @@ -113,8 +113,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); if (exchange == null) { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), - durable, false, 0); + exchange = + _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, + false, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -183,9 +184,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { _messageStore.createQueue(queue); - } catch (Exception e) + } + catch (Exception e) { - throw new JMException("problem creating queue " + queue.getName()); + JMException jme = new JMException("problem creating queue " + queue.getName()); + jme.initCause(e); + throw jme; } } @@ -200,9 +204,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); - throw new MBeanException(jme, "Error in creating queue " + queueName); + throw new MBeanException(ex, "Error in creating queue " + queueName); } } @@ -228,17 +230,16 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - if( queue.isDurable() ) + if (queue.isDurable()) { _messageStore.destroyQueue(queue); } } catch (Exception ex) { - ex.printStackTrace(); - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); - throw new MBeanException(jme, "Error in deleting queue " + queueName); + /*ex.printStackTrace(); + JMException jme = new JMException(ex.getMessage());*/ + throw new MBeanException(ex, "Error in deleting queue " + queueName); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java index 44de0d3d98..55d34fb2f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java @@ -181,7 +181,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot create Exchange: " + exchange); + throw new InternalErrorException("Cannot create Exchange: " + exchange, e); } finally { if (connection != null) @@ -195,7 +195,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Exchange: " + exchange); + throw new InternalErrorException("Cannot create Exchange: " + exchange, e); } } } @@ -223,7 +223,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot remove Exchange: " + exchange); + throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); } finally { if (connection != null) @@ -237,7 +237,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Exchange: " + exchange); + throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); } } } @@ -274,7 +274,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot create Exchange: " + exchange); + throw new InternalErrorException("Cannot create Exchange: " + exchange, e); } finally { if (connection != null) @@ -288,7 +288,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Exchange: " + exchange); + throw new InternalErrorException("Cannot create Exchange: " + exchange, e); } } } @@ -316,7 +316,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot remove Exchange: " + exchange); + throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); } finally { if (connection != null) @@ -330,7 +330,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Exchange: " + exchange); + throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); } } } @@ -364,7 +364,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot create Queue: " + queue); + throw new InternalErrorException("Cannot create Queue: " + queue, e); } finally { if (connection != null) @@ -378,7 +378,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Queue: " + queue); + throw new InternalErrorException("Cannot create Queue: " + queue, e); } } } @@ -404,7 +404,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot remove Queue: " + queue); + throw new InternalErrorException("Cannot remove Queue: " + queue, e); } finally { if (connection != null) @@ -418,7 +418,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Queue: " + queue); + throw new InternalErrorException("Cannot remove Queue: " + queue, e); } } } @@ -441,7 +441,7 @@ public class JDBCStore implements MessageStore stage(connection, m); } catch (Exception e) { - throw new InternalErrorException("Cannot stage Message: " + m); + throw new InternalErrorException("Cannot stage Message: " + m, e); } finally { if (connection != null) @@ -455,7 +455,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot stage Message: " + m); + throw new InternalErrorException("Cannot stage Message: " + m, e); } } } @@ -481,7 +481,7 @@ public class JDBCStore implements MessageStore appendContent(connection, m, data, offset, size); } catch (Exception e) { - throw new InternalErrorException("Cannot stage Message: " + m); + throw new InternalErrorException("Cannot stage Message: " + m, e); } finally { if (connection != null) @@ -495,7 +495,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot stage Message: " + m); + throw new InternalErrorException("Cannot stage Message: " + m, e); } } } @@ -545,7 +545,7 @@ public class JDBCStore implements MessageStore return result; } catch (Exception e) { - throw new InternalErrorException("Cannot load Message: " + m); + throw new InternalErrorException("Cannot load Message: " + m, e); } finally { if (connection != null) @@ -559,7 +559,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot load Message: " + m); + throw new InternalErrorException("Cannot load Message: " + m, e); } } } @@ -577,7 +577,7 @@ public class JDBCStore implements MessageStore destroy(connection, m); } catch (Exception e) { - throw new InternalErrorException("Cannot destroy message: " + m); + throw new InternalErrorException("Cannot destroy message: " + m, e); } finally { if (connection != null) @@ -591,7 +591,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot destroy message: " + m); + throw new InternalErrorException("Cannot destroy message: " + m, e); } } } @@ -644,7 +644,7 @@ public class JDBCStore implements MessageStore queue.enqueue(m); } catch (Exception e) { - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); } finally { if (tx == null && connection != null) @@ -658,7 +658,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); } } } @@ -710,7 +710,7 @@ public class JDBCStore implements MessageStore queue.dequeue(m); } catch (Exception e) { - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); } finally { if (tx == null && connection != null) @@ -724,7 +724,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue); + throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); } } } @@ -762,7 +762,7 @@ public class JDBCStore implements MessageStore return result; } catch (Exception e) { - throw new InternalErrorException("Cannot get all queues"); + throw new InternalErrorException("Cannot get all queues", e); } finally { if (connection != null) @@ -776,7 +776,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get all queues"); + throw new InternalErrorException("Cannot get all queues", e); } } } @@ -793,7 +793,7 @@ public class JDBCStore implements MessageStore return getAllMessages(connection, queue); } catch (Exception e) { - throw new InternalErrorException("Cannot get all queues"); + throw new InternalErrorException("Cannot get all queues", e); } finally { if (connection != null) @@ -807,7 +807,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get all queues"); + throw new InternalErrorException("Cannot get all queues", e); } } } @@ -922,7 +922,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot commit connection ="); + throw new InternalErrorException("Cannot commit connection =", e); } } @@ -939,7 +939,7 @@ public class JDBCStore implements MessageStore // we did not manage to rollback this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot rollback connection"); + throw new InternalErrorException("Cannot rollback connection", e); } } @@ -1029,7 +1029,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot save record: " + record); + throw new InternalErrorException("Cannot save record: " + record, e); } } @@ -1053,7 +1053,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot save xid: " + xid); + throw new InternalErrorException("Cannot save xid: " + xid, e); } } @@ -1074,7 +1074,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot delete record: " + tx.getXidID()); + throw new InternalErrorException("Cannot delete record: " + tx.getXidID(), e); } } @@ -1095,7 +1095,7 @@ public class JDBCStore implements MessageStore pstmt.executeUpdate(); } catch (Exception e) { - throw new InternalErrorException("Cannot delete xid: " + tx.getXidID()); + throw new InternalErrorException("Cannot delete xid: " + tx.getXidID(), e); } } @@ -1212,7 +1212,7 @@ public class JDBCStore implements MessageStore return result; } catch (Exception e) { - throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); + throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m, e); } finally { if (connection != null) @@ -1226,7 +1226,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); + throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m, e); } } } @@ -1261,7 +1261,7 @@ public class JDBCStore implements MessageStore return result; } catch (Exception e) { - throw new InternalErrorException("Cannot get Content Header of message: " + m); + throw new InternalErrorException("Cannot get Content Header of message: " + m, e); } finally { if (connection != null) @@ -1275,7 +1275,7 @@ public class JDBCStore implements MessageStore // we did not manage to commit this connection // it is better to release it _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get Content Header of message: " + m); + throw new InternalErrorException("Cannot get Content Header of message: " + m, e); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 2d3f5e5131..2e506b9751 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -27,20 +27,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.management.JMException; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; -import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.AMQException; import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.configuration.PropertyUtils; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.AMQUserManagementMBean; -import org.apache.qpid.AMQException; - -import javax.management.JMException; public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager { @@ -107,7 +107,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab } private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) - throws FileNotFoundException, ConfigurationException + throws FileNotFoundException, ConfigurationException { String baseName = _base + "(" + index + ").attributes.attribute."; List argumentNames = config.getList(baseName + "name"); @@ -139,9 +139,9 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (method == null) { throw new ConfigurationException("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"); + + principalDatabase.getClass() + + " hence unable to configure principal database. The method must be public and " + + "have a single String argument with a void return type"); } try @@ -152,7 +152,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { if (ite instanceof ConfigurationException) { - throw(ConfigurationException) ite; + throw (ConfigurationException) ite; } else { @@ -178,7 +178,8 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (principalDBs.size() == 0) { - throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)"); + throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + + ".principal-database)"); } String databaseName = principalDBs.get(0); @@ -196,18 +197,19 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (jmxaccesslist.size() == 0) { - throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)"); + throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + + ".access)"); } String jmxaccesssFile = null; - + try { jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); } catch (PropertyException e) { - throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); + throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'", e); } try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java index e60fb89bf7..0ea531630d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java @@ -191,7 +191,7 @@ public class JDBCTransactionManager implements TransactionManager } catch (Exception e) { _log.error("Cannot prepare tx: " + xid); - throw new InternalErrorException("Cannot prepare tx: " + xid); + throw new InternalErrorException("Cannot prepare tx: " + xid, e); } tx.prepare(); } -- cgit v1.2.1 From 98d79fa020c71de88eca07b526008ca25e7cb193 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Tue, 22 May 2007 14:08:02 +0000 Subject: All exceptions now have one contructor. Some multiple cons left in as deprecated, will eliminate in a week or so. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@540590 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exception/UnknownXidException.java | 8 ++++---- .../java/org/apache/qpid/server/messageStore/JDBCStore.java | 4 ++-- .../org/apache/qpid/server/txn/JDBCTransactionManager.java | 2 +- .../org/apache/qpid/server/txn/MemoryTransactionManager.java | 10 +++------- 4 files changed, 10 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java index b8a8de90a0..e4a5de8ecb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java @@ -50,8 +50,6 @@ public class UnknownXidException extends Exception * * @param xid The unknown xid. * @param cause The casue for the xid to be unknown - * - * @deprecated */ public UnknownXidException(Xid xid, Throwable cause) { @@ -66,10 +64,10 @@ public class UnknownXidException extends Exception * * @deprecated */ - public UnknownXidException(Xid xid, String reason) + /*public UnknownXidException(Xid xid, String reason) { super("The Xid: " + xid + " is unknown, The reason is: " + reason); - } + }*/ /** * Constructs a newr UnknownXidException with a reason message and cause @@ -77,6 +75,8 @@ public class UnknownXidException extends Exception * @param reason The reason why the xid is unknown * @param xid The unknown xid. * @param cause The casue for the xid to be unknown + * + * @deprected */ public UnknownXidException(Xid xid, String reason, Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java index 55d34fb2f0..e2d07c1c10 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java @@ -1107,7 +1107,7 @@ public class JDBCStore implements MessageStore JDBCTransaction tx = getTx(xid); if (tx == null) { - throw new UnknownXidException(xid); + throw new UnknownXidException(xid, null); } updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 1); @@ -1121,7 +1121,7 @@ public class JDBCStore implements MessageStore JDBCTransaction tx = getTx(xid); if (tx == null) { - throw new UnknownXidException(xid); + throw new UnknownXidException(xid, null); } updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 0); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java index 0ea531630d..26ddbc881d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java @@ -524,7 +524,7 @@ public class JDBCTransactionManager implements TransactionManager Transaction tx = _xidMap.get(xid); if (tx == null) { - throw new UnknownXidException(xid); + throw new UnknownXidException(xid, null); } return (JDBCTransaction) tx; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java index a361f85e2d..8b0d986d4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java @@ -19,13 +19,9 @@ package org.apache.qpid.server.txn; import java.util.HashMap; import java.util.Set; - import javax.transaction.xa.Xid; - import org.apache.commons.configuration.Configuration; - import org.apache.log4j.Logger; - import org.apache.qpid.server.exception.*; import org.apache.qpid.server.messageStore.MessageStore; @@ -199,7 +195,7 @@ public class MemoryTransactionManager implements TransactionManager } catch (InvalidXidException e) { - throw new UnknownXidException(xid, e.getMessage(), e); + throw new UnknownXidException(xid, e); } catch (Exception e) { @@ -246,7 +242,7 @@ public class MemoryTransactionManager implements TransactionManager } catch (InvalidXidException e) { - throw new UnknownXidException(xid, e.getMessage(), e); + throw new UnknownXidException(xid, e); } catch (Exception e) { @@ -317,7 +313,7 @@ public class MemoryTransactionManager implements TransactionManager Transaction tx = _xidMap.get(xid); if (tx == null) { - throw new UnknownXidException(xid, "", null); + throw new UnknownXidException(xid, null); } return tx; -- cgit v1.2.1 From f9e83f70ff57ca31d0849926ecc6271673404b0b Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Tue, 29 May 2007 10:19:25 +0000 Subject: Added to the Javadoc git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@542476 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 142 ++++++++++++++------- .../server/protocol/AMQPFastProtocolHandler.java | 85 ++++++------ 2 files changed, 136 insertions(+), 91 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index c345b43aeb..6f970730ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -26,8 +26,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; import java.util.List; -import java.util.StringTokenizer; - import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -36,17 +34,14 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; 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 org.apache.qpid.AMQException; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; @@ -66,7 +61,10 @@ import org.apache.qpid.url.URLSyntaxException; @SuppressWarnings({ "AccessStaticViaInstance" }) public class Main { + /** Used for debugging. */ private static final Logger _logger = Logger.getLogger(Main.class); + + /** Used for logging operator messages. */ public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; @@ -74,8 +72,8 @@ public class Main private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; public static final String QPID_HOME = "QPID_HOME"; private static final int IPV4_ADDRESS_LENGTH = 4; - - private static final char IPV4_LITERAL_SEPARATOR = '.'; + + private static final char IPV4_LITERAL_SEPARATOR = '.'; protected static class InitException extends Exception { @@ -88,6 +86,9 @@ public class Main protected final Options options = new Options(); protected CommandLine commandLine; + /** + * @todo Side-effecting constructor; eliminate. Put the processing sequence in the main method. + */ protected Main(String[] args) { setOptions(options); @@ -115,30 +116,35 @@ public class Main } } + /** + * Sets up the command line options, with usage help, ready for parsing the command line against. + * + * @param options The object to store the configured command line options in. + */ 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"); + 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"); + 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"); + 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"); + 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"); + 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); @@ -149,6 +155,11 @@ public class Main options.addOption(bind); } + /** + * @todo Handles command line, but there is already a parse command line method. Put all command line handling + * in a single flow of control. Also part implements the top-level handler, which would more neatly be kept + * together in one place. + */ protected void execute() { // note this understands either --help or -h. If an option only has a long name you can use that but if @@ -204,6 +215,14 @@ public class Main } } + /** + * Reads the configuration file and performs configuration specified in it. Then hands over to bind to do the + * actual broker start-up. + * + * @todo A bit confusing, seperate out configuration from start-up. Call config method to handle the configuration + * from the config file, in the main flow of control (possibly #main method). Then call #startup or #bind + * to start the broker. + */ protected void startup() throws InitException, ConfigurationException, Exception { final String QpidHome = System.getProperty(QPID_HOME); @@ -241,14 +260,14 @@ public class Main ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + // fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say - // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); + // Starting Qpid Client + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + + QpidProperties.getBuildVersion()); ConnectorConfiguration connectorConfig = - ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); @@ -295,11 +314,10 @@ public class Main } bind(port, connectorConfig); - } protected void setupVirtualHosts(String configFileParent, String configFilePath) - throws ConfigurationException, AMQException, URLSyntaxException + throws ConfigurationException, AMQException, URLSyntaxException { String configVar = "${conf}"; @@ -326,13 +344,19 @@ public class Main if (fileNames[each].endsWith(".xml")) { VirtualHostConfiguration vHostConfig = - new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); + new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); vHostConfig.performBindings(); } } } } + /** + * Assembles/configures the components that Mina needs, then start Mina running to accept connections. + * + * @todo Partially implements top-level error handler. Better to let these errors fall through to a single + * top-level handler. + */ protected void bind(int port, ConnectorConfiguration connectorConfig) { String bindAddr = commandLine.getOptionValue("b"); @@ -373,7 +397,7 @@ public class Main } acceptor.bind(bindAddress, handler, sconfig); - //fixme qpid.AMQP should be using qpidproperties to get value + // fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -383,8 +407,8 @@ public class Main try { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); - //fixme qpid.AMQP should be using qpidproperties to get value + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + // fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); } @@ -394,9 +418,9 @@ public class Main } } - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); + // fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + + QpidProperties.getBuildVersion()); } catch (Exception e) { @@ -404,38 +428,60 @@ public class Main } } + /** + * Processes the command line and starts the broker running. This method acts as a top-level error handler for + * any exceptions that fall out of the code below this point. These exceptions are logged before System.exit is + * called with an error code. + * + * @param args The command line arguments. + */ public static void main(String[] args) { + // Use a try block so that any exceptions that fall through to the top-level are logged before the application + // exits with an error code. + // try + { + // Parse the command line. + + // Create an instance of the Main broker entry point class and start it running. + } + // catch () + { + // Log the exception as an error. + + // Exit with an error code. + } new Main(args); } private byte[] parseIP(String address) throws Exception { - char[] literalBuffer = address.toCharArray(); + char[] literalBuffer = address.toCharArray(); int byteCount = 0; int currByte = 0; byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; - for (int i = 0 ; i < literalBuffer.length ; i++) + for (int i = 0; i < literalBuffer.length; i++) { char currChar = literalBuffer[i]; - if ((currChar >= '0') && (currChar <= '9')) + if ((currChar >= '0') && (currChar <= '9')) { - currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); - } + currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); + } - if (currChar == IPV4_LITERAL_SEPARATOR || (i + 1 == literalBuffer.length)) + if ((currChar == IPV4_LITERAL_SEPARATOR) || ((i + 1) == literalBuffer.length)) { - ip[byteCount++] = (byte)currByte; + ip[byteCount++] = (byte) currByte; currByte = 0; - } + } } if (byteCount != 4) { throw new Exception("Invalid IP address: " + address); - } - return ip; + } + + return ip; } private void configureLogging(File logConfigFile, String logWatchConfig) @@ -448,7 +494,7 @@ public class Main 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"); + + "a non-negative integer. Using default of zero (no watching configured"); } if (logConfigFile.exists() && logConfigFile.canRead()) @@ -457,7 +503,7 @@ public class Main if (logWatchTime > 0) { System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " - + logWatchTime + " seconds"); + + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index d8b7814d31..84ec91d569 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,7 +22,6 @@ package org.apache.qpid.server.protocol; import java.io.IOException; import java.net.InetSocketAddress; - import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.IdleStatus; @@ -31,7 +30,6 @@ 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 org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.framing.AMQDataBlock; @@ -60,10 +58,9 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter private final IApplicationRegistry _applicationRegistry; - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) { - this(ApplicationRegistry.getInstance(applicationRegistryInstance)); + this(ApplicationRegistry.getInstance(applicationRegistryInstance)); } public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) @@ -87,41 +84,43 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); + ConnectorConfiguration connectorConfig = + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); if (connectorConfig.enableExecutorPool) { if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); + new SSLFilter(sslContextFactory.buildServerContext())); } + protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); } else { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); + protocolSession.getFilterChain().addLast("protocolFilter", pcf); if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - + new SSLFilter(sslContextFactory.buildServerContext())); + } + } } /** * Separated into its own, protected, method to allow easier reuse */ - protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException + protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) + throws AMQException { new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); } @@ -135,8 +134,8 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter { _logger.info("Protocol Session closed"); final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - //fixme -- this can be null - if(amqProtocolSession != null) + // fixme -- this can be null + if (amqProtocolSession != null) { amqProtocolSession.closeSession(); } @@ -145,14 +144,14 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter public void sessionIdle(IoSession session, IdleStatus status) throws Exception { _logger.debug("Protocol Session [" + this + "] idle: " + status); - if(IdleStatus.WRITER_IDLE.equals(status)) + if (IdleStatus.WRITER_IDLE.equals(status)) { - //write heartbeat frame: + // write heartbeat frame: session.write(HeartbeatBody.FRAME); } - else if(IdleStatus.READER_IDLE.equals(status)) + else if (IdleStatus.READER_IDLE.equals(status)) { - //failover: + // failover: throw new IOException("Timed out while waiting for heartbeat from peer."); } @@ -170,22 +169,21 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _logger.error("Error in protocol initiation " + session + ": " + throwable.getMessage(), throwable); } - else if(throwable instanceof IOException) + else if (throwable instanceof IOException) { _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); } else { _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); - + // Be aware of possible changes to parameter order as versions change. - protocolSession.write(ConnectionCloseBody.createAMQFrame(0, - session.getProtocolMajorVersion(), - session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - 200, // replyCode - new AMQShortString(throwable.getMessage()) // replyText + protocolSession.write(ConnectionCloseBody.createAMQFrame(0, session.getProtocolMajorVersion(), + session.getProtocolMinorVersion(), // AMQP version (major, minor) + 0, // classId + 0, // methodId + 200, // replyCode + new AMQShortString(throwable.getMessage()) // replyText )); protocolSession.close(); } @@ -212,7 +210,8 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter } else { - throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); + throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + + message); } } @@ -230,11 +229,11 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _logger.debug("Message sent: " + object); } } - - protected boolean isSSLClient(ConnectorConfiguration connectionConfig, - IoSession protocolSession) + + protected boolean isSSLClient(ConnectorConfiguration connectionConfig, IoSession protocolSession) { - InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); - return addr.getPort() == connectionConfig.sslPort; + InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); + + return addr.getPort() == connectionConfig.sslPort; } } -- cgit v1.2.1 From 1d23b9ec5e7296aecefe94a532a9f22dfb5fa5bb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 15 Jun 2007 16:28:46 +0000 Subject: Merged revisions 439476-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-531858,531860-531864,531866-531907,531909-531916,531918-531936,531938-531988,531990-532001,532003-532371,532373-532465,532467-532727,532729-532765,532767-532785,532788-532790,532792-532793,532795-533064,533066-533074,533076,533080-533130,533132-533139,533142-533703,533705-533720,533722-533763,533766-533818,533820-533839,533841-533859,533862-534035,534037-534112,534114-534116,534118-534472,534474-534477,534479-534762,534764-534896,534898-534902,534904-535253,535255-535308,535310-535808,535810-535873,535875-536007,536009-536140,536142-536162,536165-536242,536244-536252,536254-536278,536280-536338,536340-536448,536450-536479,536481-536482,536484-536485,536487-536495,536497,536500-536505,536507-536561,536563-536570,536572,536574-536583,536586-536823,536825-537014,537016-537018,537020-537025,537027-537028,537030-537160,537162-537170,537172-537672,537674-537781,537783-537833,537836-537840,537842-537844,537846-537953,537955-538034,538036-538078,538080-538083,538085-538097,538099-538108,538110-538239,538241-538881,538883-538906,538908-538911,538913-538921,538923-539177,539179-539190,539192-539475,539477-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541919,541921-544507,544509-544865,544867-545145,545147-547177,547179-547627 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r539470 | ritchiem | 2007-05-18 14:50:59 +0100 (Fri, 18 May 2007) | 1 line QPID-401 Integrated python tests with maven tested on windows CMD.exe and linux FC5 ........ r539481 | ritchiem | 2007-05-18 15:30:06 +0100 (Fri, 18 May 2007) | 1 line QPID-401 Update to allow -Dskip-python-tests to disable python checking ........ r539484 | ritchiem | 2007-05-18 15:35:13 +0100 (Fri, 18 May 2007) | 1 line QPID-401 Update to allow -Dskip-python-tests to disable python checking ........ r541247 | rgodfrey | 2007-05-24 10:57:00 +0100 (Thu, 24 May 2007) | 1 line QPID-482 : Small performance tweaks ........ r542484 | rupertlssmith | 2007-05-29 11:52:29 +0100 (Tue, 29 May 2007) | 1 line Can now pass property to skip python tests, set in settings.xml ........ r542789 | ritchiem | 2007-05-30 11:09:28 +0100 (Wed, 30 May 2007) | 1 line Update to ensure fastinstall profile skips the broker python tests. ........ r543496 | rupertlssmith | 2007-06-01 15:33:07 +0100 (Fri, 01 Jun 2007) | 1 line QPID-402: FailoverException falling through to client. All blocking operations now wrapped in failover support wrappers. ........ r544109 | ritchiem | 2007-06-04 10:47:53 +0100 (Mon, 04 Jun 2007) | 7 lines Addition of a sustained test client. This is currently setup for running a pub/sub test. The test allows for multiple clients to connect and participate in testing the broker throughput. A single producer continually sends messages to a topic which the clients then send batched results back about. The producer uses the timings in the reports to update the rate at which it sends messages. Ideally reaching a steady state where all messages produced are received by everyone within a specified time frame. ........ r544422 | ritchiem | 2007-06-05 09:50:54 +0100 (Tue, 05 Jun 2007) | 1 line Added documentation on how to run the sustained tests. ........ r546096 | rupertlssmith | 2007-06-11 12:23:08 +0100 (Mon, 11 Jun 2007) | 1 line Set up top dir location and path to parent pom. Needed in preparation for deploy and release plugins. ........ r546190 | rupertlssmith | 2007-06-11 17:43:57 +0100 (Mon, 11 Jun 2007) | 1 line Removed log4j dependency from client. Using slf4j instead, end-user to supply logging implementation as desired. Log4j used for tests. ........ r546441 | rupertlssmith | 2007-06-12 10:52:29 +0100 (Tue, 12 Jun 2007) | 1 line QPID-465, now throws UnsupportedOperationException when sending to a null queue in QueueSender. ........ r546458 | ritchiem | 2007-06-12 12:41:17 +0100 (Tue, 12 Jun 2007) | 1 line Added repository info for running mvn rat:check ........ r547627 | ritchiem | 2007-06-15 12:21:40 +0100 (Fri, 15 Jun 2007) | 1 line QPID-511 adjusted to use the ReadWriteThreadModel rather than setting editing the filterChain directly which could cause problems when using an InVM transport due to the way the InVM transport alters the filter chain during a connect call. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@547730 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 8 ++++++-- .../amqp0_8/ProtocolOutputConverterImpl.java | 18 ++++++------------ .../queue/ConcurrentSelectorDeliveryManager.java | 22 ++++++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 6f970730ec..29ea69caf7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -24,6 +24,7 @@ import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.BindException; import java.util.Collection; import java.util.List; import org.apache.commons.cli.CommandLine; @@ -171,7 +172,8 @@ public class Main } else if (commandLine.hasOption("v")) { - String ver = "Qpid 0.9.0.0"; + String ver = QpidProperties.getVersionString(); + StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: "); boolean first = true; @@ -357,7 +359,7 @@ public class Main * @todo Partially implements top-level error handler. Better to let these errors fall through to a single * top-level handler. */ - protected void bind(int port, ConnectorConfiguration connectorConfig) + protected void bind(int port, ConnectorConfiguration connectorConfig) throws BindException { String bindAddr = commandLine.getOptionValue("b"); if (bindAddr == null) @@ -425,6 +427,8 @@ public class Main catch (Exception e) { _logger.error("Unable to bind service to registry: " + e, e); + //fixme this need tidying up + throw new BindException(e.getMessage()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index 28b2489142..8462ed9557 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -182,10 +182,8 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter deliveryTag, pb.getExchange(), messageHandle.isRedelivered(), pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; + + return deliverFrame.toByteBuffer(); } private ByteBuffer createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) @@ -201,10 +199,8 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter queueSize, messageHandle.isRedelivered(), pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? - getOkFrame.writePayload(buf); - buf.flip(); - return buf; + + return getOkFrame.toByteBuffer(); } public byte getProtocolMinorVersion() @@ -225,10 +221,8 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter message.getMessagePublishInfo().getExchange(), replyCode, replyText, message.getMessagePublishInfo().getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? - returnFrame.writePayload(buf); - buf.flip(); - return buf; + + return returnFrame.toByteBuffer(); } public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 0fb5e6d88a..2aa759b35d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -717,7 +717,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException { - if (_log.isDebugEnabled()) + + final boolean debugEnabled = _log.isDebugEnabled(); + if (debugEnabled) { _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); } @@ -732,7 +734,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (s == null) //no-one can take the message right now. { - if (_log.isDebugEnabled()) + if (debugEnabled) { _log.debug(debugIdentity() + "Testing Message(" + msg + ") for Queued Delivery:" + currentStatus()); } @@ -744,7 +746,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _lock.unlock(); //Pre Deliver to all subscriptions - if (_log.isDebugEnabled()) + if (debugEnabled) { _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() + " subscribers to give the message to:" + currentStatus()); @@ -755,7 +757,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // stop if the message gets delivered whilst PreDelivering if we have a shared queue. if (_queue.isShared() && msg.getDeliveredToConsumer()) { - if (_log.isDebugEnabled()) + if (debugEnabled) { _log.debug(debugIdentity() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + ") is already delivered."); @@ -766,7 +768,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // Only give the message to those that want them. if (sub.hasInterest(msg)) { - if (_log.isDebugEnabled()) + if (debugEnabled) { _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(msg) + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); @@ -795,9 +797,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else { - if (_log.isInfoEnabled()) + if (debugEnabled) { - _log.info(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + + _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); } } @@ -805,9 +807,9 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (!msg.isTaken(_queue)) { - if (_log.isInfoEnabled()) + if (debugEnabled) { - _log.info(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + + _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + " Subscriber:" + System.identityHashCode(s)); } @@ -815,7 +817,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else { - if (_log.isDebugEnabled()) + if (debugEnabled) { _log.debug(debugIdentity() + " Message(" + msg.toString() + ") has been taken so disregarding deliver request to Subscriber:" + -- cgit v1.2.1 From 8c8ee073330c02ba451a7a1a57e7da7110e4d8c0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 18 Jun 2007 16:29:49 +0000 Subject: Merged revisions 539476-539480,539482-539483,539485-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541246,541248-541919,541921-542483,542485-542788,542790-543495,543497-544108,544110-544421,544423-544507,544509-546095,546097-546189,546191-546440,546442-546457,546459-547177,547179-547626,547628-548381 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r539476 | ritchiem | 2007-05-18 15:12:28 +0100 (Fri, 18 May 2007) | 1 line QPID-401 Update to pom to correctly set the broker.dir ........ r544866 | rupertlssmith | 2007-06-06 16:25:02 +0100 (Wed, 06 Jun 2007) | 1 line Updated examples to build source jar. Also put the java14 retrotranslated module back in now that the strange repeating build problem is solved. ........ r545146 | ritchiem | 2007-06-07 12:30:01 +0100 (Thu, 07 Jun 2007) | 1 line POM update renumbering tests now we have trimmed down the tests being run. ........ r548276 | ritchiem | 2007-06-18 10:59:32 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates. ........ r548279 | ritchiem | 2007-06-18 11:17:20 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates. ........ r548302 | ritchiem | 2007-06-18 11:49:50 +0100 (Mon, 18 Jun 2007) | 2 lines Various License header updates. Update to PrincipalDatabase's to ensure they work correctly with # comments. ........ r548308 | ritchiem | 2007-06-18 11:58:38 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates, missed this file. Though the first update of it via the JMX console will remove the license. ........ r548312 | rupertlssmith | 2007-06-18 12:03:09 +0100 (Mon, 18 Jun 2007) | 1 line Added SLF4J to Log4J binding. ........ r548315 | ritchiem | 2007-06-18 12:07:45 +0100 (Mon, 18 Jun 2007) | 1 line Old lib dir from M1 ........ r548317 | ritchiem | 2007-06-18 12:13:57 +0100 (Mon, 18 Jun 2007) | 1 line Old lib dirs from M1 ........ r548319 | ritchiem | 2007-06-18 12:16:25 +0100 (Mon, 18 Jun 2007) | 1 line Mistakenly checked in Intelij file ........ r548381 | ritchiem | 2007-06-18 16:37:41 +0100 (Mon, 18 Jun 2007) | 1 line QPID-525 Memory leak in DestWildExchange. Used routing key in remove rather than empty queue ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@548400 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/DestWildExchange.java | 3 +-- .../qpid/server/exchange/FanoutExchange.java | 21 ++++++++++++++++++++ .../qpid/server/handler/BasicGetMethodHandler.java | 21 ++++++++++++++++++++ .../qpid/server/handler/QueuePurgeHandler.java | 21 ++++++++++++++++++++ .../qpid/server/management/MBeanAttribute.java | 23 ++++++++++++++++++++-- .../qpid/server/management/MBeanConstructor.java | 23 ++++++++++++++++++++-- .../qpid/server/management/MBeanDescription.java | 23 ++++++++++++++++++++-- .../qpid/server/management/MBeanOperation.java | 23 ++++++++++++++++++++-- .../server/management/MBeanOperationParameter.java | 23 ++++++++++++++++++++-- .../security/access/AMQUserManagementMBean.java | 2 +- .../PlainPasswordFilePrincipalDatabase.java | 15 +++++++------- .../PlainPasswordVhostFilePrincipalDatabase.java | 8 ++++---- 12 files changed, 181 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 25ec0c3a2d..222e341b1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -222,7 +222,6 @@ public class DestWildExchange extends AbstractExchange { _logger.warn("No queues found for routing key " + routingKey); _logger.warn("Routing map contains: " + _routingKey2queues); - //todo Check for valid topic - mritchie return; } } @@ -288,7 +287,7 @@ public class DestWildExchange extends AbstractExchange } if (queues.isEmpty()) { - _routingKey2queues.remove(queues); + _routingKey2queues.remove(routingKey); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 28d4b19f2e..6148fd4e1c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.exchange; import java.util.concurrent.CopyOnWriteArraySet; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index b88c2ebf3a..782a89c704 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.handler; import org.apache.log4j.Logger; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index 0c00436470..3e1937bb43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java index 3b5db7d6c7..7d42297699 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.management; import java.lang.annotation.ElementType; @@ -9,8 +30,6 @@ import java.lang.annotation.Target; /** * 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) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java index 7a600005e2..9138e03085 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.management; import java.lang.annotation.ElementType; @@ -8,8 +29,6 @@ import java.lang.annotation.Target; /** * Annotation for MBean constructors. - * @author Bhupendra Bhardwaj - * @version 0.1 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.CONSTRUCTOR) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java index 97717662dd..448fed3280 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.management; import java.lang.annotation.ElementType; @@ -8,8 +29,6 @@ import java.lang.annotation.Target; /** * Annotation for MBean class. - * @author Bhupendra Bhardwaj - * @version 0.1 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java index f94be2f42f..a2dca3e51d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.management; import java.lang.annotation.ElementType; @@ -10,8 +31,6 @@ import javax.management.MBeanOperationInfo; /** * Annotation for MBean operations. - * @author Bhupendra Bhardwaj - * @version 0.1 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java index ad03b740ab..aba5ec70d8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -1,3 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + package org.apache.qpid.server.management; import java.lang.annotation.ElementType; @@ -7,8 +28,6 @@ import java.lang.annotation.Target; /** * Annotation for MBean operation parameters. - * @author Bhupendra Bhardwaj - * @version 0.1 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java index 155afa961e..2dc7fcbc1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -414,7 +414,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana rights.renameTo(old); FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Last edited by user:" + getCurrentJMXUser()); + _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); output.close(); // Rename new file to main file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index c49f4e2a33..b29ea66bfc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -29,18 +29,17 @@ import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.BufferedReader; import java.io.FileReader; -import java.io.UnsupportedEncodingException; -import java.util.regex.Pattern; -import java.util.Map; +import java.io.IOException; +import java.security.Principal; import java.util.HashMap; -import java.util.List; import java.util.LinkedList; -import java.security.Principal; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; /** * Represents a user database where the account information is stored in a simple flat file. @@ -212,7 +211,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase reader = new BufferedReader(new FileReader(_passwordFile)); String line; - while ((line = reader.readLine()) != null) + while ((line = reader.readLine()) != null && !line.startsWith("#")) { String[] result = _regexp.split(line); if (result == null || result.length < 2) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java index 598f8f8b4c..f4f3385c75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -20,17 +20,17 @@ */ package org.apache.qpid.server.security.auth.database; +import org.apache.log4j.Logger; import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.access.AccessRights; +import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.log4j.Logger; -import java.io.IOException; import java.io.BufferedReader; import java.io.FileReader; +import java.io.IOException; import java.security.Principal; /** @@ -61,7 +61,7 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr reader = new BufferedReader(new FileReader(_passwordFile)); String line; - while ((line = reader.readLine()) != null) + while ((line = reader.readLine()) != null && !line.startsWith("#")) { String[] result = _regexp.split(line); if (result == null || result.length < 3) -- cgit v1.2.1 From b2c634a7f67a5f480d0e4c5a449662627ab62497 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 20 Jun 2007 09:20:24 +0000 Subject: Merged revisions 549011 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r549011 | ritchiem | 2007-06-20 10:12:43 +0100 (Wed, 20 Jun 2007) | 1 line Proper update to PrincipalDatabase's to ensure they work correctly with # comments. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@549016 13f79535-47bb-0310-9956-ffa450edef68 --- .../PlainPasswordFilePrincipalDatabase.java | 21 ++++++++++++--------- .../PlainPasswordVhostFilePrincipalDatabase.java | 19 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index b29ea66bfc..352d41a0ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -211,17 +211,20 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase reader = new BufferedReader(new FileReader(_passwordFile)); String line; - while ((line = reader.readLine()) != null && !line.startsWith("#")) + while ((line = reader.readLine()) != null) { - String[] result = _regexp.split(line); - if (result == null || result.length < 2) + if (!line.startsWith("#")) { - continue; - } - - if (name.equals(result[0])) - { - return result[1].toCharArray(); + String[] result = _regexp.split(line); + if (result == null || result.length < 2) + { + continue; + } + + if (name.equals(result[0])) + { + return result[1].toCharArray(); + } } } return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java index f4f3385c75..5c372f6c2c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -61,17 +61,20 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr reader = new BufferedReader(new FileReader(_passwordFile)); String line; - while ((line = reader.readLine()) != null && !line.startsWith("#")) + while ((line = reader.readLine()) != null) { - String[] result = _regexp.split(line); - if (result == null || result.length < 3) + if (!line.startsWith("#")) { - continue; - } + String[] result = _regexp.split(line); + if (result == null || result.length < 3) + { + continue; + } - if (user.equals(result[0])) - { - return result[2].split(","); + if (user.equals(result[0])) + { + return result[2].split(","); + } } } return null; -- cgit v1.2.1 From 810d80bbafb2b4826710a3e9388df89adfa220af Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 27 Jun 2007 15:34:57 +0000 Subject: Merged revisions 549530-550509 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r549530 | rupertlssmith | 2007-06-21 17:14:03 +0100 (Thu, 21 Jun 2007) | 1 line Added minimal checkstyle to project reports. Fixed some problems with site generation. ........ r549849 | rupertlssmith | 2007-06-22 16:39:27 +0100 (Fri, 22 Jun 2007) | 1 line Added Immediate and Mandatory message tests. ........ r550509 | ritchiem | 2007-06-25 15:16:30 +0100 (Mon, 25 Jun 2007) | 1 line Update to provide a SustainedTestCase, this sends batches of messages to the broker. The rate of publication is regulated by the average consume rate advertised by all connected clients. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@551199 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/txn/CleanupMessageOperation.java | 51 +++++++------- .../qpid/server/txn/LocalTransactionalContext.java | 82 +++++++++++++--------- 2 files changed, 73 insertions(+), 60 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java index 609a85c22f..988f589339 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -1,31 +1,35 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server.txn; -import java.util.List; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.NoConsumersException; import org.apache.qpid.server.store.StoreContext; +import java.util.List; + /** * @author Apache Software Foundation */ @@ -44,33 +48,26 @@ public class CleanupMessageOperation implements TxnOp } public void prepare(StoreContext context) 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 + // 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(StoreContext context) { - - try + // No-op can't be done here has this is before the message has been attempted to be delivered. + /*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(StoreContext context) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 93459beb45..4e684098d0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -1,26 +1,27 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server.txn; -import java.util.LinkedList; -import java.util.List; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.ack.TxAck; @@ -28,9 +29,13 @@ import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.NoConsumersException; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; +import java.util.LinkedList; +import java.util.List; + /** A transactional context that only supports local transactions. */ public class LocalTransactionalContext implements TransactionalContext { @@ -54,6 +59,7 @@ public class LocalTransactionalContext implements TransactionalContext private boolean _inTran = false; + /** Are there messages to deliver. NOT Has the message been delivered */ private boolean _messageDelivered = false; private static class DeliveryDetails @@ -62,7 +68,6 @@ public class LocalTransactionalContext implements TransactionalContext public AMQQueue queue; private boolean deliverFirst; - public DeliveryDetails(AMQMessage message, AMQQueue queue, boolean deliverFirst) { this.message = message; @@ -72,15 +77,14 @@ public class LocalTransactionalContext implements TransactionalContext } public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, - List returnMessages) + List returnMessages) { _messageStore = messageStore; _storeContext = storeContext; _returnMessages = returnMessages; - //_txnBuffer.enlist(new StoreMessageOperation(messageStore)); + // _txnBuffer.enlist(new StoreMessageOperation(messageStore)); } - public StoreContext getStoreContext() { return _storeContext; @@ -90,11 +94,12 @@ public class LocalTransactionalContext implements TransactionalContext { _txnBuffer.rollback(_storeContext); // Hack to deal with uncommitted non-transactional writes - if(_messageStore.inTran(_storeContext)) + if (_messageStore.inTran(_storeContext)) { _messageStore.abortTran(_storeContext); _inTran = false; } + _postCommitDeliveryList.clear(); } @@ -106,7 +111,7 @@ public class LocalTransactionalContext implements TransactionalContext // 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. -// message.incrementReference(); + // message.incrementReference(); _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); _messageDelivered = true; _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); @@ -119,7 +124,7 @@ public class LocalTransactionalContext implements TransactionalContext message.incrementReference(); _messageDelivered = true; - */ + */ } private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException @@ -131,16 +136,16 @@ public class LocalTransactionalContext implements TransactionalContext } public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException { - //check that the tag exists to give early failure - if (!multiple || deliveryTag > 0) + // 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. + // 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) { beginTranIfNecessary(); @@ -148,7 +153,7 @@ public class LocalTransactionalContext implements TransactionalContext _txnBuffer.enlist(_ackOp); } // update the op to include this ack request - if (multiple && deliveryTag == 0) + if (multiple && (deliveryTag == 0)) { // if have signalled to ack all, that refers only // to all at this time @@ -178,6 +183,7 @@ public class LocalTransactionalContext implements TransactionalContext { _log.debug("Starting transaction on message store: " + this); } + _messageStore.beginTran(_storeContext); _inTran = true; } @@ -189,12 +195,13 @@ public class LocalTransactionalContext implements TransactionalContext { _log.debug("Committing transactional context: " + this); } + if (_ackOp != null) { _messageDelivered = true; _ackOp.consolidate(); - //already enlisted, after commit will reset regardless of outcome + // already enlisted, after commit will reset regardless of outcome _ackOp = null; } @@ -202,7 +209,7 @@ public class LocalTransactionalContext implements TransactionalContext { _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); } - //fixme fail commit here ... QPID-440 + // fixme fail commit here ... QPID-440 try { _txnBuffer.commit(_storeContext); @@ -215,7 +222,7 @@ public class LocalTransactionalContext implements TransactionalContext try { - postCommitDelivery(); + postCommitDelivery(_returnMessages); } catch (AMQException e) { @@ -224,23 +231,32 @@ public class LocalTransactionalContext implements TransactionalContext } } - private void postCommitDelivery() throws AMQException + private void postCommitDelivery(List returnMessages) throws AMQException { if (_log.isDebugEnabled()) { _log.debug("Performing post commit delivery"); } + try { for (DeliveryDetails dd : _postCommitDeliveryList) { dd.queue.process(_storeContext, dd.message, dd.deliverFirst); + + try + { + dd.message.checkDeliveredToConsumer(); + } + catch (NoConsumersException nce) + { + returnMessages.add(nce); + } } } finally { _postCommitDeliveryList.clear(); } - } } -- cgit v1.2.1 From d04f3d35696e5ba66fd383828449fb81824646a0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 27 Jun 2007 15:49:51 +0000 Subject: Merged revisions 550748-551121 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r550748 | ritchiem | 2007-06-26 10:20:17 +0100 (Tue, 26 Jun 2007) | 1 line Added xml file for logging during sustained tests ........ r550773 | rupertlssmith | 2007-06-26 12:03:04 +0100 (Tue, 26 Jun 2007) | 1 line Immediate and mandatory flag tests added. ........ r550849 | rupertlssmith | 2007-06-26 17:43:58 +0100 (Tue, 26 Jun 2007) | 1 line QPID-509 Mandatory messages not returned outside a transaction. They are now. ........ r551117 | ritchiem | 2007-06-27 11:51:34 +0100 (Wed, 27 Jun 2007) | 2 lines Update to the sustained test to ensure late joining occurs correctly and improved stabilisation. Additional system properties now documented on wiki. http://cwiki.apache.org/qpid/sustained-tests.html ........ r551118 | ritchiem | 2007-06-27 11:51:51 +0100 (Wed, 27 Jun 2007) | 1 line Added intelij files to ignore list ........ r551119 | ritchiem | 2007-06-27 11:55:34 +0100 (Wed, 27 Jun 2007) | 1 line POM update to add Apache content to built jars ........ r551120 | ritchiem | 2007-06-27 11:58:25 +0100 (Wed, 27 Jun 2007) | 1 line Updated default guest password as it was not correct. ........ r551121 | ritchiem | 2007-06-27 12:00:48 +0100 (Wed, 27 Jun 2007) | 1 line Added additional information to log message when available to aid the explination of a failed connection ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@551207 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 25 ++-- .../qpid/server/exchange/DestNameExchange.java | 2 +- .../qpid/server/exchange/DestWildExchange.java | 94 ++++++++------ .../qpid/server/exchange/FanoutExchange.java | 71 +++++------ .../qpid/server/exchange/HeadersExchange.java | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 139 ++++++++++----------- .../org/apache/qpid/server/queue/AMQQueue.java | 14 ++- 7 files changed, 183 insertions(+), 164 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 43a04dbfa1..28a9e85489 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,18 +20,9 @@ */ package org.apache.qpid.server; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentBody; @@ -52,6 +43,16 @@ import org.apache.qpid.server.queue.Subscription; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + public class AMQChannel { public static final int DEFAULT_PREFETCH = 5000; @@ -208,7 +209,8 @@ public class AMQChannel _currentMessage.setPublisher(publisher); } - public void publishContentHeader(ContentHeaderBody contentHeaderBody) throws AMQException + public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession) + throws AMQException { if (_currentMessage == null) { @@ -230,6 +232,7 @@ public class AMQChannel // check and deliver if header says body length is zero if (contentHeaderBody.bodySize == 0) { + _txnContext.messageProcessed(protocolSession); _currentMessage = null; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 01242f90de..0dcceaddbb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -169,7 +169,7 @@ public class DestNameExchange extends AbstractExchange if (queues == null || queues.isEmpty()) { String msg = "Routing key " + routingKey + " is not known to " + this; - if (info.isMandatory()) + if (info.isMandatory() || info.isImmediate()) { throw new NoRouteException(msg, payload, null); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 222e341b1a..f6a95b5e55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -20,13 +20,18 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.LinkedList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; @@ -41,24 +46,21 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +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>(); - // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); + private ConcurrentHashMap> _routingKey2queues = + new ConcurrentHashMap>(); + // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); private static final String TOPIC_SEPARATOR = "."; private static final String AMQP_STAR = "*"; private static final String AMQP_HASH = "#"; @@ -90,7 +92,7 @@ public class DestWildExchange extends AbstractExchange queueList.add(q.getName().toString()); } - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + Object[] bindingItemValues = { key.toString(), queueList.toArray(new String[0]) }; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -118,7 +120,6 @@ public class DestWildExchange extends AbstractExchange } // End of MBean class - public AMQShortString getType() { return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; @@ -140,6 +141,7 @@ public class DestWildExchange extends AbstractExchange { queueList = _routingKey2queues.get(routingKey); } + if (!queueList.contains(queue)) { queueList.add(queue); @@ -165,8 +167,8 @@ public class DestWildExchange extends AbstractExchange for (int index = 0; index < size; index++) { - //if there are more levels - if (index + 1 < size) + // if there are more levels + if ((index + 1) < size) { if (_subscription.get(index).equals(AMQP_HASH)) { @@ -175,7 +177,7 @@ public class DestWildExchange extends AbstractExchange // we don't need #.# delete this one _subscription.remove(index); size--; - //redo this normalisation + // redo this normalisation index--; } @@ -186,7 +188,7 @@ public class DestWildExchange extends AbstractExchange _subscription.add(index + 1, _subscription.remove(index)); } } - }//if we have more levels + } // if we have more levels } StringBuilder sb = new StringBuilder(); @@ -211,9 +213,9 @@ public class DestWildExchange extends AbstractExchange List queues = getMatchedQueues(routingKey); // if we have no registered queues we have nothing to do // TODO: add support for the immediate flag - if (queues == null || queues.size() == 0) + if ((queues == null) || queues.isEmpty()) { - if (info.isMandatory()) + if (info.isMandatory() || info.isImmediate()) { String msg = "Topic " + routingKey + " is not known to " + this; throw new NoRouteException(msg, payload, null); @@ -222,6 +224,7 @@ public class DestWildExchange extends AbstractExchange { _logger.warn("No queues found for routing key " + routingKey); _logger.warn("Routing map contains: " + _routingKey2queues); + return; } } @@ -238,14 +241,15 @@ public class DestWildExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { List queues = _routingKey2queues.get(normalize(routingKey)); - return queues != null && queues.contains(queue); - } + return (queues != null) && queues.contains(queue); + } public boolean isBound(AMQShortString routingKey) throws AMQException { List queues = _routingKey2queues.get(normalize(routingKey)); - return queues != null && !queues.isEmpty(); + + return (queues != null) && !queues.isEmpty(); } public boolean isBound(AMQQueue queue) throws AMQException @@ -257,6 +261,7 @@ public class DestWildExchange extends AbstractExchange return true; } } + return false; } @@ -279,12 +284,14 @@ public class DestWildExchange extends AbstractExchange " with routing key " + routingKey + ". No queue was registered with that routing key", null); } + boolean removedQ = queues.remove(queue); if (!removedQ) { throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + " with routing key " + routingKey, null); } + if (queues.isEmpty()) { _routingKey2queues.remove(routingKey); @@ -304,7 +311,6 @@ public class DestWildExchange extends AbstractExchange } } - private List getMatchedQueues(AMQShortString routingKey) { List list = new LinkedList(); @@ -334,7 +340,6 @@ public class DestWildExchange extends AbstractExchange queueList.add(queTok.nextToken()); } - int depth = 0; boolean matching = true; boolean done = false; @@ -343,25 +348,26 @@ public class DestWildExchange extends AbstractExchange while (matching && !done) { - if (queueList.size() == depth + queueskip || routingkeyList.size() == depth + routingskip) + if ((queueList.size() == (depth + queueskip)) || (routingkeyList.size() == (depth + routingskip))) { done = true; // if it was the routing key that ran out of digits - if (routingkeyList.size() == depth + routingskip) + if (routingkeyList.size() == (depth + routingskip)) { if (queueList.size() > (depth + queueskip)) - { // a hash and it is the last entry - matching = queueList.get(depth + queueskip).equals(AMQP_HASH) && queueList.size() == depth + queueskip + 1; + { // a hash and it is the last entry + matching = + queueList.get(depth + queueskip).equals(AMQP_HASH) + && (queueList.size() == (depth + queueskip + 1)); } } - else if (routingkeyList.size() > depth + routingskip) + else if (routingkeyList.size() > (depth + routingskip)) { // There is still more routing key to check matching = false; } - continue; } @@ -377,27 +383,33 @@ public class DestWildExchange extends AbstractExchange else if (queueList.get(depth + queueskip).equals(AMQP_HASH)) { // Is this a # at the end - if (queueList.size() == depth + queueskip + 1) + if (queueList.size() == (depth + queueskip + 1)) { done = true; + continue; } // otherwise # in the middle - while (routingkeyList.size() > depth + routingskip) + while (routingkeyList.size() > (depth + routingskip)) { if (routingkeyList.get(depth + routingskip).equals(queueList.get(depth + queueskip + 1))) { queueskip++; depth++; + break; } + routingskip++; } + continue; } + matching = false; } + depth++; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 6148fd4e1c..bf00eeb9d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -1,27 +1,36 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ - package org.apache.qpid.server.exchange; -import java.util.concurrent.CopyOnWriteArraySet; +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; @@ -36,16 +45,7 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; +import java.util.concurrent.CopyOnWriteArraySet; public class FanoutExchange extends AbstractExchange { @@ -63,7 +63,7 @@ public class FanoutExchange extends AbstractExchange private final class FanoutExchangeMBean extends ExchangeMBean { @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException + public FanoutExchangeMBean() throws JMException { super(); _exchangeType = "fanout"; @@ -79,9 +79,7 @@ public class FanoutExchange extends AbstractExchange { String queueName = queue.getName().toString(); - - - Object[] bindingItemValues = {queueName, new String[] {queueName}}; + Object[] bindingItemValues = { queueName, new String[] { queueName } }; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -98,7 +96,7 @@ public class FanoutExchange extends AbstractExchange } try - { + { queue.bind(new AMQShortString(binding), null, FanoutExchange.this); } catch (AMQException ex) @@ -107,8 +105,7 @@ public class FanoutExchange extends AbstractExchange } } - }// End of MBean class - + } // End of MBean class protected ExchangeMBean createMBean() throws AMQException { @@ -147,7 +144,6 @@ public class FanoutExchange extends AbstractExchange { assert queue != null; - if (!_queues.remove(queue)) { throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + @@ -159,10 +155,10 @@ public class FanoutExchange extends AbstractExchange { final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); final AMQShortString routingKey = publishInfo.getRoutingKey(); - if (_queues == null || _queues.isEmpty()) + if ((_queues == null) || _queues.isEmpty()) { String msg = "No queues bound to " + this; - if (publishInfo.isMandatory()) + if (publishInfo.isMandatory() || publishInfo.isImmediate()) { throw new NoRouteException(msg, payload, null); } @@ -193,13 +189,12 @@ public class FanoutExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey) throws AMQException { - return _queues != null && !_queues.isEmpty(); + return (_queues != null) && !_queues.isEmpty(); } public boolean isBound(AMQQueue queue) throws AMQException { - return _queues.contains(queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 8205924207..e86094e26f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -229,7 +229,7 @@ public class HeadersExchange extends AbstractExchange String msg = "Exchange " + getName() + ": message not routable."; - if (payload.getMessagePublishInfo().isMandatory()) + if (payload.getMessagePublishInfo().isMandatory() || payload.getMessagePublishInfo().isImmediate()) { throw new NoRouteException(msg, payload, null); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 82e969b496..c9f5e42286 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,24 +20,13 @@ */ package org.apache.qpid.server.protocol; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.security.Principal; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; - import org.apache.log4j.Logger; + import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoServiceConfig; import org.apache.mina.common.IoSession; import org.apache.mina.transport.vmpipe.VmPipeAddress; + import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; @@ -46,22 +35,34 @@ import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.*; import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -public class AMQMinaProtocolSession implements AMQProtocolSession, - Managable +import javax.management.JMException; +import javax.security.sasl.SaslServer; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); @@ -111,25 +112,20 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private ProtocolOutputConverter _protocolOutputConverter; private Principal _authorizedID; - public ManagedObject getManagedObject() { return _managedObject; } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, - AMQCodecFactory codecFactory) - throws AMQException + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) + throws AMQException { _stateManager = new AMQStateManager(virtualHostRegistry, this); _minaProtocolSession = session; session.setAttachment(this); - _codecFactory = codecFactory; - try { IoServiceConfig config = session.getServiceConfig(); @@ -140,16 +136,15 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, catch (RuntimeException e) { e.printStackTrace(); - // throw e; + // throw e; } -// this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); + // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); } - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, - AMQCodecFactory codecFactory, AMQStateManager stateManager) - throws AMQException + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, + AMQStateManager stateManager) throws AMQException { _stateManager = stateManager; _minaProtocolSession = session; @@ -182,8 +177,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return (AMQProtocolSession) minaProtocolSession.getAttachment(); } - public void dataBlockReceived(AMQDataBlock message) - throws Exception + public void dataBlockReceived(AMQDataBlock message) throws Exception { _lastReceived = message; if (message instanceof ProtocolInitiation) @@ -203,8 +197,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, } } - private void frameReceived(AMQFrame frame) - throws AMQException + private void frameReceived(AMQFrame frame) throws AMQException { int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); @@ -252,13 +245,13 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, String locales = "en_US"; // Interfacing with generated code - be aware of possible changes to parameter order as versions change. - AMQFrame response = ConnectionStartBody.createAMQFrame((short) 0, - getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor) - locales.getBytes(), // locales - mechanisms.getBytes(), // mechanisms - null, // serverProperties - (short) getProtocolMajorVersion(), // versionMajor - (short) getProtocolMinorVersion()); // versionMinor + AMQFrame response = + ConnectionStartBody.createAMQFrame((short) 0, getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor) + locales.getBytes(), // locales + mechanisms.getBytes(), // mechanisms + null, // serverProperties + (short) getProtocolMajorVersion(), // versionMajor + (short) getProtocolMinorVersion()); // versionMinor _minaProtocolSession.write(response); } catch (AMQException e) @@ -269,21 +262,19 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, // TODO: Close connection (but how to wait until message is sent?) // ritchiem 2006-12-04 will this not do? -// WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); -// future.join(); -// close connection + // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); + // future.join(); + // close connection } } - private void methodFrameReceived(int channelId, AMQMethodBody methodBody) { - final AMQMethodEvent evt = new AMQMethodEvent(channelId, - methodBody); + final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); - //Check that this channel is not closing + // Check that this channel is not closing if (channelAwaitingClosure(channelId)) { if ((evt.getMethod() instanceof ChannelCloseOkBody)) @@ -299,11 +290,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.info("Channel[" + channelId + "] awaiting closure ignoring"); } + return; } } - try { try @@ -315,10 +306,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { for (AMQMethodListener listener : _frameListeners) { - wasAnyoneInterested = listener.methodReceived(evt) || - wasAnyoneInterested; + wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; } } + if (!wasAnyoneInterested) { throw new AMQNoMethodHandlerException(evt, null); @@ -332,6 +323,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.info("Closing channel due to: " + e.getMessage()); } + writeFrame(e.getCloseFrame(channelId)); closeChannel(channelId); } @@ -341,14 +333,17 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); } + if (_logger.isInfoEnabled()) { _logger.info("Closing connection due to: " + e.getMessage()); } + closeSession(); - AMQConnectionException ce = evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, - AMQConstant.CHANNEL_ERROR.getName().toString()); + AMQConnectionException ce = + evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); _stateManager.changeState(AMQState.CONNECTION_CLOSING); writeFrame(ce.getCloseFrame(channelId)); @@ -360,6 +355,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _logger.info("Closing connection due to: " + e.getMessage()); } + closeSession(); _stateManager.changeState(AMQState.CONNECTION_CLOSING); writeFrame(e.getCloseFrame(channelId)); @@ -372,17 +368,17 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { listener.error(e); } + _minaProtocolSession.close(); } } - private void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException { AMQChannel channel = getAndAssertChannel(channelId); - channel.publishContentHeader(body); + channel.publishContentHeader(body, this); } @@ -427,15 +423,15 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId, null); } + return channel; } public AMQChannel getChannel(int channelId) throws AMQException { - final AMQChannel channel = ((channelId & CHANNEL_CACHE_SIZE) == channelId) - ? _cachedChannels[channelId] - : _channelMap.get(channelId); - if (channel == null || channel.isClosing()) + final AMQChannel channel = + ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); + if ((channel == null) || channel.isClosing()) { return null; } @@ -466,8 +462,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, if (_channelMap.size() == _maxNoOfChannels) { - String errorMessage = toString() + ": maximum number of channels has been reached (" + - _maxNoOfChannels + "); can't create channel"; + String errorMessage = + toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels + + "); can't create channel"; _logger.error(errorMessage); throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage, null); } @@ -480,6 +477,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _cachedChannels[channelId] = channel; } + checkForNotification(); } @@ -504,7 +502,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void commitTransactions(AMQChannel channel) throws AMQException { - if (channel != null && channel.isTransactional()) + if ((channel != null) && channel.isTransactional()) { channel.commit(); } @@ -512,7 +510,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public void rollbackTransactions(AMQChannel channel) throws AMQException { - if (channel != null && channel.isTransactional()) + if ((channel != null) && channel.isTransactional()) { channel.rollback(); } @@ -597,6 +595,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { channel.close(this); } + _channelMap.clear(); for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) { @@ -615,6 +614,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { _managedObject.unregister(); } + for (Task task : _taskList) { task.doTask(this); @@ -687,6 +687,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, { setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); } + if (_clientProperties.getString(ClientProperties.version.toString()) != null) { _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); @@ -715,7 +716,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public boolean isProtocolVersion(byte major, byte minor) { - return getProtocolMajorVersion() == major && getProtocolMinorVersion() == minor; + return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); } public VersionSpecificRegistry getRegistry() @@ -723,13 +724,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _registry; } - public Object getClientIdentifier() { return _minaProtocolSession.getRemoteAddress(); } - public VirtualHost getVirtualHost() { return _virtualHost; @@ -769,6 +768,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, public String getClientVersion() { - return _clientVersion == null ? null : _clientVersion.toString(); + return (_clientVersion == null) ? null : _clientVersion.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index a803ef1227..6273ac997b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -49,6 +49,16 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.virtualhost.VirtualHost; +import javax.management.JMException; + +import java.text.MessageFormat; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + /** * 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. @@ -607,7 +617,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue delete(); } - public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException + /*public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException { // fixme not sure what this is doing. should we be passing deliverFirst through here? // This code is not used so when it is perhaps it should @@ -623,7 +633,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue // from the queue: dequeue(storeContext, msg); } - } + }*/ // public DeliveryManager getDeliveryManager() // { -- cgit v1.2.1 From 4fbd28b6078d6b3fbfe528a99d6e27963c68f99b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 31 Jul 2007 15:53:37 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-531858,531860-531864,531866-531907,531909-531916,531918-531936,531938-531988,531990-532001,532003-532371,532373-532465,532467-532727,532729-532765,532767-532785,532788-532790,532792-532793,532795-533064,533066-533074,533076,533080-533130,533132-533139,533142-533703,533705-533720,533722-533763,533766-533818,533820-533839,533841-533859,533862-534035,534037-534112,534114-534116,534118-534472,534474-534477,534479-534762,534764-534896,534898-534902,534904-535253,535255-535308,535310-535808,535810-535873,535875-536007,536009-536140,536142-536162,536165-536242,536244-536252,536254-536278,536280-536338,536340-536448,536450-536479,536481-536482,536484-536485,536487-536495,536497,536500-536505,536507-536561,536563-536570,536572,536574-536583,536586-536823,536825-537014,537016-537018,537020-537025,537027-537028,537030-537160,537162-537170,537172-537672,537674-537781,537783-537833,537836-537840,537842-537844,537846-537953,537955-538034,538036-538078,538080-538083,538085-538097,538099-538108,538110-538239,538241-538881,538883-538906,538908-538911,538913-538921,538923-539177,539179-539190,539192-539469,539471-539475,539477-539480,539482-539483,539485-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541246,541248-542483,542485-542788,542790-543495,543497-544108,544110-544421,544423-544507,544509-544865,544867-545145,545147-546095,546097-546189,546191-546440,546442-546457,546459-547177,547179-547626,547628-548275,548277-548278,548280-548301,548303-548307,548309-548311,548313-548314,548316,548318,548320-548380,548382-549010,549012-549529,549531-549848,549850-550508,550510-550747,550749-550772,550774-550848,550850-551116,551122-553446,553448-561282 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r541920 | tomasr | 2007-05-26 18:35:51 +0100 (Sat, 26 May 2007) | 1 line QPID-136 Initial Prefetch Implementation ........ r549112 | arnaudsimon | 2007-06-20 15:11:03 +0100 (Wed, 20 Jun 2007) | 1 line changed setText to use UTF8 as default encoder ........ r551167 | arnaudsimon | 2007-06-27 15:08:50 +0100 (Wed, 27 Jun 2007) | 1 line added public void declareAndBind(AMQDestination amqd) ........ r551174 | ritchiem | 2007-06-27 15:23:21 +0100 (Wed, 27 Jun 2007) | 3 lines Caused each of these tests to run 10 times to help identify any race conditions that were occuring. Updated the CommitRollbackTest to be more robust in the detection of failure. ........ r551175 | ritchiem | 2007-06-27 15:23:52 +0100 (Wed, 27 Jun 2007) | 1 line Allowed more of the constants to be set via system properties. ........ r551176 | ritchiem | 2007-06-27 15:25:13 +0100 (Wed, 27 Jun 2007) | 1 line renamed the passwd programme qpid-passwd to match the change in bin directory. ........ r552441 | rupertlssmith | 2007-07-02 10:23:54 +0100 (Mon, 02 Jul 2007) | 1 line Added log4j as slfj logger for perftests. ........ r552499 | rupertlssmith | 2007-07-02 15:17:45 +0100 (Mon, 02 Jul 2007) | 1 line Added some documentation. ........ r553172 | rupertlssmith | 2007-07-04 12:11:04 +0100 (Wed, 04 Jul 2007) | 1 line Messages moved by management console now commited on the message store. ........ r553248 | ritchiem | 2007-07-04 17:05:55 +0100 (Wed, 04 Jul 2007) | 6 lines Addition of the MessageStore Tool. Small changes to the Exchanges to allow the extraction of currently listed items. Extracted initial broker configuration mechanism to a reusable class. Have modified broker to use it. Move the Passwd.java to new tools package structure on the broker. ........ r553265 | ritchiem | 2007-07-04 17:42:59 +0100 (Wed, 04 Jul 2007) | 1 line Tidied up some extranious logging. ........ r553432 | rupertlssmith | 2007-07-05 10:28:33 +0100 (Thu, 05 Jul 2007) | 1 line Fixed test state carrying over to mandatory message test from immediate. Also added in-vm clean up to other tests. ........ r553480 | ritchiem | 2007-07-05 13:40:50 +0100 (Thu, 05 Jul 2007) | 2 lines Minor changes and tidy up when running via command line. Added Copy command. ........ r553482 | ritchiem | 2007-07-05 13:44:42 +0100 (Thu, 05 Jul 2007) | 2 lines Forgot to compile before committing. Missed a method change in the Select command. ........ r554964 | rupertlssmith | 2007-07-10 15:40:04 +0100 (Tue, 10 Jul 2007) | 1 line Added message copy method. ........ r555249 | rupertlssmith | 2007-07-11 12:52:39 +0100 (Wed, 11 Jul 2007) | 1 line Update perftests to center better around current performance. ........ r556011 | rupertlssmith | 2007-07-13 15:24:03 +0100 (Fri, 13 Jul 2007) | 1 line Moved test framework into its own package and cleaned it up. ........ r556024 | rupertlssmith | 2007-07-13 16:02:06 +0100 (Fri, 13 Jul 2007) | 1 line Completed javadoc for test framework. ........ r556628 | rgodfrey | 2007-07-16 14:50:57 +0100 (Mon, 16 Jul 2007) | 1 line QPID-537 : Make AMQMessage.incrementReference public ........ r556675 | cctrieloff | 2007-07-16 18:36:21 +0100 (Mon, 16 Jul 2007) | 2 lines added notice entries ........ r556680 | cctrieloff | 2007-07-16 18:56:40 +0100 (Mon, 16 Jul 2007) | 2 lines clean up ........ r556682 | cctrieloff | 2007-07-16 18:58:37 +0100 (Mon, 16 Jul 2007) | 2 lines removed optional cppunit as not in distributed packages ........ r556845 | ritchiem | 2007-07-17 09:26:33 +0100 (Tue, 17 Jul 2007) | 3 lines Additional logging in case of broker failure at startup. Use broker logger at error level as well as System.out ........ r556847 | ritchiem | 2007-07-17 09:35:35 +0100 (Tue, 17 Jul 2007) | 3 lines Update to the MessageStore Tool to provide Move and Purge functionality. Updated to remove the AMQExceptions that will be removed from the Exchange class. ........ r556861 | ritchiem | 2007-07-17 10:26:47 +0100 (Tue, 17 Jul 2007) | 2 lines QPID-538 Check to ensure a duplicate binding is not created. ........ r556868 | ritchiem | 2007-07-17 10:55:56 +0100 (Tue, 17 Jul 2007) | 1 line Addition of simple pub/sub examples. ........ r556869 | ritchiem | 2007-07-17 10:56:17 +0100 (Tue, 17 Jul 2007) | 1 line QPID-540 Prevent NPE when purging message from the main _message queue in the ConcurrentSelectorDeliveryManager that have been delivered via a Subscribers _messageQueue. Ensuring that any expired messages are still correctly handled. i.e. the Queue size/depth is reduced and the message correctly dequeued from the underlying store. ........ r556871 | ritchiem | 2007-07-17 10:57:35 +0100 (Tue, 17 Jul 2007) | 1 line White space & code formatting change ........ r556872 | ritchiem | 2007-07-17 10:58:35 +0100 (Tue, 17 Jul 2007) | 3 lines Added additional information to hard-error logging in exceptionReceived. Fully expanded imports ........ r556888 | ritchiem | 2007-07-17 12:33:08 +0100 (Tue, 17 Jul 2007) | 1 line Change to allow the management port to be specified on the command line, via -m or --mport ........ r556890 | ritchiem | 2007-07-17 12:38:10 +0100 (Tue, 17 Jul 2007) | 4 lines QPID-541 A large portion of memory was being wasted in 32k ByteBuffers being held by the AMQShortStrings. Patch submitted by Robert Godfrey to intern() the AMQSSs to reduce memory usage. Current implementation *will* impact performance due to the usage of a static Map for storage. However, a thread local implementation is in the works. ........ r556898 | rgodfrey | 2007-07-17 13:00:57 +0100 (Tue, 17 Jul 2007) | 1 line QPID-541 : Change to use threadlocal maps for intern for the common case to avoid excessive synchronization. In the uncommon case will require more lookup. ........ r556958 | rupertlssmith | 2007-07-17 17:22:16 +0100 (Tue, 17 Jul 2007) | 1 line Refactored the distributed test clients and coordinator to support different distribution and sequencing engines. ........ r556967 | rupertlssmith | 2007-07-17 17:40:14 +0100 (Tue, 17 Jul 2007) | 1 line Removed unused package. ........ r556968 | rupertlssmith | 2007-07-17 17:42:00 +0100 (Tue, 17 Jul 2007) | 1 line Retired old interop tests. ........ r556969 | rupertlssmith | 2007-07-17 17:43:49 +0100 (Tue, 17 Jul 2007) | 1 line Properties file not needed any more. Test properties all driven from MessagingTestConfigProperties. ........ r557276 | ritchiem | 2007-07-18 15:36:11 +0100 (Wed, 18 Jul 2007) | 1 line Updates to pom files and Licensing/Notice files for M2 release. ........ r557279 | ritchiem | 2007-07-18 15:51:42 +0100 (Wed, 18 Jul 2007) | 1 line This is left over from ANT ........ r557281 | ritchiem | 2007-07-18 15:54:06 +0100 (Wed, 18 Jul 2007) | 1 line updated comment to refelect property values ........ r557286 | ritchiem | 2007-07-18 16:02:22 +0100 (Wed, 18 Jul 2007) | 1 line Set default mvn build to assembly:assembly ........ r557288 | ritchiem | 2007-07-18 16:09:07 +0100 (Wed, 18 Jul 2007) | 1 line Ensure the top level release-docs directory is included in the builds ........ r557306 | ritchiem | 2007-07-18 17:01:58 +0100 (Wed, 18 Jul 2007) | 1 line Update fix incorrect license headers. ........ r557312 | ritchiem | 2007-07-18 17:07:01 +0100 (Wed, 18 Jul 2007) | 1 line added license ........ r557314 | ritchiem | 2007-07-18 17:11:17 +0100 (Wed, 18 Jul 2007) | 1 line added license ........ r557452 | aconway | 2007-07-19 03:03:02 +0100 (Thu, 19 Jul 2007) | 14 lines * lib/broker/Daemon.cpp, .h - Rewrote to remove libdaemon dependency. - PID file stored in /var/run if root, /tmp otherwise. * src/qpidd.cpp: Use new Daemon.cpp. - lock files stored in /var/run (for root) or /tmp. - updated to trunk daemon flag behavior. * lib/broker/Makefile.am (libqpidbroker_la_LIBADD): - Daemon.cpp now needs -lboost_iostreams * NOTICE, README: Removed mention of libdaemon. ........ r558027 | ritchiem | 2007-07-20 17:08:05 +0100 (Fri, 20 Jul 2007) | 1 line Added a logger but only used to control the toString inclusion of password. If in debug mode it will include password otherwise the password is "********". ........ r558072 | astitcher | 2007-07-20 18:49:41 +0100 (Fri, 20 Jul 2007) | 2 lines Fixed the license from the "old" apache copyright notice ........ r558083 | aconway | 2007-07-20 19:29:08 +0100 (Fri, 20 Jul 2007) | 2 lines Remove -ldaemon, we no longer require libdaemon. ........ r558099 | aconway | 2007-07-20 20:20:01 +0100 (Fri, 20 Jul 2007) | 2 lines Ignore QPID_ env variables that don't correspond to known options. ........ r558108 | cctrieloff | 2007-07-20 20:55:40 +0100 (Fri, 20 Jul 2007) | 2 lines typo fix ........ r558114 | rajith | 2007-07-20 21:11:03 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558115 | rajith | 2007-07-20 21:12:20 +0100 (Fri, 20 Jul 2007) | 1 line Checking in the release notes ........ r558116 | aconway | 2007-07-20 21:16:20 +0100 (Fri, 20 Jul 2007) | 3 lines Removed .txt from RELEASE_NOTES Added RELEASE_NOTES to EXTRA_DIST in Makefile.am ........ r558168 | rajith | 2007-07-20 23:03:42 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558170 | rajith | 2007-07-20 23:04:11 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558630 | gsim | 2007-07-23 08:21:49 +0100 (Mon, 23 Jul 2007) | 3 lines Revised release notes: removed bug fixed on this branch, removed outstanding feature lists as it is not terribly accurate or helpful. ........ r559419 | rupertlssmith | 2007-07-25 13:17:59 +0100 (Wed, 25 Jul 2007) | 1 line Refactored interop tests into general distributed test framework. Moved framework under systests from integrationtests. ........ r559427 | ritchiem | 2007-07-25 13:40:24 +0100 (Wed, 25 Jul 2007) | 2 lines AMQMessage - added //todo-s and removed unused parameter StoreContext from expired() method call. ConcurrentSelectorDeliveryManager - Update to reflect expired() call change. Created new _reaperContextStore to be used when performing reaper operations such as message dequeue due to expiration. Removed old commented code. ........ r559455 | rupertlssmith | 2007-07-25 14:40:16 +0100 (Wed, 25 Jul 2007) | 1 line Added to comments. ........ r559456 | rupertlssmith | 2007-07-25 14:41:21 +0100 (Wed, 25 Jul 2007) | 1 line Removed redundant method. ........ r559458 | rupertlssmith | 2007-07-25 14:57:21 +0100 (Wed, 25 Jul 2007) | 1 line Refactored packaging of test framework. ........ r559461 | rupertlssmith | 2007-07-25 15:00:16 +0100 (Wed, 25 Jul 2007) | 1 line Removed redundant packages. ........ r559943 | rhs | 2007-07-26 20:15:17 +0100 (Thu, 26 Jul 2007) | 1 line adding missing ack ........ r559944 | rhs | 2007-07-26 20:15:44 +0100 (Thu, 26 Jul 2007) | 1 line removed old script ........ r560198 | ritchiem | 2007-07-27 12:30:34 +0100 (Fri, 27 Jul 2007) | 1 line Added files to ignore list ........ r560225 | ritchiem | 2007-07-27 14:33:50 +0100 (Fri, 27 Jul 2007) | 1 line Converted namespaces from Qpid.* to Apache.Qpid.* ........ r560471 | tomasr | 2007-07-28 03:35:41 +0100 (Sat, 28 Jul 2007) | 1 line Removed using directives causing compilation failure in .NET 1.1 ........ r561278 | ritchiem | 2007-07-31 10:07:57 +0100 (Tue, 31 Jul 2007) | 8 lines Changes to POMs. Client pom now builds a single jar with all dependancies included in the single bundle. systests/pom.xml adjusted to include only *Test.class items. This will fix the current Error on OptOutTestCase management/eclipse-plugin/pom.xml - editied to include there required MANIFEST.MF to identify plugin to eclipse distribution/src/main/assembly/management-eclipse-plugin.xml editied to include there required MANIFEST.MF to identify the plugin distribution/pom.xml - white space Also updated log4j.xml default to create an alert.log file from the AMQQueue alerting. Added a debug.log4j.xml that gives example of debugging the broker via log4j. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@561365 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 3 - .../apache/qpid/configuration/Configuration.java | 188 ++++++ .../java/org/apache/qpid/server/AMQChannel.java | 10 +- .../src/main/java/org/apache/qpid/server/Main.java | 56 +- .../qpid/server/exchange/AbstractExchange.java | 6 + .../server/exchange/DefaultExchangeRegistry.java | 19 +- .../qpid/server/exchange/DestNameExchange.java | 11 +- .../qpid/server/exchange/DestWildExchange.java | 21 +- .../org/apache/qpid/server/exchange/Exchange.java | 28 +- .../qpid/server/exchange/ExchangeRegistry.java | 4 + .../qpid/server/exchange/FanoutExchange.java | 29 +- .../qpid/server/exchange/HeadersExchange.java | 61 +- .../server/handler/BasicConsumeMethodHandler.java | 18 +- .../server/handler/BasicPublishMethodHandler.java | 10 + .../handler/ConnectionStartOkMethodHandler.java | 3 +- .../qpid/server/handler/ExchangeBoundHandler.java | 25 +- .../server/handler/ExchangeDeclareHandler.java | 4 +- .../qpid/server/handler/QueueBindHandler.java | 17 +- .../qpid/server/handler/QueueDeclareHandler.java | 7 + .../management/JMXManagedObjectRegistry.java | 44 +- .../management/MBeanInvocationHandlerImpl.java | 25 +- .../server/protocol/AMQPFastProtocolHandler.java | 28 +- .../org/apache/qpid/server/queue/AMQMessage.java | 16 +- .../org/apache/qpid/server/queue/AMQQueue.java | 250 ++++++-- .../apache/qpid/server/queue/AMQQueueMBean.java | 66 +-- .../queue/ConcurrentSelectorDeliveryManager.java | 109 ++-- .../qpid/server/queue/DefaultQueueRegistry.java | 17 +- .../apache/qpid/server/queue/ExchangeBindings.java | 13 +- .../apache/qpid/server/queue/MessageMetaData.java | 24 +- .../qpid/server/queue/NotificationCheck.java | 25 +- .../server/queue/QueueNotificationListener.java | 26 +- .../apache/qpid/server/queue/QueueRegistry.java | 6 + .../qpid/server/queue/TransientMessageData.java | 25 +- .../org/apache/qpid/server/security/Passwd.java | 81 --- .../qpid/server/txn/NonTransactionalContext.java | 25 +- .../qpid/server/txn/TransactionalContext.java | 124 +++- .../qpid/server/virtualhost/VirtualHost.java | 262 +++++++++ .../qpid/tools/messagestore/MessageStoreTool.java | 648 +++++++++++++++++++++ .../messagestore/commands/AbstractCommand.java | 66 +++ .../qpid/tools/messagestore/commands/Clear.java | 85 +++ .../qpid/tools/messagestore/commands/Command.java | 36 ++ .../qpid/tools/messagestore/commands/Copy.java | 56 ++ .../qpid/tools/messagestore/commands/Dump.java | 299 ++++++++++ .../qpid/tools/messagestore/commands/Help.java | 98 ++++ .../qpid/tools/messagestore/commands/List.java | 314 ++++++++++ .../qpid/tools/messagestore/commands/Load.java | 94 +++ .../qpid/tools/messagestore/commands/Move.java | 166 ++++++ .../qpid/tools/messagestore/commands/Purge.java | 68 +++ .../qpid/tools/messagestore/commands/Quit.java | 54 ++ .../qpid/tools/messagestore/commands/Select.java | 233 ++++++++ .../qpid/tools/messagestore/commands/Show.java | 513 ++++++++++++++++ .../org/apache/qpid/tools/security/Passwd.java | 81 +++ .../org/apache/qpid/tools/utils/CommandParser.java | 51 ++ .../java/org/apache/qpid/tools/utils/Console.java | 90 +++ .../qpid/tools/utils/SimpleCommandParser.java | 121 ++++ .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 ++++++++++++ .../qpid/tools/utils/utils/CommandParser.java | 51 ++ .../org/apache/qpid/tools/utils/utils/Console.java | 75 +++ .../qpid/tools/utils/utils/RSHCommandParser.java | 352 +++++++++++ .../tools/utils/utils/SimpleCommandParser.java | 116 ++++ 60 files changed, 5297 insertions(+), 419 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 931c15a664..7e0c4defe1 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -31,7 +31,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPOutputStream; import org.apache.log4j.helpers.CountingQuietWriter; @@ -39,8 +38,6 @@ import org.apache.log4j.helpers.LogLog; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.spi.LoggingEvent; -import org.apache.qpid.framing.FieldTable; - /** *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java new file mode 100644 index 0000000000..40ff590a0a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.configuration; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class Configuration +{ + public static final String QPID_HOME = "QPID_HOME"; + + final String QPIDHOME = System.getProperty(QPID_HOME); + + private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); + + public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + protected final Options _options = new Options(); + protected CommandLine _commandLine; + protected File _configFile; + + + public Configuration() + { + + } + + public void processCommandline(String[] args) throws InitException + { + try + { + _commandLine = new PosixParser().parse(_options, args); + } + catch (ParseException e) + { + throw new InitException("Unable to parse commmandline", e); + } + + final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); + setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); + } + + public void setConfig(File file) + { + _configFile = file; + } + + /** + * @param option The option to set. + */ + public void setOption(Option option) + { + _options.addOption(option); + } + + /** + * getOptionValue from the configuration + * @param option variable argument, first string is option to get, second if present is the default value. + * @return the String for the given option or null if not present (if default value not specified) + */ + public String getOptionValue(String... option) + { + if (option.length == 1) + { + return _commandLine.getOptionValue(option[0]); + } + else if (option.length == 2) + { + return _commandLine.getOptionValue(option[0], option[1]); + } + return null; + } + + public void loadConfig(File file) throws InitException + { + setConfig(file); + loadConfig(); + } + + private void loadConfig() throws InitException + { + 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, null); + } + else + { + _devlog.debug("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); +// } + } + + +// private void configureLogging(File logConfigFile, String logWatchConfig) +// { +// int logWatchTime = 0; +// try +// { +// logWatchTime = Integer.parseInt(logWatchConfig); +// } +// catch (NumberFormatException e) +// { +// _devlog.error("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()) +// { +// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); +// if (logWatchTime > 0) +// { +// _devlog.info("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(); +// } +// } + + public File getConfigFile() + { + return _configFile; + } + + + public class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 28a9e85489..7f14946834 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -582,9 +582,9 @@ public class AMQChannel final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); - if (_log.isInfoEnabled()) + if (_log.isDebugEnabled()) { - _log.info("unacked map Size:" + _unacknowledgedMessageMap.size()); + _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); } // Process the Unacked-Map. @@ -640,15 +640,15 @@ public class AMQChannel }); // Process Messages to Resend - if (_log.isInfoEnabled()) + if (_log.isDebugEnabled()) { if (!msgToResend.isEmpty()) { - _log.info("Preparing (" + msgToResend.size() + ") message to resend."); + _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); } else { - _log.info("No message to resend."); + _log.debug("No message to resend."); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 29ea69caf7..dd6546585f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -34,6 +34,7 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; +import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; @@ -48,6 +49,7 @@ import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -55,11 +57,19 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.url.URLSyntaxException; +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; + /** * Main entry point for AMQPD. * */ -@SuppressWarnings({ "AccessStaticViaInstance" }) +@SuppressWarnings({"AccessStaticViaInstance"}) public class Main { /** Used for debugging. */ @@ -133,6 +143,12 @@ public class Main OptionBuilder.withArgName("port").hasArg() .withDescription("listen on the specified port. Overrides any value in the config file") .withLongOpt("port").create("p"); + Option mport = + OptionBuilder.withArgName("mport").hasArg() + .withDescription("listen on the specified management port. Overrides any value in the config file") + .withLongOpt("mport").create("m"); + + Option bind = OptionBuilder.withArgName("bind").hasArg() .withDescription("bind to the specified address. Overrides any value in the config file") @@ -153,6 +169,7 @@ public class Main options.addOption(logconfig); options.addOption(logwatchconfig); options.addOption(port); + options.addOption(mport); options.addOption(bind); } @@ -203,15 +220,19 @@ public class Main catch (InitException e) { System.out.println(e.getMessage()); + _brokerLogger.error("Initialisation Error : " + e.getMessage()); + } catch (ConfigurationException e) { System.out.println("Error configuring message broker: " + e); + _brokerLogger.error("Error configuring message broker: " + e); e.printStackTrace(); } catch (Exception e) { System.out.println("Error intialising message broker: " + e); + _brokerLogger.error("Error intialising message broker: " + e); e.printStackTrace(); } } @@ -260,7 +281,15 @@ public class Main configureLogging(logConfigFile, logWatchConfig); } - ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); + ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); + + + updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); + + + + ApplicationRegistry.initialise(config); + // fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say @@ -318,6 +347,29 @@ public class Main bind(port, connectorConfig); } + /** + * Update the configuration data with the management port. + * @param configuration + * @param managementPort The string from the command line + */ + private void updateManagementPort(Configuration configuration, String managementPort) + { + if (managementPort != null) + { + int mport; + int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); + try + { + mport = Integer.parseInt(managementPort); + configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); + } + catch (NumberFormatException e) + { + _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); + } + } + } + protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 868ac31a54..9ebb893362 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,9 +38,13 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.List; +import java.util.Map; + public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; @@ -189,6 +193,8 @@ public abstract class AbstractExchange implements Exchange, Managable } } + abstract public Map> getBindings(); + public String toString() { return getClass().getName() + "[" + getName() +"]"; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index f3bdecc32e..377a73dd31 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,18 +20,20 @@ */ package org.apache.qpid.server.exchange; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.exception.InternalErrorException; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + public class DefaultExchangeRegistry implements ExchangeRegistry { private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); @@ -64,7 +66,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) throws AMQException { _exchangeMap.put(exchange.getName(), exchange); - if(exchange.isDurable()) + if (exchange.isDurable()) { try { @@ -86,13 +88,18 @@ public class DefaultExchangeRegistry implements ExchangeRegistry return _defaultExchange; } + public Collection getExchangeNames() + { + return _exchangeMap.keySet(); + } + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); if (e != null) { - if(e.isDurable()) + if (e.isDurable()) { try { @@ -112,7 +119,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public Exchange getExchange(AMQShortString name) { - if((name == null) || name.length() == 0) + if ((name == null) || name.length() == 0) { return getDefaultExchange(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 0dcceaddbb..c24f9a37e1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -26,22 +26,16 @@ import java.util.Map; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -222,4 +216,9 @@ public class DestNameExchange extends AbstractExchange { return !_index.getBindingsMap().isEmpty(); } + + public Map> getBindings() + { + return _index.getBindingsMap(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index f6a95b5e55..e1a3a24d3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -21,11 +21,9 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -35,17 +33,11 @@ import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -59,7 +51,7 @@ public class DestWildExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(DestWildExchange.class); private ConcurrentHashMap> _routingKey2queues = - new ConcurrentHashMap>(); + new ConcurrentHashMap>(); // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); private static final String TOPIC_SEPARATOR = "."; private static final String AMQP_STAR = "*"; @@ -92,7 +84,7 @@ public class DestWildExchange extends AbstractExchange queueList.add(q.getName().toString()); } - Object[] bindingItemValues = { key.toString(), queueList.toArray(new String[0]) }; + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -311,6 +303,11 @@ public class DestWildExchange extends AbstractExchange } } + public Map> getBindings() + { + return _routingKey2queues; + } + private List getMatchedQueues(AMQShortString routingKey) { List list = new LinkedList(); @@ -358,8 +355,8 @@ public class DestWildExchange extends AbstractExchange if (queueList.size() > (depth + queueskip)) { // a hash and it is the last entry matching = - queueList.get(depth + queueskip).equals(AMQP_HASH) - && (queueList.size() == (depth + queueskip + 1)); + queueList.get(depth + queueskip).equals(AMQP_HASH) + && (queueList.size() == (depth + queueskip + 1)); } } else if (routingkeyList.size() > (depth + routingskip)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index a5f77cc2a4..37cd85a8f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -27,9 +27,13 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.List; +import java.util.Map; + public interface Exchange { AMQShortString getName(); + AMQShortString getType(); void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; @@ -51,6 +55,17 @@ public interface Exchange void route(AMQMessage message) throws AMQException; + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments + * @param routingKey + * @param arguments + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); + /** * Determines whether a message would be isBound to a particular queue using a specific routing key * @param routingKey @@ -58,22 +73,25 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException; + boolean isBound(AMQShortString routingKey, AMQQueue queue); /** - * Determines whether a message is routing to any queue using a specific routing key + * Determines whether a message is routing to any queue using a specific _routing key * @param routingKey * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey) throws AMQException; + boolean isBound(AMQShortString routingKey); - boolean isBound(AMQQueue queue) throws AMQException; + boolean isBound(AMQQueue queue); /** * Returns true if this exchange has at least one binding associated with it. * @return * @throws AMQException */ - boolean hasBindings() throws AMQException; + boolean hasBindings(); + + Map> getBindings(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index d3a466565f..fe3b19e74e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import java.util.Collection; + public interface ExchangeRegistry extends MessageRouter { @@ -43,5 +45,7 @@ public interface ExchangeRegistry extends MessageRouter Exchange getDefaultExchange(); + Collection getExchangeNames(); + void initialise() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index bf00eeb9d3..1a705248c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -34,17 +33,13 @@ import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - +import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; public class FanoutExchange extends AbstractExchange @@ -79,7 +74,7 @@ public class FanoutExchange extends AbstractExchange { String queueName = queue.getName().toString(); - Object[] bindingItemValues = { queueName, new String[] { queueName } }; + Object[] bindingItemValues = {queueName, new String[]{queueName}}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -120,6 +115,11 @@ public class FanoutExchange extends AbstractExchange } } + public Map> getBindings() + { + return null; + } + public AMQShortString getType() { return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; @@ -181,24 +181,29 @@ public class FanoutExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { return _queues.contains(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { return (_queues != null) && !_queues.isEmpty(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { return _queues.contains(queue); } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_queues.isEmpty(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index e86094e26f..9bb1ee6a62 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -20,23 +20,6 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; @@ -50,6 +33,23 @@ import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import javax.management.JMException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + /** * An exchange that binds queues based on a set of required headers and header values * and routes messages to these queues by matching the headers of the message against @@ -91,13 +91,13 @@ public class HeadersExchange extends AbstractExchange private final class HeadersExchangeMBean extends ExchangeMBean { @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException + public HeadersExchangeMBean() throws JMException { super(); _exchangeType = "headers"; init(); } - + /** * initialises the OpenType objects. */ @@ -113,7 +113,7 @@ public class HeadersExchange extends AbstractExchange _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", _bindingItemNames, _bindingItemNames, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, _bindingItemIndexNames); } public TabularData bindings() throws OpenDataException @@ -169,7 +169,7 @@ public class HeadersExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } - String[] bindings = binding.split(","); + String[] bindings = binding.split(","); FieldTable bindingMap = new FieldTable(); for (int i = 0; i < bindings.length; i++) { @@ -241,17 +241,23 @@ public class HeadersExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + //fixme isBound here should take the arguements in to consideration. + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { return isBound(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { return hasBindings(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { for (Registration r : _bindings) { @@ -263,7 +269,7 @@ public class HeadersExchange extends AbstractExchange return false; } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_bindings.isEmpty(); } @@ -288,6 +294,11 @@ public class HeadersExchange extends AbstractExchange } } + public Map> getBindings() + { + return null; + } + private static class Registration { private final HeadersBinding binding; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 9346eecbb2..ab4f2c4e64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -100,6 +100,12 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { @@ -77,7 +77,7 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); } - + if (body.routingKey == null) { body.routingKey = queue.getName(); @@ -97,9 +97,18 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); } + + if (body.routingKey != null) + { + body.routingKey = body.routingKey.intern(); + } + try - { - queue.bind(body.routingKey, body.arguments, exch); + { + if (!exch.isBound(body.routingKey, body.arguments, queue)) + { + queue.bind(body.routingKey, body.arguments, exch); + } } catch (AMQInvalidRoutingKeyException rke) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index f9e94af697..28967841a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -93,8 +93,15 @@ public class QueueDeclareHandler implements StateAwareMethodListener foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - // move messages to another queue - anotherQueue.startMovingMessages(); - anotherQueue.enqueueMovedMessages(storeContext, foundMessagesList); + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity + * on the queues being moved between is suspended during the move. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param queueName The queue to move the messages to. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + + MessageStore fromStore = getVirtualHost().getMessageStore(); + MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); - // moving is successful, now remove from original queue - _deliveryMgr.removeMovedMessages(foundMessagesList); + if (toStore != fromStore) + { + throw new RuntimeException("Can only move messages between queues on the same message store."); } + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + toQueue.startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + message.takeReference(); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Removes messages from this queue, and also commits the remove on the message store. Delivery activity + * on the queues being moved between is suspended during the remove. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + { + MessageStore fromStore = getVirtualHost().getMessageStore(); + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // remove the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // remove the messages on the in-memory queues. + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. finally { - // remove the lock and start the async delivery - anotherQueue.stopMovingMessages(); stopMovingMessages(); } } @@ -458,7 +639,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (incrementSubscriberCount() > 1) { @@ -481,13 +662,12 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (_logger.isDebugEnabled()) { - _logger.debug(MessageFormat.format( - "Registering protocol session {0} with channel {1} and " + "consumer tag {2} with {3}", ps, channel, - consumerTag, this)); + _logger.debug(MessageFormat.format("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, filters, noLocal, this); + _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); if (subscription.filtersMessages()) { @@ -525,8 +705,8 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (_logger.isDebugEnabled()) { _logger.debug(MessageFormat.format( - "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, - consumerTag, this)); + "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", + ps, channel, consumerTag, this)); } Subscription removedSubscription; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index bbaa7379f6..07872d7644 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -18,30 +18,23 @@ * under the License. * */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ package org.apache.qpid.server.queue; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.store.StoreContext; import javax.management.JMException; import javax.management.MBeanException; @@ -60,30 +53,25 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import org.apache.log4j.Logger; - -import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; /** - * MBean class for AMQQueue. It implements all the management features exposed - * for an AMQQueue. + * AMQQueueMBean is the management bean for an {@link AMQQueue}. + * + *

      CRC Caption
      Responsibilities Collaborations + *
      */ @MBeanDescription("Management Interface for AMQQueue") public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener { + /** Used for debugging purposes. */ private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 2aa759b35d..907d68b733 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -20,19 +20,6 @@ */ package org.apache.qpid.server.queue; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.Collections; -import java.util.HashSet; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; @@ -42,8 +29,21 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.MessageQueue; import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; +import org.apache.qpid.util.MessageQueue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; /** Manages delivery of messages on behalf of a queue */ @@ -87,6 +87,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private final Object _queueHeadLock = new Object(); private String _processingThreadName = ""; + + /** Used by any reaping thread to purge messages */ + private StoreContext _reapingStoreContext = new StoreContext(); + ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -453,12 +457,31 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) while (purgeMessage(message, sub)) { + // if we are purging then ensure we mark this message taken for the current subscriber + // the current subscriber may be null in the case of a get or a purge but this is ok. +// boolean alreadyTaken = message.taken(_queue, sub); + //remove the already taken message or expired AMQMessage removed = messages.poll(); assert removed == message; - _totalMessageSize.addAndGet(-message.getSize()); + // if the message expired then the _totalMessageSize needs adjusting + if (message.expired(_queue)) + { + _totalMessageSize.addAndGet(-message.getSize()); + + // Use the reapingStoreContext as any sub(if we have one) may be in a tx. + message.dequeue(_reapingStoreContext, _queue); + + if (_log.isInfoEnabled()) + { + _log.info(debugIdentity() + " Doing clean up of the main _message queue."); + } + } + + //else the clean up is not required as the message has already been taken for this queue therefore + // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. if (_log.isTraceEnabled()) { @@ -473,7 +496,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * + * This method will return true if the message is to be purged from the queue. + * + * + * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) * @param message * @param sub * @return @@ -493,15 +519,15 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // if the message is null then don't purge as we have no messagse. if (message != null) { + // Check that the message hasn't expired. + if (message.expired(_queue)) + { + return true; + } + // if we have a subscriber perform message checks if (sub != null) { - // Check that the message hasn't expired. - if (message.expired(sub.getChannel().getStoreContext(), _queue)) - { - return true; - } - // if we have a queue browser(we don't purge) so check mark the message as taken purge = ((!sub.isBrowser() || message.isTaken(_queue))); } @@ -606,7 +632,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isInfoEnabled()) { - _log.info(debugIdentity() + "We could do clean up of the main _message queue here"); + //fixme - we should do the clean up as the message remains on the _message queue + // this is resulting in the next consumer receiving the message and then attempting to purge it + // + _log.info(debugIdentity() + "We should do clean up of the main _message queue here"); } } @@ -617,7 +646,14 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } catch (AMQException e) { - message.release(_queue); + if (message != null) + { + message.release(_queue); + } + else + { + _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); + } _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -696,25 +732,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } -// private void sendNextMessage(Subscription sub) -// { -// if (sub.filtersMessages()) -// { -// sendNextMessage(sub, sub.getPreDeliveryQueue()); -// if (sub.isAutoClose()) -// { -// if (sub.getPreDeliveryQueue().isEmpty()) -// { -// sub.close(); -// } -// } -// } -// else -// { -// sendNextMessage(sub, _messages); -// } -// } - public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException { @@ -723,8 +740,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); } - // This shouldn't be done here. -// msg.release(); //Check if we have someone to deliver the message to. _lock.lock(); @@ -800,7 +815,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + - "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); + "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); } } } @@ -810,7 +825,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); + " Subscriber:" + System.identityHashCode(s)); } deliver(context, name, msg, deliverFirst); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index c0f1e7f40c..cbe9246f09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,13 +20,14 @@ */ package org.apache.qpid.server.queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + public class DefaultQueueRegistry implements QueueRegistry { private ConcurrentMap _queueMap = new ConcurrentHashMap(); @@ -57,4 +58,14 @@ public class DefaultQueueRegistry implements QueueRegistry { return _queueMap.get(name); } + + public Collection getQueueNames() + { + return _queueMap.keySet(); + } + + public Collection getQueues() + { + return _queueMap.values(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index a8247aa2db..60c1a8f574 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -46,7 +46,7 @@ class ExchangeBindings ExchangeBinding(AMQShortString routingKey, Exchange exchange) { - this(routingKey, exchange,EMPTY_ARGUMENTS); + this(routingKey, exchange, EMPTY_ARGUMENTS); } ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) @@ -80,7 +80,10 @@ class ExchangeBindings public boolean equals(Object o) { - if (!(o instanceof ExchangeBinding)) return false; + if (!(o instanceof ExchangeBinding)) + { + return false; + } ExchangeBinding eb = (ExchangeBinding) o; return _exchange.equals(eb._exchange) && _routingKey.equals(eb._routingKey) @@ -104,16 +107,16 @@ class ExchangeBindings */ void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments )); + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); } public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments )); + _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); } - + /** * Deregisters this queue from any exchange it has been bound to */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java index 285f05fb20..6118a4c11f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -1,18 +1,22 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 00ccffdea1..6b3d65661f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java index 9554d34f00..959ca03c80 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -1,22 +1,26 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 QueueNotificationListener { void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index ed2101fd75..13c150f82b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.messageStore.StorableQueue; +import java.util.Collection; public interface QueueRegistry { @@ -35,4 +36,9 @@ public interface QueueRegistry void unregisterQueue(AMQShortString name) throws AMQException; AMQQueue getQueue(AMQShortString name); + + Collection getQueueNames(); + + Collection getQueues(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 7c8064789e..79ee6b93a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java deleted file mode 100644 index f9e093dba7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security; - -import org.apache.commons.codec.binary.Base64; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; - -public class Passwd -{ - public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException - { - if (args.length != 2) - { - System.out.println("Passwd "); - System.exit(0); - } - - byte[] data = args[1].getBytes("utf-8"); - - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - Base64 b64 = new Base64(); - - byte[] encoded = b64.encode(digest); - - output(args[0], encoded); - } - - private static void output(String user, byte[] encoded) throws IOException - { - -// File passwdFile = new File("qpid.passwd"); - - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 8becaf52b9..d9500429af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index 88451e2fca..fee25c07df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -28,24 +28,144 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.StoreContext; /** - * @author Robert Greig (robert.j.greig@jpmorgan.com) + * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. + * Different levels of transactional support for the delivery of messages may be provided by different implementations + * of this interface. + * + *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. + * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} + * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. + * + *

      + *
      CRC Card
      Responsibilities + *
      Explicitly accept a transaction start notification. + *
      Commit all pending operations in a transaction. + *
      Rollback all pending operations in a transaction. + *
      Deliver a message to a queue as part of a transaction. + *
      Redeliver a message to a queue as part of a transaction. + *
      Mark a message as acknowledged as part of a transaction. + *
      Accept notification that a message has been completely received as part of a transaction. + *
      Accept notification that a message has been fully processed as part of a transaction. + *
      Associate a message store context with this transaction context. + *
      + * + * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional + * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them + * somewhere else, a seperate interface for example. + * + * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides + * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any + * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean + * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be + * conceptually neater. + * + * For example: + *

      + * public interface Transactional
      + * {
      + *    public void commit();
      + *    public void rollback();
      + * }
      + *
      + * public interface TransactionalQueue extends Transactional, SizeableQueue
      + * {}
      + *
      + * public class Queues
      + * {
      + *    ...
      + *    // For transactional messaging, take a transactional view onto the queue.
      + *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      + *
      + *    // For non-transactional messaging, take a non-transactional view onto the queue.
      + *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      + * }
      + * 
      */ public interface TransactionalContext { + /** + * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} + * should automatically begin the next transaction in the chain. + * + * @throws AMQException If the transaction cannot be started for any reason. + */ void beginTranIfNecessary() throws AMQException; + /** + * Makes all pending operations on the transaction permanent and visible. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ void commit() throws AMQException; + /** + * Erases all pending operations on the transaction. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ void rollback() throws AMQException; + /** + * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a + * redelivery, and should be placed on the front of the queue. + * + *

      This is an 'enqueue' operation. + * + * @param message The message to deliver. + * @param queue The queue to deliver the message to. + * @param deliverFirst true to place the message on the front of the queue for redelivery, false + * for normal FIFO message ordering. + * + * @throws AMQException If the message cannot be delivered for any reason. + */ void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException; + /** + * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by + * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' + * flag is set, in which case an acknowledgement up to the latest delivered message should be done. + * + *

      This is a 'dequeue' operation. + * + * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement + * up to the latest message. + * @param lastDeliveryTag The latest message delivered. + * @param multiple true if all message ids up the acknowledged one or latest delivered, are + * to be acknowledged, false otherwise. + * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message + * from. + * + * @throws AMQException If the message cannot be acknowledged for any reason. + */ void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + /** + * Notifies the transactional context that a message has been fully received. The actual message that was received + * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, + * flushing its data to disk. + * + * @param persistent true if the received message is persistent, false otherwise. + * + * @throws AMQException If the fully received event cannot be processed for any reason. + */ void messageFullyReceived(boolean persistent) throws AMQException; + /** + * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual + * message that was delivered is not specified. This event may be used to trigger a process related to the + * outcome of the delivery of the message, for example, cleaning up failed deliveries. + * + * @param protocolSession The protocol session of the deliverable message. + * + * @throws AMQException If the message processed event cannot be handled for any reason. + */ void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; + /** + * Gets the message store context associated with this transactional context. + * + * @return The message store context associated with this transactional context. + */ StoreContext getStoreContext(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 6638689299..235555c58b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,3 +1,4 @@ +<<<<<<< .working /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -286,3 +287,264 @@ public class VirtualHost implements Accessable } } +======= +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private AccessManager _accessManager; + + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + /** + * Used for testing only + * @param name + * @param store + * @throws Exception + */ + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, null, store); + } + + /** + * Normal Constructor + * @param name + * @param hostConfig + * @throws Exception + */ + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + // This isn't needed to be registered + //_virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(this); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + _exchangeRegistry.initialise(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = new AccessManagerImpl(name, hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(this, "store", config); + } + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public AccessManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} +>>>>>>> .merge-right.r553432 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java new file mode 100644 index 0000000000..afa7916074 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -0,0 +1,648 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.commands.Clear; +import org.apache.qpid.tools.messagestore.commands.Command; +import org.apache.qpid.tools.messagestore.commands.Copy; +import org.apache.qpid.tools.messagestore.commands.Dump; +import org.apache.qpid.tools.messagestore.commands.Help; +import org.apache.qpid.tools.messagestore.commands.List; +import org.apache.qpid.tools.messagestore.commands.Load; +import org.apache.qpid.tools.messagestore.commands.Quit; +import org.apache.qpid.tools.messagestore.commands.Select; +import org.apache.qpid.tools.messagestore.commands.Show; +import org.apache.qpid.tools.utils.CommandParser; +import org.apache.qpid.tools.utils.Console; +import org.apache.qpid.tools.utils.SimpleCommandParser; +import org.apache.qpid.tools.utils.SimpleConsole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * MessageStoreTool. + */ +public class MessageStoreTool +{ + /** Text outputted at the start of each console.*/ + private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; + + /** I/O Wrapper. */ + protected Console _console; + + /** Batch mode flag. */ + protected boolean _batchMode; + + /** Internal State object. */ + private State _state = new State(); + + private HashMap _commands = new HashMap(); + + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); + + /** Loaded configuration file. */ + private Configuration _config; + + /** Control used for main run loop. */ + private boolean _running = true; + private boolean _initialised = false; + + //---------------------------------------------------------------------------------------------------/ + + public static void main(String[] args) throws Configuration.InitException + { + + MessageStoreTool tool = new MessageStoreTool(args); + + tool.start(); + } + + + public MessageStoreTool(String[] args) throws Configuration.InitException + { + this(args, System.in, System.out); + } + + public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException + { + BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); + BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); + + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); + _batchMode = false; + + _console = new SimpleConsole(consoleWriter, consoleReader); + + _config = new Configuration(); + + setOptions(); + _config.processCommandline(args); + } + + + private void setOptions() + { + 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 By " + + "default looks for a file named " + + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) + .withLongOpt("config") + .create("c"); + + _config.setOption(help); + _config.setOption(version); + _config.setOption(configFile); + } + + public State getState() + { + return _state; + } + + public Map getCommands() + { + return _commands; + } + + public void setConfigurationFile(String configfile) throws Configuration.InitException + { + _config.loadConfig(new File(configfile)); + setup(); + } + + public Console getConsole() + { + return _console; + } + + public void setConsole(Console console) + { + _console = console; + } + + /** + * Simple ShutdownHook to cleanly shutdown the databases + */ + class ShutdownHook implements Runnable + { + MessageStoreTool _tool; + + ShutdownHook(MessageStoreTool messageStoreTool) + { + _tool = messageStoreTool; + } + + public void run() + { + _tool.quit(); + } + } + + public void quit() + { + _running = false; + + if (_initialised) + { + ApplicationRegistry.remove(1); + } + + _console.println("...exiting"); + + _console.close(); + } + + public void setBatchMode(boolean batchmode) + { + _batchMode = batchmode; + } + + /** + * Main loop + */ + protected void start() + { + setup(); + + if (!_initialised) + { + System.exit(1); + } + + _console.println(""); + + _console.println(BOILER_PLATE); + + runCLI(); + } + + private void setup() + { + loadDefaultVirtualHosts(); + + loadCommands(); + + _state.clearAll(); + } + + private void loadCommands() + { + _commands.clear(); + //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands + _commands.put("close", new Clear(this)); + _commands.put("copy", new Copy(this)); + _commands.put("dump", new Dump(this)); + _commands.put("help", new Help(this)); + _commands.put("list", new List(this)); + _commands.put("load", new Load(this)); + _commands.put("quit", new Quit(this)); + _commands.put("select", new Select(this)); + _commands.put("show", new Show(this)); + } + + private void loadDefaultVirtualHosts() + { + final File configFile = _config.getConfigFile(); + + loadVirtualHosts(configFile); + } + + private void loadVirtualHosts(File configFile) + { + + if (!configFile.exists()) + { + _devlog.error("Config file not found:" + configFile.getAbsolutePath()); + return; + } + else + { + _devlog.debug("using config file :" + configFile.getAbsolutePath()); + } + + try + { + ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); + + ApplicationRegistry.remove(1); + + ApplicationRegistry.initialise(registry); + + checkMessageStores(); + _initialised = true; + } + catch (ConfigurationException e) + { + _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); + e.printStackTrace(); + } + catch (Exception e) + { + _console.println("Unable to load configuration due to: " + e.getMessage()); + e.printStackTrace(); + } + + + } + + private void checkMessageStores() + { + Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); + + boolean warning = false; + for (VirtualHost vhost : vhosts) + { + if (vhost.getMessageStore() instanceof MemoryMessageStore) + { + _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " + + "Changes will not persist."); + warning = true; + } + } + + if (warning) + { + _console.println(""); + _console.println("Please ensure you are using the correct config file currently using '" + + _config.getConfigFile().getAbsolutePath() + "'"); + _console.println("New config file can be specifed by 'load ' or -c on the commandline."); + _console.println(""); + } + } + + private void runCLI() + { + while (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + String[] args = _console.readCommand(); + + while (args != null) + { + exec(args); + + if (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + args = _console.readCommand(); + } + } + } + } + + private void printPrompt() + { + _console.print(prompt()); + } + + + /** + * Execute a script (batch mode). + * + * @param script The file script + */ + protected void runScripts(String script) + { + //Store Current State + boolean oldBatch = _batchMode; + CommandParser oldParser = _console.getCommandParser(); + setBatchMode(true); + + try + { + _devlog.debug("Running script '" + script + "'"); + + _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); + + start(); + } + catch (java.io.FileNotFoundException e) + { + _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); + } + + //Restore previous state + _console.setCommandParser(oldParser); + setBatchMode(oldBatch); + } + + public String prompt() + { + String state = _state.toString(); + if (state != null && state.length() != 0) + { + return state + ":bdb$ "; + } + else + { + return "bdb$ "; + } + } + + /** + * Execute the command. + * + * @param args [command, arg0, arg1...]. + */ + protected void exec(String[] args) + { + // Comment lines start with a # + if (args.length == 0 || args[0].startsWith("#")) + { + return; + } + + final String command = args[0]; + + Command cmd = _commands.get(command); + + if (cmd == null) + { + _console.println("Command not understood: " + command); + } + else + { + cmd.execute(args); + } + } + + + /** + * Displays usage info. + */ + protected static void help() + { + System.out.println(BOILER_PLATE); + System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); + System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); + } + + + /** + * This class is used to store the current state of the tool. + * + * This is then interrogated by the various commands to augment their behaviour. + * + * + */ + public class State + { + private VirtualHost _vhost = null; + private AMQQueue _queue = null; + private Exchange _exchange = null; + private java.util.List _msgids = null; + + public State() + { + } + + public void setQueue(AMQQueue queue) + { + _queue = queue; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void setVhost(VirtualHost vhost) + { + _vhost = vhost; + } + + public VirtualHost getVhost() + { + return _vhost; + } + + public Exchange getExchange() + { + return _exchange; + } + + public void setExchange(Exchange exchange) + { + _exchange = exchange; + } + + public String toString() + { + StringBuilder status = new StringBuilder(); + + if (_vhost != null) + { + status.append(_vhost.getName()); + + if (_exchange != null) + { + status.append("["); + status.append(_exchange.getName()); + status.append("]"); + + if (_queue != null) + { + status.append("->'"); + status.append(_queue.getName()); + status.append("'"); + + if (_msgids != null) + { + status.append(printMessages()); + } + } + } + } + + return status.toString(); + } + + + public String printMessages() + { + StringBuilder sb = new StringBuilder(); + + Long previous = null; + + Long start = null; + for (Long id : _msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(id); + start = null; + } + else + { + sb.append(","); + sb.append(previous); + } + } + } + + previous = id; + } + + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(_msgids.get(_msgids.size() - 1)); + } + else + { + sb.append(","); + sb.append(previous); + } + + // surround list in () + sb.replace(0, 1, "("); + sb.append(")"); + return sb.toString(); + } + + public void clearAll() + { + _vhost = null; + clearExchange(); + } + + public void clearExchange() + { + _exchange = null; + clearQueue(); + } + + public void clearQueue() + { + _queue = null; + clearMessages(); + } + + public void clearMessages() + { + _msgids = null; + } + + /** + * A common location to provide parsing of the message id string + * utilised by a number of the commands. + * The String is comma separated list of ids that can be individual ids + * or a range (4-10) + * + * @param msgString string of msg ids to parse 1,2,4-10 + */ + public void setMessages(String msgString) + { + StringTokenizer tok = new StringTokenizer(msgString, ","); + + if (tok.hasMoreTokens()) + { + _msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + _msgids.add(l); + } + } + } + else + { + _msgids.add(Long.parseLong(next)); + } + } + + } + + public void setMessages(java.util.List msgids) + { + _msgids = msgids; + } + + public java.util.List getMessages() + { + return _msgids; + } + }//Class State + +}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java new file mode 100644 index 0000000000..5444197cb4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +public abstract class AbstractCommand implements Command +{ + protected Console _console; + protected MessageStoreTool _tool; + + public AbstractCommand(MessageStoreTool tool) + { + _console = tool.getConsole(); + _tool = tool; + } + + public void setOutput(Console out) + { + _console = out; + } + + protected void commandError(String message, String[] args) + { + _console.print(getCommand() + " : " + message); + + if (args != null) + { + for (int i = 1; i < args.length; i++) + { + _console.print(args[i]); + } + } + _console.println(""); + _console.println(help()); + } + + + public abstract String help(); + + public abstract String usage(); + + public abstract String getCommand(); + + + public abstract void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java new file mode 100644 index 0000000000..b0006b3fe6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Clear extends AbstractCommand +{ + public Clear(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Clears any selection."; + } + + public String usage() + { + return "clear [ all | virtualhost | exchange | queue | msgs ]"; + } + + public String getCommand() + { + return "clear"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 1) + { + doClose("all"); + } + else + { + doClose(args[1]); + } + } + + private void doClose(String type) + { + if (type.equals("virtualhost") + || type.equals("all")) + { + _tool.getState().clearAll(); + } + + if (type.equals("exchange")) + { + _tool.getState().clearExchange(); + } + + if (type.equals("queue")) + { + _tool.getState().clearQueue(); + } + + if (type.equals("msgs")) + { + _tool.getState().clearMessages(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java new file mode 100644 index 0000000000..bfa775a34a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.utils.Console; + +public interface Command +{ + public void setOutput(Console out); + + public String help(); + + public abstract String usage(); + + String getCommand(); + + public void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java new file mode 100644 index 0000000000..96ecb36952 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Copy extends Move +{ + public Copy(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Copy messages between queues.\n" + + "The currently selected message set will be copied to the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "copy to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "copy"; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue, StoreContext storeContext) + { + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), storeContext); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java new file mode 100644 index 0000000000..eea53252c6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -0,0 +1,299 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.commons.codec.binary.Hex; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class Dump extends Show +{ + private static final int LINE_SIZE = 8; + private static final String DEFAULT_ENCODING = "utf-8"; + private static final boolean SPACE_BYTES = true; + private static final String BYTE_SPACER = " "; + private static final String NON_PRINTING_ASCII_CHAR = "?"; + + protected boolean _content = true; + + public Dump(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Dump selected message content. Default: show=content"; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; + } + + public String getCommand() + { + return "dump"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _content = arg.contains("content") || arg.contains("all"); + } + } + + parseArgs(args); + } + + performShow(); + } + + + protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + List display = new LinkedList(); + + List hex = new LinkedList(); + List ascii = new LinkedList(); + display.add(hex); + display.add(ascii); + + for (AMQMessage msg : messages) + { + if (!includeMsg(msg, msgids)) + { + continue; + } + + //Add divider between messages + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + // Show general message information + hex.add(Show.Columns.ID.name()); + ascii.add(msg.getMessageId().toString()); + + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + if (showRouting) + { + addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); + } + if (showHeaders) + { + addShowInformation(hex, ascii, msg, "Headers", false, true, false); + } + if (showMessageHeaders) + { + addShowInformation(hex, ascii, msg, null, false, false, true); + } + + // Add Content Body seciont + hex.add("Content Body"); + ascii.add(""); + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + Iterator bodies = msg.getContentBodyIterator(); + if (bodies.hasNext()) + { + + hex.add("Hex"); + hex.add(Console.ROW_DIVIDER); + + + ascii.add("ASCII"); + ascii.add(Console.ROW_DIVIDER); + + while (bodies.hasNext()) + { + ContentChunk chunk = (ContentChunk) bodies.next(); + + //Duplicate so we don't destroy original data :) + ByteBuffer hexBuffer = chunk.getData().duplicate(); + + ByteBuffer charBuffer = hexBuffer.duplicate(); + + Hex hexencoder = new Hex(); + + while (hexBuffer.hasRemaining()) + { + byte[] line = new byte[LINE_SIZE]; + + int bufsize = hexBuffer.remaining(); + if (bufsize < LINE_SIZE) + { + hexBuffer.get(line, 0, bufsize); + } + else + { + bufsize = line.length; + hexBuffer.get(line); + } + + byte[] encoded = hexencoder.encode(line); + + try + { + String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); + String hexLine = ""; + + int strKength = encStr.length(); + for (int c = 0; c < strKength; c++) + { + hexLine += encStr.charAt(c); + + if (c % 2 == 1 && SPACE_BYTES) + { + hexLine += BYTE_SPACER; + } + } + + hex.add(hexLine); + } + catch (UnsupportedEncodingException e) + { + _console.println(e.getMessage()); + return null; + } + } + + while (charBuffer.hasRemaining()) + { + String asciiLine = ""; + + for (int pos = 0; pos < LINE_SIZE; pos++) + { + if (charBuffer.hasRemaining()) + { + byte ch = charBuffer.get(); + + if (isPrintable(ch)) + { + asciiLine += (char) ch; + } + else + { + asciiLine += NON_PRINTING_ASCII_CHAR; + } + + if (SPACE_BYTES) + { + asciiLine += BYTE_SPACER; + } + } + else + { + break; + } + } + + ascii.add(asciiLine); + } + } + } + else + { + List result = new LinkedList(); + + display.add(result); + result.add("No ContentBodies"); + } + } + + // if hex is empty then we have no data to display + if (hex.size() == 0) + { + return null; + } + + return display; + } + + private void addShowInformation(List column1, List column2, AMQMessage msg, + String title, boolean routing, boolean headers, boolean messageHeaders) + { + List single = new LinkedList(); + single.add(msg); + + List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); + + //Reformat data + if (title != null) + { + column1.add(title); + column2.add(""); + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + // look at all columns in the routing Data + for (List item : routingData) + { + // the item should be: + // Title + // *divider + // value + // otherwise we can't reason about the correct value + if (item.size() == 3) + { + //Filter out the columns we are not interested in. + + String columnName = item.get(0).toString(); + + if (!(columnName.equals(Show.Columns.ID.name()) + || columnName.equals(Show.Columns.Size.name()))) + { + column1.add(columnName); + column2.add(item.get(2).toString()); + } + } + } + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + private boolean isPrintable(byte c) + { + return c > 31 && c < 127; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java new file mode 100644 index 0000000000..0f9546541b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.Map; + +public class Help extends AbstractCommand +{ + public Help(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Provides detailed help on commands."; + } + + public String getCommand() + { + return "help"; + } + + public String usage() + { + return "help []"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + Command command = _tool.getCommands().get(args[1]); + if (command != null) + { + _console.println(command.help()); + _console.println("Usage:" + command.usage()); + } + else + { + commandError("Command not found: ", args); + } + } + else + { + java.util.List data = new LinkedList(); + + java.util.List commandName = new LinkedList(); + java.util.List commandDescription = new LinkedList(); + + data.add(commandName); + data.add(commandDescription); + + //Set up Headers + commandName.add("Command"); + commandDescription.add("Description"); + + commandName.add(Console.ROW_DIVIDER); + commandDescription.add(Console.ROW_DIVIDER); + + //Add current Commands with descriptions + Map commands = _tool.getCommands(); + + for (Command command : commands.values()) + { + commandName.add(command.getCommand()); + commandDescription.add(command.help()); + } + + _console.printMap("Available Commands", data); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java new file mode 100644 index 0000000000..df8b59ec19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -0,0 +1,314 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.Collection; +import java.util.LinkedList; + +public class List extends AbstractCommand +{ + + public List(MessageStoreTool tool) + { + super(tool); + } + + public void setOutput(Console out) + { + _console = out; + } + + public String help() + { + return "list available items."; + } + + public String usage() + { + return "list queues [] | exchanges | bindings [] | all"; + } + + public String getCommand() + { + return "list"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + if ((args[1].equals("exchanges")) + || (args[1].equals("queues")) + || (args[1].equals("bindings")) + || (args[1].equals("all"))) + { + if (args.length == 2) + { + doList(args[1]); + } + else if (args.length == 3) + { + doList(args[1], args[2]); + } + } + else + { + commandError("Unknown options. ", args); + } + } + else if (args.length < 2) + { + doList("all"); + } + else + { + doList(args[1]); + } + } + + private void doList(String... listItem) + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + listVirtualHosts(); + return; + } + + VirtualHost vhost = _tool.getState().getVhost(); + + java.util.List data = null; + + if (listItem[0].equals("queues")) + { + if (listItem.length > 1) + { + data = listQueues(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + data = listQueues(vhost, exchange); + } + } + + if (listItem[0].equals("exchanges")) + { + data = listExchanges(vhost); + } + + if (listItem[0].equals("bindings")) + { + + if (listItem.length > 1) + { + data = listBindings(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + + data = listBindings(vhost, exchange); + } + } + + if (data != null) + { + if (data.size() == 1) + { + _console.println("No '" + listItem[0] + "' to display,"); + } + else + { + _console.displayList(true, data.toArray(new String[0])); + } + } + + + if (listItem[0].equals("all")) + { + + boolean displayed = false; + Exchange exchange = _tool.getState().getExchange(); + + //Do the display here for each one so that they are pretty printed + data = listQueues(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (exchange == null) + { + data = listExchanges(vhost); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + } + + data = listBindings(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (!displayed) + { + _console.println("Nothing to list"); + } + } + } + + private void listVirtualHosts() + { + Collection vhosts = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHosts(); + + String[] data = new String[vhosts.size() + 1]; + + data[0] = "Available VirtualHosts"; + + int index = 1; + for (VirtualHost vhost : vhosts) + { + data[index] = vhost.getName(); + index++; + } + + _console.displayList(true, data); + } + + private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) + { + return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listBindings(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueueNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Current Bindings"); + + for (AMQShortString queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.toString()); + } + } + else + { + data.add(queue.toString()); + } + } + + return data; + } + + private java.util.List listExchanges(VirtualHost vhost) + { + Collection queues = vhost.getExchangeRegistry().getExchangeNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Exchanges"); + + for (AMQShortString queue : queues) + { + data.add(queue.toString()); + } + + return data; + } + + private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) + { + return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listQueues(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueues(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Queues"); + + for (AMQQueue queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.getName().toString()); + } + } + else + { + data.add(queue.getName().toString()); + } + } + + if (exchange != null) + { + if (queues.size() == 1) + { + return null; + } + } + + return data; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java new file mode 100644 index 0000000000..244a311c30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Load extends AbstractCommand +{ + public Load(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Loads specified broker configuration file."; + } + + public String usage() + { + return "load "; + } + + public String getCommand() + { + return "load"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 2) + { + _console.print("load " + args[1] + ": additional options not understood:"); + for (int i = 2; i < args.length; i++) + { + _console.print(args[i] + " "); + } + _console.println(""); + } + else if (args.length < 2) + { + _console.println("Enter Configuration file."); + String input = _console.readln(); + if (input != null) + { + doLoad(input); + } + else + { + _console.println("Did not recognise config file."); + } + } + else + { + doLoad(args[1]); + } + } + + private void doLoad(String configfile) + { + _console.println("Loading Configuration:" + configfile); + + try + { + _tool.setConfigurationFile(configfile); + } + catch (Configuration.InitException e) + { + _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java new file mode 100644 index 0000000000..a9497fd23e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.List; + +public class Move extends AbstractCommand +{ + + /** + * Since the Coopy command is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + private StoreContext _storeContext = new StoreContext(); + + public Move(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Move messages between queues.\n" + + "The currently selected message set will be moved to the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "move to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "move"; + } + + public void execute(String... args) + { + AMQQueue toQueue = null; + AMQQueue fromQueue = _tool.getState().getQueue(); + java.util.List msgids = _tool.getState().getMessages(); + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("to=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("from=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("msgids=")) + { + String msgidStr = arg.substring(arg.indexOf("=") + 1); + + // Record the current message selection + java.util.List currentIDs = _tool.getState().getMessages(); + + // Use the ToolState class to perform the messasge parsing + _tool.getState().setMessages(msgidStr); + msgids = _tool.getState().getMessages(); + + // Reset the original selection of messages + _tool.getState().setMessages(currentIDs); + } + } + } + + if (!checkRequirements(fromQueue, toQueue, msgids)) + { + return; + } + + processIDs(fromQueue, toQueue, msgids); + } + + private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + Long previous = null; + Long start = null; + + for (long id : msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, id, toQueue, _storeContext); + } + else + { + //move a single id + doCommand(fromQueue, id, id, toQueue, _storeContext); + } + } + } + + previous = id; + } + } + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) + { + if (toQueue == null) + { + _console.println("Destination queue not specifed."); + _console.println(usage()); + return false; + } + + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue, StoreContext storeContext) + { + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java new file mode 100644 index 0000000000..7154159b40 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Purge extends Move +{ + public Purge(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Purge messages from a queue.\n" + + "The currently selected message set will be purged from the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "purge from= [msgids=]"; + } + + public String getCommand() + { + return "purge"; + } + + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue, StoreContext storeContext) + { + fromQueue.removeMessagesFromQueue(start, end, storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java new file mode 100644 index 0000000000..a81bc07c38 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Quit extends AbstractCommand +{ + public Quit(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Quit the tool."; + } + + public String usage() + { + return "quit"; + } + + public String getCommand() + { + return "quit"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals("quit"); + + _tool.quit(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java new file mode 100644 index 0000000000..5e9b7028e9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.StringTokenizer; + +public class Select extends AbstractCommand +{ + + public Select(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Perform a selection."; + } + + public String usage() + { + return "select virtualhost |exchange |queue | msgs id="; + } + + public String getCommand() + { + return "select"; + } + + public void execute(String... args) + { + assert args.length > 2; + assert args[0].equals("select"); + + if (args.length < 3) + { + if (args[1].equals("show")) + { + doSelect(args[1], null); + } + else + { + _console.print("select : unknown command:"); + _console.println(help()); + } + } + else + { + if (args[1].equals("virtualhost") + || args[1].equals("vhost") + || args[1].equals("exchange") + || args[1].equals("queue") + || args[1].equals("msg") + ) + { + doSelect(args[1], args[2]); + } + else + { + _console.println(help()); + } + } + } + + private void doSelect(String type, String item) + { + if (type.equals("virtualhost")) + { + + VirtualHost vhost = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHost(item); + + if (vhost == null) + { + _console.println("Virtualhost '" + item + "' not found."); + } + else + { + _tool.getState().setVhost(vhost); + } + } + + if (type.equals("exchange")) + { + + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + + Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); + + if (exchange == null) + { + _console.println("Exchange '" + item + "' not found."); + } + else + { + _tool.getState().setExchange(exchange); + } + + if (_tool.getState().getQueue() != null) + { + if (!exchange.isBound(_tool.getState().getQueue())) + { + _tool.getState().setQueue(null); + } + } + } + + if (type.equals("queue")) + { + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); + + if (queue == null) + { + _console.println("Queue '" + item + "' not found."); + } + else + { + _tool.getState().setQueue(queue); + + if (_tool.getState().getExchange() == null) + { + for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) + { + Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); + if (exchange.isBound(queue)) + { + _tool.getState().setExchange(exchange); + break; + } + } + } + + //remove the message selection + _tool.getState().setMessages((java.util.List) null); + } + } + + if (type.equals("msg")) + { + if (item.startsWith("id=")) + { + StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); + + java.util.List msgids = null; + + if (tok.hasMoreTokens()) + { + msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + msgids.add(l); + } + } + } + else + { + msgids.add(Long.parseLong(next)); + } + } + + _tool.getState().setMessages(msgids); + } + + } + + if (type.equals("show")) + { + _console.println(_tool.getState().toString()); + if (_tool.getState().getMessages() != null) + { + _console.print("Msgs:"); + for (Long l : _tool.getState().getMessages()) + { + _console.print(" " + l); + } + _console.println(""); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java new file mode 100644 index 0000000000..5988cdabfc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -0,0 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +public class Show extends AbstractCommand +{ + protected boolean _amqHeaders = false; + protected boolean _routing = false; + protected boolean _msgHeaders = false; + + public Show(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Shows the messages headers."; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; + } + + public String getCommand() + { + return "show"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 2) + { + parseArgs("all"); + } + else + { + parseArgs(args); + } + + performShow(); + } + + protected void parseArgs(String... args) + { + List msgids = null; + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); + _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); + _routing = arg.contains("routing") || arg.contains("all"); + } + + if (arg.startsWith("id=")) + { + _tool.getState().setMessages(msgids); + } + }//for args + }// if args > 2 + } + + protected void performShow() + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); + return; + } + + AMQQueue _queue = _tool.getState().getQueue(); + + List msgids = _tool.getState().getMessages(); + + if (_queue != null) + { + List messages = _queue.getMessagesOnTheQueue(); + if (messages == null || messages.size() == 0) + { + _console.println("No messages on queue"); + return; + } + + List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); + if (data != null) + { + _console.printMap(null, data); + } + else + { + String message = "No data to display."; + if (msgids != null) + { + message += " Is message selection correct? " + _tool.getState().printMessages(); + } + _console.println(message); + } + + } + else + { + _console.println("No Queue specified to show."); + } + } + + /** + * Create the list data for display from the messages. + * + * @param msgids The list of message ids to display + * @param messages A list of messages to format and display. + * @param showHeaders should the header info be shown + * @param showRouting show the routing info be shown + * @param showMessageHeaders show the msg headers be shown + * @return the formated data lists for printing + */ + protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + // Currenly exposed message properties +// //Printing the content Body +// msg.getContentBodyIterator(); +// //Print the Headers +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); +// +// //Print out all the property names +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); +// +// msg.getMessageId(); +// msg.getSize(); +// msg.getArrivalTime(); + +// msg.getDeliveredSubscription(); +// msg.getDeliveredToConsumer(); +// msg.getMessageHandle(); +// msg.getMessageId(); +// msg.getMessagePublishInfo(); +// msg.getPublisher(); + +// msg.getStoreContext(); +// msg.isAllContentReceived(); +// msg.isPersistent(); +// msg.isRedelivered(); +// msg.isRejectedBy(); +// msg.isTaken(); + + //Header setup + + List data = new LinkedList(); + + List id = new LinkedList(); + data.add(id); + id.add(Columns.ID.name()); + id.add(Console.ROW_DIVIDER); + + List exchange = new LinkedList(); + List routingkey = new LinkedList(); + List immediate = new LinkedList(); + List mandatory = new LinkedList(); + if (showRouting) + { + data.add(exchange); + exchange.add(Columns.Exchange.name()); + exchange.add(Console.ROW_DIVIDER); + + data.add(routingkey); + routingkey.add(Columns.RoutingKey.name()); + routingkey.add(Console.ROW_DIVIDER); + + data.add(immediate); + immediate.add(Columns.isImmediate.name()); + immediate.add(Console.ROW_DIVIDER); + + data.add(mandatory); + mandatory.add(Columns.isMandatory.name()); + mandatory.add(Console.ROW_DIVIDER); + } + + List size = new LinkedList(); + List appid = new LinkedList(); + List clusterid = new LinkedList(); + List contenttype = new LinkedList(); + List correlationid = new LinkedList(); + List deliverymode = new LinkedList(); + List encoding = new LinkedList(); + List arrival = new LinkedList(); + List expiration = new LinkedList(); + List priority = new LinkedList(); + List propertyflag = new LinkedList(); + List replyto = new LinkedList(); + List timestamp = new LinkedList(); + List type = new LinkedList(); + List userid = new LinkedList(); + List ispersitent = new LinkedList(); + List isredelivered = new LinkedList(); + List isdelivered = new LinkedList(); + + data.add(size); + size.add(Columns.Size.name()); + size.add(Console.ROW_DIVIDER); + + if (showHeaders) + { + data.add(ispersitent); + ispersitent.add(Columns.isPersistent.name()); + ispersitent.add(Console.ROW_DIVIDER); + + data.add(isredelivered); + isredelivered.add(Columns.isRedelivered.name()); + isredelivered.add(Console.ROW_DIVIDER); + + data.add(isdelivered); + isdelivered.add(Columns.isDelivered.name()); + isdelivered.add(Console.ROW_DIVIDER); + + data.add(appid); + appid.add(Columns.App_ID.name()); + appid.add(Console.ROW_DIVIDER); + + data.add(clusterid); + clusterid.add(Columns.Cluster_ID.name()); + clusterid.add(Console.ROW_DIVIDER); + + data.add(contenttype); + contenttype.add(Columns.Content_Type.name()); + contenttype.add(Console.ROW_DIVIDER); + + data.add(correlationid); + correlationid.add(Columns.Correlation_ID.name()); + correlationid.add(Console.ROW_DIVIDER); + + data.add(deliverymode); + deliverymode.add(Columns.Delivery_Mode.name()); + deliverymode.add(Console.ROW_DIVIDER); + + data.add(encoding); + encoding.add(Columns.Encoding.name()); + encoding.add(Console.ROW_DIVIDER); + + data.add(arrival); + expiration.add(Columns.Arrival.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(expiration); + expiration.add(Columns.Expiration.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(priority); + priority.add(Columns.Priority.name()); + priority.add(Console.ROW_DIVIDER); + + data.add(propertyflag); + propertyflag.add(Columns.Property_Flag.name()); + propertyflag.add(Console.ROW_DIVIDER); + + data.add(replyto); + replyto.add(Columns.ReplyTo.name()); + replyto.add(Console.ROW_DIVIDER); + + data.add(timestamp); + timestamp.add(Columns.Timestamp.name()); + timestamp.add(Console.ROW_DIVIDER); + + data.add(type); + type.add(Columns.Type.name()); + type.add(Console.ROW_DIVIDER); + + data.add(userid); + userid.add(Columns.UserID.name()); + userid.add(Console.ROW_DIVIDER); + } + + List msgHeaders = new LinkedList(); + if (showMessageHeaders) + { + data.add(msgHeaders); + msgHeaders.add(Columns.MsgHeaders.name()); + msgHeaders.add(Console.ROW_DIVIDER); + } + + //Add create the table of data + for (AMQMessage msg : messages) + { + if (!includeMsg(msg, msgids)) + { + continue; + } + + id.add(msg.getMessageId().toString()); + + size.add("" + msg.getSize()); + + arrival.add("" + msg.getArrivalTime()); + + try + { + ispersitent.add(msg.isPersistent() ? "true" : "false"); + } + catch (AMQException e) + { + ispersitent.add("n/a"); + } + + isredelivered.add(msg.isRedelivered() ? "true" : "false"); + + isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + +// msg.getMessageHandle(); + + BasicContentHeaderProperties headers = null; + + try + { + headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + } + catch (AMQException e) + { + //ignore +// commandError("Unable to read properties for message: " + e.getMessage(), null); + } + + if (headers != null) + { + String appidS = headers.getAppIdAsString(); + appid.add(appidS == null ? "null" : appidS); + + String clusterS = headers.getClusterIdAsString(); + clusterid.add(clusterS == null ? "null" : clusterS); + + String contentS = headers.getContentTypeAsString(); + contenttype.add(contentS == null ? "null" : contentS); + + String correlationS = headers.getCorrelationIdAsString(); + correlationid.add(correlationS == null ? "null" : correlationS); + + deliverymode.add("" + headers.getDeliveryMode()); + + AMQShortString encodeSS = headers.getEncoding(); + encoding.add(encodeSS == null ? "null" : encodeSS.toString()); + + expiration.add("" + headers.getExpiration()); + + FieldTable headerFT = headers.getHeaders(); + msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); + + priority.add("" + headers.getPriority()); + propertyflag.add("" + headers.getPropertyFlags()); + + AMQShortString replytoSS = headers.getReplyTo(); + replyto.add(replytoSS == null ? "null" : replytoSS.toString()); + + timestamp.add("" + headers.getTimestamp()); + + AMQShortString typeSS = headers.getType(); + type.add(typeSS == null ? "null" : typeSS.toString()); + + AMQShortString useridSS = headers.getUserId(); + userid.add(useridSS == null ? "null" : useridSS.toString()); + + MessagePublishInfo info = null; + try + { + info = msg.getMessagePublishInfo(); + } + catch (AMQException e) + { + //ignore + } + + if (info != null) + { + AMQShortString exchangeSS = info.getExchange(); + exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); + + AMQShortString routingkeySS = info.getRoutingKey(); + routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); + + immediate.add(info.isImmediate() ? "true" : "false"); + mandatory.add(info.isMandatory() ? "true" : "false"); + } + +// msg.getPublisher(); -- only used in clustering +// msg.getStoreContext(); +// msg.isAllContentReceived(); + + }// if headers!=null + +// need to access internal map and do lookups. +// msg.isTaken(); +// msg.getDeliveredSubscription(); +// msg.isRejectedBy(); + + } + + // if id only had the header and the divider in it then we have no data to display + if (id.size() == 2) + { + return null; + } + return data; + } + + protected boolean includeMsg(AMQMessage msg, List msgids) + { + if (msgids == null) + { + return true; + } + + Long msgid = msg.getMessageId(); + + boolean found = false; + + if (msgids != null) + { + //check msgid is in msgids + for (Long l : msgids) + { + if (l.equals(msgid)) + { + found = true; + break; + } + } + } + return found; + } + + public enum Columns + { + ID, + Size, + Exchange, + RoutingKey, + isImmediate, + isMandatory, + isPersistent, + isRedelivered, + isDelivered, + App_ID, + Cluster_ID, + Content_Type, + Correlation_ID, + Delivery_Mode, + Encoding, + Arrival, + Expiration, + Priority, + Property_Flag, + ReplyTo, + Timestamp, + Type, + UserID, + MsgHeaders + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java new file mode 100644 index 0000000000..c27c52eb8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java new file mode 100644 index 0000000000..986fea32cc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +public interface CommandParser +{ + /** + * If there is more than one command received on the last parse request. + * + * Subsequent calls to parse will utilise this input rather than reading new data from the input source + * @return boolean + */ + boolean more(); + + /** + * True if the currently parsed command has been requested as a background operation + * + * @return boolean + */ + boolean isBackground(); + + /** + * Parses user commands, and groups tokens in the + * String[] format that all Java main's love. + * + * If more than one command is provided in one input line then the more() method will return true. + * A subsequent call to parse() will continue to parse that input line before reading new input. + * + * @return input split in args[] format; null if eof. + * @throws java.io.IOException if there is a problem reading from the input stream + */ + String[] parse() throws java.io.IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java new file mode 100644 index 0000000000..cf457d1ea5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.util.List; + +public interface Console +{ + public enum CellFormat + { + CENTRED, LEFT, RIGHT + } + + public static String ROW_DIVIDER = "*divider"; + + public void print(String... message); + + public void println(String... message); + + public String readln(); + + /** + * Reads and parses the command line. + * + * + * @return The next command or null + */ + public String[] readCommand(); + + public CommandParser getCommandParser(); + + public void setCommandParser(CommandParser parser); + + /** + * + * Prints the list of String nicely. + * + * +-------------+ + * | Heading | + * +-------------+ + * | Item 1 | + * | Item 2 | + * | Item 3 | + * +-------------+ + * + * @param hasTitle should list[0] be used as a heading + * @param list The list of Strings to display + */ + public void displayList(boolean hasTitle, String... list); + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * +----------------------------+ (*divider) + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + void printMap(String title, List entries); + + + public void close(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java new file mode 100644 index 0000000000..09444ccdd7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.StringTokenizer; + +public class SimpleCommandParser implements CommandParser +{ + private static final String COMMAND_SEPERATOR = ";"; + + /** Input source of commands */ + protected BufferedReader _reader; + + /** The next list of commands from the command line */ + private StringBuilder _nextCommand = null; + + public SimpleCommandParser(BufferedReader reader) + { + _reader = reader; + } + + public boolean more() + { + return _nextCommand != null; + } + + public boolean isBackground() + { + return false; + } + + public String[] parse() throws IOException + { + String[] commands = null; + + String input = null; + + if (_nextCommand == null) + { + input = _reader.readLine(); + } + else + { + input = _nextCommand.toString(); + _nextCommand = null; + } + + if (input == null) + { + return null; + } + + StringTokenizer tok = new StringTokenizer(input, " "); + + int tokenCount = tok.countTokens(); + int index = 0; + + if (tokenCount > 0) + { + commands = new String[tokenCount]; + boolean commandComplete = false; + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + + if (next.equals(COMMAND_SEPERATOR)) + { + commandComplete = true; + _nextCommand = new StringBuilder(); + continue; + } + + if (commandComplete) + { + _nextCommand.append(next); + _nextCommand.append(" "); + } + else + { + commands[index] = next; + index++; + } + } + + } + + //Reduce the String[] if not all the tokens were used in this command. + // i.e. there is more than one command on the line. + if (index != tokenCount) + { + String[] shortCommands = new String[index]; + System.arraycopy(commands, 0, shortCommands, 0, index); + return shortCommands; + } + else + { + return commands; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java new file mode 100644 index 0000000000..ec080a4611 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +public class SimpleConsole implements Console +{ + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); + + /** Console Writer. */ + protected static BufferedWriter _consoleWriter; + + /** Console Reader. */ + protected static BufferedReader _consoleReader; + + /** Parser for command-line input. */ + protected CommandParser _parser; + + public SimpleConsole(BufferedWriter writer, BufferedReader reader) + { + _consoleWriter = writer; + _consoleReader = reader; + _parser = new SimpleCommandParser(_consoleReader); + } + + public void print(String... message) + { + try + { + for (String s : message) + { + _consoleWriter.write(s); + } + _consoleWriter.flush(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); + } + + } + + public void println(String... message) + { + print(message); + print(System.getProperty("line.separator")); + } + + + public String readln() + { + try + { + return _consoleReader.readLine(); + } + catch (IOException e) + { + _devlog.debug("Unable to read input due to:" + e.getMessage()); + return null; + } + } + + public String[] readCommand() + { + try + { + return _parser.parse(); + } + catch (IOException e) + { + _devlog.error("Error reading command:" + e.getMessage()); + return new String[0]; + } + } + + public CommandParser getCommandParser() + { + return _parser; + } + + public void setCommandParser(CommandParser parser) + { + _parser = parser; + } + + public void displayList(boolean hasTitle, String... list) + { + java.util.List data = new LinkedList(); + + java.util.List values = new LinkedList(); + + data.add(values); + + for (String value : list) + { + values.add(value); + } + + if (hasTitle) + { + values.add(1, "*divider"); + } + + printMap(null, data); + } + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + public void printMap(String title, java.util.List entries) + { + try + { + int columns = entries.size(); + + int[] columnWidth = new int[columns]; + + // calculate row count + int rowMax = 0; + + //the longest item + int itemMax = 0; + + for (int i = 0; i < columns; i++) + { + int columnIRowMax = entries.get(i).size(); + + if (columnIRowMax > rowMax) + { + rowMax = columnIRowMax; + } + for (Object values : entries.get(i)) + { + if (values.toString().equals(Console.ROW_DIVIDER)) + { + continue; + } + + int itemLength = values.toString().length(); + + //note for single width + if (itemLength > itemMax) + { + itemMax = itemLength; + } + + //note for mulit width + if (itemLength > columnWidth[i]) + { + columnWidth[i] = itemLength; + } + + } + } + + int tableWidth = 0; + + + for (int i = 0; i < columns; i++) + { + // plus 2 for the space padding + columnWidth[i] += 2; + } + for (int size : columnWidth) + { + tableWidth += size; + } + tableWidth += (columns - 1); + + if (title != null) + { + if (title.length() > tableWidth) + { + tableWidth = title.length(); + } + + printCellRow("+", "-", tableWidth); + + printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); + _consoleWriter.newLine(); + + } + + //put top line | or bottom of title + printCellRow("+", "-", tableWidth); + + //print the table data + int row = 0; + + for (; row < rowMax; row++) + { + for (int i = 0; i < columns; i++) + { + java.util.List columnData = entries.get(i); + + String value; + // does this column have a value for this row + if (columnData.size() > row) + { + value = " " + columnData.get(row).toString() + " "; + } + else + { + value = " "; + } + + if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) + { + printCellRow("+", "-", tableWidth); + //move on to the next row + break; + } + else + { + printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); + } + + // if it is the last row then do a new line. + if (i == columns - 1) + { + _consoleWriter.newLine(); + } + } + } + + printCellRow("+", "-", tableWidth); + + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write."); + } + } + + public void close() + { + + try + { + _consoleReader.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); + } + + try + { + + _consoleWriter.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); + } + + } + + private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException + { + int pad = cellWidth - cell.length(); + + if (column == 0) + { + _consoleWriter.write(edge); + } + + switch (format) + { + case CENTRED: + printPad(" ", pad / 2); + break; + case RIGHT: + printPad(" ", pad); + break; + } + + _consoleWriter.write(cell); + + + switch (format) + { + case CENTRED: + // if pad isn't even put the extra one on the right + if (pad % 2 == 0) + { + printPad(" ", pad / 2); + } + else + { + printPad(" ", (pad / 2) + 1); + } + break; + case LEFT: + printPad(" ", pad); + break; + } + + + _consoleWriter.write(edge); + + } + + private void printCellRow(String edge, String mid, int cellWidth) throws IOException + { + _consoleWriter.write(edge); + + printPad(mid, cellWidth); + + _consoleWriter.write(edge); + _consoleWriter.newLine(); + } + + private void printPad(String padChar, int count) throws IOException + { + for (int i = 0; i < count; i++) + { + _consoleWriter.write(padChar); + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java new file mode 100644 index 0000000000..6a95529059 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package com.redhat.etp.qpid.utils; + +public interface CommandParser +{ + /** + * If there is more than one command received on the last parse request. + * + * Subsequent calls to parse will utilise this input rather than reading new data from the input source + * @return boolean + */ + boolean more(); + + /** + * True if the currently parsed command has been requested as a background operation + * + * @return boolean + */ + boolean isBackground(); + + /** + * Parses user commands, and groups tokens in the + * String[] format that all Java main's love. + * + * If more than one command is provided in one input line then the more() method will return true. + * A subsequent call to parse() will continue to parse that input line before reading new input. + * + * @return input split in args[] format; null if eof. + * @throws java.io.IOException if there is a problem reading from the input stream + */ + String[] parse() throws java.io.IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java new file mode 100644 index 0000000000..892a48254c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package com.redhat.etp.qpid; + +import java.util.List; + +public interface Console +{ + public enum CellFormat + { + CENTRED, LEFT, RIGHT + } + + public static String ROW_DIVIDER = "*divider"; + + public void print(String... message); + + public void println(String... message); + + public String[] readln(); + + /** + * + * Prints the list of String nicely. + * + * +-------------+ + * | Heading | + * +-------------+ + * | Item 1 | + * | Item 2 | + * | Item 3 | + * +-------------+ + * + * @param hasTitle should list[0] be used as a heading + * @param list The list of Strings to display + */ + public void displayList(boolean hasTitle, String... list); + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * +----------------------------+ (*divider) + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + void printMap(String title, List entries); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java new file mode 100644 index 0000000000..ea4045c917 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java @@ -0,0 +1,352 @@ +/* + * The Java Shell: jsh core -- RELEASE: alpha3 + * (C)1999 Osvaldo Pinali Doederlein. + * + * LICENSE + * ======= + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CHANGES + * ======= + * 1.0.2 - Added support for non-quoted '\' escape char (Not interpreted by the shell) + * 1.0.1 - Added support for arguments in aliases + * 1.0.0 - Initial release; split from Shell and enhanced a lot. + * + * LINKS + * ===== + * Contact: mailto@osvaldo.visionnaire.com.br, mailto@g.collin@appliweb.net + * Site #1: http://www.geocities.com/ResearchTriangle/Node/2005/ + * Site #2: http://www.appliweb.net/jsh + */ + +package com.redhat.etp.qpid.utils; + +import java.io.BufferedReader; +import java.util.Vector; + +/** + * The Java Shell. + *

      + * Provides an environment for launching and controlling Java apps. + *

      + * TODO: - Support for applets! + * - Support for variable replacement + * + * @author Osvaldo Pinali Doederlein. + */ +public class RSHCommandParser implements CommandParser +{ + /** Where commands come from. */ + protected BufferedReader reader; + /** Continuation for command line. */ + protected String contLine = null; + /** Run next command in background? */ + protected boolean background; + protected String[] env; // Commands passed in args. + + public RSHCommandParser(BufferedReader reader) + { + this(reader, null); + } + + public RSHCommandParser(BufferedReader reader, String env[]) + { + this.reader = reader; + this.env = env; + if (env == null) + { + this.env = new String[0]; + } + } + + + public boolean more() + { + return contLine != null; + } + + public boolean isBackground() + { + return background; + } + + /** + * Solves and expands aliases in an argument array. + * This expansion affects only the first (if any) argument; the + * typical thing to do, as we don't want to expand parameters. + * We recursively parse the result to be sure we expand everything. + * For example, an alias can be expanded to further aliases, or it can contains args. + * + * @param args Raw arguments. + * @return args resolved and expanded. + */ + public static String[] expand(String[] args) + { + if (args.length > 0) + { + String expanded = args[0];//Alias.resolve(args[0]); + + // Try to expand recursively the command line + if (expanded != args[0]) + { + RSHCommandParser recurse = new RSHCommandParser(new BufferedReader( + new java.io.StringReader(expanded))); + + try + { + String cmdLine[] = recurse.parse(); + cmdLine = recurse.expand(cmdLine); + + // do we need to handle new arguments and insert them in the command array ? + if (cmdLine.length > 1) + { + String[] newArgs = new String[cmdLine.length + args.length - 1]; + System.arraycopy(cmdLine, 0, newArgs, 0, cmdLine.length); + + if (args.length > 1) + { + System.arraycopy(args, 1, newArgs, cmdLine.length, args.length - 1); + } + + args = newArgs; + } + else if (cmdLine.length == 1) + { + args[0] = cmdLine[0]; + } + } + catch (java.io.IOException e) + { + } + } + } + + return args; + } + + public String[] parse() throws java.io.IOException + { + final int READ = 0, QUOTE = 1, SKIP = 2, ESCAPE = 3, NONQUOTEDESCAPE = 4, VARIABLE = 5; + final int EOF = 0xFFFF; + int mode = SKIP; + Vector args = new Vector(); + StringBuffer current = new StringBuffer(); + StringBuffer varName = null; + background = false; + String line; + + if (contLine == null) + { + line = reader.readLine(); + } + else + { + line = contLine; + contLine = null; + } + + if (line == null) + { + reader = null; + return null; + } + + for (int pos = 0; pos < line.length(); ++pos) + { + char c = line.charAt(pos); + + switch (mode) + { + case SKIP: + switch (c) + { + case' ': + case'\t': + break; + case'\"': + mode = QUOTE; + break; + case'&': + background = true; + case';': + contLine = line.substring(pos + 1); + pos = line.length(); + break; + default: + mode = READ; + --pos; + } + break; + + case READ: + switch (c) + { + case'\"': + mode = QUOTE; + break; + case';': + case'&': + --pos; + case' ': + case'\t': + mode = SKIP; + break; + case'\\': + mode = NONQUOTEDESCAPE; + break; + case'$': + mode = VARIABLE; + varName = new StringBuffer(); + break; + default: + current.append(c); + } + if ((mode != READ) && (mode != NONQUOTEDESCAPE)) + { + args.addElement(current.toString()); + current = new StringBuffer(); + } + break; + + case QUOTE: + switch (c) + { + case'\"': + mode = READ; + break; + case'\\': + mode = ESCAPE; + break; + default: + current.append(c); + } + break; + + case ESCAPE: + switch (c) + { + case'n': + c = '\n'; + break; + case'r': + c = '\r'; + break; + case't': + c = '\t'; + break; + case'b': + c = '\b'; + break; + case'f': + c = '\f'; + break; + default: + current.append('\\'); + break; + } + mode = QUOTE; + current.append(c); + break; + case NONQUOTEDESCAPE: + switch (c) + { + case';': + mode = READ; + current.append(c); + break; + default: // This is not a escaped char. + mode = READ; + current.append('\\'); + current.append(c); + break; + } + break; + case VARIABLE: + switch (c) + { + case'$': + { +// String val = Set.get(new String(varName)); +// if (val != null) +// { +// current.append(val); +// } + mode = READ; + break; + } + case'@': + { + StringBuffer val = new StringBuffer(); + int i; + for (i = 0; i < env.length; i++) + { + val.append(env[i]); + val.append(' '); + } + current.append(val); + mode = READ; + break; + } + case'0': + case'1': + case'2': + case'3': + case'4': + case'5': + case'6': + case'7': + case'8': + case'9': + { + if (varName.length() == 0) + { + int value = Integer.parseInt(new String(new char[]{c})); + if (env.length > value) + { + current.append(env[value]); + } + mode = READ; + break; + } + // else fall back + } + default: + varName.append(c); + break; + } + break; + } + } + + if (current.length() > 0) + { + args.addElement(current.toString()); + } + return expand(toArray(args)); + } + + private String[] toArray(Vector strings) + { + String[] arr = new String[strings.size()]; + + for (int i = 0; i < strings.size(); ++i) + { + arr[i] = (String) strings.elementAt(i); + } + + return arr; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java new file mode 100644 index 0000000000..98e816554e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package com.redhat.etp.qpid.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.StringTokenizer; + +public class SimpleCommandParser implements CommandParser +{ + private static final String COMMAND_SEPERATOR = ";"; + + /** Input source of commands */ + protected BufferedReader _reader; + + /** The next list of commands from the command line */ + private StringBuilder _nextCommand = null; + + public SimpleCommandParser(BufferedReader reader) + { + _reader = reader; + } + + public boolean more() + { + return _nextCommand != null; + } + + public boolean isBackground() + { + return false; + } + + public String[] parse() throws IOException + { + String[] commands = null; + + String input = null; + + if (_nextCommand == null) + { + input = _reader.readLine(); + } + else + { + input = _nextCommand.toString(); + _nextCommand = null; + } + + StringTokenizer tok = new StringTokenizer(input, " "); + + int tokenCount = tok.countTokens(); + int index = 0; + + if (tokenCount > 0) + { + commands = new String[tokenCount]; + boolean commandComplete = false; + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + + if (next.equals(COMMAND_SEPERATOR)) + { + commandComplete = true; + _nextCommand = new StringBuilder(); + continue; + } + + if (commandComplete) + { + _nextCommand.append(next); + _nextCommand.append(" "); + } + else + { + commands[index] = next; + index++; + } + } + + } + + //Reduce the String[] if not all the tokens were used in this command. + // i.e. there is more than one command on the line. + if (index != tokenCount) + { + String[] shortCommands = new String[index]; + System.arraycopy(commands, 0, shortCommands, 0, index); + return shortCommands; + } + else + { + return commands; + } + } +} -- cgit v1.2.1 From c06860ce45b4f52be1ba934fd4d92da10c9cc25f Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 31 Jul 2007 22:34:12 +0000 Subject: Rolled back revision 561365 and commented out some broken code in ClientSession.java. The trunk should now build. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@561578 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 3 + .../apache/qpid/configuration/Configuration.java | 188 ------ .../java/org/apache/qpid/server/AMQChannel.java | 10 +- .../src/main/java/org/apache/qpid/server/Main.java | 56 +- .../qpid/server/exchange/AbstractExchange.java | 6 - .../server/exchange/DefaultExchangeRegistry.java | 19 +- .../qpid/server/exchange/DestNameExchange.java | 11 +- .../qpid/server/exchange/DestWildExchange.java | 21 +- .../org/apache/qpid/server/exchange/Exchange.java | 28 +- .../qpid/server/exchange/ExchangeRegistry.java | 4 - .../qpid/server/exchange/FanoutExchange.java | 29 +- .../qpid/server/exchange/HeadersExchange.java | 61 +- .../server/handler/BasicConsumeMethodHandler.java | 18 +- .../server/handler/BasicPublishMethodHandler.java | 10 - .../handler/ConnectionStartOkMethodHandler.java | 3 +- .../qpid/server/handler/ExchangeBoundHandler.java | 25 +- .../server/handler/ExchangeDeclareHandler.java | 4 +- .../qpid/server/handler/QueueBindHandler.java | 17 +- .../qpid/server/handler/QueueDeclareHandler.java | 7 - .../management/JMXManagedObjectRegistry.java | 44 +- .../management/MBeanInvocationHandlerImpl.java | 25 +- .../server/protocol/AMQPFastProtocolHandler.java | 28 +- .../org/apache/qpid/server/queue/AMQMessage.java | 16 +- .../org/apache/qpid/server/queue/AMQQueue.java | 250 ++------ .../apache/qpid/server/queue/AMQQueueMBean.java | 66 ++- .../queue/ConcurrentSelectorDeliveryManager.java | 109 ++-- .../qpid/server/queue/DefaultQueueRegistry.java | 17 +- .../apache/qpid/server/queue/ExchangeBindings.java | 13 +- .../apache/qpid/server/queue/MessageMetaData.java | 24 +- .../qpid/server/queue/NotificationCheck.java | 25 +- .../server/queue/QueueNotificationListener.java | 26 +- .../apache/qpid/server/queue/QueueRegistry.java | 6 - .../qpid/server/queue/TransientMessageData.java | 25 +- .../org/apache/qpid/server/security/Passwd.java | 81 +++ .../qpid/server/txn/NonTransactionalContext.java | 25 +- .../qpid/server/txn/TransactionalContext.java | 124 +--- .../qpid/server/virtualhost/VirtualHost.java | 262 --------- .../qpid/tools/messagestore/MessageStoreTool.java | 648 --------------------- .../messagestore/commands/AbstractCommand.java | 66 --- .../qpid/tools/messagestore/commands/Clear.java | 85 --- .../qpid/tools/messagestore/commands/Command.java | 36 -- .../qpid/tools/messagestore/commands/Copy.java | 56 -- .../qpid/tools/messagestore/commands/Dump.java | 299 ---------- .../qpid/tools/messagestore/commands/Help.java | 98 ---- .../qpid/tools/messagestore/commands/List.java | 314 ---------- .../qpid/tools/messagestore/commands/Load.java | 94 --- .../qpid/tools/messagestore/commands/Move.java | 166 ------ .../qpid/tools/messagestore/commands/Purge.java | 68 --- .../qpid/tools/messagestore/commands/Quit.java | 54 -- .../qpid/tools/messagestore/commands/Select.java | 233 -------- .../qpid/tools/messagestore/commands/Show.java | 513 ---------------- .../org/apache/qpid/tools/security/Passwd.java | 81 --- .../org/apache/qpid/tools/utils/CommandParser.java | 51 -- .../java/org/apache/qpid/tools/utils/Console.java | 90 --- .../qpid/tools/utils/SimpleCommandParser.java | 121 ---- .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 ------------ .../qpid/tools/utils/utils/CommandParser.java | 51 -- .../org/apache/qpid/tools/utils/utils/Console.java | 75 --- .../qpid/tools/utils/utils/RSHCommandParser.java | 352 ----------- .../tools/utils/utils/SimpleCommandParser.java | 116 ---- 60 files changed, 419 insertions(+), 5297 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 7e0c4defe1..931c15a664 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPOutputStream; import org.apache.log4j.helpers.CountingQuietWriter; @@ -38,6 +39,8 @@ import org.apache.log4j.helpers.LogLog; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.spi.LoggingEvent; +import org.apache.qpid.framing.FieldTable; + /** *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java deleted file mode 100644 index 40ff590a0a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.configuration; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -public class Configuration -{ - public static final String QPID_HOME = "QPID_HOME"; - - final String QPIDHOME = System.getProperty(QPID_HOME); - - private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); - - public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - protected final Options _options = new Options(); - protected CommandLine _commandLine; - protected File _configFile; - - - public Configuration() - { - - } - - public void processCommandline(String[] args) throws InitException - { - try - { - _commandLine = new PosixParser().parse(_options, args); - } - catch (ParseException e) - { - throw new InitException("Unable to parse commmandline", e); - } - - final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); - setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); - } - - public void setConfig(File file) - { - _configFile = file; - } - - /** - * @param option The option to set. - */ - public void setOption(Option option) - { - _options.addOption(option); - } - - /** - * getOptionValue from the configuration - * @param option variable argument, first string is option to get, second if present is the default value. - * @return the String for the given option or null if not present (if default value not specified) - */ - public String getOptionValue(String... option) - { - if (option.length == 1) - { - return _commandLine.getOptionValue(option[0]); - } - else if (option.length == 2) - { - return _commandLine.getOptionValue(option[0], option[1]); - } - return null; - } - - public void loadConfig(File file) throws InitException - { - setConfig(file); - loadConfig(); - } - - private void loadConfig() throws InitException - { - 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, null); - } - else - { - _devlog.debug("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); -// } - } - - -// private void configureLogging(File logConfigFile, String logWatchConfig) -// { -// int logWatchTime = 0; -// try -// { -// logWatchTime = Integer.parseInt(logWatchConfig); -// } -// catch (NumberFormatException e) -// { -// _devlog.error("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()) -// { -// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); -// if (logWatchTime > 0) -// { -// _devlog.info("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(); -// } -// } - - public File getConfigFile() - { - return _configFile; - } - - - public class InitException extends Exception - { - InitException(String msg, Throwable cause) - { - super(msg, cause); - } - } -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 7f14946834..28a9e85489 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -582,9 +582,9 @@ public class AMQChannel final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); - if (_log.isDebugEnabled()) + if (_log.isInfoEnabled()) { - _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); + _log.info("unacked map Size:" + _unacknowledgedMessageMap.size()); } // Process the Unacked-Map. @@ -640,15 +640,15 @@ public class AMQChannel }); // Process Messages to Resend - if (_log.isDebugEnabled()) + if (_log.isInfoEnabled()) { if (!msgToResend.isEmpty()) { - _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); + _log.info("Preparing (" + msgToResend.size() + ") message to resend."); } else { - _log.debug("No message to resend."); + _log.info("No message to resend."); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index dd6546585f..29ea69caf7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -34,7 +34,6 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; @@ -49,7 +48,6 @@ import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -57,19 +55,11 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.url.URLSyntaxException; -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.List; - /** * Main entry point for AMQPD. * */ -@SuppressWarnings({"AccessStaticViaInstance"}) +@SuppressWarnings({ "AccessStaticViaInstance" }) public class Main { /** Used for debugging. */ @@ -143,12 +133,6 @@ public class Main OptionBuilder.withArgName("port").hasArg() .withDescription("listen on the specified port. Overrides any value in the config file") .withLongOpt("port").create("p"); - Option mport = - OptionBuilder.withArgName("mport").hasArg() - .withDescription("listen on the specified management port. Overrides any value in the config file") - .withLongOpt("mport").create("m"); - - Option bind = OptionBuilder.withArgName("bind").hasArg() .withDescription("bind to the specified address. Overrides any value in the config file") @@ -169,7 +153,6 @@ public class Main options.addOption(logconfig); options.addOption(logwatchconfig); options.addOption(port); - options.addOption(mport); options.addOption(bind); } @@ -220,19 +203,15 @@ public class Main catch (InitException e) { System.out.println(e.getMessage()); - _brokerLogger.error("Initialisation Error : " + e.getMessage()); - } catch (ConfigurationException e) { System.out.println("Error configuring message broker: " + e); - _brokerLogger.error("Error configuring message broker: " + e); e.printStackTrace(); } catch (Exception e) { System.out.println("Error intialising message broker: " + e); - _brokerLogger.error("Error intialising message broker: " + e); e.printStackTrace(); } } @@ -281,15 +260,7 @@ public class Main configureLogging(logConfigFile, logWatchConfig); } - ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); - - - updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); - - - - ApplicationRegistry.initialise(config); - + ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); // fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say @@ -347,29 +318,6 @@ public class Main bind(port, connectorConfig); } - /** - * Update the configuration data with the management port. - * @param configuration - * @param managementPort The string from the command line - */ - private void updateManagementPort(Configuration configuration, String managementPort) - { - if (managementPort != null) - { - int mport; - int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); - try - { - mport = Integer.parseInt(managementPort); - configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); - } - catch (NumberFormatException e) - { - _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); - } - } - } - protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 9ebb893362..868ac31a54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,13 +38,9 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.List; -import java.util.Map; - public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; @@ -193,8 +189,6 @@ public abstract class AbstractExchange implements Exchange, Managable } } - abstract public Map> getBindings(); - public String toString() { return getClass().getName() + "[" + getName() +"]"; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 377a73dd31..f3bdecc32e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,20 +20,18 @@ */ package org.apache.qpid.server.exchange; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.exception.InternalErrorException; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - public class DefaultExchangeRegistry implements ExchangeRegistry { private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); @@ -66,7 +64,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) throws AMQException { _exchangeMap.put(exchange.getName(), exchange); - if (exchange.isDurable()) + if(exchange.isDurable()) { try { @@ -88,18 +86,13 @@ public class DefaultExchangeRegistry implements ExchangeRegistry return _defaultExchange; } - public Collection getExchangeNames() - { - return _exchangeMap.keySet(); - } - public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); if (e != null) { - if (e.isDurable()) + if(e.isDurable()) { try { @@ -119,7 +112,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public Exchange getExchange(AMQShortString name) { - if ((name == null) || name.length() == 0) + if((name == null) || name.length() == 0) { return getDefaultExchange(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index c24f9a37e1..0dcceaddbb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -26,16 +26,22 @@ import java.util.Map; import javax.management.JMException; import javax.management.MBeanException; +import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -216,9 +222,4 @@ public class DestNameExchange extends AbstractExchange { return !_index.getBindingsMap().isEmpty(); } - - public Map> getBindings() - { - return _index.getBindingsMap(); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index e1a3a24d3e..f6a95b5e55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -21,9 +21,11 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -33,11 +35,17 @@ import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; +import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -51,7 +59,7 @@ public class DestWildExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(DestWildExchange.class); private ConcurrentHashMap> _routingKey2queues = - new ConcurrentHashMap>(); + new ConcurrentHashMap>(); // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); private static final String TOPIC_SEPARATOR = "."; private static final String AMQP_STAR = "*"; @@ -84,7 +92,7 @@ public class DestWildExchange extends AbstractExchange queueList.add(q.getName().toString()); } - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + Object[] bindingItemValues = { key.toString(), queueList.toArray(new String[0]) }; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -303,11 +311,6 @@ public class DestWildExchange extends AbstractExchange } } - public Map> getBindings() - { - return _routingKey2queues; - } - private List getMatchedQueues(AMQShortString routingKey) { List list = new LinkedList(); @@ -355,8 +358,8 @@ public class DestWildExchange extends AbstractExchange if (queueList.size() > (depth + queueskip)) { // a hash and it is the last entry matching = - queueList.get(depth + queueskip).equals(AMQP_HASH) - && (queueList.size() == (depth + queueskip + 1)); + queueList.get(depth + queueskip).equals(AMQP_HASH) + && (queueList.size() == (depth + queueskip + 1)); } } else if (routingkeyList.size() > (depth + routingskip)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 37cd85a8f8..a5f77cc2a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -27,13 +27,9 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.List; -import java.util.Map; - public interface Exchange { AMQShortString getName(); - AMQShortString getType(); void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; @@ -55,17 +51,6 @@ public interface Exchange void route(AMQMessage message) throws AMQException; - - /** - * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments - * @param routingKey - * @param arguments - * @param queue - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); - /** * Determines whether a message would be isBound to a particular queue using a specific routing key * @param routingKey @@ -73,25 +58,22 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey, AMQQueue queue); + boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException; /** - * Determines whether a message is routing to any queue using a specific _routing key + * Determines whether a message is routing to any queue using a specific routing key * @param routingKey * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey); + boolean isBound(AMQShortString routingKey) throws AMQException; - boolean isBound(AMQQueue queue); + boolean isBound(AMQQueue queue) throws AMQException; /** * Returns true if this exchange has at least one binding associated with it. * @return * @throws AMQException */ - boolean hasBindings(); - - Map> getBindings(); - + boolean hasBindings() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index fe3b19e74e..d3a466565f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -23,8 +23,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import java.util.Collection; - public interface ExchangeRegistry extends MessageRouter { @@ -45,7 +43,5 @@ public interface ExchangeRegistry extends MessageRouter Exchange getDefaultExchange(); - Collection getExchangeNames(); - void initialise() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 1a705248c1..bf00eeb9d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -33,13 +34,17 @@ import org.apache.qpid.server.queue.AMQQueue; import javax.management.JMException; import javax.management.MBeanException; +import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; +import javax.management.openmbean.TabularType; + import java.util.concurrent.CopyOnWriteArraySet; public class FanoutExchange extends AbstractExchange @@ -74,7 +79,7 @@ public class FanoutExchange extends AbstractExchange { String queueName = queue.getName().toString(); - Object[] bindingItemValues = {queueName, new String[]{queueName}}; + Object[] bindingItemValues = { queueName, new String[] { queueName } }; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -115,11 +120,6 @@ public class FanoutExchange extends AbstractExchange } } - public Map> getBindings() - { - return null; - } - public AMQShortString getType() { return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; @@ -181,29 +181,24 @@ public class FanoutExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { return _queues.contains(queue); } - public boolean isBound(AMQShortString routingKey) + public boolean isBound(AMQShortString routingKey) throws AMQException { return (_queues != null) && !_queues.isEmpty(); } - public boolean isBound(AMQQueue queue) + public boolean isBound(AMQQueue queue) throws AMQException { return _queues.contains(queue); } - public boolean hasBindings() + public boolean hasBindings() throws AMQException { return !_queues.isEmpty(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 9bb1ee6a62..e86094e26f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -20,18 +20,10 @@ */ package org.apache.qpid.server.exchange; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import javax.management.JMException; import javax.management.openmbean.ArrayType; @@ -44,11 +36,19 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; /** * An exchange that binds queues based on a set of required headers and header values @@ -91,13 +91,13 @@ public class HeadersExchange extends AbstractExchange private final class HeadersExchangeMBean extends ExchangeMBean { @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException + public HeadersExchangeMBean() throws JMException { super(); _exchangeType = "headers"; init(); } - + /** * initialises the OpenType objects. */ @@ -113,7 +113,7 @@ public class HeadersExchange extends AbstractExchange _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", _bindingItemNames, _bindingItemNames, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, _bindingItemIndexNames); } public TabularData bindings() throws OpenDataException @@ -169,7 +169,7 @@ public class HeadersExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } - String[] bindings = binding.split(","); + String[] bindings = binding.split(","); FieldTable bindingMap = new FieldTable(); for (int i = 0; i < bindings.length; i++) { @@ -241,23 +241,17 @@ public class HeadersExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - //fixme isBound here should take the arguements in to consideration. - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) + public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException { return isBound(queue); } - public boolean isBound(AMQShortString routingKey) + public boolean isBound(AMQShortString routingKey) throws AMQException { return hasBindings(); } - public boolean isBound(AMQQueue queue) + public boolean isBound(AMQQueue queue) throws AMQException { for (Registration r : _bindings) { @@ -269,7 +263,7 @@ public class HeadersExchange extends AbstractExchange return false; } - public boolean hasBindings() + public boolean hasBindings() throws AMQException { return !_bindings.isEmpty(); } @@ -294,11 +288,6 @@ public class HeadersExchange extends AbstractExchange } } - public Map> getBindings() - { - return null; - } - private static class Registration { private final HeadersBinding binding; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index ab4f2c4e64..9346eecbb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -100,12 +100,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { @@ -77,7 +77,7 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); } - + if (body.routingKey == null) { body.routingKey = queue.getName(); @@ -97,18 +97,9 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); } - - if (body.routingKey != null) - { - body.routingKey = body.routingKey.intern(); - } - try - { - if (!exch.isBound(body.routingKey, body.arguments, queue)) - { - queue.bind(body.routingKey, body.arguments, exch); - } + { + queue.bind(body.routingKey, body.arguments, exch); } catch (AMQInvalidRoutingKeyException rke) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 28967841a2..f9e94af697 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -93,15 +93,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity - * on the queues being moved between is suspended during the move. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param queueName The queue to move the messages to. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - - MessageStore fromStore = getVirtualHost().getMessageStore(); - MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + // move messages to another queue + anotherQueue.startMovingMessages(); + anotherQueue.enqueueMovedMessages(storeContext, foundMessagesList); - if (toStore != fromStore) - { - throw new RuntimeException("Can only move messages between queues on the same message store."); + // moving is successful, now remove from original queue + _deliveryMgr.removeMovedMessages(foundMessagesList); } - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - toQueue.startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - message.takeReference(); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Removes messages from this queue, and also commits the remove on the message store. Delivery activity - * on the queues being moved between is suspended during the remove. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) - { - MessageStore fromStore = getVirtualHost().getMessageStore(); - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // remove the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // remove the messages on the in-memory queues. - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. finally { + // remove the lock and start the async delivery + anotherQueue.stopMovingMessages(); stopMovingMessages(); } } @@ -639,7 +458,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (incrementSubscriberCount() > 1) { @@ -662,12 +481,13 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (_logger.isDebugEnabled()) { - _logger.debug(MessageFormat.format("Registering protocol session {0} with channel {1} and " - + "consumer tag {2} with {3}", ps, channel, consumerTag, this)); + _logger.debug(MessageFormat.format( + "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, filters, noLocal, this); + _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); if (subscription.filtersMessages()) { @@ -705,8 +525,8 @@ public class AMQQueue implements Managable, Comparable, StorableQueue if (_logger.isDebugEnabled()) { _logger.debug(MessageFormat.format( - "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", - ps, channel, consumerTag, this)); + "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, + consumerTag, this)); } Subscription removedSubscription; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 07872d7644..bbaa7379f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -18,23 +18,30 @@ * under the License. * */ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ package org.apache.qpid.server.queue; -import org.apache.log4j.Logger; - -import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; import javax.management.JMException; import javax.management.MBeanException; @@ -53,25 +60,30 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.store.StoreContext; /** - * AMQQueueMBean is the management bean for an {@link AMQQueue}. - * - *

      CRC Caption - * Responsibilities Collaborations - * + * MBean class for AMQQueue. It implements all the management features exposed + * for an AMQQueue. */ @MBeanDescription("Management Interface for AMQQueue") public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener { - /** Used for debugging purposes. */ private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); - private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 907d68b733..2aa759b35d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -20,6 +20,19 @@ */ package org.apache.qpid.server.queue; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.Collections; +import java.util.HashSet; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; @@ -29,21 +42,8 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; import org.apache.qpid.util.MessageQueue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; +import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; /** Manages delivery of messages on behalf of a queue */ @@ -87,10 +87,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private final Object _queueHeadLock = new Object(); private String _processingThreadName = ""; - - /** Used by any reaping thread to purge messages */ - private StoreContext _reapingStoreContext = new StoreContext(); - ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -457,31 +453,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) while (purgeMessage(message, sub)) { - // if we are purging then ensure we mark this message taken for the current subscriber - // the current subscriber may be null in the case of a get or a purge but this is ok. -// boolean alreadyTaken = message.taken(_queue, sub); - //remove the already taken message or expired AMQMessage removed = messages.poll(); assert removed == message; - // if the message expired then the _totalMessageSize needs adjusting - if (message.expired(_queue)) - { - _totalMessageSize.addAndGet(-message.getSize()); - - // Use the reapingStoreContext as any sub(if we have one) may be in a tx. - message.dequeue(_reapingStoreContext, _queue); - - if (_log.isInfoEnabled()) - { - _log.info(debugIdentity() + " Doing clean up of the main _message queue."); - } - } - - //else the clean up is not required as the message has already been taken for this queue therefore - // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. + _totalMessageSize.addAndGet(-message.getSize()); if (_log.isTraceEnabled()) { @@ -496,10 +473,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * This method will return true if the message is to be purged from the queue. - * - * - * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) + * * @param message * @param sub * @return @@ -519,15 +493,15 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // if the message is null then don't purge as we have no messagse. if (message != null) { - // Check that the message hasn't expired. - if (message.expired(_queue)) - { - return true; - } - // if we have a subscriber perform message checks if (sub != null) { + // Check that the message hasn't expired. + if (message.expired(sub.getChannel().getStoreContext(), _queue)) + { + return true; + } + // if we have a queue browser(we don't purge) so check mark the message as taken purge = ((!sub.isBrowser() || message.isTaken(_queue))); } @@ -632,10 +606,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isInfoEnabled()) { - //fixme - we should do the clean up as the message remains on the _message queue - // this is resulting in the next consumer receiving the message and then attempting to purge it - // - _log.info(debugIdentity() + "We should do clean up of the main _message queue here"); + _log.info(debugIdentity() + "We could do clean up of the main _message queue here"); } } @@ -646,14 +617,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } catch (AMQException e) { - if (message != null) - { - message.release(_queue); - } - else - { - _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); - } + message.release(_queue); _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -732,6 +696,25 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } +// private void sendNextMessage(Subscription sub) +// { +// if (sub.filtersMessages()) +// { +// sendNextMessage(sub, sub.getPreDeliveryQueue()); +// if (sub.isAutoClose()) +// { +// if (sub.getPreDeliveryQueue().isEmpty()) +// { +// sub.close(); +// } +// } +// } +// else +// { +// sendNextMessage(sub, _messages); +// } +// } + public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException { @@ -740,6 +723,8 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); } + // This shouldn't be done here. +// msg.release(); //Check if we have someone to deliver the message to. _lock.lock(); @@ -815,7 +800,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + - "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); + "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); } } } @@ -825,7 +810,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); + " Subscriber:" + System.identityHashCode(s)); } deliver(context, name, msg, deliverFirst); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index cbe9246f09..c0f1e7f40c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,14 +20,13 @@ */ package org.apache.qpid.server.queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - public class DefaultQueueRegistry implements QueueRegistry { private ConcurrentMap _queueMap = new ConcurrentHashMap(); @@ -58,14 +57,4 @@ public class DefaultQueueRegistry implements QueueRegistry { return _queueMap.get(name); } - - public Collection getQueueNames() - { - return _queueMap.keySet(); - } - - public Collection getQueues() - { - return _queueMap.values(); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index 60c1a8f574..a8247aa2db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -46,7 +46,7 @@ class ExchangeBindings ExchangeBinding(AMQShortString routingKey, Exchange exchange) { - this(routingKey, exchange, EMPTY_ARGUMENTS); + this(routingKey, exchange,EMPTY_ARGUMENTS); } ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) @@ -80,10 +80,7 @@ class ExchangeBindings public boolean equals(Object o) { - if (!(o instanceof ExchangeBinding)) - { - return false; - } + if (!(o instanceof ExchangeBinding)) return false; ExchangeBinding eb = (ExchangeBinding) o; return _exchange.equals(eb._exchange) && _routingKey.equals(eb._routingKey) @@ -107,16 +104,16 @@ class ExchangeBindings */ void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments )); } public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); + _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments )); } - + /** * Deregisters this queue from any exchange it has been bound to */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java index 6118a4c11f..285f05fb20 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -1,22 +1,18 @@ /* * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 6b3d65661f..00ccffdea1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -1,21 +1,18 @@ /* * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java index 959ca03c80..9554d34f00 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -1,26 +1,22 @@ /* * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 QueueNotificationListener { void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index 13c150f82b..ed2101fd75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -25,7 +25,6 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.messageStore.StorableQueue; -import java.util.Collection; public interface QueueRegistry { @@ -36,9 +35,4 @@ public interface QueueRegistry void unregisterQueue(AMQShortString name) throws AMQException; AMQQueue getQueue(AMQShortString name); - - Collection getQueueNames(); - - Collection getQueues(); - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 79ee6b93a3..7c8064789e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -1,21 +1,18 @@ /* * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java new file mode 100644 index 0000000000..f9e093dba7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index d9500429af..8becaf52b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -1,21 +1,18 @@ /* * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index fee25c07df..88451e2fca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -28,144 +28,24 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.StoreContext; /** - * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. - * Different levels of transactional support for the delivery of messages may be provided by different implementations - * of this interface. - * - *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. - * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} - * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. - * - *

      - *
      CRC Card
      Responsibilities - *
      Explicitly accept a transaction start notification. - *
      Commit all pending operations in a transaction. - *
      Rollback all pending operations in a transaction. - *
      Deliver a message to a queue as part of a transaction. - *
      Redeliver a message to a queue as part of a transaction. - *
      Mark a message as acknowledged as part of a transaction. - *
      Accept notification that a message has been completely received as part of a transaction. - *
      Accept notification that a message has been fully processed as part of a transaction. - *
      Associate a message store context with this transaction context. - *
      - * - * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional - * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them - * somewhere else, a seperate interface for example. - * - * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides - * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any - * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean - * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be - * conceptually neater. - * - * For example: - *

      - * public interface Transactional
      - * {
      - *    public void commit();
      - *    public void rollback();
      - * }
      - *
      - * public interface TransactionalQueue extends Transactional, SizeableQueue
      - * {}
      - *
      - * public class Queues
      - * {
      - *    ...
      - *    // For transactional messaging, take a transactional view onto the queue.
      - *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      - *
      - *    // For non-transactional messaging, take a non-transactional view onto the queue.
      - *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      - * }
      - * 
      + * @author Robert Greig (robert.j.greig@jpmorgan.com) */ public interface TransactionalContext { - /** - * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} - * should automatically begin the next transaction in the chain. - * - * @throws AMQException If the transaction cannot be started for any reason. - */ void beginTranIfNecessary() throws AMQException; - /** - * Makes all pending operations on the transaction permanent and visible. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ void commit() throws AMQException; - /** - * Erases all pending operations on the transaction. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ void rollback() throws AMQException; - /** - * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a - * redelivery, and should be placed on the front of the queue. - * - *

      This is an 'enqueue' operation. - * - * @param message The message to deliver. - * @param queue The queue to deliver the message to. - * @param deliverFirst true to place the message on the front of the queue for redelivery, false - * for normal FIFO message ordering. - * - * @throws AMQException If the message cannot be delivered for any reason. - */ void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException; - /** - * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by - * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' - * flag is set, in which case an acknowledgement up to the latest delivered message should be done. - * - *

      This is a 'dequeue' operation. - * - * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement - * up to the latest message. - * @param lastDeliveryTag The latest message delivered. - * @param multiple true if all message ids up the acknowledged one or latest delivered, are - * to be acknowledged, false otherwise. - * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message - * from. - * - * @throws AMQException If the message cannot be acknowledged for any reason. - */ void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - /** - * Notifies the transactional context that a message has been fully received. The actual message that was received - * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, - * flushing its data to disk. - * - * @param persistent true if the received message is persistent, false otherwise. - * - * @throws AMQException If the fully received event cannot be processed for any reason. - */ void messageFullyReceived(boolean persistent) throws AMQException; - /** - * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual - * message that was delivered is not specified. This event may be used to trigger a process related to the - * outcome of the delivery of the message, for example, cleaning up failed deliveries. - * - * @param protocolSession The protocol session of the deliverable message. - * - * @throws AMQException If the message processed event cannot be handled for any reason. - */ void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; - /** - * Gets the message store context associated with this transactional context. - * - * @return The message store context associated with this transactional context. - */ StoreContext getStoreContext(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 235555c58b..6638689299 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,4 +1,3 @@ -<<<<<<< .working /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -287,264 +286,3 @@ public class VirtualHost implements Accessable } } -======= -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - - private final String _name; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - - } // End of MBean class - - /** - * Used for testing only - * @param name - * @param store - * @throws Exception - */ - public VirtualHost(String name, MessageStore store) throws Exception - { - this(name, null, store); - } - - /** - * Normal Constructor - * @param name - * @param hostConfig - * @throws Exception - */ - public VirtualHost(String name, Configuration hostConfig) throws Exception - { - this(name, hostConfig, null); - } - - private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception - { - _name = name; - - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - _exchangeRegistry.initialise(); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - - _accessManager = new AccessManagerImpl(name, hostConfig); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - } - - private void initialiseMessageStore(Configuration config) throws Exception - { - String messageStoreClass = config.getString("store.class"); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - _messageStore.configure(this, "store", config); - } - - - public T getConfiguredObject(Class instanceType, Configuration config) - { - T instance; - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); - } - Configurator.configure(instance); - - return instance; - } - - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - if (_messageStore != null) - { - _messageStore.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } -} ->>>>>>> .merge-right.r553432 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java deleted file mode 100644 index afa7916074..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore; - -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.commands.Clear; -import org.apache.qpid.tools.messagestore.commands.Command; -import org.apache.qpid.tools.messagestore.commands.Copy; -import org.apache.qpid.tools.messagestore.commands.Dump; -import org.apache.qpid.tools.messagestore.commands.Help; -import org.apache.qpid.tools.messagestore.commands.List; -import org.apache.qpid.tools.messagestore.commands.Load; -import org.apache.qpid.tools.messagestore.commands.Quit; -import org.apache.qpid.tools.messagestore.commands.Select; -import org.apache.qpid.tools.messagestore.commands.Show; -import org.apache.qpid.tools.utils.CommandParser; -import org.apache.qpid.tools.utils.Console; -import org.apache.qpid.tools.utils.SimpleCommandParser; -import org.apache.qpid.tools.utils.SimpleConsole; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * MessageStoreTool. - */ -public class MessageStoreTool -{ - /** Text outputted at the start of each console.*/ - private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; - - /** I/O Wrapper. */ - protected Console _console; - - /** Batch mode flag. */ - protected boolean _batchMode; - - /** Internal State object. */ - private State _state = new State(); - - private HashMap _commands = new HashMap(); - - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); - - /** Loaded configuration file. */ - private Configuration _config; - - /** Control used for main run loop. */ - private boolean _running = true; - private boolean _initialised = false; - - //---------------------------------------------------------------------------------------------------/ - - public static void main(String[] args) throws Configuration.InitException - { - - MessageStoreTool tool = new MessageStoreTool(args); - - tool.start(); - } - - - public MessageStoreTool(String[] args) throws Configuration.InitException - { - this(args, System.in, System.out); - } - - public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException - { - BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); - BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); - - Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); - _batchMode = false; - - _console = new SimpleConsole(consoleWriter, consoleReader); - - _config = new Configuration(); - - setOptions(); - _config.processCommandline(args); - } - - - private void setOptions() - { - 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 By " - + "default looks for a file named " - + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) - .withLongOpt("config") - .create("c"); - - _config.setOption(help); - _config.setOption(version); - _config.setOption(configFile); - } - - public State getState() - { - return _state; - } - - public Map getCommands() - { - return _commands; - } - - public void setConfigurationFile(String configfile) throws Configuration.InitException - { - _config.loadConfig(new File(configfile)); - setup(); - } - - public Console getConsole() - { - return _console; - } - - public void setConsole(Console console) - { - _console = console; - } - - /** - * Simple ShutdownHook to cleanly shutdown the databases - */ - class ShutdownHook implements Runnable - { - MessageStoreTool _tool; - - ShutdownHook(MessageStoreTool messageStoreTool) - { - _tool = messageStoreTool; - } - - public void run() - { - _tool.quit(); - } - } - - public void quit() - { - _running = false; - - if (_initialised) - { - ApplicationRegistry.remove(1); - } - - _console.println("...exiting"); - - _console.close(); - } - - public void setBatchMode(boolean batchmode) - { - _batchMode = batchmode; - } - - /** - * Main loop - */ - protected void start() - { - setup(); - - if (!_initialised) - { - System.exit(1); - } - - _console.println(""); - - _console.println(BOILER_PLATE); - - runCLI(); - } - - private void setup() - { - loadDefaultVirtualHosts(); - - loadCommands(); - - _state.clearAll(); - } - - private void loadCommands() - { - _commands.clear(); - //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands - _commands.put("close", new Clear(this)); - _commands.put("copy", new Copy(this)); - _commands.put("dump", new Dump(this)); - _commands.put("help", new Help(this)); - _commands.put("list", new List(this)); - _commands.put("load", new Load(this)); - _commands.put("quit", new Quit(this)); - _commands.put("select", new Select(this)); - _commands.put("show", new Show(this)); - } - - private void loadDefaultVirtualHosts() - { - final File configFile = _config.getConfigFile(); - - loadVirtualHosts(configFile); - } - - private void loadVirtualHosts(File configFile) - { - - if (!configFile.exists()) - { - _devlog.error("Config file not found:" + configFile.getAbsolutePath()); - return; - } - else - { - _devlog.debug("using config file :" + configFile.getAbsolutePath()); - } - - try - { - ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); - - ApplicationRegistry.remove(1); - - ApplicationRegistry.initialise(registry); - - checkMessageStores(); - _initialised = true; - } - catch (ConfigurationException e) - { - _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); - e.printStackTrace(); - } - catch (Exception e) - { - _console.println("Unable to load configuration due to: " + e.getMessage()); - e.printStackTrace(); - } - - - } - - private void checkMessageStores() - { - Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); - - boolean warning = false; - for (VirtualHost vhost : vhosts) - { - if (vhost.getMessageStore() instanceof MemoryMessageStore) - { - _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " - + "Changes will not persist."); - warning = true; - } - } - - if (warning) - { - _console.println(""); - _console.println("Please ensure you are using the correct config file currently using '" - + _config.getConfigFile().getAbsolutePath() + "'"); - _console.println("New config file can be specifed by 'load ' or -c on the commandline."); - _console.println(""); - } - } - - private void runCLI() - { - while (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - String[] args = _console.readCommand(); - - while (args != null) - { - exec(args); - - if (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - args = _console.readCommand(); - } - } - } - } - - private void printPrompt() - { - _console.print(prompt()); - } - - - /** - * Execute a script (batch mode). - * - * @param script The file script - */ - protected void runScripts(String script) - { - //Store Current State - boolean oldBatch = _batchMode; - CommandParser oldParser = _console.getCommandParser(); - setBatchMode(true); - - try - { - _devlog.debug("Running script '" + script + "'"); - - _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); - - start(); - } - catch (java.io.FileNotFoundException e) - { - _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); - } - - //Restore previous state - _console.setCommandParser(oldParser); - setBatchMode(oldBatch); - } - - public String prompt() - { - String state = _state.toString(); - if (state != null && state.length() != 0) - { - return state + ":bdb$ "; - } - else - { - return "bdb$ "; - } - } - - /** - * Execute the command. - * - * @param args [command, arg0, arg1...]. - */ - protected void exec(String[] args) - { - // Comment lines start with a # - if (args.length == 0 || args[0].startsWith("#")) - { - return; - } - - final String command = args[0]; - - Command cmd = _commands.get(command); - - if (cmd == null) - { - _console.println("Command not understood: " + command); - } - else - { - cmd.execute(args); - } - } - - - /** - * Displays usage info. - */ - protected static void help() - { - System.out.println(BOILER_PLATE); - System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); - System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); - } - - - /** - * This class is used to store the current state of the tool. - * - * This is then interrogated by the various commands to augment their behaviour. - * - * - */ - public class State - { - private VirtualHost _vhost = null; - private AMQQueue _queue = null; - private Exchange _exchange = null; - private java.util.List _msgids = null; - - public State() - { - } - - public void setQueue(AMQQueue queue) - { - _queue = queue; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public void setVhost(VirtualHost vhost) - { - _vhost = vhost; - } - - public VirtualHost getVhost() - { - return _vhost; - } - - public Exchange getExchange() - { - return _exchange; - } - - public void setExchange(Exchange exchange) - { - _exchange = exchange; - } - - public String toString() - { - StringBuilder status = new StringBuilder(); - - if (_vhost != null) - { - status.append(_vhost.getName()); - - if (_exchange != null) - { - status.append("["); - status.append(_exchange.getName()); - status.append("]"); - - if (_queue != null) - { - status.append("->'"); - status.append(_queue.getName()); - status.append("'"); - - if (_msgids != null) - { - status.append(printMessages()); - } - } - } - } - - return status.toString(); - } - - - public String printMessages() - { - StringBuilder sb = new StringBuilder(); - - Long previous = null; - - Long start = null; - for (Long id : _msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(id); - start = null; - } - else - { - sb.append(","); - sb.append(previous); - } - } - } - - previous = id; - } - - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(_msgids.get(_msgids.size() - 1)); - } - else - { - sb.append(","); - sb.append(previous); - } - - // surround list in () - sb.replace(0, 1, "("); - sb.append(")"); - return sb.toString(); - } - - public void clearAll() - { - _vhost = null; - clearExchange(); - } - - public void clearExchange() - { - _exchange = null; - clearQueue(); - } - - public void clearQueue() - { - _queue = null; - clearMessages(); - } - - public void clearMessages() - { - _msgids = null; - } - - /** - * A common location to provide parsing of the message id string - * utilised by a number of the commands. - * The String is comma separated list of ids that can be individual ids - * or a range (4-10) - * - * @param msgString string of msg ids to parse 1,2,4-10 - */ - public void setMessages(String msgString) - { - StringTokenizer tok = new StringTokenizer(msgString, ","); - - if (tok.hasMoreTokens()) - { - _msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - _msgids.add(l); - } - } - } - else - { - _msgids.add(Long.parseLong(next)); - } - } - - } - - public void setMessages(java.util.List msgids) - { - _msgids = msgids; - } - - public java.util.List getMessages() - { - return _msgids; - } - }//Class State - -}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java deleted file mode 100644 index 5444197cb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -public abstract class AbstractCommand implements Command -{ - protected Console _console; - protected MessageStoreTool _tool; - - public AbstractCommand(MessageStoreTool tool) - { - _console = tool.getConsole(); - _tool = tool; - } - - public void setOutput(Console out) - { - _console = out; - } - - protected void commandError(String message, String[] args) - { - _console.print(getCommand() + " : " + message); - - if (args != null) - { - for (int i = 1; i < args.length; i++) - { - _console.print(args[i]); - } - } - _console.println(""); - _console.println(help()); - } - - - public abstract String help(); - - public abstract String usage(); - - public abstract String getCommand(); - - - public abstract void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java deleted file mode 100644 index b0006b3fe6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Clear extends AbstractCommand -{ - public Clear(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Clears any selection."; - } - - public String usage() - { - return "clear [ all | virtualhost | exchange | queue | msgs ]"; - } - - public String getCommand() - { - return "clear"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 1) - { - doClose("all"); - } - else - { - doClose(args[1]); - } - } - - private void doClose(String type) - { - if (type.equals("virtualhost") - || type.equals("all")) - { - _tool.getState().clearAll(); - } - - if (type.equals("exchange")) - { - _tool.getState().clearExchange(); - } - - if (type.equals("queue")) - { - _tool.getState().clearQueue(); - } - - if (type.equals("msgs")) - { - _tool.getState().clearMessages(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java deleted file mode 100644 index bfa775a34a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.utils.Console; - -public interface Command -{ - public void setOutput(Console out); - - public String help(); - - public abstract String usage(); - - String getCommand(); - - public void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java deleted file mode 100644 index 96ecb36952..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Copy extends Move -{ - public Copy(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Copy messages between queues.\n" + - "The currently selected message set will be copied to the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; - } - - public String usage() - { - return "copy to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "copy"; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue, StoreContext storeContext) - { - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), storeContext); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java deleted file mode 100644 index eea53252c6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.commons.codec.binary.Hex; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.io.UnsupportedEncodingException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -public class Dump extends Show -{ - private static final int LINE_SIZE = 8; - private static final String DEFAULT_ENCODING = "utf-8"; - private static final boolean SPACE_BYTES = true; - private static final String BYTE_SPACER = " "; - private static final String NON_PRINTING_ASCII_CHAR = "?"; - - protected boolean _content = true; - - public Dump(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Dump selected message content. Default: show=content"; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; - } - - public String getCommand() - { - return "dump"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _content = arg.contains("content") || arg.contains("all"); - } - } - - parseArgs(args); - } - - performShow(); - } - - - protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - List display = new LinkedList(); - - List hex = new LinkedList(); - List ascii = new LinkedList(); - display.add(hex); - display.add(ascii); - - for (AMQMessage msg : messages) - { - if (!includeMsg(msg, msgids)) - { - continue; - } - - //Add divider between messages - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - // Show general message information - hex.add(Show.Columns.ID.name()); - ascii.add(msg.getMessageId().toString()); - - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - if (showRouting) - { - addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); - } - if (showHeaders) - { - addShowInformation(hex, ascii, msg, "Headers", false, true, false); - } - if (showMessageHeaders) - { - addShowInformation(hex, ascii, msg, null, false, false, true); - } - - // Add Content Body seciont - hex.add("Content Body"); - ascii.add(""); - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - Iterator bodies = msg.getContentBodyIterator(); - if (bodies.hasNext()) - { - - hex.add("Hex"); - hex.add(Console.ROW_DIVIDER); - - - ascii.add("ASCII"); - ascii.add(Console.ROW_DIVIDER); - - while (bodies.hasNext()) - { - ContentChunk chunk = (ContentChunk) bodies.next(); - - //Duplicate so we don't destroy original data :) - ByteBuffer hexBuffer = chunk.getData().duplicate(); - - ByteBuffer charBuffer = hexBuffer.duplicate(); - - Hex hexencoder = new Hex(); - - while (hexBuffer.hasRemaining()) - { - byte[] line = new byte[LINE_SIZE]; - - int bufsize = hexBuffer.remaining(); - if (bufsize < LINE_SIZE) - { - hexBuffer.get(line, 0, bufsize); - } - else - { - bufsize = line.length; - hexBuffer.get(line); - } - - byte[] encoded = hexencoder.encode(line); - - try - { - String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); - String hexLine = ""; - - int strKength = encStr.length(); - for (int c = 0; c < strKength; c++) - { - hexLine += encStr.charAt(c); - - if (c % 2 == 1 && SPACE_BYTES) - { - hexLine += BYTE_SPACER; - } - } - - hex.add(hexLine); - } - catch (UnsupportedEncodingException e) - { - _console.println(e.getMessage()); - return null; - } - } - - while (charBuffer.hasRemaining()) - { - String asciiLine = ""; - - for (int pos = 0; pos < LINE_SIZE; pos++) - { - if (charBuffer.hasRemaining()) - { - byte ch = charBuffer.get(); - - if (isPrintable(ch)) - { - asciiLine += (char) ch; - } - else - { - asciiLine += NON_PRINTING_ASCII_CHAR; - } - - if (SPACE_BYTES) - { - asciiLine += BYTE_SPACER; - } - } - else - { - break; - } - } - - ascii.add(asciiLine); - } - } - } - else - { - List result = new LinkedList(); - - display.add(result); - result.add("No ContentBodies"); - } - } - - // if hex is empty then we have no data to display - if (hex.size() == 0) - { - return null; - } - - return display; - } - - private void addShowInformation(List column1, List column2, AMQMessage msg, - String title, boolean routing, boolean headers, boolean messageHeaders) - { - List single = new LinkedList(); - single.add(msg); - - List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); - - //Reformat data - if (title != null) - { - column1.add(title); - column2.add(""); - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - // look at all columns in the routing Data - for (List item : routingData) - { - // the item should be: - // Title - // *divider - // value - // otherwise we can't reason about the correct value - if (item.size() == 3) - { - //Filter out the columns we are not interested in. - - String columnName = item.get(0).toString(); - - if (!(columnName.equals(Show.Columns.ID.name()) - || columnName.equals(Show.Columns.Size.name()))) - { - column1.add(columnName); - column2.add(item.get(2).toString()); - } - } - } - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - private boolean isPrintable(byte c) - { - return c > 31 && c < 127; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java deleted file mode 100644 index 0f9546541b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.Map; - -public class Help extends AbstractCommand -{ - public Help(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Provides detailed help on commands."; - } - - public String getCommand() - { - return "help"; - } - - public String usage() - { - return "help []"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - Command command = _tool.getCommands().get(args[1]); - if (command != null) - { - _console.println(command.help()); - _console.println("Usage:" + command.usage()); - } - else - { - commandError("Command not found: ", args); - } - } - else - { - java.util.List data = new LinkedList(); - - java.util.List commandName = new LinkedList(); - java.util.List commandDescription = new LinkedList(); - - data.add(commandName); - data.add(commandDescription); - - //Set up Headers - commandName.add("Command"); - commandDescription.add("Description"); - - commandName.add(Console.ROW_DIVIDER); - commandDescription.add(Console.ROW_DIVIDER); - - //Add current Commands with descriptions - Map commands = _tool.getCommands(); - - for (Command command : commands.values()) - { - commandName.add(command.getCommand()); - commandDescription.add(command.help()); - } - - _console.printMap("Available Commands", data); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java deleted file mode 100644 index df8b59ec19..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.Collection; -import java.util.LinkedList; - -public class List extends AbstractCommand -{ - - public List(MessageStoreTool tool) - { - super(tool); - } - - public void setOutput(Console out) - { - _console = out; - } - - public String help() - { - return "list available items."; - } - - public String usage() - { - return "list queues [] | exchanges | bindings [] | all"; - } - - public String getCommand() - { - return "list"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - if ((args[1].equals("exchanges")) - || (args[1].equals("queues")) - || (args[1].equals("bindings")) - || (args[1].equals("all"))) - { - if (args.length == 2) - { - doList(args[1]); - } - else if (args.length == 3) - { - doList(args[1], args[2]); - } - } - else - { - commandError("Unknown options. ", args); - } - } - else if (args.length < 2) - { - doList("all"); - } - else - { - doList(args[1]); - } - } - - private void doList(String... listItem) - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - listVirtualHosts(); - return; - } - - VirtualHost vhost = _tool.getState().getVhost(); - - java.util.List data = null; - - if (listItem[0].equals("queues")) - { - if (listItem.length > 1) - { - data = listQueues(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - data = listQueues(vhost, exchange); - } - } - - if (listItem[0].equals("exchanges")) - { - data = listExchanges(vhost); - } - - if (listItem[0].equals("bindings")) - { - - if (listItem.length > 1) - { - data = listBindings(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - - data = listBindings(vhost, exchange); - } - } - - if (data != null) - { - if (data.size() == 1) - { - _console.println("No '" + listItem[0] + "' to display,"); - } - else - { - _console.displayList(true, data.toArray(new String[0])); - } - } - - - if (listItem[0].equals("all")) - { - - boolean displayed = false; - Exchange exchange = _tool.getState().getExchange(); - - //Do the display here for each one so that they are pretty printed - data = listQueues(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (exchange == null) - { - data = listExchanges(vhost); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - } - - data = listBindings(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (!displayed) - { - _console.println("Nothing to list"); - } - } - } - - private void listVirtualHosts() - { - Collection vhosts = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHosts(); - - String[] data = new String[vhosts.size() + 1]; - - data[0] = "Available VirtualHosts"; - - int index = 1; - for (VirtualHost vhost : vhosts) - { - data[index] = vhost.getName(); - index++; - } - - _console.displayList(true, data); - } - - private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) - { - return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listBindings(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueueNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Current Bindings"); - - for (AMQShortString queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.toString()); - } - } - else - { - data.add(queue.toString()); - } - } - - return data; - } - - private java.util.List listExchanges(VirtualHost vhost) - { - Collection queues = vhost.getExchangeRegistry().getExchangeNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Exchanges"); - - for (AMQShortString queue : queues) - { - data.add(queue.toString()); - } - - return data; - } - - private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) - { - return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listQueues(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueues(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Queues"); - - for (AMQQueue queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.getName().toString()); - } - } - else - { - data.add(queue.getName().toString()); - } - } - - if (exchange != null) - { - if (queues.size() == 1) - { - return null; - } - } - - return data; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java deleted file mode 100644 index 244a311c30..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Load extends AbstractCommand -{ - public Load(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Loads specified broker configuration file."; - } - - public String usage() - { - return "load "; - } - - public String getCommand() - { - return "load"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 2) - { - _console.print("load " + args[1] + ": additional options not understood:"); - for (int i = 2; i < args.length; i++) - { - _console.print(args[i] + " "); - } - _console.println(""); - } - else if (args.length < 2) - { - _console.println("Enter Configuration file."); - String input = _console.readln(); - if (input != null) - { - doLoad(input); - } - else - { - _console.println("Did not recognise config file."); - } - } - else - { - doLoad(args[1]); - } - } - - private void doLoad(String configfile) - { - _console.println("Loading Configuration:" + configfile); - - try - { - _tool.setConfigurationFile(configfile); - } - catch (Configuration.InitException e) - { - _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java deleted file mode 100644 index a9497fd23e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.List; - -public class Move extends AbstractCommand -{ - - /** - * Since the Coopy command is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - private StoreContext _storeContext = new StoreContext(); - - public Move(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Move messages between queues.\n" + - "The currently selected message set will be moved to the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; - } - - public String usage() - { - return "move to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "move"; - } - - public void execute(String... args) - { - AMQQueue toQueue = null; - AMQQueue fromQueue = _tool.getState().getQueue(); - java.util.List msgids = _tool.getState().getMessages(); - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("to=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("from=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("msgids=")) - { - String msgidStr = arg.substring(arg.indexOf("=") + 1); - - // Record the current message selection - java.util.List currentIDs = _tool.getState().getMessages(); - - // Use the ToolState class to perform the messasge parsing - _tool.getState().setMessages(msgidStr); - msgids = _tool.getState().getMessages(); - - // Reset the original selection of messages - _tool.getState().setMessages(currentIDs); - } - } - } - - if (!checkRequirements(fromQueue, toQueue, msgids)) - { - return; - } - - processIDs(fromQueue, toQueue, msgids); - } - - private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - Long previous = null; - Long start = null; - - for (long id : msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - //move a range of ids - doCommand(fromQueue, start, id, toQueue, _storeContext); - } - else - { - //move a single id - doCommand(fromQueue, id, id, toQueue, _storeContext); - } - } - } - - previous = id; - } - } - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) - { - if (toQueue == null) - { - _console.println("Destination queue not specifed."); - _console.println(usage()); - return false; - } - - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue, StoreContext storeContext) - { - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java deleted file mode 100644 index 7154159b40..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Purge extends Move -{ - public Purge(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Purge messages from a queue.\n" + - "The currently selected message set will be purged from the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; - } - - public String usage() - { - return "purge from= [msgids=]"; - } - - public String getCommand() - { - return "purge"; - } - - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue, StoreContext storeContext) - { - fromQueue.removeMessagesFromQueue(start, end, storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java deleted file mode 100644 index a81bc07c38..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Quit extends AbstractCommand -{ - public Quit(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Quit the tool."; - } - - public String usage() - { - return "quit"; - } - - public String getCommand() - { - return "quit"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals("quit"); - - _tool.quit(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java deleted file mode 100644 index 5e9b7028e9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.LinkedList; -import java.util.StringTokenizer; - -public class Select extends AbstractCommand -{ - - public Select(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Perform a selection."; - } - - public String usage() - { - return "select virtualhost |exchange |queue | msgs id="; - } - - public String getCommand() - { - return "select"; - } - - public void execute(String... args) - { - assert args.length > 2; - assert args[0].equals("select"); - - if (args.length < 3) - { - if (args[1].equals("show")) - { - doSelect(args[1], null); - } - else - { - _console.print("select : unknown command:"); - _console.println(help()); - } - } - else - { - if (args[1].equals("virtualhost") - || args[1].equals("vhost") - || args[1].equals("exchange") - || args[1].equals("queue") - || args[1].equals("msg") - ) - { - doSelect(args[1], args[2]); - } - else - { - _console.println(help()); - } - } - } - - private void doSelect(String type, String item) - { - if (type.equals("virtualhost")) - { - - VirtualHost vhost = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHost(item); - - if (vhost == null) - { - _console.println("Virtualhost '" + item + "' not found."); - } - else - { - _tool.getState().setVhost(vhost); - } - } - - if (type.equals("exchange")) - { - - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - - Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); - - if (exchange == null) - { - _console.println("Exchange '" + item + "' not found."); - } - else - { - _tool.getState().setExchange(exchange); - } - - if (_tool.getState().getQueue() != null) - { - if (!exchange.isBound(_tool.getState().getQueue())) - { - _tool.getState().setQueue(null); - } - } - } - - if (type.equals("queue")) - { - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); - - if (queue == null) - { - _console.println("Queue '" + item + "' not found."); - } - else - { - _tool.getState().setQueue(queue); - - if (_tool.getState().getExchange() == null) - { - for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) - { - Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); - if (exchange.isBound(queue)) - { - _tool.getState().setExchange(exchange); - break; - } - } - } - - //remove the message selection - _tool.getState().setMessages((java.util.List) null); - } - } - - if (type.equals("msg")) - { - if (item.startsWith("id=")) - { - StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); - - java.util.List msgids = null; - - if (tok.hasMoreTokens()) - { - msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - msgids.add(l); - } - } - } - else - { - msgids.add(Long.parseLong(next)); - } - } - - _tool.getState().setMessages(msgids); - } - - } - - if (type.equals("show")) - { - _console.println(_tool.getState().toString()); - if (_tool.getState().getMessages() != null) - { - _console.print("Msgs:"); - for (Long l : _tool.getState().getMessages()) - { - _console.print(" " + l); - } - _console.println(""); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java deleted file mode 100644 index 5988cdabfc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.List; -import java.util.StringTokenizer; - -public class Show extends AbstractCommand -{ - protected boolean _amqHeaders = false; - protected boolean _routing = false; - protected boolean _msgHeaders = false; - - public Show(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Shows the messages headers."; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; - } - - public String getCommand() - { - return "show"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 2) - { - parseArgs("all"); - } - else - { - parseArgs(args); - } - - performShow(); - } - - protected void parseArgs(String... args) - { - List msgids = null; - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); - _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); - _routing = arg.contains("routing") || arg.contains("all"); - } - - if (arg.startsWith("id=")) - { - _tool.getState().setMessages(msgids); - } - }//for args - }// if args > 2 - } - - protected void performShow() - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); - return; - } - - AMQQueue _queue = _tool.getState().getQueue(); - - List msgids = _tool.getState().getMessages(); - - if (_queue != null) - { - List messages = _queue.getMessagesOnTheQueue(); - if (messages == null || messages.size() == 0) - { - _console.println("No messages on queue"); - return; - } - - List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); - if (data != null) - { - _console.printMap(null, data); - } - else - { - String message = "No data to display."; - if (msgids != null) - { - message += " Is message selection correct? " + _tool.getState().printMessages(); - } - _console.println(message); - } - - } - else - { - _console.println("No Queue specified to show."); - } - } - - /** - * Create the list data for display from the messages. - * - * @param msgids The list of message ids to display - * @param messages A list of messages to format and display. - * @param showHeaders should the header info be shown - * @param showRouting show the routing info be shown - * @param showMessageHeaders show the msg headers be shown - * @return the formated data lists for printing - */ - protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - // Currenly exposed message properties -// //Printing the content Body -// msg.getContentBodyIterator(); -// //Print the Headers -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); -// -// //Print out all the property names -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); -// -// msg.getMessageId(); -// msg.getSize(); -// msg.getArrivalTime(); - -// msg.getDeliveredSubscription(); -// msg.getDeliveredToConsumer(); -// msg.getMessageHandle(); -// msg.getMessageId(); -// msg.getMessagePublishInfo(); -// msg.getPublisher(); - -// msg.getStoreContext(); -// msg.isAllContentReceived(); -// msg.isPersistent(); -// msg.isRedelivered(); -// msg.isRejectedBy(); -// msg.isTaken(); - - //Header setup - - List data = new LinkedList(); - - List id = new LinkedList(); - data.add(id); - id.add(Columns.ID.name()); - id.add(Console.ROW_DIVIDER); - - List exchange = new LinkedList(); - List routingkey = new LinkedList(); - List immediate = new LinkedList(); - List mandatory = new LinkedList(); - if (showRouting) - { - data.add(exchange); - exchange.add(Columns.Exchange.name()); - exchange.add(Console.ROW_DIVIDER); - - data.add(routingkey); - routingkey.add(Columns.RoutingKey.name()); - routingkey.add(Console.ROW_DIVIDER); - - data.add(immediate); - immediate.add(Columns.isImmediate.name()); - immediate.add(Console.ROW_DIVIDER); - - data.add(mandatory); - mandatory.add(Columns.isMandatory.name()); - mandatory.add(Console.ROW_DIVIDER); - } - - List size = new LinkedList(); - List appid = new LinkedList(); - List clusterid = new LinkedList(); - List contenttype = new LinkedList(); - List correlationid = new LinkedList(); - List deliverymode = new LinkedList(); - List encoding = new LinkedList(); - List arrival = new LinkedList(); - List expiration = new LinkedList(); - List priority = new LinkedList(); - List propertyflag = new LinkedList(); - List replyto = new LinkedList(); - List timestamp = new LinkedList(); - List type = new LinkedList(); - List userid = new LinkedList(); - List ispersitent = new LinkedList(); - List isredelivered = new LinkedList(); - List isdelivered = new LinkedList(); - - data.add(size); - size.add(Columns.Size.name()); - size.add(Console.ROW_DIVIDER); - - if (showHeaders) - { - data.add(ispersitent); - ispersitent.add(Columns.isPersistent.name()); - ispersitent.add(Console.ROW_DIVIDER); - - data.add(isredelivered); - isredelivered.add(Columns.isRedelivered.name()); - isredelivered.add(Console.ROW_DIVIDER); - - data.add(isdelivered); - isdelivered.add(Columns.isDelivered.name()); - isdelivered.add(Console.ROW_DIVIDER); - - data.add(appid); - appid.add(Columns.App_ID.name()); - appid.add(Console.ROW_DIVIDER); - - data.add(clusterid); - clusterid.add(Columns.Cluster_ID.name()); - clusterid.add(Console.ROW_DIVIDER); - - data.add(contenttype); - contenttype.add(Columns.Content_Type.name()); - contenttype.add(Console.ROW_DIVIDER); - - data.add(correlationid); - correlationid.add(Columns.Correlation_ID.name()); - correlationid.add(Console.ROW_DIVIDER); - - data.add(deliverymode); - deliverymode.add(Columns.Delivery_Mode.name()); - deliverymode.add(Console.ROW_DIVIDER); - - data.add(encoding); - encoding.add(Columns.Encoding.name()); - encoding.add(Console.ROW_DIVIDER); - - data.add(arrival); - expiration.add(Columns.Arrival.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(expiration); - expiration.add(Columns.Expiration.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(priority); - priority.add(Columns.Priority.name()); - priority.add(Console.ROW_DIVIDER); - - data.add(propertyflag); - propertyflag.add(Columns.Property_Flag.name()); - propertyflag.add(Console.ROW_DIVIDER); - - data.add(replyto); - replyto.add(Columns.ReplyTo.name()); - replyto.add(Console.ROW_DIVIDER); - - data.add(timestamp); - timestamp.add(Columns.Timestamp.name()); - timestamp.add(Console.ROW_DIVIDER); - - data.add(type); - type.add(Columns.Type.name()); - type.add(Console.ROW_DIVIDER); - - data.add(userid); - userid.add(Columns.UserID.name()); - userid.add(Console.ROW_DIVIDER); - } - - List msgHeaders = new LinkedList(); - if (showMessageHeaders) - { - data.add(msgHeaders); - msgHeaders.add(Columns.MsgHeaders.name()); - msgHeaders.add(Console.ROW_DIVIDER); - } - - //Add create the table of data - for (AMQMessage msg : messages) - { - if (!includeMsg(msg, msgids)) - { - continue; - } - - id.add(msg.getMessageId().toString()); - - size.add("" + msg.getSize()); - - arrival.add("" + msg.getArrivalTime()); - - try - { - ispersitent.add(msg.isPersistent() ? "true" : "false"); - } - catch (AMQException e) - { - ispersitent.add("n/a"); - } - - isredelivered.add(msg.isRedelivered() ? "true" : "false"); - - isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); - -// msg.getMessageHandle(); - - BasicContentHeaderProperties headers = null; - - try - { - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); - } - catch (AMQException e) - { - //ignore -// commandError("Unable to read properties for message: " + e.getMessage(), null); - } - - if (headers != null) - { - String appidS = headers.getAppIdAsString(); - appid.add(appidS == null ? "null" : appidS); - - String clusterS = headers.getClusterIdAsString(); - clusterid.add(clusterS == null ? "null" : clusterS); - - String contentS = headers.getContentTypeAsString(); - contenttype.add(contentS == null ? "null" : contentS); - - String correlationS = headers.getCorrelationIdAsString(); - correlationid.add(correlationS == null ? "null" : correlationS); - - deliverymode.add("" + headers.getDeliveryMode()); - - AMQShortString encodeSS = headers.getEncoding(); - encoding.add(encodeSS == null ? "null" : encodeSS.toString()); - - expiration.add("" + headers.getExpiration()); - - FieldTable headerFT = headers.getHeaders(); - msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); - - priority.add("" + headers.getPriority()); - propertyflag.add("" + headers.getPropertyFlags()); - - AMQShortString replytoSS = headers.getReplyTo(); - replyto.add(replytoSS == null ? "null" : replytoSS.toString()); - - timestamp.add("" + headers.getTimestamp()); - - AMQShortString typeSS = headers.getType(); - type.add(typeSS == null ? "null" : typeSS.toString()); - - AMQShortString useridSS = headers.getUserId(); - userid.add(useridSS == null ? "null" : useridSS.toString()); - - MessagePublishInfo info = null; - try - { - info = msg.getMessagePublishInfo(); - } - catch (AMQException e) - { - //ignore - } - - if (info != null) - { - AMQShortString exchangeSS = info.getExchange(); - exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); - - AMQShortString routingkeySS = info.getRoutingKey(); - routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); - - immediate.add(info.isImmediate() ? "true" : "false"); - mandatory.add(info.isMandatory() ? "true" : "false"); - } - -// msg.getPublisher(); -- only used in clustering -// msg.getStoreContext(); -// msg.isAllContentReceived(); - - }// if headers!=null - -// need to access internal map and do lookups. -// msg.isTaken(); -// msg.getDeliveredSubscription(); -// msg.isRejectedBy(); - - } - - // if id only had the header and the divider in it then we have no data to display - if (id.size() == 2) - { - return null; - } - return data; - } - - protected boolean includeMsg(AMQMessage msg, List msgids) - { - if (msgids == null) - { - return true; - } - - Long msgid = msg.getMessageId(); - - boolean found = false; - - if (msgids != null) - { - //check msgid is in msgids - for (Long l : msgids) - { - if (l.equals(msgid)) - { - found = true; - break; - } - } - } - return found; - } - - public enum Columns - { - ID, - Size, - Exchange, - RoutingKey, - isImmediate, - isMandatory, - isPersistent, - isRedelivered, - isDelivered, - App_ID, - Cluster_ID, - Content_Type, - Correlation_ID, - Delivery_Mode, - Encoding, - Arrival, - Expiration, - Priority, - Property_Flag, - ReplyTo, - Timestamp, - Type, - UserID, - MsgHeaders - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java deleted file mode 100644 index c27c52eb8e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.security; - -import org.apache.commons.codec.binary.Base64; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; - -public class Passwd -{ - public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException - { - if (args.length != 2) - { - System.out.println("Passwd "); - System.exit(0); - } - - byte[] data = args[1].getBytes("utf-8"); - - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - Base64 b64 = new Base64(); - - byte[] encoded = b64.encode(digest); - - output(args[0], encoded); - } - - private static void output(String user, byte[] encoded) throws IOException - { - -// File passwdFile = new File("qpid.passwd"); - - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java deleted file mode 100644 index 986fea32cc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -public interface CommandParser -{ - /** - * If there is more than one command received on the last parse request. - * - * Subsequent calls to parse will utilise this input rather than reading new data from the input source - * @return boolean - */ - boolean more(); - - /** - * True if the currently parsed command has been requested as a background operation - * - * @return boolean - */ - boolean isBackground(); - - /** - * Parses user commands, and groups tokens in the - * String[] format that all Java main's love. - * - * If more than one command is provided in one input line then the more() method will return true. - * A subsequent call to parse() will continue to parse that input line before reading new input. - * - * @return input split in args[] format; null if eof. - * @throws java.io.IOException if there is a problem reading from the input stream - */ - String[] parse() throws java.io.IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java deleted file mode 100644 index cf457d1ea5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.util.List; - -public interface Console -{ - public enum CellFormat - { - CENTRED, LEFT, RIGHT - } - - public static String ROW_DIVIDER = "*divider"; - - public void print(String... message); - - public void println(String... message); - - public String readln(); - - /** - * Reads and parses the command line. - * - * - * @return The next command or null - */ - public String[] readCommand(); - - public CommandParser getCommandParser(); - - public void setCommandParser(CommandParser parser); - - /** - * - * Prints the list of String nicely. - * - * +-------------+ - * | Heading | - * +-------------+ - * | Item 1 | - * | Item 2 | - * | Item 3 | - * +-------------+ - * - * @param hasTitle should list[0] be used as a heading - * @param list The list of Strings to display - */ - public void displayList(boolean hasTitle, String... list); - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * +----------------------------+ (*divider) - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - void printMap(String title, List entries); - - - public void close(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java deleted file mode 100644 index 09444ccdd7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.StringTokenizer; - -public class SimpleCommandParser implements CommandParser -{ - private static final String COMMAND_SEPERATOR = ";"; - - /** Input source of commands */ - protected BufferedReader _reader; - - /** The next list of commands from the command line */ - private StringBuilder _nextCommand = null; - - public SimpleCommandParser(BufferedReader reader) - { - _reader = reader; - } - - public boolean more() - { - return _nextCommand != null; - } - - public boolean isBackground() - { - return false; - } - - public String[] parse() throws IOException - { - String[] commands = null; - - String input = null; - - if (_nextCommand == null) - { - input = _reader.readLine(); - } - else - { - input = _nextCommand.toString(); - _nextCommand = null; - } - - if (input == null) - { - return null; - } - - StringTokenizer tok = new StringTokenizer(input, " "); - - int tokenCount = tok.countTokens(); - int index = 0; - - if (tokenCount > 0) - { - commands = new String[tokenCount]; - boolean commandComplete = false; - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - - if (next.equals(COMMAND_SEPERATOR)) - { - commandComplete = true; - _nextCommand = new StringBuilder(); - continue; - } - - if (commandComplete) - { - _nextCommand.append(next); - _nextCommand.append(" "); - } - else - { - commands[index] = next; - index++; - } - } - - } - - //Reduce the String[] if not all the tokens were used in this command. - // i.e. there is more than one command on the line. - if (index != tokenCount) - { - String[] shortCommands = new String[index]; - System.arraycopy(commands, 0, shortCommands, 0, index); - return shortCommands; - } - else - { - return commands; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java deleted file mode 100644 index ec080a4611..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -public class SimpleConsole implements Console -{ - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); - - /** Console Writer. */ - protected static BufferedWriter _consoleWriter; - - /** Console Reader. */ - protected static BufferedReader _consoleReader; - - /** Parser for command-line input. */ - protected CommandParser _parser; - - public SimpleConsole(BufferedWriter writer, BufferedReader reader) - { - _consoleWriter = writer; - _consoleReader = reader; - _parser = new SimpleCommandParser(_consoleReader); - } - - public void print(String... message) - { - try - { - for (String s : message) - { - _consoleWriter.write(s); - } - _consoleWriter.flush(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); - } - - } - - public void println(String... message) - { - print(message); - print(System.getProperty("line.separator")); - } - - - public String readln() - { - try - { - return _consoleReader.readLine(); - } - catch (IOException e) - { - _devlog.debug("Unable to read input due to:" + e.getMessage()); - return null; - } - } - - public String[] readCommand() - { - try - { - return _parser.parse(); - } - catch (IOException e) - { - _devlog.error("Error reading command:" + e.getMessage()); - return new String[0]; - } - } - - public CommandParser getCommandParser() - { - return _parser; - } - - public void setCommandParser(CommandParser parser) - { - _parser = parser; - } - - public void displayList(boolean hasTitle, String... list) - { - java.util.List data = new LinkedList(); - - java.util.List values = new LinkedList(); - - data.add(values); - - for (String value : list) - { - values.add(value); - } - - if (hasTitle) - { - values.add(1, "*divider"); - } - - printMap(null, data); - } - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - public void printMap(String title, java.util.List entries) - { - try - { - int columns = entries.size(); - - int[] columnWidth = new int[columns]; - - // calculate row count - int rowMax = 0; - - //the longest item - int itemMax = 0; - - for (int i = 0; i < columns; i++) - { - int columnIRowMax = entries.get(i).size(); - - if (columnIRowMax > rowMax) - { - rowMax = columnIRowMax; - } - for (Object values : entries.get(i)) - { - if (values.toString().equals(Console.ROW_DIVIDER)) - { - continue; - } - - int itemLength = values.toString().length(); - - //note for single width - if (itemLength > itemMax) - { - itemMax = itemLength; - } - - //note for mulit width - if (itemLength > columnWidth[i]) - { - columnWidth[i] = itemLength; - } - - } - } - - int tableWidth = 0; - - - for (int i = 0; i < columns; i++) - { - // plus 2 for the space padding - columnWidth[i] += 2; - } - for (int size : columnWidth) - { - tableWidth += size; - } - tableWidth += (columns - 1); - - if (title != null) - { - if (title.length() > tableWidth) - { - tableWidth = title.length(); - } - - printCellRow("+", "-", tableWidth); - - printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); - _consoleWriter.newLine(); - - } - - //put top line | or bottom of title - printCellRow("+", "-", tableWidth); - - //print the table data - int row = 0; - - for (; row < rowMax; row++) - { - for (int i = 0; i < columns; i++) - { - java.util.List columnData = entries.get(i); - - String value; - // does this column have a value for this row - if (columnData.size() > row) - { - value = " " + columnData.get(row).toString() + " "; - } - else - { - value = " "; - } - - if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) - { - printCellRow("+", "-", tableWidth); - //move on to the next row - break; - } - else - { - printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); - } - - // if it is the last row then do a new line. - if (i == columns - 1) - { - _consoleWriter.newLine(); - } - } - } - - printCellRow("+", "-", tableWidth); - - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write."); - } - } - - public void close() - { - - try - { - _consoleReader.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); - } - - try - { - - _consoleWriter.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); - } - - } - - private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException - { - int pad = cellWidth - cell.length(); - - if (column == 0) - { - _consoleWriter.write(edge); - } - - switch (format) - { - case CENTRED: - printPad(" ", pad / 2); - break; - case RIGHT: - printPad(" ", pad); - break; - } - - _consoleWriter.write(cell); - - - switch (format) - { - case CENTRED: - // if pad isn't even put the extra one on the right - if (pad % 2 == 0) - { - printPad(" ", pad / 2); - } - else - { - printPad(" ", (pad / 2) + 1); - } - break; - case LEFT: - printPad(" ", pad); - break; - } - - - _consoleWriter.write(edge); - - } - - private void printCellRow(String edge, String mid, int cellWidth) throws IOException - { - _consoleWriter.write(edge); - - printPad(mid, cellWidth); - - _consoleWriter.write(edge); - _consoleWriter.newLine(); - } - - private void printPad(String padChar, int count) throws IOException - { - for (int i = 0; i < count; i++) - { - _consoleWriter.write(padChar); - } - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java deleted file mode 100644 index 6a95529059..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/CommandParser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package com.redhat.etp.qpid.utils; - -public interface CommandParser -{ - /** - * If there is more than one command received on the last parse request. - * - * Subsequent calls to parse will utilise this input rather than reading new data from the input source - * @return boolean - */ - boolean more(); - - /** - * True if the currently parsed command has been requested as a background operation - * - * @return boolean - */ - boolean isBackground(); - - /** - * Parses user commands, and groups tokens in the - * String[] format that all Java main's love. - * - * If more than one command is provided in one input line then the more() method will return true. - * A subsequent call to parse() will continue to parse that input line before reading new input. - * - * @return input split in args[] format; null if eof. - * @throws java.io.IOException if there is a problem reading from the input stream - */ - String[] parse() throws java.io.IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java deleted file mode 100644 index 892a48254c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/Console.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package com.redhat.etp.qpid; - -import java.util.List; - -public interface Console -{ - public enum CellFormat - { - CENTRED, LEFT, RIGHT - } - - public static String ROW_DIVIDER = "*divider"; - - public void print(String... message); - - public void println(String... message); - - public String[] readln(); - - /** - * - * Prints the list of String nicely. - * - * +-------------+ - * | Heading | - * +-------------+ - * | Item 1 | - * | Item 2 | - * | Item 3 | - * +-------------+ - * - * @param hasTitle should list[0] be used as a heading - * @param list The list of Strings to display - */ - public void displayList(boolean hasTitle, String... list); - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * +----------------------------+ (*divider) - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - void printMap(String title, List entries); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java deleted file mode 100644 index ea4045c917..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/RSHCommandParser.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * The Java Shell: jsh core -- RELEASE: alpha3 - * (C)1999 Osvaldo Pinali Doederlein. - * - * LICENSE - * ======= - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CHANGES - * ======= - * 1.0.2 - Added support for non-quoted '\' escape char (Not interpreted by the shell) - * 1.0.1 - Added support for arguments in aliases - * 1.0.0 - Initial release; split from Shell and enhanced a lot. - * - * LINKS - * ===== - * Contact: mailto@osvaldo.visionnaire.com.br, mailto@g.collin@appliweb.net - * Site #1: http://www.geocities.com/ResearchTriangle/Node/2005/ - * Site #2: http://www.appliweb.net/jsh - */ - -package com.redhat.etp.qpid.utils; - -import java.io.BufferedReader; -import java.util.Vector; - -/** - * The Java Shell. - *

      - * Provides an environment for launching and controlling Java apps. - *

      - * TODO: - Support for applets! - * - Support for variable replacement - * - * @author Osvaldo Pinali Doederlein. - */ -public class RSHCommandParser implements CommandParser -{ - /** Where commands come from. */ - protected BufferedReader reader; - /** Continuation for command line. */ - protected String contLine = null; - /** Run next command in background? */ - protected boolean background; - protected String[] env; // Commands passed in args. - - public RSHCommandParser(BufferedReader reader) - { - this(reader, null); - } - - public RSHCommandParser(BufferedReader reader, String env[]) - { - this.reader = reader; - this.env = env; - if (env == null) - { - this.env = new String[0]; - } - } - - - public boolean more() - { - return contLine != null; - } - - public boolean isBackground() - { - return background; - } - - /** - * Solves and expands aliases in an argument array. - * This expansion affects only the first (if any) argument; the - * typical thing to do, as we don't want to expand parameters. - * We recursively parse the result to be sure we expand everything. - * For example, an alias can be expanded to further aliases, or it can contains args. - * - * @param args Raw arguments. - * @return args resolved and expanded. - */ - public static String[] expand(String[] args) - { - if (args.length > 0) - { - String expanded = args[0];//Alias.resolve(args[0]); - - // Try to expand recursively the command line - if (expanded != args[0]) - { - RSHCommandParser recurse = new RSHCommandParser(new BufferedReader( - new java.io.StringReader(expanded))); - - try - { - String cmdLine[] = recurse.parse(); - cmdLine = recurse.expand(cmdLine); - - // do we need to handle new arguments and insert them in the command array ? - if (cmdLine.length > 1) - { - String[] newArgs = new String[cmdLine.length + args.length - 1]; - System.arraycopy(cmdLine, 0, newArgs, 0, cmdLine.length); - - if (args.length > 1) - { - System.arraycopy(args, 1, newArgs, cmdLine.length, args.length - 1); - } - - args = newArgs; - } - else if (cmdLine.length == 1) - { - args[0] = cmdLine[0]; - } - } - catch (java.io.IOException e) - { - } - } - } - - return args; - } - - public String[] parse() throws java.io.IOException - { - final int READ = 0, QUOTE = 1, SKIP = 2, ESCAPE = 3, NONQUOTEDESCAPE = 4, VARIABLE = 5; - final int EOF = 0xFFFF; - int mode = SKIP; - Vector args = new Vector(); - StringBuffer current = new StringBuffer(); - StringBuffer varName = null; - background = false; - String line; - - if (contLine == null) - { - line = reader.readLine(); - } - else - { - line = contLine; - contLine = null; - } - - if (line == null) - { - reader = null; - return null; - } - - for (int pos = 0; pos < line.length(); ++pos) - { - char c = line.charAt(pos); - - switch (mode) - { - case SKIP: - switch (c) - { - case' ': - case'\t': - break; - case'\"': - mode = QUOTE; - break; - case'&': - background = true; - case';': - contLine = line.substring(pos + 1); - pos = line.length(); - break; - default: - mode = READ; - --pos; - } - break; - - case READ: - switch (c) - { - case'\"': - mode = QUOTE; - break; - case';': - case'&': - --pos; - case' ': - case'\t': - mode = SKIP; - break; - case'\\': - mode = NONQUOTEDESCAPE; - break; - case'$': - mode = VARIABLE; - varName = new StringBuffer(); - break; - default: - current.append(c); - } - if ((mode != READ) && (mode != NONQUOTEDESCAPE)) - { - args.addElement(current.toString()); - current = new StringBuffer(); - } - break; - - case QUOTE: - switch (c) - { - case'\"': - mode = READ; - break; - case'\\': - mode = ESCAPE; - break; - default: - current.append(c); - } - break; - - case ESCAPE: - switch (c) - { - case'n': - c = '\n'; - break; - case'r': - c = '\r'; - break; - case't': - c = '\t'; - break; - case'b': - c = '\b'; - break; - case'f': - c = '\f'; - break; - default: - current.append('\\'); - break; - } - mode = QUOTE; - current.append(c); - break; - case NONQUOTEDESCAPE: - switch (c) - { - case';': - mode = READ; - current.append(c); - break; - default: // This is not a escaped char. - mode = READ; - current.append('\\'); - current.append(c); - break; - } - break; - case VARIABLE: - switch (c) - { - case'$': - { -// String val = Set.get(new String(varName)); -// if (val != null) -// { -// current.append(val); -// } - mode = READ; - break; - } - case'@': - { - StringBuffer val = new StringBuffer(); - int i; - for (i = 0; i < env.length; i++) - { - val.append(env[i]); - val.append(' '); - } - current.append(val); - mode = READ; - break; - } - case'0': - case'1': - case'2': - case'3': - case'4': - case'5': - case'6': - case'7': - case'8': - case'9': - { - if (varName.length() == 0) - { - int value = Integer.parseInt(new String(new char[]{c})); - if (env.length > value) - { - current.append(env[value]); - } - mode = READ; - break; - } - // else fall back - } - default: - varName.append(c); - break; - } - break; - } - } - - if (current.length() > 0) - { - args.addElement(current.toString()); - } - return expand(toArray(args)); - } - - private String[] toArray(Vector strings) - { - String[] arr = new String[strings.size()]; - - for (int i = 0; i < strings.size(); ++i) - { - arr[i] = (String) strings.elementAt(i); - } - - return arr; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java deleted file mode 100644 index 98e816554e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/utils/SimpleCommandParser.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package com.redhat.etp.qpid.utils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.StringTokenizer; - -public class SimpleCommandParser implements CommandParser -{ - private static final String COMMAND_SEPERATOR = ";"; - - /** Input source of commands */ - protected BufferedReader _reader; - - /** The next list of commands from the command line */ - private StringBuilder _nextCommand = null; - - public SimpleCommandParser(BufferedReader reader) - { - _reader = reader; - } - - public boolean more() - { - return _nextCommand != null; - } - - public boolean isBackground() - { - return false; - } - - public String[] parse() throws IOException - { - String[] commands = null; - - String input = null; - - if (_nextCommand == null) - { - input = _reader.readLine(); - } - else - { - input = _nextCommand.toString(); - _nextCommand = null; - } - - StringTokenizer tok = new StringTokenizer(input, " "); - - int tokenCount = tok.countTokens(); - int index = 0; - - if (tokenCount > 0) - { - commands = new String[tokenCount]; - boolean commandComplete = false; - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - - if (next.equals(COMMAND_SEPERATOR)) - { - commandComplete = true; - _nextCommand = new StringBuilder(); - continue; - } - - if (commandComplete) - { - _nextCommand.append(next); - _nextCommand.append(" "); - } - else - { - commands[index] = next; - index++; - } - } - - } - - //Reduce the String[] if not all the tokens were used in this command. - // i.e. there is more than one command on the line. - if (index != tokenCount) - { - String[] shortCommands = new String[index]; - System.arraycopy(commands, 0, shortCommands, 0, index); - return shortCommands; - } - else - { - return commands; - } - } -} -- cgit v1.2.1 From 66eda1edbca3bf08002af9a06ee58cf906e6fa08 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Mon, 6 Aug 2007 13:06:35 +0000 Subject: QPID-543 : Add ability to register cusom exchange types git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@563125 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/AbstractExchange.java | 15 +---- .../server/exchange/DefaultExchangeFactory.java | 64 +++++++++++++++------- .../qpid/server/exchange/DestNameExchange.java | 25 +++++++++ .../qpid/server/exchange/DestWildExchange.java | 27 +++++++++ .../org/apache/qpid/server/exchange/Exchange.java | 4 +- .../qpid/server/exchange/ExchangeFactory.java | 4 ++ .../qpid/server/exchange/ExchangeRegistry.java | 2 + .../apache/qpid/server/exchange/ExchangeType.java | 34 ++++++++++++ .../qpid/server/exchange/FanoutExchange.java | 29 ++++++++++ .../qpid/server/exchange/HeadersExchange.java | 28 ++++++++++ .../qpid/server/exchange/ManagedExchange.java | 3 - .../qpid/server/virtualhost/VirtualHost.java | 2 + 12 files changed, 199 insertions(+), 38 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 868ac31a54..246de230ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -49,7 +49,7 @@ public abstract class AbstractExchange implements Exchange, Managable protected boolean _durable; protected String _exchangeType; - protected int _ticket; + private VirtualHost _virtualHost; @@ -114,11 +114,6 @@ public abstract class AbstractExchange implements Exchange, Managable return _exchangeType; } - public Integer getTicketNo() - { - return _ticket; - } - public boolean isDurable() { return _durable; @@ -155,13 +150,12 @@ public abstract class AbstractExchange implements Exchange, Managable */ protected abstract ExchangeMBean createMBean() throws AMQException; - public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + public void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException { _virtualHost = host; _name = name; _durable = durable; _autoDelete = autoDelete; - _ticket = ticket; _exchangeMbean = createMBean(); _exchangeMbean.register(); } @@ -176,11 +170,6 @@ public abstract class AbstractExchange implements Exchange, Managable return _autoDelete; } - public int getTicket() - { - return _ticket; - } - public void close() throws AMQException { if (_exchangeMbean != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 39a5bba8b7..e3b715d45f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -24,6 +24,8 @@ import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.exchange.ExchangeDefaults; @@ -34,42 +36,66 @@ public class DefaultExchangeFactory implements ExchangeFactory { private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); - private Map> _exchangeClassMap = new HashMap>(); + private Map> _exchangeClassMap = new HashMap>(); private final VirtualHost _host; public DefaultExchangeFactory(VirtualHost host) { _host = host; - _exchangeClassMap.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestNameExchange.class); - _exchangeClassMap.put(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, org.apache.qpid.server.exchange.DestWildExchange.class); - _exchangeClassMap.put(ExchangeDefaults.HEADERS_EXCHANGE_CLASS, org.apache.qpid.server.exchange.HeadersExchange.class); - _exchangeClassMap.put(ExchangeDefaults.FANOUT_EXCHANGE_CLASS, org.apache.qpid.server.exchange.FanoutExchange.class); + registerExchangeType(DestNameExchange.TYPE); + registerExchangeType(DestWildExchange.TYPE); + registerExchangeType(HeadersExchange.TYPE); + registerExchangeType(FanoutExchange.TYPE); + + } + public void registerExchangeType(ExchangeType type) + { + _exchangeClassMap.put(type.getName(), type); } public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException { - Class exchClass = _exchangeClassMap.get(type); - if (exchClass == null) + ExchangeType exchType = _exchangeClassMap.get(type); + if (exchType == null) { throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null); } - try - { - Exchange e = exchClass.newInstance(); - e.initialise(_host, exchange, durable, ticket, autoDelete); - return e; - } - catch (InstantiationException e) - { - throw new AMQException(null, "Unable to create exchange: " + e, e); - } - catch (IllegalAccessException e) + Exchange e = exchType.newInstance(_host, exchange, durable, autoDelete); + return e; + } + + public void initialise(Configuration hostConfig) + { + for(Object className : hostConfig.getList("custom-exchanges.class-name")) { - throw new AMQException(null, "Unable to create exchange: " + e, e); + try + { + Class exchangeTypeClass = (Class) Class.forName(String.valueOf(className)); + ExchangeType type = exchangeTypeClass.newInstance(); + registerExchangeType(type); + + } + catch (ClassNotFoundException e) + { + _logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\""); + } + catch (ClassCastException classCastEx) + { + _logger.error("No custom exchange class: \""+String.valueOf(className)+"\" cannot be registered as it does not extend class \""+ExchangeType.class+"\""); + } + catch (IllegalAccessException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } + catch (InstantiationException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 0dcceaddbb..6177980b92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -48,6 +48,7 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; public class DestNameExchange extends AbstractExchange { @@ -58,6 +59,30 @@ public class DestNameExchange extends AbstractExchange */ private final Index _index = new Index(); + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DestNameExchange.class; + } + + public DestNameExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + DestNameExchange exch = new DestNameExchange(); + exch.initialise(host,name,durable,autoDelete); + return exch; + } + }; + /** * MBean class implementing the management interfaces. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index f6a95b5e55..20f0517789 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -32,6 +32,7 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import javax.management.MBeanException; @@ -56,6 +57,32 @@ import java.util.concurrent.CopyOnWriteArrayList; public class DestWildExchange extends AbstractExchange { + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DestWildExchange.class; + } + + public DestWildExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + DestWildExchange exch = new DestWildExchange(); + exch.initialise(host,name,durable,autoDelete); + return exch; + } + }; + + private static final Logger _logger = Logger.getLogger(DestWildExchange.class); private ConcurrentHashMap> _routingKey2queues = diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index a5f77cc2a4..03b264f8fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -32,7 +32,7 @@ public interface Exchange AMQShortString getName(); AMQShortString getType(); - void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + boolean isDurable(); @@ -41,8 +41,6 @@ public interface Exchange */ boolean isAutoDelete(); - int getTicket(); - void close() throws AMQException; void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index e07fd0b8fc..b7b88b9157 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.exchange; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -29,4 +31,6 @@ public interface ExchangeFactory Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException; + + void initialise(Configuration hostConfig); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index d3a466565f..0003b8302f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.exchange; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java new file mode 100644 index 0000000000..472de2da5c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; + + +public interface ExchangeType +{ + public AMQShortString getName(); + public Class getExchangeClass(); + public T newInstance(VirtualHost host, AMQShortString name, + boolean durable, boolean autoDelete) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index bf00eeb9d3..8895539538 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import javax.management.MBeanException; @@ -49,8 +50,36 @@ import java.util.concurrent.CopyOnWriteArraySet; public class FanoutExchange extends AbstractExchange { + + private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return FanoutExchange.class; + } + + public FanoutExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + FanoutExchange exch = new FanoutExchange(); + exch.initialise(host,name,durable,autoDelete); + return exch; + } + }; + + /** * Maps from queue name to queue instances */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index e86094e26f..bed08daeaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -49,6 +49,7 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; /** * An exchange that binds queues based on a set of required headers and header values @@ -81,6 +82,33 @@ public class HeadersExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(HeadersExchange.class); + + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return HeadersExchange.class; + } + + public HeadersExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + HeadersExchange exch = new HeadersExchange(); + exch.initialise(host,name,durable,autoDelete); + return exch; + } + }; + + private final List _bindings = new CopyOnWriteArrayList(); /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index 5d6d68b3c8..bb33341aef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -52,9 +52,6 @@ public interface ManagedExchange @MBeanAttribute(name="ExchangeType", description="Exchange Type") String getExchangeType() throws IOException; - @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") - Integer getTicketNo() throws IOException; - /** * Tells if the exchange is durable or not. * @return true if the exchange is durable. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 6638689299..6518d8b765 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -146,6 +146,7 @@ public class VirtualHost implements Accessable _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); _exchangeRegistry = new DefaultExchangeRegistry(this); if (store != null) @@ -164,6 +165,7 @@ public class VirtualHost implements Accessable _exchangeRegistry.initialise(); + _logger.warn("VirtualHost authentication Managers require spec change to be operational."); _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); -- cgit v1.2.1 From 94b0978c09b14308c25b7c5b02792c192b0c5521 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 30 Aug 2007 12:19:31 +0000 Subject: Remerge of M2. All tests pass locally Testing done in Intelij and mvn command line via windows/cygwin. Python tests removed from auto build pending Jython-siztion. Tested running broker in intelij and python run-tests from cygwin. All tests pass. (CombinedTest still exhibts a race condition. but that has always been so.) Additional Race condition identified (around MsgReject/AutoDeleteQueues) during testing patch to follow. systests are inconsistent Some use TestableMemoryMessageStore some use MemoryMessgaeStore. Lets not roll back this change if issues are discovered. Lets work together to go forward and address any issues. I have spent a lot of time ensuring the tests work for me so I hope that they work for you. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@571129 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 3 - .../apache/qpid/configuration/Configuration.java | 188 ++++++ .../apache/qpid/server/AMQBrokerManagerMBean.java | 52 +- .../java/org/apache/qpid/server/AMQChannel.java | 209 +++---- .../qpid/server/ConsumerTagNotUniqueException.java | 7 +- .../src/main/java/org/apache/qpid/server/Main.java | 74 ++- .../configuration/VirtualHostConfiguration.java | 36 +- .../qpid/server/exchange/AbstractExchange.java | 9 +- .../server/exchange/DefaultExchangeRegistry.java | 48 +- .../qpid/server/exchange/DestNameExchange.java | 53 +- .../qpid/server/exchange/DestWildExchange.java | 36 +- .../org/apache/qpid/server/exchange/Exchange.java | 27 +- .../qpid/server/exchange/ExchangeRegistry.java | 5 +- .../qpid/server/exchange/FanoutExchange.java | 67 ++- .../qpid/server/exchange/HeadersExchange.java | 100 ++-- .../server/handler/BasicConsumeMethodHandler.java | 18 +- .../server/handler/BasicPublishMethodHandler.java | 9 + .../server/handler/BasicRejectMethodHandler.java | 7 +- .../qpid/server/handler/ExchangeBoundHandler.java | 25 +- .../server/handler/ExchangeDeclareHandler.java | 4 +- .../qpid/server/handler/QueueBindHandler.java | 17 +- .../qpid/server/handler/QueueDeclareHandler.java | 22 +- .../qpid/server/handler/QueueDeleteHandler.java | 6 +- .../management/JMXManagedObjectRegistry.java | 44 +- .../management/MBeanInvocationHandlerImpl.java | 25 +- .../apache/qpid/server/messageStore/JDBCStore.java | 390 +++++++----- .../qpid/server/messageStore/MessageStore.java | 22 +- .../server/protocol/AMQPFastProtocolHandler.java | 48 +- .../org/apache/qpid/server/queue/AMQMessage.java | 99 ++-- .../org/apache/qpid/server/queue/AMQQueue.java | 333 +++++++++-- .../apache/qpid/server/queue/AMQQueueMBean.java | 62 +- .../queue/ConcurrentSelectorDeliveryManager.java | 81 +-- .../qpid/server/queue/DefaultQueueRegistry.java | 17 +- .../apache/qpid/server/queue/ExchangeBindings.java | 11 +- .../qpid/server/queue/InMemoryMessageHandle.java | 44 +- .../qpid/server/queue/MessageHandleFactory.java | 8 +- .../apache/qpid/server/queue/MessageMetaData.java | 24 +- .../qpid/server/queue/NotificationCheck.java | 25 +- .../server/queue/QueueNotificationListener.java | 25 +- .../apache/qpid/server/queue/QueueRegistry.java | 7 +- .../qpid/server/queue/StorableMessageHandle.java | 61 +- .../qpid/server/queue/TransientMessageData.java | 25 +- .../server/queue/WeakReferenceMessageHandle.java | 1 - .../ConfigurationFilePrincipalDatabaseManager.java | 10 +- .../txn/DistributedTransactionalContext.java | 2 - .../qpid/server/txn/NonTransactionalContext.java | 42 +- .../qpid/server/txn/TransactionalContext.java | 124 +++- .../qpid/server/util/NullApplicationRegistry.java | 8 +- .../qpid/server/virtualhost/VirtualHost.java | 579 +++++++++--------- .../qpid/tools/messagestore/MessageStoreTool.java | 652 +++++++++++++++++++++ .../messagestore/commands/AbstractCommand.java | 66 +++ .../qpid/tools/messagestore/commands/Clear.java | 85 +++ .../qpid/tools/messagestore/commands/Command.java | 36 ++ .../qpid/tools/messagestore/commands/Copy.java | 55 ++ .../qpid/tools/messagestore/commands/Dump.java | 299 ++++++++++ .../qpid/tools/messagestore/commands/Help.java | 98 ++++ .../qpid/tools/messagestore/commands/List.java | 314 ++++++++++ .../qpid/tools/messagestore/commands/Load.java | 94 +++ .../qpid/tools/messagestore/commands/Move.java | 205 +++++++ .../qpid/tools/messagestore/commands/Purge.java | 68 +++ .../qpid/tools/messagestore/commands/Quit.java | 54 ++ .../qpid/tools/messagestore/commands/Select.java | 233 ++++++++ .../qpid/tools/messagestore/commands/Show.java | 512 ++++++++++++++++ .../org/apache/qpid/tools/security/Passwd.java | 81 +++ .../org/apache/qpid/tools/utils/CommandParser.java | 51 ++ .../java/org/apache/qpid/tools/utils/Console.java | 90 +++ .../qpid/tools/utils/SimpleCommandParser.java | 121 ++++ .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 ++++++++++++ 68 files changed, 5453 insertions(+), 1163 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 931c15a664..7e0c4defe1 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -31,7 +31,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPOutputStream; import org.apache.log4j.helpers.CountingQuietWriter; @@ -39,8 +38,6 @@ import org.apache.log4j.helpers.LogLog; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.spi.LoggingEvent; -import org.apache.qpid.framing.FieldTable; - /** *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java new file mode 100644 index 0000000000..40ff590a0a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.configuration; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class Configuration +{ + public static final String QPID_HOME = "QPID_HOME"; + + final String QPIDHOME = System.getProperty(QPID_HOME); + + private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); + + public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + protected final Options _options = new Options(); + protected CommandLine _commandLine; + protected File _configFile; + + + public Configuration() + { + + } + + public void processCommandline(String[] args) throws InitException + { + try + { + _commandLine = new PosixParser().parse(_options, args); + } + catch (ParseException e) + { + throw new InitException("Unable to parse commmandline", e); + } + + final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); + setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); + } + + public void setConfig(File file) + { + _configFile = file; + } + + /** + * @param option The option to set. + */ + public void setOption(Option option) + { + _options.addOption(option); + } + + /** + * getOptionValue from the configuration + * @param option variable argument, first string is option to get, second if present is the default value. + * @return the String for the given option or null if not present (if default value not specified) + */ + public String getOptionValue(String... option) + { + if (option.length == 1) + { + return _commandLine.getOptionValue(option[0]); + } + else if (option.length == 2) + { + return _commandLine.getOptionValue(option[0], option[1]); + } + return null; + } + + public void loadConfig(File file) throws InitException + { + setConfig(file); + loadConfig(); + } + + private void loadConfig() throws InitException + { + 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, null); + } + else + { + _devlog.debug("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); +// } + } + + +// private void configureLogging(File logConfigFile, String logWatchConfig) +// { +// int logWatchTime = 0; +// try +// { +// logWatchTime = Integer.parseInt(logWatchConfig); +// } +// catch (NumberFormatException e) +// { +// _devlog.error("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()) +// { +// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); +// if (logWatchTime > 0) +// { +// _devlog.info("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(); +// } +// } + + public File getConfigFile() + { + return _configFile; + } + + + public class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index f2cc6e8bca..6d67686d1c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -37,19 +37,11 @@ */ package org.apache.qpid.server; -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -58,11 +50,16 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + /** * This MBean implements the broker management interface and exposes the * Broker level management features like creating and deleting exchanges and queue. @@ -113,9 +110,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); if (exchange == null) { - exchange = - _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, - false, 0); + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), + new AMQShortString(type), durable, false, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -181,20 +177,21 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { - try - { + //DTX MessageStore +// try +// { _messageStore.createQueue(queue); - } - catch (Exception e) - { - JMException jme = new JMException("problem creating queue " + queue.getName()); - jme.initCause(e); - throw jme; - } +// } +// catch (Exception e) +// { +// JMException jme = new JMException("problem creating queue " + queue.getName()); +// jme.initCause(e); +// throw jme; +// } } Configuration virtualHostDefaultQueueConfiguration = - VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + VirtualHostConfiguration.getDefaultQueueConfiguration(queue); if (virtualHostDefaultQueueConfiguration != null) { Configurator.configure(queue, virtualHostDefaultQueueConfiguration); @@ -230,10 +227,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - if (queue.isDurable()) - { - _messageStore.destroyQueue(queue); - } + + //DTX MessageStore +// if (queue.isDurable()) +// { +// _messageStore.destroyQueue(queue); + _messageStore.removeQueue(queue.getName()); +// } } catch (Exception ex) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 28a9e85489..bd93ae2f85 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -21,8 +21,6 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; - - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentBody; @@ -34,14 +32,17 @@ 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.exchange.NoRouteException; -import org.apache.qpid.server.messageStore.MessageStore; 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.queue.Subscription; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.*; +import org.apache.qpid.server.txn.LocalTransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.txn.TransactionalContext; import java.util.Collection; import java.util.HashMap; @@ -75,14 +76,10 @@ public class AMQChannel */ 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 - */ + /** 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. - */ + /** This tag is unique per subscription to a queue. The server returns this in response to a basic.consume request. */ private int _consumerTag; /** @@ -92,9 +89,7 @@ public class AMQChannel */ private AMQMessage _currentMessage; - /** - * Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. - */ + /** Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */ private final Map _consumerTag2QueueMap = new HashMap(); private final MessageStore _messageStore; @@ -126,7 +121,7 @@ public class AMQChannel private boolean _closing; public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, - MessageStore messageStore, MessageRouter exchanges) throws AMQException + MessageStore messageStore, MessageRouter exchanges) throws AMQException { _session = session; _channelId = channelId; @@ -140,13 +135,15 @@ public class AMQChannel _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } - /** - * Sets this channel to be part of a local transaction - */ + /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { - _txnContext = - new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); + + _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); + + // Why is the LocalTransactionalContext always a DTX one? +// _txnContext = +// new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); } public boolean isTransactional() @@ -210,7 +207,7 @@ public class AMQChannel } public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession) - throws AMQException + throws AMQException { if (_currentMessage == null) { @@ -256,8 +253,8 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received if (_currentMessage.addContentBodyFrame(_storeContext, - protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody))) + protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk( + contentBody))) { // callback to allow the context to do any post message processing // primary use is to allow message return processing in the non-tx case @@ -307,12 +304,14 @@ public class AMQChannel * @param exclusive Flag requesting exclusive access to the queue * @param acks Are acks enabled for this subscriber * @param filters Filters to apply to this 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 AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) { @@ -343,6 +342,7 @@ public class AMQChannel * Called from the protocol session to close this channel and clean up. T * * @param session The session to close + * * @throws AMQException if there is an error during closure */ public void close(AMQProtocolSession session) throws AMQException @@ -408,7 +408,7 @@ public class AMQChannel if (_log.isDebugEnabled()) { _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag - + ") with a queue(" + queue + ") for " + consumerTag); + + ") with a queue(" + queue + ") for " + consumerTag); } } } @@ -454,7 +454,7 @@ public class AMQChannel // if (_nonTransactedContext == null) { _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; @@ -490,6 +490,7 @@ public class AMQChannel * Requeue a single message * * @param deliveryTag The message to requeue + * * @throws AMQException If something goes wrong. */ public void requeue(long deliveryTag) throws AMQException @@ -516,7 +517,7 @@ public class AMQChannel // if (_nonTransactedContext == null) { _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; @@ -536,7 +537,7 @@ public class AMQChannel else { _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() - + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); + + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); // _log.error("Requested requeue of message:" + deliveryTag + // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); // @@ -547,25 +548,26 @@ public class AMQChannel else { _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." - + _unacknowledgedMessageMap.size()); + + _unacknowledgedMessageMap.size()); if (_log.isDebugEnabled()) { _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - int count = 0; + { + int count = 0; - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - _log.debug( + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug( (count++) + ": (" + message.message.debugIdentity() + ")" + "[" + message.deliveryTag + "]"); - return false; // Continue - } + return false; // Continue + } - public void visitComplete() - { } - }); + public void visitComplete() + { + } + }); } } @@ -575,6 +577,7 @@ public class AMQChannel * Called to resend all outstanding unacknowledged messages to this same channel. * * @param requeue Are the messages to be requeued or dropped. + * * @throws AMQException When something goes wrong. */ public void resend(final boolean requeue) throws AMQException @@ -582,73 +585,74 @@ public class AMQChannel final List msgToRequeue = new LinkedList(); final List msgToResend = new LinkedList(); - if (_log.isInfoEnabled()) + if (_log.isDebugEnabled()) { - _log.info("unacked map Size:" + _unacknowledgedMessageMap.size()); + _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); } // Process the Unacked-Map. // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException { - public boolean callback(UnacknowledgedMessage message) throws AMQException + AMQShortString consumerTag = message.consumerTag; + AMQMessage msg = message.message; + msg.setRedelivered(true); + if (consumerTag != null) { - AMQShortString consumerTag = message.consumerTag; - AMQMessage msg = message.message; - msg.setRedelivered(true); - if (consumerTag != null) + // Consumer exists + if (_consumerTag2QueueMap.containsKey(consumerTag)) { - // Consumer exists - if (_consumerTag2QueueMap.containsKey(consumerTag)) - { - msgToResend.add(message); - } - else // consumer has gone - { - msgToRequeue.add(message); - } + msgToResend.add(message); } - else + else // consumer has gone { - // Message has no consumer tag, so was "delivered" to a GET - // or consumer no longer registered - // cannot resend, so re-queue. - if (message.queue != null) + msgToRequeue.add(message); + } + } + else + { + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (message.queue != null) + { + if (requeue) { - if (requeue) - { - msgToRequeue.add(message); - } - else - { - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); - } + msgToRequeue.add(message); } else { - _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); } } - - // false means continue processing - return false; + else + { + _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + } } - public void visitComplete() - { } - }); + // false means continue processing + return false; + } + + public void visitComplete() + { + } + }); // Process Messages to Resend - if (_log.isInfoEnabled()) + if (_log.isDebugEnabled()) { if (!msgToResend.isEmpty()) { - _log.info("Preparing (" + msgToResend.size() + ") message to resend."); + _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); } else { - _log.info("No message to resend."); + _log.debug("No message to resend."); } } @@ -692,7 +696,7 @@ public class AMQChannel if (_log.isDebugEnabled()) { _log.debug("Subscription(" + System.identityHashCode(sub) - + ") closed during resend so requeuing message"); + + ") closed during resend so requeuing message"); } // move this message to requeue msgToRequeue.add(message); @@ -702,7 +706,7 @@ public class AMQChannel if (_log.isDebugEnabled()) { _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" - + System.identityHashCode(sub)); + + System.identityHashCode(sub)); } sub.addToResendQueue(msg); @@ -716,7 +720,7 @@ public class AMQChannel if (_log.isInfoEnabled()) { _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() - + ")to prevent loss"); + + ")to prevent loss"); } // move this message to requeue msgToRequeue.add(message); @@ -740,7 +744,7 @@ public class AMQChannel if (_nonTransactedContext == null) { _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); } deliveryContext = _nonTransactedContext; @@ -768,34 +772,36 @@ public class AMQChannel * 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 { - public boolean callback(UnacknowledgedMessage message) throws AMQException + if (message.queue == queue) { - if (message.queue == queue) + try { - try - { - message.discard(_storeContext); - message.queue = null; - } - catch (AMQException e) - { - _log.error( + message.discard(_storeContext); + message.queue = null; + } + catch (AMQException e) + { + _log.error( "Error decrementing ref count on message " + message.message.getMessageId() + ": " + e, e); - } } - - return false; } - public void visitComplete() - { } - }); + return false; + } + + public void visitComplete() + { + } + }); } /** @@ -804,6 +810,7 @@ public class AMQChannel * @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 @@ -842,8 +849,8 @@ public class AMQChannel boolean suspend; suspend = - ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) - || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); + ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) + || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); setSuspended(suspend); } @@ -928,7 +935,7 @@ public class AMQChannel { AMQMessage message = bouncedMessage.getAMQMessage(); session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); + new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); @@ -943,7 +950,7 @@ public class AMQChannel else { boolean willSuspend = - ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); + ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); if (!willSuspend) { final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java index 3253650d14..3dc2654bd5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -32,4 +32,5 @@ package org.apache.qpid.server; * @todo Consider replacing with an AMQNotAllowedException, as this is the status code returned when this happens. */ public class ConsumerTagNotUniqueException extends Exception -{ } +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 29ea69caf7..8932dd25f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,13 +20,6 @@ */ package org.apache.qpid.server; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.BindException; -import java.util.Collection; -import java.util.List; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -34,6 +27,7 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; +import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; @@ -48,6 +42,7 @@ import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -55,11 +50,19 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.url.URLSyntaxException; +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; + /** * Main entry point for AMQPD. * */ -@SuppressWarnings({ "AccessStaticViaInstance" }) +@SuppressWarnings({"AccessStaticViaInstance"}) public class Main { /** Used for debugging. */ @@ -133,6 +136,12 @@ public class Main OptionBuilder.withArgName("port").hasArg() .withDescription("listen on the specified port. Overrides any value in the config file") .withLongOpt("port").create("p"); + Option mport = + OptionBuilder.withArgName("mport").hasArg() + .withDescription("listen on the specified management port. Overrides any value in the config file") + .withLongOpt("mport").create("m"); + + Option bind = OptionBuilder.withArgName("bind").hasArg() .withDescription("bind to the specified address. Overrides any value in the config file") @@ -153,6 +162,7 @@ public class Main options.addOption(logconfig); options.addOption(logwatchconfig); options.addOption(port); + options.addOption(mport); options.addOption(bind); } @@ -203,15 +213,19 @@ public class Main catch (InitException e) { System.out.println(e.getMessage()); + _brokerLogger.error("Initialisation Error : " + e.getMessage()); + } catch (ConfigurationException e) { System.out.println("Error configuring message broker: " + e); + _brokerLogger.error("Error configuring message broker: " + e); e.printStackTrace(); } catch (Exception e) { System.out.println("Error intialising message broker: " + e); + _brokerLogger.error("Error intialising message broker: " + e); e.printStackTrace(); } } @@ -260,13 +274,21 @@ public class Main configureLogging(logConfigFile, logWatchConfig); } - ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); + ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); + - // fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); + + + + ApplicationRegistry.initialise(config); + + + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " - + QpidProperties.getBuildVersion()); + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); @@ -316,6 +338,30 @@ public class Main } bind(port, connectorConfig); + + } + + /** + * Update the configuration data with the management port. + * @param configuration + * @param managementPort The string from the command line + */ + private void updateManagementPort(Configuration configuration, String managementPort) + { + if (managementPort != null) + { + int mport; + int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); + try + { + mport = Integer.parseInt(managementPort); + configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); + } + catch (NumberFormatException e) + { + _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); + } + } } protected void setupVirtualHosts(String configFileParent, String configFilePath) @@ -421,8 +467,8 @@ public class Main } // fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " - + QpidProperties.getBuildVersion()); + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index e337b26b33..d1589092e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -36,7 +36,7 @@ import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exception.InternalErrorException; import org.apache.qpid.server.exception.QueueAlreadyExistsException; @@ -193,19 +193,22 @@ public class VirtualHostConfiguration if (queue.isDurable()) { - try - { - messageStore.createQueue(queue); - } catch (InternalErrorException e) - { - _logger.error("Problem when creating Queue '" + queueNameString - + "' on virtual host " + virtualHost.getName() + ", not creating."); - - } catch (QueueAlreadyExistsException e) - { - _logger.error("Queue '" + queueNameString - + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); - } + + messageStore.createQueue(queue); + //DTX MessageStore +// try +// { +// messageStore.createQueue(queue); +// } catch (InternalErrorException e) +// { +// _logger.error("Problem when creating Queue '" + queueNameString +// + "' on virtual host " + virtualHost.getName() + ", not creating."); +// +// } catch (QueueAlreadyExistsException e) +// { +// _logger.error("Queue '" + queueNameString +// + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); +// } } queueRegistry.registerQueue(queue); @@ -260,10 +263,7 @@ public class VirtualHostConfiguration } - public void performBindings() - throws - AMQException, - ConfigurationException + public void performBindings() throws AMQException, ConfigurationException { List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); String defaultVirtualHostName = _config.getString("default"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 246de230ec..0558906fb6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,19 +38,20 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.List; +import java.util.Map; + public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; - - protected boolean _durable; protected String _exchangeType; - private VirtualHost _virtualHost; protected ExchangeMBean _exchangeMbean; @@ -178,6 +179,8 @@ public abstract class AbstractExchange implements Exchange, Managable } } + abstract public Map> getBindings(); + public String toString() { return getClass().getName() + "[" + getName() +"]"; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index f3bdecc32e..23a4bec6bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,17 +20,18 @@ */ package org.apache.qpid.server.exchange; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.exception.InternalErrorException; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public class DefaultExchangeRegistry implements ExchangeRegistry { @@ -66,13 +67,15 @@ public class DefaultExchangeRegistry implements ExchangeRegistry _exchangeMap.put(exchange.getName(), exchange); if(exchange.isDurable()) { - try - { getMessageStore().createExchange(exchange); - } catch (InternalErrorException e) - { - throw new AMQException(null, "problem registering excahgne " + exchange, e); - } + //DTX MessageStore +// try +// { +// getMessageStore().createExchange(exchange); +// } catch (InternalErrorException e) +// { +// throw new AMQException(null, "problem registering excahgne " + exchange, e); +// } } } @@ -86,21 +89,28 @@ public class DefaultExchangeRegistry implements ExchangeRegistry return _defaultExchange; } + public Collection getExchangeNames() + { + return _exchangeMap.keySet(); + } + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); if (e != null) { - if(e.isDurable()) + if (e.isDurable()) { - try - { - getMessageStore().removeExchange(e); - } catch (InternalErrorException e1) - { - throw new AMQException(null, "Problem unregistering Exchange " + name, e1); - } + getMessageStore().removeExchange(e); + //DTX MessageStore +// try +// { +// getMessageStore().removeExchange(e); +// } catch (InternalErrorException e1) +// { +// throw new AMQException(null, "Problem unregistering Exchange " + name, e1); +// } } e.close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 6177980b92..d1cc9b892f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -20,28 +20,10 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -50,6 +32,17 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +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); @@ -78,7 +71,7 @@ public class DestNameExchange extends AbstractExchange boolean autoDelete) throws AMQException { DestNameExchange exch = new DestNameExchange(); - exch.initialise(host,name,durable,autoDelete); + exch.initialise(host, name, durable, autoDelete); return exch; } }; @@ -90,7 +83,7 @@ public class DestNameExchange extends AbstractExchange private final class DestNameExchangeMBean extends ExchangeMBean { @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DestNameExchangeMBean() throws JMException + public DestNameExchangeMBean() throws JMException { super(); _exchangeType = "direct"; @@ -200,7 +193,7 @@ public class DestNameExchange extends AbstractExchange } else { - _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); + _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); _logger.warn(msg); } } @@ -218,19 +211,24 @@ public class DestNameExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { final List queues = _index.get(routingKey); return queues != null && queues.contains(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { final List queues = _index.get(routingKey); return queues != null && !queues.isEmpty(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { Map> bindings = _index.getBindingsMap(); for (List queues : bindings.values()) @@ -243,8 +241,13 @@ public class DestNameExchange extends AbstractExchange return false; } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_index.getBindingsMap().isEmpty(); } + + public Map> getBindings() + { + return _index.getBindingsMap(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java index 20f0517789..25dc32fd41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -21,11 +21,9 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; @@ -36,17 +34,11 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -77,7 +69,7 @@ public class DestWildExchange extends AbstractExchange boolean autoDelete) throws AMQException { DestWildExchange exch = new DestWildExchange(); - exch.initialise(host,name,durable,autoDelete); + exch.initialise(host, name, durable, autoDelete); return exch; } }; @@ -86,7 +78,7 @@ public class DestWildExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(DestWildExchange.class); private ConcurrentHashMap> _routingKey2queues = - new ConcurrentHashMap>(); + new ConcurrentHashMap>(); // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); private static final String TOPIC_SEPARATOR = "."; private static final String AMQP_STAR = "*"; @@ -119,7 +111,7 @@ public class DestWildExchange extends AbstractExchange queueList.add(q.getName().toString()); } - Object[] bindingItemValues = { key.toString(), queueList.toArray(new String[0]) }; + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -265,21 +257,26 @@ public class DestWildExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { List queues = _routingKey2queues.get(normalize(routingKey)); return (queues != null) && queues.contains(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { List queues = _routingKey2queues.get(normalize(routingKey)); return (queues != null) && !queues.isEmpty(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { for (List queues : _routingKey2queues.values()) { @@ -292,7 +289,7 @@ public class DestWildExchange extends AbstractExchange return false; } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_routingKey2queues.isEmpty(); } @@ -338,6 +335,11 @@ public class DestWildExchange extends AbstractExchange } } + public Map> getBindings() + { + return _routingKey2queues; + } + private List getMatchedQueues(AMQShortString routingKey) { List list = new LinkedList(); @@ -385,8 +387,8 @@ public class DestWildExchange extends AbstractExchange if (queueList.size() > (depth + queueskip)) { // a hash and it is the last entry matching = - queueList.get(depth + queueskip).equals(AMQP_HASH) - && (queueList.size() == (depth + queueskip + 1)); + queueList.get(depth + queueskip).equals(AMQP_HASH) + && (queueList.size() == (depth + queueskip + 1)); } } else if (routingkeyList.size() > (depth + routingskip)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 03b264f8fa..78749de612 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -27,12 +27,15 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.List; +import java.util.Map; + public interface Exchange { AMQShortString getName(); AMQShortString getType(); - + void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException; boolean isDurable(); @@ -49,6 +52,17 @@ public interface Exchange void route(AMQMessage message) throws AMQException; + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments + * @param routingKey + * @param arguments + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); + /** * Determines whether a message would be isBound to a particular queue using a specific routing key * @param routingKey @@ -56,7 +70,7 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException; + boolean isBound(AMQShortString routingKey, AMQQueue queue); /** * Determines whether a message is routing to any queue using a specific routing key @@ -64,14 +78,17 @@ public interface Exchange * @return * @throws AMQException */ - boolean isBound(AMQShortString routingKey) throws AMQException; + boolean isBound(AMQShortString routingKey); - boolean isBound(AMQQueue queue) throws AMQException; + boolean isBound(AMQQueue queue); /** * Returns true if this exchange has at least one binding associated with it. * @return * @throws AMQException */ - boolean hasBindings() throws AMQException; + boolean hasBindings(); + + Map> getBindings(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index 0003b8302f..2e101beb84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -20,11 +20,10 @@ */ package org.apache.qpid.server.exchange; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import java.util.Collection; public interface ExchangeRegistry extends MessageRouter { @@ -45,5 +44,7 @@ public interface ExchangeRegistry extends MessageRouter Exchange getDefaultExchange(); + Collection getExchangeNames(); + void initialise() throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 8895539538..77590ea54d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -35,17 +34,13 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - +import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; public class FanoutExchange extends AbstractExchange @@ -56,28 +51,28 @@ public class FanoutExchange extends AbstractExchange public static final ExchangeType TYPE = new ExchangeType() - { + { - public AMQShortString getName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } + public AMQShortString getName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } - public Class getExchangeClass() - { - return FanoutExchange.class; - } + public Class getExchangeClass() + { + return FanoutExchange.class; + } - public FanoutExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - FanoutExchange exch = new FanoutExchange(); - exch.initialise(host,name,durable,autoDelete); - return exch; - } - }; + public FanoutExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + FanoutExchange exch = new FanoutExchange(); + exch.initialise(host, name, durable, autoDelete); + return exch; + } + }; /** @@ -108,7 +103,7 @@ public class FanoutExchange extends AbstractExchange { String queueName = queue.getName().toString(); - Object[] bindingItemValues = { queueName, new String[] { queueName } }; + Object[] bindingItemValues = {queueName, new String[]{queueName}}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); _bindingList.put(bindingData); } @@ -149,6 +144,11 @@ public class FanoutExchange extends AbstractExchange } } + public Map> getBindings() + { + return null; + } + public AMQShortString getType() { return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; @@ -210,24 +210,29 @@ public class FanoutExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable fieldtable, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { return _queues.contains(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { return (_queues != null) && !_queues.isEmpty(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { return _queues.contains(queue); } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_queues.isEmpty(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index bed08daeaf..426cd090c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -20,23 +20,6 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; @@ -51,6 +34,23 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import javax.management.JMException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + /** * An exchange that binds queues based on a set of required headers and header values * and routes messages to these queues by matching the headers of the message against @@ -83,30 +83,29 @@ public class HeadersExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - public static final ExchangeType TYPE = new ExchangeType() - { + { - public AMQShortString getName() - { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; - } + public AMQShortString getName() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } - public Class getExchangeClass() - { - return HeadersExchange.class; - } + public Class getExchangeClass() + { + return HeadersExchange.class; + } - public HeadersExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - HeadersExchange exch = new HeadersExchange(); - exch.initialise(host,name,durable,autoDelete); - return exch; - } - }; + public HeadersExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + boolean autoDelete) throws AMQException + { + HeadersExchange exch = new HeadersExchange(); + exch.initialise(host, name, durable, autoDelete); + return exch; + } + }; private final List _bindings = new CopyOnWriteArrayList(); @@ -119,13 +118,13 @@ public class HeadersExchange extends AbstractExchange private final class HeadersExchangeMBean extends ExchangeMBean { @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException + public HeadersExchangeMBean() throws JMException { super(); _exchangeType = "headers"; init(); } - + /** * initialises the OpenType objects. */ @@ -141,7 +140,7 @@ public class HeadersExchange extends AbstractExchange _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", _bindingItemNames, _bindingItemNames, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, _bindingItemIndexNames); } public TabularData bindings() throws OpenDataException @@ -197,7 +196,7 @@ public class HeadersExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } - String[] bindings = binding.split(","); + String[] bindings = binding.split(","); FieldTable bindingMap = new FieldTable(); for (int i = 0; i < bindings.length; i++) { @@ -269,17 +268,23 @@ public class HeadersExchange extends AbstractExchange } } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) throws AMQException + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + //fixme isBound here should take the arguements in to consideration. + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) { return isBound(queue); } - public boolean isBound(AMQShortString routingKey) throws AMQException + public boolean isBound(AMQShortString routingKey) { return hasBindings(); } - public boolean isBound(AMQQueue queue) throws AMQException + public boolean isBound(AMQQueue queue) { for (Registration r : _bindings) { @@ -291,7 +296,7 @@ public class HeadersExchange extends AbstractExchange return false; } - public boolean hasBindings() throws AMQException + public boolean hasBindings() { return !_bindings.isEmpty(); } @@ -316,6 +321,11 @@ public class HeadersExchange extends AbstractExchange } } + public Map> getBindings() + { + return null; + } + private static class Registration { private final HeadersBinding binding; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 9346eecbb2..ab4f2c4e64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -100,6 +100,12 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { @@ -71,7 +70,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener { @@ -77,7 +77,7 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); } - + if (body.routingKey == null) { body.routingKey = queue.getName(); @@ -97,9 +97,18 @@ public class QueueBindHandler implements StateAwareMethodListener { throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); } + + if (body.routingKey != null) + { + body.routingKey = body.routingKey.intern(); + } + try - { - queue.bind(body.routingKey, body.arguments, exch); + { + if (!exch.isBound(body.routingKey, body.arguments, queue)) + { + queue.bind(body.routingKey, body.arguments, exch); + } } catch (AMQInvalidRoutingKeyException rke) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index f9e94af697..9be0dabb68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -42,11 +42,9 @@ 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.messageStore.MessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; import org.apache.commons.configuration.Configuration; public class QueueDeclareHandler implements StateAwareMethodListener @@ -95,6 +93,11 @@ public class QueueDeclareHandler implements StateAwareMethodListener result = new HashMap(); try { - TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); + //TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); // re-create all the tx connection = (MyConnection) _connectionPool.acquireInstance(); @@ -840,11 +911,11 @@ public class JDBCStore implements MessageStore } foundTx = new JDBCTransaction(); foundXid = new XidImpl(rs.getBlob(3).getBytes(1, (int) rs.getBlob(3).length()), - rs.getInt(2), rs.getBlob(4).getBytes(1, (int) rs.getBlob(4).length())); + rs.getInt(2), rs.getBlob(4).getBytes(1, (int) rs.getBlob(4).length())); // get all the records Statement stmtr = connection.getConnection().createStatement(); ResultSet rsr = stmtr.executeQuery("SELECT * FROM " + _tableNameRecord + - " WHERE XID_ID = " + rs.getLong(1)); + " WHERE XID_ID = " + rs.getLong(1)); int foundType; AMQQueue foundQueue; StorableMessage foundMessage; @@ -854,11 +925,14 @@ public class JDBCStore implements MessageStore // those messages were not recovered before so they need to be recreated foundType = rsr.getInt(2); foundQueue = _queueMap.get(new Integer(rsr.getInt(4))); - foundMessage = new AMQMessage(rs.getLong(3), this, messageHandleFactory, txnContext); + + //DTX MessageStore - this -> null , txContext -> null + foundMessage = new AMQMessage(rs.getLong(3), null, messageHandleFactory, null); if (foundType == JDBCAbstractRecord.TYPE_DEQUEUE) { foundRecord = new JDBCDequeueRecord(foundMessage, foundQueue); - } else + } + else { foundRecord = new JDBCEnqueueRecord(foundMessage, foundQueue); } @@ -870,10 +944,12 @@ public class JDBCStore implements MessageStore } rs.close(); return result; - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot recover: ", e); - } finally + } + finally { if (connection != null) { @@ -881,7 +957,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -917,7 +994,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -934,7 +1012,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().rollback(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to rollback this connection // it is better to release it @@ -952,7 +1031,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("SELECT Payload FROM " + _tableNameMessage + - " WHERE MessageID = ? "); + " WHERE MessageID = ? "); connection.getStatements()[SELECT_MESSAGE_PAYLOAD] = pstmt; } pstmt.setLong(1, m.getMessageId()); @@ -960,14 +1039,15 @@ public class JDBCStore implements MessageStore if (!rs.next()) { throw new MessageDoesntExistException("Cannot append content of message Id " - + m.getMessageId() + " as it has not been found"); + + m.getMessageId() + " as it has not been found"); } Blob myBlob = rs.getBlob(1); byte[] oldPayload; if (myBlob != null && myBlob.length() > 0) { oldPayload = myBlob.getBytes(1, (int) myBlob.length()); - } else + } + else { oldPayload = new byte[0]; } @@ -980,7 +1060,7 @@ public class JDBCStore implements MessageStore if (pstmtUpdate == null) { pstmtUpdate = connection.getConnection().prepareStatement("UPDATE " + _tableNameMessage + - " SET Payload = ? WHERE MessageID = ?"); + " SET Payload = ? WHERE MessageID = ?"); connection.getStatements()[UPDATE_MESSAGE_PAYLOAD] = pstmtUpdate; } pstmtUpdate.setBytes(1, newPayload); @@ -996,7 +1076,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameMessage + - " (MessageID,Header,ExchangeName,RoutingKey,Mandatory,Is_Immediate) VALUES (?,?,?,?,?,?)"); + " (MessageID,Header,ExchangeName,RoutingKey,Mandatory,Is_Immediate) VALUES (?,?,?,?,?,?)"); connection.getStatements()[STAGE_MESSAGE] = pstmt; } pstmt.setLong(1, m.getMessageId()); @@ -1019,7 +1099,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameRecord + - " (XID_ID,Type,MessageID,QueueID) VALUES (?,?,?,?)"); + " (XID_ID,Type,MessageID,QueueID) VALUES (?,?,?,?)"); connection.getStatements()[SAVE_RECORD] = pstmt; } pstmt.setLong(1, tx.getXidID()); @@ -1027,7 +1107,8 @@ public class JDBCStore implements MessageStore pstmt.setLong(3, record.getMessageID()); pstmt.setLong(4, record.getQueueID()); pstmt.executeUpdate(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot save record: " + record, e); } @@ -1043,7 +1124,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameTransaction + - " (XID_ID,FormatId, BranchQualifier,GlobalTransactionId) VALUES (?,?,?,?)"); + " (XID_ID,FormatId, BranchQualifier,GlobalTransactionId) VALUES (?,?,?,?)"); connection.getStatements()[SAVE_XID] = pstmt; } pstmt.setLong(1, tx.getXidID()); @@ -1051,7 +1132,8 @@ public class JDBCStore implements MessageStore pstmt.setBytes(3, xid.getBranchQualifier()); pstmt.setBytes(4, xid.getGlobalTransactionId()); pstmt.executeUpdate(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot save xid: " + xid, e); } @@ -1067,12 +1149,13 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameRecord + - " WHERE XID_ID = ?"); + " WHERE XID_ID = ?"); connection.getStatements()[DELETE_RECORD] = pstmt; } pstmt.setLong(1, tx.getXidID()); pstmt.executeUpdate(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot delete record: " + tx.getXidID(), e); } @@ -1088,12 +1171,13 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameTransaction + - " WHERE XID_ID = ?"); + " WHERE XID_ID = ?"); connection.getStatements()[DELETE_XID] = pstmt; } pstmt.setLong(1, tx.getXidID()); pstmt.executeUpdate(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot delete xid: " + tx.getXidID(), e); } @@ -1142,14 +1226,15 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("UPDATE " + _tableNameQueueMessageRelation + - " SET Prepared = ? WHERE MessageID = ? AND QueueID = ?"); + " SET Prepared = ? WHERE MessageID = ? AND QueueID = ?"); connection.getStatements()[UPDATE_QMR] = pstmt; } pstmt.setInt(1, prepared); pstmt.setLong(2, messageId); pstmt.setInt(3, queueID); pstmt.executeUpdate(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot update QMR", e); } @@ -1169,8 +1254,8 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("SELECT ExchangeName, RoutingKey," + - " Mandatory, Is_Immediate from " + _tableNameMessage + - " WHERE MessageID = ?"); + " Mandatory, Is_Immediate from " + _tableNameMessage + + " WHERE MessageID = ?"); connection.getStatements()[GET_MESSAGE_INFO] = pstmt; } pstmt.setLong(1, m.getMessageId()); @@ -1204,16 +1289,19 @@ public class JDBCStore implements MessageStore return routingKey; } }; - } else + } + else { throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); } rs.close(); return result; - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m, e); - } finally + } + finally { if (connection != null) { @@ -1221,7 +1309,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -1245,7 +1334,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("SELECT Header from " + _tableNameMessage + - " WHERE MessageID = ?"); + " WHERE MessageID = ?"); connection.getStatements()[GET_CONTENT_HEADER] = pstmt; } pstmt.setLong(1, m.getMessageId()); @@ -1253,16 +1342,19 @@ public class JDBCStore implements MessageStore if (rs.next()) { result = new ContentHeaderBody(ByteBuffer.wrap(rs.getBlob(1).getBytes(1, (int) rs.getBlob(1).length())), 0); - } else + } + else { throw new InternalErrorException("Cannot get Content Header of message: " + m); } rs.close(); return result; - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot get Content Header of message: " + m, e); - } finally + } + finally { if (connection != null) { @@ -1270,7 +1362,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -1287,21 +1380,21 @@ public class JDBCStore implements MessageStore AMQException { List result = new ArrayList(); - TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); +// TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); PreparedStatement pstmt = connection.getStatements()[GET_ALL_MESSAGES]; if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("SELECT " + _tableNameMessage + ".MessageID, Header FROM " + - _tableNameMessage + - " INNER JOIN " + - _tableNameQueueMessageRelation + - " ON " + - _tableNameMessage + ".MessageID = " + _tableNameQueueMessageRelation + ".MessageID" + - " WHERE " + - _tableNameQueueMessageRelation + ".QueueID = ?" + - " AND " + - _tableNameQueueMessageRelation + ".Prepared = 0"); + _tableNameMessage + + " INNER JOIN " + + _tableNameQueueMessageRelation + + " ON " + + _tableNameMessage + ".MessageID = " + _tableNameQueueMessageRelation + ".MessageID" + + " WHERE " + + _tableNameQueueMessageRelation + ".QueueID = ?" + + " AND " + + _tableNameQueueMessageRelation + ".Prepared = 0"); connection.getStatements()[GET_ALL_MESSAGES] = pstmt; } pstmt.setInt(1, queue.getQueueID()); @@ -1310,7 +1403,10 @@ public class JDBCStore implements MessageStore // ContentHeaderBody hb; while (rs.next()) { - foundMessage = new AMQMessage(rs.getLong(1), this, messageHandleFactory, txnContext); + + //DTX MessageStore - this -> null , txContext -> null + foundMessage = new AMQMessage(rs.getLong(1), null, messageHandleFactory, null); + result.add(foundMessage); } rs.close(); @@ -1340,7 +1436,7 @@ public class JDBCStore implements MessageStore owner = new AMQShortString(rs.getString(3)); } foundQueue = new AMQQueue(new AMQShortString(rs.getString(2)), - true, owner, false, _virtualHost); + true, owner, false, _virtualHost); // get all the Messages of that queue foundMessages = getAllMessages(connection, foundQueue); // enqueue those messages @@ -1350,7 +1446,7 @@ public class JDBCStore implements MessageStore } for (StorableMessage foundMessage : foundMessages) { - foundMessage.staged(); + foundMessage.staged(); foundMessage.enqueue(foundQueue); foundQueue.enqueue(foundMessage); foundQueue.process(context, (AMQMessage) foundMessage, false); @@ -1362,10 +1458,12 @@ public class JDBCStore implements MessageStore } rs.close(); return result; - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot recover: ", e); - } finally + } + finally { if (connection != null) { @@ -1373,7 +1471,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -1404,7 +1503,7 @@ public class JDBCStore implements MessageStore // get all the bindings Statement stmtb = connection.getConnection().createStatement(); ResultSet rsb = stmtb.executeQuery("SELECT * FROM " + _tableNameExchangeQueueRelation + - " WHERE Name = '" + rs.getString(1) + "'"); + " WHERE Name = '" + rs.getString(1) + "'"); while (rsb.next()) { foundQueue = queueMap.get(new Integer(rsb.getInt(1))); @@ -1426,10 +1525,12 @@ public class JDBCStore implements MessageStore _virtualHost.getExchangeRegistry().registerExchange(foundExchange); } rs.close(); - } catch (Exception e) + } + catch (Exception e) { throw new InternalErrorException("Cannot recover: ", e); - } finally + } + finally { if (connection != null) { @@ -1437,7 +1538,8 @@ public class JDBCStore implements MessageStore { connection.getConnection().commit(); _connectionPool.releaseInstance(connection); - } catch (SQLException e) + } + catch (SQLException e) { // we did not manage to commit this connection // it is better to release it @@ -1456,7 +1558,7 @@ public class JDBCStore implements MessageStore if (pstmt == null) { pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameMessage + - " WHERE MessageID = ?"); + " WHERE MessageID = ?"); connection.getStatements()[DELETE_MESSAGE] = pstmt; } pstmt.setLong(1, m.getMessageId()); @@ -1589,8 +1691,8 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameMessage + " (MessageID FLOAT NOT NULL, Header BLOB," + - " Payload BLOB, ExchangeName VARCHAR(1024), RoutingKey VARCHAR(1024)," + - " Mandatory INTEGER, Is_Immediate INTEGER, PRIMARY KEY(MessageID))"); + " Payload BLOB, ExchangeName VARCHAR(1024), RoutingKey VARCHAR(1024)," + + " Mandatory INTEGER, Is_Immediate INTEGER, PRIMARY KEY(MessageID))"); myconnection._connection.commit(); } catch (SQLException ex) @@ -1602,7 +1704,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameQueue + " (QueueID INTEGER NOT NULL, " + - "Name VARCHAR(1024) NOT NULL, Owner VARCHAR(1024), PRIMARY KEY(QueueID))"); + "Name VARCHAR(1024) NOT NULL, Owner VARCHAR(1024), PRIMARY KEY(QueueID))"); myconnection._connection.commit(); } catch (SQLException ex) @@ -1614,7 +1716,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameQueueMessageRelation + " (QueueID INTEGER NOT NULL, " + - "MessageID FLOAT NOT NULL, Prepared INTEGER)"); + "MessageID FLOAT NOT NULL, Prepared INTEGER)"); myconnection._connection.commit(); } catch (SQLException ex) @@ -1625,7 +1727,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameExchange + " (Name VARCHAR(1024) NOT NULL, " + - "Type VARCHAR(1024) NOT NULL, PRIMARY KEY(Name))"); + "Type VARCHAR(1024) NOT NULL, PRIMARY KEY(Name))"); myconnection._connection.commit(); } catch (SQLException ex) @@ -1636,7 +1738,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameExchangeQueueRelation + " (QueueID INTEGER NOT NULL, " + - "Name VARCHAR(1024) NOT NULL, RoutingKey VARCHAR(1024), FieldTable BLOB )"); + "Name VARCHAR(1024) NOT NULL, RoutingKey VARCHAR(1024), FieldTable BLOB )"); myconnection._connection.commit(); } catch (SQLException ex) @@ -1647,7 +1749,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameRecord + " (XID_ID FLOAT, Type INTEGER, MessageID FLOAT, " + - "QueueID INTEGER, PRIMARY KEY(Type, MessageID, QueueID))"); + "QueueID INTEGER, PRIMARY KEY(Type, MessageID, QueueID))"); // we could alter the table with QueueID as foreign key myconnection._connection.commit(); } @@ -1659,7 +1761,7 @@ public class JDBCStore implements MessageStore try { stmt.executeUpdate("CREATE TABLE " + _tableNameTransaction + " (XID_ID FLOAT, FormatId INTEGER, " + - "BranchQualifier BLOB, GlobalTransactionId BLOB, PRIMARY KEY(XID_ID))"); + "BranchQualifier BLOB, GlobalTransactionId BLOB, PRIMARY KEY(XID_ID))"); myconnection._connection.commit(); } catch (SQLException ex) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java index 913f3ed9c6..f5dc160fc6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java @@ -18,15 +18,23 @@ */ package org.apache.qpid.server.messageStore; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.exchange.Exchange; +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.exception.InternalErrorException; +import org.apache.qpid.server.exception.InvalidXidException; +import org.apache.qpid.server.exception.MessageAlreadyStagedException; +import org.apache.qpid.server.exception.MessageDoesntExistException; +import org.apache.qpid.server.exception.QueueAlreadyExistsException; +import org.apache.qpid.server.exception.QueueDoesntExistException; +import org.apache.qpid.server.exception.UnknownXidException; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.virtualhost.VirtualHost; import javax.transaction.xa.Xid; import java.util.Collection; @@ -203,7 +211,7 @@ public interface MessageStore * @throws InternalErrorException In case of internal message store problem * @throws MessageDoesntExistException If the message does not exist */ - public MessagePublishInfo getMessagePublishInfo(StorableMessage m) + public MessagePublishInfo getMessagePublishInfo(StorableMessage m) throws InternalErrorException, MessageDoesntExistException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 84ec91d569..0c80414a3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -44,6 +44,9 @@ import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.ssl.SSLContextFactory; +import java.io.IOException; +import java.net.InetSocketAddress; + /** * The protocol handler handles "protocol events" for all connections. The state * associated with an individual connection is accessed through the protocol session. @@ -80,12 +83,12 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter final AMQCodecFactory codecFactory = new AMQCodecFactory(true); createSession(protocolSession, _applicationRegistry, codecFactory); - _logger.info("Protocol session created"); + _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); - ConnectorConfiguration connectorConfig = - ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); + ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). + getConfiguredObject(ConnectorConfiguration.class); if (connectorConfig.enableExecutorPool) { if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) @@ -95,7 +98,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter String certType = connectorConfig.certType; SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); + new SSLFilter(sslContextFactory.buildServerContext())); } protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); @@ -119,22 +122,21 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter /** * Separated into its own, protected, method to allow easier reuse */ - protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) - throws AMQException + protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException { new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); } public void sessionOpened(IoSession protocolSession) throws Exception { - _logger.info("Session opened"); + _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); } public void sessionClosed(IoSession protocolSession) throws Exception { - _logger.info("Protocol Session closed"); + _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - // fixme -- this can be null + //fixme -- this can be null if (amqProtocolSession != null) { amqProtocolSession.closeSession(); @@ -143,15 +145,15 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter public void sessionIdle(IoSession session, IdleStatus status) throws Exception { - _logger.debug("Protocol Session [" + this + "] idle: " + status); + _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); if (IdleStatus.WRITER_IDLE.equals(status)) { - // write heartbeat frame: + //write heartbeat frame: session.write(HeartbeatBody.FRAME); } else if (IdleStatus.READER_IDLE.equals(status)) { - // failover: + //failover: throw new IOException("Timed out while waiting for heartbeat from peer."); } @@ -167,7 +169,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter protocolSession.close(); - _logger.error("Error in protocol initiation " + session + ": " + throwable.getMessage(), throwable); + _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); } else if (throwable instanceof IOException) { @@ -178,13 +180,14 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); // Be aware of possible changes to parameter order as versions change. - protocolSession.write(ConnectionCloseBody.createAMQFrame(0, session.getProtocolMajorVersion(), - session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - 200, // replyCode - new AMQShortString(throwable.getMessage()) // replyText - )); + protocolSession.write(ConnectionCloseBody.createAMQFrame(0, + session.getProtocolMajorVersion(), + session.getProtocolMinorVersion(), // AMQP version (major, minor) + 0, // classId + 0, // methodId + 200, // replyCode + new AMQShortString(throwable.getMessage()) // replyText + )); protocolSession.close(); } } @@ -203,6 +206,7 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter if (message instanceof AMQDataBlock) { amqProtocolSession.dataBlockReceived((AMQDataBlock) message); + } else if (message instanceof ByteBuffer) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 95f75fdb36..d5100dc8e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,17 +20,8 @@ */ package org.apache.qpid.server.queue; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - - -/** Combines the information that make up a deliverable message into a more manageable form. */ - import org.apache.log4j.Logger; - import org.apache.mina.common.ByteBuffer; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; @@ -40,22 +31,33 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.messageStore.StorableMessage; import org.apache.qpid.server.messageStore.StorableQueue; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + /** * Combines the information that make up a deliverable message into a more manageable form. */ public class AMQMessage implements StorableMessage { + /** Used for debugging purposes. */ private static final Logger _log = Logger.getLogger(AMQMessage.class); - // The ordered list of queues into which this message is enqueued. + // The ordered list of queues into which this message is enqueued. private List _queues = new LinkedList(); // Indicates whether this message is staged private boolean _isStaged = false; @@ -66,7 +68,7 @@ public class AMQMessage implements StorableMessage private Set _tokens; /** - * Only use in clustering - should ideally be removed? + * Only use in clustering - //todo: should ideally be removed? */ private AMQProtocolSession _publisher; @@ -76,12 +78,13 @@ public class AMQMessage implements StorableMessage private AMQMessageHandle _messageHandle; + /** Holds the transactional context in which this message is being processed. */ // TODO: ideally this should be able to go into the transient message date - check this! (RG) private 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. + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. */ private boolean _deliveredToConsumer; /** @@ -89,18 +92,25 @@ public class AMQMessage implements StorableMessage * checkDelieveredToConsumer is called, the message may already have been received and acknowledged, and the body * removed from the store. */ + + /** Flag to indicate that this message requires 'immediate' delivery. */ private boolean _immediate; // private Subscription _takenBySubcription; // private AtomicBoolean _taken = new AtomicBoolean(false); private TransientMessageData _transientMessageData = new TransientMessageData(); + //todo: this should be part of a messageOnQueue object private Set _rejectedBy = null; + //todo: this should be part of a messageOnQueue object private Map _takenMap = new HashMap(); + //todo: this should be part of a messageOnQueue object private Map _takenBySubcriptionMap = new HashMap(); private final int hashcode = System.identityHashCode(this); + + //todo: this should be part of a messageOnQueue object private long _expiration; public String debugIdentity() @@ -111,9 +121,9 @@ public class AMQMessage implements StorableMessage public void setExpiration() { long expiration = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); long timestamp = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false)) { @@ -176,8 +186,8 @@ public class AMQMessage implements StorableMessage { AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - _messageId, ++_index)); + getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), + _messageId, ++_index)); return new AMQFrame(_channel, cb); } @@ -259,10 +269,11 @@ public class AMQMessage implements StorableMessage * @param messageId * @param store * @param factory + * * @throws AMQException */ public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws AMQException + throws AMQException { _messageId = messageId; _messageHandle = factory.createMessageHandle(store, this, true); @@ -279,7 +290,7 @@ public class AMQMessage implements StorableMessage * @param contentHeader */ public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader) throws AMQException + ContentHeaderBody contentHeader) throws AMQException { this(messageId, info, txnContext); setContentHeaderBody(contentHeader); @@ -294,11 +305,12 @@ public class AMQMessage implements StorableMessage * @param contentHeader * @param destinationQueues * @param contentBodies + * * @throws AMQException */ public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, - MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException + ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, + MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException { this(messageId, info, txnContext, contentHeader); _transientMessageData.setDestinationQueues(destinationQueues); @@ -443,22 +455,23 @@ public class AMQMessage implements StorableMessage } public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) - throws AMQException + throws AMQException { final boolean persistent = isPersistent(); _messageHandle = factory.createMessageHandle(store, this, persistent); - // if (persistent) - // { - _txnContext.beginTranIfNecessary(); - // } + if (persistent) //DTX was removed + { + _txnContext.beginTranIfNecessary(); + } // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store - // for (AMQQueue q : _transientMessageData.getDestinationQueues()) - // { - // _messageHandle.enqueue(storeContext, _messageId, q); - // } + //DTX was removed + for (AMQQueue q : _transientMessageData.getDestinationQueues()) + { + _messageHandle.enqueue(storeContext, _messageId, q); + } if (_transientMessageData.getContentHeaderBody().bodySize == 0) { @@ -494,11 +507,12 @@ public class AMQMessage implements StorableMessage */ public AMQMessage takeReference() { - _referenceCount.incrementAndGet(); + incrementReference(); // _referenceCount.incrementAndGet(); return this; } + /** * Threadsafe. Increment the reference count on the message. */ @@ -516,6 +530,7 @@ public class AMQMessage implements StorableMessage * message store. * * @param storeContext + * * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that * failed */ @@ -555,7 +570,7 @@ public class AMQMessage implements StorableMessage if (count < 0) { throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0.", - null); + null); } } } @@ -684,6 +699,7 @@ public class AMQMessage implements StorableMessage * 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 @@ -756,14 +772,13 @@ public class AMQMessage implements StorableMessage /** * Checks to see if the message has expired. If it has the message is dequeued. * - * @param storecontext - * @param queue + * @param queue The queue to check the expiration against. (Currently not used) * * @return true if the message has expire * * @throws AMQException */ - public boolean expired(StoreContext storecontext, AMQQueue queue) throws AMQException + public boolean expired(AMQQueue queue) throws AMQException { // note: If the storecontext isn't need then we can remove the getChannel() from Subscription. @@ -771,12 +786,7 @@ public class AMQMessage implements StorableMessage { long now = System.currentTimeMillis(); - if (now > _expiration) - { - dequeue(storecontext, queue); - - return true; - } + return (now > _expiration); } return false; @@ -803,7 +813,7 @@ public class AMQMessage implements StorableMessage // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, - _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); + _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); // we then allow the transactional context to do something with the message content // now that it has all been received, before we attempt delivery @@ -1039,7 +1049,7 @@ public class AMQMessage implements StorableMessage // _taken + " by :" + _takenBySubcription; return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " - + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); + + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } public Subscription getDeliveredSubscription(AMQQueue queue) @@ -1053,6 +1063,7 @@ public class AMQMessage implements StorableMessage public void reject(Subscription subscription) { + if (subscription != null) { if (_rejectedBy == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 6273ac997b..b4a92b3483 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,38 +20,26 @@ */ package org.apache.qpid.server.queue; -import java.text.MessageFormat; -import java.util.Collection; -import java.util.Hashtable; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.management.JMException; - import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exception.InternalErrorException; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.messageStore.StorableMessage; import org.apache.qpid.server.messageStore.StorableQueue; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; - import java.text.MessageFormat; +import java.util.Collection; +import java.util.Hashtable; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -65,6 +53,49 @@ import java.util.concurrent.atomic.AtomicLong; */ public class AMQQueue implements Managable, Comparable, StorableQueue { + //FROM M2 - think these have been replaced by *Exception in the broker exception package +// /** +// * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription +// * already exists. +// * +// *

      +// *
      CRC Card
      Responsibilities Collaborations +// *
      Represent failure to create a subscription, because an exclusive subscription already exists. +// *
      +// * +// * @todo Not an AMQP exception as no status code. +// * +// * @todo Move to top level, used outside this class. +// */ +// public static final class ExistingExclusiveSubscription extends AMQException +// { +// +// public ExistingExclusiveSubscription() +// { +// super(""); +// } +// } +// +// /** +// * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription +// * already exists. +// * +// *

      +// *
      CRC Card
      Responsibilities Collaborations +// *
      Represent failure to create an exclusize subscription, as a subscription already exists. +// *
      +// * +// * @todo Not an AMQP exception as no status code. +// * +// * @todo Move to top level, used outside this class. +// */ +// public static final class ExistingSubscriptionPreventsExclusive extends AMQException +// { +// public ExistingSubscriptionPreventsExclusive() +// { +// super(""); + // } + // } public static int s_queueID = 0; private static final Logger _logger = Logger.getLogger(AMQQueue.class); @@ -163,22 +194,22 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException + throws AMQException { this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), - new SubscriptionSet(), new SubscriptionImpl.Factory()); + new SubscriptionSet(), new SubscriptionImpl.Factory()); } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException + VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException { this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, - new SubscriptionImpl.Factory()); + new SubscriptionImpl.Factory()); } protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, - SubscriptionFactory subscriptionFactory) throws AMQException + VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, + SubscriptionFactory subscriptionFactory) throws AMQException { if (name == null) { @@ -298,32 +329,217 @@ public class AMQQueue implements Managable, Comparable, StorableQueue * (enqueue in other queue) - Once sending to other Queue is successful, remove messages from this queue - remove * locks from both queues and start async delivery * - * @param fromMessageId - * @param toMessageId - * @param queueName - * @param storeContext + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param queueName The queue to move the messages to. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. */ public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) + StoreContext storeContext) { - // prepare the delivery manager for moving messages by stopping the async delivery and creating a lock - AMQQueue anotherQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + + MessageStore fromStore = getVirtualHost().getMessageStore(); + MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + + if (toStore != fromStore) + { + throw new RuntimeException("Can only move messages between queues on the same message store."); + } + try { + // Obtain locks to prevent activity on the queues being moved between. startMovingMessages(); + toQueue.startMovingMessages(); + + // Get the list of messages to move. List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - // move messages to another queue - anotherQueue.startMovingMessages(); - anotherQueue.enqueueMovedMessages(storeContext, foundMessagesList); + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity + * on the queues being moved between is suspended during the move. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param queueName The queue to move the messages to. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - // moving is successful, now remove from original queue - _deliveryMgr.removeMovedMessages(foundMessagesList); + MessageStore fromStore = getVirtualHost().getMessageStore(); + MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + + if (toStore != fromStore) + { + throw new RuntimeException("Can only move messages between queues on the same message store."); } + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + toQueue.startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + message.takeReference(); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Removes messages from this queue, and also commits the remove on the message store. Delivery activity + * on the queues being moved between is suspended during the remove. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + { + MessageStore fromStore = getVirtualHost().getMessageStore(); + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // remove the messages in on the message store. + for (AMQMessage message : foundMessagesList) + { + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // remove the messages on the in-memory queues. + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. finally { - // remove the lock and start the async delivery - anotherQueue.stopMovingMessages(); stopMovingMessages(); } } @@ -426,14 +642,16 @@ public class AMQQueue implements Managable, Comparable, StorableQueue exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - try - { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); - } - catch (InternalErrorException e) - { - throw new AMQException(null, "Problem binding queue ", e); - } + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + //DTX MessageStore +// try +// { +// _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); +// } +// catch (InternalErrorException e) +// { +// throw new AMQException(null, "Problem binding queue ", e); +// } } _bindings.addBinding(routingKey, arguments, exchange); @@ -444,21 +662,24 @@ public class AMQQueue implements Managable, Comparable, StorableQueue exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - try - { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); - } - catch (InternalErrorException e) - { - throw new AMQException(null, "problem unbinding queue", e); - } + + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + //DTX MessageStore +// try +// { +// _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); +// } +// catch (InternalErrorException e) +// { +// throw new AMQException(null, "problem unbinding queue", e); +// } } _bindings.remove(routingKey, arguments, exchange); } public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (incrementSubscriberCount() > 1) { @@ -487,7 +708,7 @@ public class AMQQueue implements Managable, Comparable, StorableQueue } Subscription subscription = - _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); + _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); if (subscription.filtersMessages()) { @@ -532,11 +753,11 @@ public class AMQQueue implements Managable, Comparable, StorableQueue Subscription removedSubscription; if ((removedSubscription = - _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, ps, consumerTag))) - == null) + _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, ps, consumerTag))) + == null) { throw new AMQException(null, "Protocol session with channel " + channel + " and consumer tag " + consumerTag - + " and protocol session key " + ps.getKey() + " not registered with queue " + this, null); + + " and protocol session key " + ps.getKey() + " not registered with queue " + this, null); } removedSubscription.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index bbaa7379f6..4331d8d870 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -18,30 +18,23 @@ * under the License. * */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ package org.apache.qpid.server.queue; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.store.StoreContext; import javax.management.JMException; import javax.management.MBeanException; @@ -60,30 +53,25 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import org.apache.log4j.Logger; - -import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; /** * MBean class for AMQQueue. It implements all the management features exposed * for an AMQQueue. + *

      CRC Caption + * Responsibilities Collaborations + * */ @MBeanDescription("Management Interface for AMQQueue") public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener { + /** Used for debugging purposes. */ private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 2aa759b35d..0639243e02 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -87,6 +87,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private final Object _queueHeadLock = new Object(); private String _processingThreadName = ""; + + /** Used by any reaping thread to purge messages */ + private StoreContext _reapingStoreContext = new StoreContext(); + ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -453,12 +457,31 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) while (purgeMessage(message, sub)) { + // if we are purging then ensure we mark this message taken for the current subscriber + // the current subscriber may be null in the case of a get or a purge but this is ok. +// boolean alreadyTaken = message.taken(_queue, sub); + //remove the already taken message or expired AMQMessage removed = messages.poll(); assert removed == message; - _totalMessageSize.addAndGet(-message.getSize()); + // if the message expired then the _totalMessageSize needs adjusting + if (message.expired(_queue)) + { + _totalMessageSize.addAndGet(-message.getSize()); + + // Use the reapingStoreContext as any sub(if we have one) may be in a tx. + message.dequeue(_reapingStoreContext, _queue); + + if (_log.isInfoEnabled()) + { + _log.info(debugIdentity() + " Doing clean up of the main _message queue."); + } + } + + //else the clean up is not required as the message has already been taken for this queue therefore + // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. if (_log.isTraceEnabled()) { @@ -473,7 +496,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } /** - * + * This method will return true if the message is to be purged from the queue. + * + * + * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) * @param message * @param sub * @return @@ -493,15 +519,15 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager // if the message is null then don't purge as we have no messagse. if (message != null) { + // Check that the message hasn't expired. + if (message.expired(_queue)) + { + return true; + } + // if we have a subscriber perform message checks if (sub != null) { - // Check that the message hasn't expired. - if (message.expired(sub.getChannel().getStoreContext(), _queue)) - { - return true; - } - // if we have a queue browser(we don't purge) so check mark the message as taken purge = ((!sub.isBrowser() || message.isTaken(_queue))); } @@ -606,7 +632,10 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { if (_log.isInfoEnabled()) { - _log.info(debugIdentity() + "We could do clean up of the main _message queue here"); + //fixme - we should do the clean up as the message remains on the _message queue + // this is resulting in the next consumer receiving the message and then attempting to purge it + // + _log.info(debugIdentity() + "We should do clean up of the main _message queue here"); } } @@ -617,7 +646,14 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } catch (AMQException e) { - message.release(_queue); + if (message != null) + { + message.release(_queue); + } + else + { + _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); + } _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -696,25 +732,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } -// private void sendNextMessage(Subscription sub) -// { -// if (sub.filtersMessages()) -// { -// sendNextMessage(sub, sub.getPreDeliveryQueue()); -// if (sub.isAutoClose()) -// { -// if (sub.getPreDeliveryQueue().isEmpty()) -// { -// sub.close(); -// } -// } -// } -// else -// { -// sendNextMessage(sub, _messages); -// } -// } - public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException { @@ -723,8 +740,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); } - // This shouldn't be done here. -// msg.release(); //Check if we have someone to deliver the message to. _lock.lock(); @@ -800,7 +815,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + - "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); + "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); } } } @@ -810,7 +825,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (debugEnabled) { _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); + " Subscriber:" + System.identityHashCode(s)); } deliver(context, name, msg, deliverFirst); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index c0f1e7f40c..cbe9246f09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,13 +20,14 @@ */ package org.apache.qpid.server.queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + public class DefaultQueueRegistry implements QueueRegistry { private ConcurrentMap _queueMap = new ConcurrentHashMap(); @@ -57,4 +58,14 @@ public class DefaultQueueRegistry implements QueueRegistry { return _queueMap.get(name); } + + public Collection getQueueNames() + { + return _queueMap.keySet(); + } + + public Collection getQueues() + { + return _queueMap.values(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index a8247aa2db..a950678487 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -80,7 +80,10 @@ class ExchangeBindings public boolean equals(Object o) { - if (!(o instanceof ExchangeBinding)) return false; + if (!(o instanceof ExchangeBinding)) + { + return false; + } ExchangeBinding eb = (ExchangeBinding) o; return _exchange.equals(eb._exchange) && _routingKey.equals(eb._routingKey) @@ -104,16 +107,16 @@ class ExchangeBindings */ void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments )); + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); } public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments )); + _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); } - + /** * Deregisters this queue from any exchange it has been bound to */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 1d9f56669e..c81360e7d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -56,9 +56,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle { } - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) - throws - AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException { return _contentHeaderBody; } @@ -68,36 +66,28 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _contentBodies.size(); } - public long getBodySize(StoreContext context, Long messageId) - throws - AMQException + public long getBodySize(StoreContext context, Long messageId) throws AMQException { return getContentHeaderBody(context, messageId).bodySize; } - public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) - throws - AMQException, - IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, 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)); + (_contentBodies.size() - 1)); } return _contentBodies.get(index); } public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) - throws - AMQException + throws AMQException { _contentBodies.add(contentBody); } - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) - throws - AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException { return _messagePublishInfo; } @@ -113,50 +103,40 @@ public class InMemoryMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(StoreContext context, Long messageId) - throws - AMQException + public boolean isPersistent(StoreContext context, Long messageId) throws AMQException { //todo remove literal values to a constant file such as AMQConstants in common ContentHeaderBody chb = getContentHeaderBody(context, messageId); return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; } /** * This is called when all the content has been received. - * * @param messagePublishInfo * @param contentHeaderBody * @throws AMQException */ public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) - throws - AMQException + throws AMQException { _messagePublishInfo = messagePublishInfo; _contentHeaderBody = contentHeaderBody; _arrivalTime = System.currentTimeMillis(); } - public void removeMessage(StoreContext storeContext, Long messageId) - throws - AMQException + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException { // NO OP } - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) - throws - AMQException + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { // NO OP } - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) - throws - AMQException + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException { // NO OP } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java index 69aaffa907..35e43aa412 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -20,14 +20,13 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.messageStore.StorableMessage; /** * 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 { @@ -37,8 +36,9 @@ public class MessageHandleFactory // just hardcoded for now if (persistent) { - // return new WeakReferenceMessageHandle(store); - return new StorableMessageHandle(store, m); + return new WeakReferenceMessageHandle(store); + //DTX MessageStore +// return new StorableMessageHandle(store, m); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java index 285f05fb20..6118a4c11f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -1,18 +1,22 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 00ccffdea1..6b3d65661f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java index 9554d34f00..d2680ffcc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index ed2101fd75..1210f0e97c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -23,8 +23,8 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.messageStore.StorableQueue; +import java.util.Collection; public interface QueueRegistry { @@ -35,4 +35,9 @@ public interface QueueRegistry void unregisterQueue(AMQShortString name) throws AMQException; AMQQueue getQueue(AMQShortString name); + + Collection getQueueNames(); + + Collection getQueues(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java index 47126f4b68..8c20050027 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java @@ -17,24 +17,21 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.JDBCStore; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.MessageDoesntExistException; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.log4j.Logger; +import org.apache.qpid.server.store.StoreContext; import javax.transaction.xa.Xid; -import java.util.List; -import java.util.LinkedList; import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; /** * Created by Arnaud Simon @@ -94,7 +91,8 @@ public class StorableMessageHandle implements AMQMessageHandle try { _contentHeaderBody = _messageStore.getContentHeaderBody(_message); - } catch (Exception e) + } + catch (Exception e) { throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); } @@ -106,17 +104,17 @@ public class StorableMessageHandle implements AMQMessageHandle throws AMQException { - if (_chunks == null ) - { - if(_message.isStaged() ) - { - loadChunks(); - } - else - { - return 0; - } - } + if (_chunks == null) + { + if (_message.isStaged()) + { + loadChunks(); + } + else + { + return 0; + } + } return _chunks.size(); } @@ -144,8 +142,8 @@ public class StorableMessageHandle implements AMQMessageHandle AMQException { try - { - _chunks = new LinkedList(); + { + _chunks = new LinkedList(); byte[] underlying = _messageStore.loadContent(_message, 1, 0); final int size = underlying.length; final org.apache.mina.common.ByteBuffer data = @@ -169,7 +167,8 @@ public class StorableMessageHandle implements AMQMessageHandle } }; _chunks.add(cb); - } catch (Exception e) + } + catch (Exception e) { throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); } @@ -198,8 +197,10 @@ public class StorableMessageHandle implements AMQMessageHandle // read it from the store try { + _messagePublishInfo = _messageStore.getMessagePublishInfo(_message); - } catch (Exception e) + } + catch (Exception e) { throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); } @@ -222,7 +223,7 @@ public class StorableMessageHandle implements AMQMessageHandle AMQException { return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; } public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, @@ -254,7 +255,8 @@ public class StorableMessageHandle implements AMQMessageHandle { _messageStore.enqueue((Xid) storeContext.getPayload(), _message, queue); } - } catch (Exception e) + } + catch (Exception e) { throw new AMQException(null, "PRoblem during message enqueue", e); } @@ -270,7 +272,8 @@ public class StorableMessageHandle implements AMQMessageHandle { _messageStore.dequeue((Xid) storeContext.getPayload(), _message, queue); } - } catch (Exception e) + } + catch (Exception e) { throw new AMQException(null, "PRoblem during message dequeue", e); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 7c8064789e..79ee6b93a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 64fb6c15d5..88eb891a20 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -34,7 +34,6 @@ import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; /** - * @author Robert Greig (robert.j.greig@jpmorgan.com) */ public class WeakReferenceMessageHandle implements AMQMessageHandle { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 2e506b9751..06eb9329a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -107,7 +107,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab } private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) - throws FileNotFoundException, ConfigurationException + throws FileNotFoundException, ConfigurationException { String baseName = _base + "(" + index + ").attributes.attribute."; List argumentNames = config.getList(baseName + "name"); @@ -139,9 +139,9 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (method == null) { throw new ConfigurationException("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"); + + principalDatabase.getClass() + + " hence unable to configure principal database. The method must be public and " + + "have a single String argument with a void return type"); } try @@ -152,7 +152,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { if (ite instanceof ConfigurationException) { - throw (ConfigurationException) ite; + throw(ConfigurationException) ite; } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java index 6c001485b9..13f66fac5b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java @@ -26,8 +26,6 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.messageStore.MessageStore; import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.InvalidXidException; import org.apache.log4j.Logger; import javax.transaction.xa.Xid; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 8becaf52b9..47c94114a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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; @@ -31,7 +34,7 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.messageStore.MessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; /** @author Apache Software Foundation */ @@ -74,7 +77,7 @@ public class NonTransactionalContext implements TransactionalContext { if (!_inTran) { - // _messageStore.beginTran(_storeContext); + _messageStore.beginTran(_storeContext); _inTran = true; } } @@ -93,10 +96,12 @@ public class NonTransactionalContext implements TransactionalContext { try { - if( ! deliverFirst ) - { - message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); - } + //DTX removed - deliverFirst is to do with the position on the Queue not enqueuing!! + // This should be done in routingComplete +// if( ! deliverFirst ) +// { +// message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); +// } queue.process(_storeContext, message, deliverFirst); //following check implements the functionality //required by the 'immediate' flag: @@ -216,7 +221,8 @@ public class NonTransactionalContext implements TransactionalContext { if (persistent) { - // _messageStore.commitTran(_storeContext); + //DTX removed this option. + _messageStore.commitTran(_storeContext); _inTran = false; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index 88451e2fca..fee25c07df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -28,24 +28,144 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.StoreContext; /** - * @author Robert Greig (robert.j.greig@jpmorgan.com) + * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. + * Different levels of transactional support for the delivery of messages may be provided by different implementations + * of this interface. + * + *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. + * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} + * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. + * + *

      + *
      CRC Card
      Responsibilities + *
      Explicitly accept a transaction start notification. + *
      Commit all pending operations in a transaction. + *
      Rollback all pending operations in a transaction. + *
      Deliver a message to a queue as part of a transaction. + *
      Redeliver a message to a queue as part of a transaction. + *
      Mark a message as acknowledged as part of a transaction. + *
      Accept notification that a message has been completely received as part of a transaction. + *
      Accept notification that a message has been fully processed as part of a transaction. + *
      Associate a message store context with this transaction context. + *
      + * + * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional + * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them + * somewhere else, a seperate interface for example. + * + * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides + * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any + * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean + * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be + * conceptually neater. + * + * For example: + *

      + * public interface Transactional
      + * {
      + *    public void commit();
      + *    public void rollback();
      + * }
      + *
      + * public interface TransactionalQueue extends Transactional, SizeableQueue
      + * {}
      + *
      + * public class Queues
      + * {
      + *    ...
      + *    // For transactional messaging, take a transactional view onto the queue.
      + *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      + *
      + *    // For non-transactional messaging, take a non-transactional view onto the queue.
      + *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      + * }
      + * 
      */ public interface TransactionalContext { + /** + * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} + * should automatically begin the next transaction in the chain. + * + * @throws AMQException If the transaction cannot be started for any reason. + */ void beginTranIfNecessary() throws AMQException; + /** + * Makes all pending operations on the transaction permanent and visible. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ void commit() throws AMQException; + /** + * Erases all pending operations on the transaction. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ void rollback() throws AMQException; + /** + * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a + * redelivery, and should be placed on the front of the queue. + * + *

      This is an 'enqueue' operation. + * + * @param message The message to deliver. + * @param queue The queue to deliver the message to. + * @param deliverFirst true to place the message on the front of the queue for redelivery, false + * for normal FIFO message ordering. + * + * @throws AMQException If the message cannot be delivered for any reason. + */ void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException; + /** + * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by + * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' + * flag is set, in which case an acknowledgement up to the latest delivered message should be done. + * + *

      This is a 'dequeue' operation. + * + * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement + * up to the latest message. + * @param lastDeliveryTag The latest message delivered. + * @param multiple true if all message ids up the acknowledged one or latest delivered, are + * to be acknowledged, false otherwise. + * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message + * from. + * + * @throws AMQException If the message cannot be acknowledged for any reason. + */ void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + /** + * Notifies the transactional context that a message has been fully received. The actual message that was received + * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, + * flushing its data to disk. + * + * @param persistent true if the received message is persistent, false otherwise. + * + * @throws AMQException If the fully received event cannot be processed for any reason. + */ void messageFullyReceived(boolean persistent) throws AMQException; + /** + * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual + * message that was delivered is not specified. This event may be used to trigger a process related to the + * outcome of the delivery of the message, for example, cleaning up failed deliveries. + * + * @param protocolSession The protocol session of the deliverable message. + * + * @throws AMQException If the message processed event cannot be handled for any reason. + */ void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; + /** + * Gets the message store context associated with this transactional context. + * + * @return The message store context associated with this transactional context. + */ StoreContext getStoreContext(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 12b2a4f7a8..4985c12dbb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -57,11 +57,11 @@ public class NullApplicationRegistry extends ApplicationRegistry super(new MapConfiguration(new HashMap())); } - public void initialise() - throws - Exception + public void initialise() throws Exception { - _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.MemoryMessageStore"); + //DTX MessageStore +// _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.MemoryMessageStore"); + _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.MemoryTransactionManager"); // _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.JDBCStore"); // _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.JDBCTransactionManager"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 6518d8b765..53844ccc4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,290 +1,289 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.messageStore.MessageStore; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - - private final String _name; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - private TransactionManager _transactionManager; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - - } // End of MBean class - - /** - * Used for testing only - * - * @param name - * @param store - * - * @throws Exception - */ - public VirtualHost(String name, MessageStore store) throws Exception - { - this(name, null, store); - } - - /** - * Normal Constructor - * - * @param name - * @param hostConfig - * - * @throws Exception - */ - public VirtualHost(String name, Configuration hostConfig) throws Exception - { - this(name, hostConfig, null); - } - - private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception - { - _name = name; - - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseTransactionManager(hostConfig); - initialiseMessageStore(hostConfig); - } - - _exchangeRegistry.initialise(); - - - _logger.warn("VirtualHost authentication Managers require spec change to be operational."); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - - _accessManager = new AccessManagerImpl(name, hostConfig); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - } - - private void initialiseMessageStore(Configuration config) throws Exception - { - String messageStoreClass = config.getString("store.class"); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - _messageStore.configure(this, _transactionManager, "store", config); - } - - private void initialiseTransactionManager(Configuration config) throws Exception - { - String transactionManagerClass = config.getString("txn.class"); - Class clazz = Class.forName(transactionManagerClass); - Object o = clazz.newInstance(); - - if (!(o instanceof TransactionManager)) - { - throw new ClassCastException("Transaction Manager class must implement " + TransactionManager.class + ". Class " + clazz + - " does not."); - } - _transactionManager = (TransactionManager) o; - } - - - public T getConfiguredObject(Class instanceType, Configuration config) - { - T instance; - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); - } - Configurator.configure(instance); - - return instance; - } - - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public TransactionManager getTransactionManager() - { - return _transactionManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - if (_messageStore != null) - { - _messageStore.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } -} - +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.txn.TransactionManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + private TransactionManager _transactionManager; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private AccessManager _accessManager; + + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + /** + * Used for testing only + * @param name + * @param store + * + * @throws Exception + */ + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, null, store); + } + + /** + * Normal Constructor + * + * @param name + * @param hostConfig + * + * @throws Exception + */ + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + // This isn't needed to be registered + //_virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + _exchangeRegistry = new DefaultExchangeRegistry(this); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseTransactionManager(hostConfig); + initialiseMessageStore(hostConfig); + } + + _exchangeRegistry.initialise(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = new AccessManagerImpl(name, hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + //DTX MessageStore +// _messageStore.configure(this, _transactionManager, "store", config); + _messageStore.configure(this, "store", config); + } + + private void initialiseTransactionManager(Configuration config) throws Exception + { + String transactionManagerClass = config.getString("txn.class"); + Class clazz = Class.forName(transactionManagerClass); + Object o = clazz.newInstance(); + + if (!(o instanceof TransactionManager)) + { + throw new ClassCastException("Transaction Manager class must implement " + TransactionManager.class + ". Class " + clazz + + " does not."); + } + _transactionManager = (TransactionManager) o; + } + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public TransactionManager getTransactionManager() + { + return _transactionManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public AccessManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java new file mode 100644 index 0000000000..edc900f401 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -0,0 +1,652 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.commands.Clear; +import org.apache.qpid.tools.messagestore.commands.Command; +import org.apache.qpid.tools.messagestore.commands.Copy; +import org.apache.qpid.tools.messagestore.commands.Dump; +import org.apache.qpid.tools.messagestore.commands.Help; +import org.apache.qpid.tools.messagestore.commands.List; +import org.apache.qpid.tools.messagestore.commands.Load; +import org.apache.qpid.tools.messagestore.commands.Quit; +import org.apache.qpid.tools.messagestore.commands.Select; +import org.apache.qpid.tools.messagestore.commands.Show; +import org.apache.qpid.tools.messagestore.commands.Move; +import org.apache.qpid.tools.messagestore.commands.Purge; +import org.apache.qpid.tools.utils.CommandParser; +import org.apache.qpid.tools.utils.Console; +import org.apache.qpid.tools.utils.SimpleCommandParser; +import org.apache.qpid.tools.utils.SimpleConsole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * MessageStoreTool. + */ +public class MessageStoreTool +{ + /** Text outputted at the start of each console.*/ + private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; + + /** I/O Wrapper. */ + protected Console _console; + + /** Batch mode flag. */ + protected boolean _batchMode; + + /** Internal State object. */ + private State _state = new State(); + + private HashMap _commands = new HashMap(); + + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); + + /** Loaded configuration file. */ + private Configuration _config; + + /** Control used for main run loop. */ + private boolean _running = true; + private boolean _initialised = false; + + //---------------------------------------------------------------------------------------------------/ + + public static void main(String[] args) throws Configuration.InitException + { + + MessageStoreTool tool = new MessageStoreTool(args); + + tool.start(); + } + + + public MessageStoreTool(String[] args) throws Configuration.InitException + { + this(args, System.in, System.out); + } + + public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException + { + BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); + BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); + + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); + _batchMode = false; + + _console = new SimpleConsole(consoleWriter, consoleReader); + + _config = new Configuration(); + + setOptions(); + _config.processCommandline(args); + } + + + private void setOptions() + { + 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 By " + + "default looks for a file named " + + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) + .withLongOpt("config") + .create("c"); + + _config.setOption(help); + _config.setOption(version); + _config.setOption(configFile); + } + + public State getState() + { + return _state; + } + + public Map getCommands() + { + return _commands; + } + + public void setConfigurationFile(String configfile) throws Configuration.InitException + { + _config.loadConfig(new File(configfile)); + setup(); + } + + public Console getConsole() + { + return _console; + } + + public void setConsole(Console console) + { + _console = console; + } + + /** + * Simple ShutdownHook to cleanly shutdown the databases + */ + class ShutdownHook implements Runnable + { + MessageStoreTool _tool; + + ShutdownHook(MessageStoreTool messageStoreTool) + { + _tool = messageStoreTool; + } + + public void run() + { + _tool.quit(); + } + } + + public void quit() + { + _running = false; + + if (_initialised) + { + ApplicationRegistry.remove(1); + } + + _console.println("...exiting"); + + _console.close(); + } + + public void setBatchMode(boolean batchmode) + { + _batchMode = batchmode; + } + + /** + * Main loop + */ + protected void start() + { + setup(); + + if (!_initialised) + { + System.exit(1); + } + + _console.println(""); + + _console.println(BOILER_PLATE); + + runCLI(); + } + + private void setup() + { + loadDefaultVirtualHosts(); + + loadCommands(); + + _state.clearAll(); + } + + private void loadCommands() + { + _commands.clear(); + //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands + _commands.put("close", new Clear(this)); + _commands.put("copy", new Copy(this)); + _commands.put("dump", new Dump(this)); + _commands.put("help", new Help(this)); + _commands.put("list", new List(this)); + _commands.put("load", new Load(this)); + _commands.put("move", new Move(this)); + _commands.put("purge", new Purge(this)); + _commands.put("quit", new Quit(this)); + _commands.put("select", new Select(this)); + _commands.put("show", new Show(this)); + } + + private void loadDefaultVirtualHosts() + { + final File configFile = _config.getConfigFile(); + + loadVirtualHosts(configFile); + } + + private void loadVirtualHosts(File configFile) + { + + if (!configFile.exists()) + { + _devlog.error("Config file not found:" + configFile.getAbsolutePath()); + return; + } + else + { + _devlog.debug("using config file :" + configFile.getAbsolutePath()); + } + + try + { + ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); + + ApplicationRegistry.remove(1); + + ApplicationRegistry.initialise(registry); + + checkMessageStores(); + _initialised = true; + } + catch (ConfigurationException e) + { + _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); + e.printStackTrace(); + } + catch (Exception e) + { + _console.println("Unable to load configuration due to: " + e.getMessage()); + e.printStackTrace(); + } + + + } + + private void checkMessageStores() + { + Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); + + boolean warning = false; + for (VirtualHost vhost : vhosts) + { + if (vhost.getMessageStore() instanceof MemoryMessageStore) + { + _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " + + "Changes will not persist."); + warning = true; + } + } + + if (warning) + { + _console.println(""); + _console.println("Please ensure you are using the correct config file currently using '" + + _config.getConfigFile().getAbsolutePath() + "'"); + _console.println("New config file can be specifed by 'load ' or -c on the commandline."); + _console.println(""); + } + } + + private void runCLI() + { + while (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + String[] args = _console.readCommand(); + + while (args != null) + { + exec(args); + + if (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + args = _console.readCommand(); + } + } + } + } + + private void printPrompt() + { + _console.print(prompt()); + } + + + /** + * Execute a script (batch mode). + * + * @param script The file script + */ + protected void runScripts(String script) + { + //Store Current State + boolean oldBatch = _batchMode; + CommandParser oldParser = _console.getCommandParser(); + setBatchMode(true); + + try + { + _devlog.debug("Running script '" + script + "'"); + + _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); + + start(); + } + catch (java.io.FileNotFoundException e) + { + _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); + } + + //Restore previous state + _console.setCommandParser(oldParser); + setBatchMode(oldBatch); + } + + public String prompt() + { + String state = _state.toString(); + if (state != null && state.length() != 0) + { + return state + ":bdb$ "; + } + else + { + return "bdb$ "; + } + } + + /** + * Execute the command. + * + * @param args [command, arg0, arg1...]. + */ + protected void exec(String[] args) + { + // Comment lines start with a # + if (args.length == 0 || args[0].startsWith("#")) + { + return; + } + + final String command = args[0]; + + Command cmd = _commands.get(command); + + if (cmd == null) + { + _console.println("Command not understood: " + command); + } + else + { + cmd.execute(args); + } + } + + + /** + * Displays usage info. + */ + protected static void help() + { + System.out.println(BOILER_PLATE); + System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); + System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); + } + + + /** + * This class is used to store the current state of the tool. + * + * This is then interrogated by the various commands to augment their behaviour. + * + * + */ + public class State + { + private VirtualHost _vhost = null; + private AMQQueue _queue = null; + private Exchange _exchange = null; + private java.util.List _msgids = null; + + public State() + { + } + + public void setQueue(AMQQueue queue) + { + _queue = queue; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void setVhost(VirtualHost vhost) + { + _vhost = vhost; + } + + public VirtualHost getVhost() + { + return _vhost; + } + + public Exchange getExchange() + { + return _exchange; + } + + public void setExchange(Exchange exchange) + { + _exchange = exchange; + } + + public String toString() + { + StringBuilder status = new StringBuilder(); + + if (_vhost != null) + { + status.append(_vhost.getName()); + + if (_exchange != null) + { + status.append("["); + status.append(_exchange.getName()); + status.append("]"); + + if (_queue != null) + { + status.append("->'"); + status.append(_queue.getName()); + status.append("'"); + + if (_msgids != null) + { + status.append(printMessages()); + } + } + } + } + + return status.toString(); + } + + + public String printMessages() + { + StringBuilder sb = new StringBuilder(); + + Long previous = null; + + Long start = null; + for (Long id : _msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(id); + start = null; + } + else + { + sb.append(","); + sb.append(previous); + } + } + } + + previous = id; + } + + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(_msgids.get(_msgids.size() - 1)); + } + else + { + sb.append(","); + sb.append(previous); + } + + // surround list in () + sb.replace(0, 1, "("); + sb.append(")"); + return sb.toString(); + } + + public void clearAll() + { + _vhost = null; + clearExchange(); + } + + public void clearExchange() + { + _exchange = null; + clearQueue(); + } + + public void clearQueue() + { + _queue = null; + clearMessages(); + } + + public void clearMessages() + { + _msgids = null; + } + + /** + * A common location to provide parsing of the message id string + * utilised by a number of the commands. + * The String is comma separated list of ids that can be individual ids + * or a range (4-10) + * + * @param msgString string of msg ids to parse 1,2,4-10 + */ + public void setMessages(String msgString) + { + StringTokenizer tok = new StringTokenizer(msgString, ","); + + if (tok.hasMoreTokens()) + { + _msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + _msgids.add(l); + } + } + } + else + { + _msgids.add(Long.parseLong(next)); + } + } + + } + + public void setMessages(java.util.List msgids) + { + _msgids = msgids; + } + + public java.util.List getMessages() + { + return _msgids; + } + }//Class State + +}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java new file mode 100644 index 0000000000..5444197cb4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +public abstract class AbstractCommand implements Command +{ + protected Console _console; + protected MessageStoreTool _tool; + + public AbstractCommand(MessageStoreTool tool) + { + _console = tool.getConsole(); + _tool = tool; + } + + public void setOutput(Console out) + { + _console = out; + } + + protected void commandError(String message, String[] args) + { + _console.print(getCommand() + " : " + message); + + if (args != null) + { + for (int i = 1; i < args.length; i++) + { + _console.print(args[i]); + } + } + _console.println(""); + _console.println(help()); + } + + + public abstract String help(); + + public abstract String usage(); + + public abstract String getCommand(); + + + public abstract void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java new file mode 100644 index 0000000000..b0006b3fe6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Clear extends AbstractCommand +{ + public Clear(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Clears any selection."; + } + + public String usage() + { + return "clear [ all | virtualhost | exchange | queue | msgs ]"; + } + + public String getCommand() + { + return "clear"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 1) + { + doClose("all"); + } + else + { + doClose(args[1]); + } + } + + private void doClose(String type) + { + if (type.equals("virtualhost") + || type.equals("all")) + { + _tool.getState().clearAll(); + } + + if (type.equals("exchange")) + { + _tool.getState().clearExchange(); + } + + if (type.equals("queue")) + { + _tool.getState().clearQueue(); + } + + if (type.equals("msgs")) + { + _tool.getState().clearMessages(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java new file mode 100644 index 0000000000..bfa775a34a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.utils.Console; + +public interface Command +{ + public void setOutput(Console out); + + public String help(); + + public abstract String usage(); + + String getCommand(); + + public void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java new file mode 100644 index 0000000000..a5b3a87616 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Copy extends Move +{ + public Copy(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Copy messages between queues.";/*\n" + + "The currently selected message set will be copied to the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; */ + } + + public String usage() + { + return "copy to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "copy"; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java new file mode 100644 index 0000000000..a0fe54994b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -0,0 +1,299 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.commons.codec.binary.Hex; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class Dump extends Show +{ + private static final int LINE_SIZE = 8; + private static final String DEFAULT_ENCODING = "utf-8"; + private static final boolean SPACE_BYTES = true; + private static final String BYTE_SPACER = " "; + private static final String NON_PRINTING_ASCII_CHAR = "?"; + + protected boolean _content = true; + + public Dump(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Dump selected message content. Default: show=content"; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; + } + + public String getCommand() + { + return "dump"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _content = arg.contains("content") || arg.contains("all"); + } + } + + parseArgs(args); + } + + performShow(); + } + + + protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + List display = new LinkedList(); + + List hex = new LinkedList(); + List ascii = new LinkedList(); + display.add(hex); + display.add(ascii); + + for (AMQMessage msg : messages) + { + if (!includeMsg(msg, msgids)) + { + continue; + } + + //Add divider between messages + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + // Show general message information + hex.add(Show.Columns.ID.name()); + ascii.add("" +msg.getMessageId()); + + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + if (showRouting) + { + addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); + } + if (showHeaders) + { + addShowInformation(hex, ascii, msg, "Headers", false, true, false); + } + if (showMessageHeaders) + { + addShowInformation(hex, ascii, msg, null, false, false, true); + } + + // Add Content Body seciont + hex.add("Content Body"); + ascii.add(""); + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + Iterator bodies = msg.getContentBodyIterator(); + if (bodies.hasNext()) + { + + hex.add("Hex"); + hex.add(Console.ROW_DIVIDER); + + + ascii.add("ASCII"); + ascii.add(Console.ROW_DIVIDER); + + while (bodies.hasNext()) + { + ContentChunk chunk = (ContentChunk) bodies.next(); + + //Duplicate so we don't destroy original data :) + ByteBuffer hexBuffer = chunk.getData().duplicate(); + + ByteBuffer charBuffer = hexBuffer.duplicate(); + + Hex hexencoder = new Hex(); + + while (hexBuffer.hasRemaining()) + { + byte[] line = new byte[LINE_SIZE]; + + int bufsize = hexBuffer.remaining(); + if (bufsize < LINE_SIZE) + { + hexBuffer.get(line, 0, bufsize); + } + else + { + bufsize = line.length; + hexBuffer.get(line); + } + + byte[] encoded = hexencoder.encode(line); + + try + { + String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); + String hexLine = ""; + + int strKength = encStr.length(); + for (int c = 0; c < strKength; c++) + { + hexLine += encStr.charAt(c); + + if (c % 2 == 1 && SPACE_BYTES) + { + hexLine += BYTE_SPACER; + } + } + + hex.add(hexLine); + } + catch (UnsupportedEncodingException e) + { + _console.println(e.getMessage()); + return null; + } + } + + while (charBuffer.hasRemaining()) + { + String asciiLine = ""; + + for (int pos = 0; pos < LINE_SIZE; pos++) + { + if (charBuffer.hasRemaining()) + { + byte ch = charBuffer.get(); + + if (isPrintable(ch)) + { + asciiLine += (char) ch; + } + else + { + asciiLine += NON_PRINTING_ASCII_CHAR; + } + + if (SPACE_BYTES) + { + asciiLine += BYTE_SPACER; + } + } + else + { + break; + } + } + + ascii.add(asciiLine); + } + } + } + else + { + List result = new LinkedList(); + + display.add(result); + result.add("No ContentBodies"); + } + } + + // if hex is empty then we have no data to display + if (hex.size() == 0) + { + return null; + } + + return display; + } + + private void addShowInformation(List column1, List column2, AMQMessage msg, + String title, boolean routing, boolean headers, boolean messageHeaders) + { + List single = new LinkedList(); + single.add(msg); + + List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); + + //Reformat data + if (title != null) + { + column1.add(title); + column2.add(""); + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + // look at all columns in the routing Data + for (List item : routingData) + { + // the item should be: + // Title + // *divider + // value + // otherwise we can't reason about the correct value + if (item.size() == 3) + { + //Filter out the columns we are not interested in. + + String columnName = item.get(0).toString(); + + if (!(columnName.equals(Show.Columns.ID.name()) + || columnName.equals(Show.Columns.Size.name()))) + { + column1.add(columnName); + column2.add(item.get(2).toString()); + } + } + } + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + private boolean isPrintable(byte c) + { + return c > 31 && c < 127; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java new file mode 100644 index 0000000000..0f9546541b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.Map; + +public class Help extends AbstractCommand +{ + public Help(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Provides detailed help on commands."; + } + + public String getCommand() + { + return "help"; + } + + public String usage() + { + return "help []"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + Command command = _tool.getCommands().get(args[1]); + if (command != null) + { + _console.println(command.help()); + _console.println("Usage:" + command.usage()); + } + else + { + commandError("Command not found: ", args); + } + } + else + { + java.util.List data = new LinkedList(); + + java.util.List commandName = new LinkedList(); + java.util.List commandDescription = new LinkedList(); + + data.add(commandName); + data.add(commandDescription); + + //Set up Headers + commandName.add("Command"); + commandDescription.add("Description"); + + commandName.add(Console.ROW_DIVIDER); + commandDescription.add(Console.ROW_DIVIDER); + + //Add current Commands with descriptions + Map commands = _tool.getCommands(); + + for (Command command : commands.values()) + { + commandName.add(command.getCommand()); + commandDescription.add(command.help()); + } + + _console.printMap("Available Commands", data); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java new file mode 100644 index 0000000000..df8b59ec19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -0,0 +1,314 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.Collection; +import java.util.LinkedList; + +public class List extends AbstractCommand +{ + + public List(MessageStoreTool tool) + { + super(tool); + } + + public void setOutput(Console out) + { + _console = out; + } + + public String help() + { + return "list available items."; + } + + public String usage() + { + return "list queues [] | exchanges | bindings [] | all"; + } + + public String getCommand() + { + return "list"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + if ((args[1].equals("exchanges")) + || (args[1].equals("queues")) + || (args[1].equals("bindings")) + || (args[1].equals("all"))) + { + if (args.length == 2) + { + doList(args[1]); + } + else if (args.length == 3) + { + doList(args[1], args[2]); + } + } + else + { + commandError("Unknown options. ", args); + } + } + else if (args.length < 2) + { + doList("all"); + } + else + { + doList(args[1]); + } + } + + private void doList(String... listItem) + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + listVirtualHosts(); + return; + } + + VirtualHost vhost = _tool.getState().getVhost(); + + java.util.List data = null; + + if (listItem[0].equals("queues")) + { + if (listItem.length > 1) + { + data = listQueues(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + data = listQueues(vhost, exchange); + } + } + + if (listItem[0].equals("exchanges")) + { + data = listExchanges(vhost); + } + + if (listItem[0].equals("bindings")) + { + + if (listItem.length > 1) + { + data = listBindings(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + + data = listBindings(vhost, exchange); + } + } + + if (data != null) + { + if (data.size() == 1) + { + _console.println("No '" + listItem[0] + "' to display,"); + } + else + { + _console.displayList(true, data.toArray(new String[0])); + } + } + + + if (listItem[0].equals("all")) + { + + boolean displayed = false; + Exchange exchange = _tool.getState().getExchange(); + + //Do the display here for each one so that they are pretty printed + data = listQueues(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (exchange == null) + { + data = listExchanges(vhost); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + } + + data = listBindings(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (!displayed) + { + _console.println("Nothing to list"); + } + } + } + + private void listVirtualHosts() + { + Collection vhosts = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHosts(); + + String[] data = new String[vhosts.size() + 1]; + + data[0] = "Available VirtualHosts"; + + int index = 1; + for (VirtualHost vhost : vhosts) + { + data[index] = vhost.getName(); + index++; + } + + _console.displayList(true, data); + } + + private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) + { + return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listBindings(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueueNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Current Bindings"); + + for (AMQShortString queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.toString()); + } + } + else + { + data.add(queue.toString()); + } + } + + return data; + } + + private java.util.List listExchanges(VirtualHost vhost) + { + Collection queues = vhost.getExchangeRegistry().getExchangeNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Exchanges"); + + for (AMQShortString queue : queues) + { + data.add(queue.toString()); + } + + return data; + } + + private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) + { + return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listQueues(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueues(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Queues"); + + for (AMQQueue queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.getName().toString()); + } + } + else + { + data.add(queue.getName().toString()); + } + } + + if (exchange != null) + { + if (queues.size() == 1) + { + return null; + } + } + + return data; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java new file mode 100644 index 0000000000..244a311c30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Load extends AbstractCommand +{ + public Load(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Loads specified broker configuration file."; + } + + public String usage() + { + return "load "; + } + + public String getCommand() + { + return "load"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 2) + { + _console.print("load " + args[1] + ": additional options not understood:"); + for (int i = 2; i < args.length; i++) + { + _console.print(args[i] + " "); + } + _console.println(""); + } + else if (args.length < 2) + { + _console.println("Enter Configuration file."); + String input = _console.readln(); + if (input != null) + { + doLoad(input); + } + else + { + _console.println("Did not recognise config file."); + } + } + else + { + doLoad(args[1]); + } + } + + private void doLoad(String configfile) + { + _console.println("Loading Configuration:" + configfile); + + try + { + _tool.setConfigurationFile(configfile); + } + catch (Configuration.InitException e) + { + _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java new file mode 100644 index 0000000000..25cff27445 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.List; + +public class Move extends AbstractCommand +{ + + /** + * Since the Coopy command is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + protected StoreContext _storeContext = new StoreContext(); + + public Move(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Move messages between queues.";/*\n" + + "The currently selected message set will be moved to the specifed queue.\n" + + "Alternatively the values can be provided on the command line.";*/ + } + + public String usage() + { + return "move to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "move"; + } + + public void execute(String... args) + { + AMQQueue toQueue = null; + AMQQueue fromQueue = _tool.getState().getQueue(); + java.util.List msgids = _tool.getState().getMessages(); + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("to=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("from=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("msgids=")) + { + String msgidStr = arg.substring(arg.indexOf("=") + 1); + + // Record the current message selection + java.util.List currentIDs = _tool.getState().getMessages(); + + // Use the ToolState class to perform the messasge parsing + _tool.getState().setMessages(msgidStr); + msgids = _tool.getState().getMessages(); + + // Reset the original selection of messages + _tool.getState().setMessages(currentIDs); + } + } + } + + if (!checkRequirements(fromQueue, toQueue, msgids)) + { + return; + } + + processIDs(fromQueue, toQueue, msgids); + } + + private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + Long previous = null; + Long start = null; + + if (msgids == null) + { + msgids = allMessageIDs(fromQueue); + } + + if (msgids == null || msgids.size() == 0) + { + _console.println("No Messages to move."); + return; + } + + for (long id : msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, id, toQueue); + start = null; + } + else + { + //move a single id + doCommand(fromQueue, id, id, toQueue); + } + } + } + + previous = id; + } + + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, previous, toQueue); + } + } + + private List allMessageIDs(AMQQueue fromQueue) + { + List ids = new LinkedList(); + + if (fromQueue != null) + { + List messages = fromQueue.getMessagesOnTheQueue(); + if (messages != null) + { + for (AMQMessage msg : messages) + { + ids.add(msg.getMessageId()); + } + } + } + + return ids; + } + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) + { + if (toQueue == null) + { + _console.println("Destination queue not specifed."); + _console.println(usage()); + return false; + } + + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) + { + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java new file mode 100644 index 0000000000..f187e26593 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Purge extends Move +{ + public Purge(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Purge messages from a queue.\n" + + "The currently selected message set will be purged from the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "purge from= [msgids=]"; + } + + public String getCommand() + { + return "purge"; + } + + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.removeMessagesFromQueue(start, end, _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java new file mode 100644 index 0000000000..a81bc07c38 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Quit extends AbstractCommand +{ + public Quit(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Quit the tool."; + } + + public String usage() + { + return "quit"; + } + + public String getCommand() + { + return "quit"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals("quit"); + + _tool.quit(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java new file mode 100644 index 0000000000..fd7d4c3f13 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.StringTokenizer; + +public class Select extends AbstractCommand +{ + + public Select(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Perform a selection."; + } + + public String usage() + { + return "select virtualhost |exchange |queue | msg id="; + } + + public String getCommand() + { + return "select"; + } + + public void execute(String... args) + { + assert args.length > 2; + assert args[0].equals("select"); + + if (args.length < 3) + { + if (args[1].equals("show")) + { + doSelect(args[1], null); + } + else + { + _console.print("select : unknown command:"); + _console.println(help()); + } + } + else + { + if (args[1].equals("virtualhost") + || args[1].equals("vhost") + || args[1].equals("exchange") + || args[1].equals("queue") + || args[1].equals("msg") + ) + { + doSelect(args[1], args[2]); + } + else + { + _console.println(help()); + } + } + } + + private void doSelect(String type, String item) + { + if (type.equals("virtualhost")) + { + + VirtualHost vhost = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHost(item); + + if (vhost == null) + { + _console.println("Virtualhost '" + item + "' not found."); + } + else + { + _tool.getState().setVhost(vhost); + } + } + + if (type.equals("exchange")) + { + + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + + Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); + + if (exchange == null) + { + _console.println("Exchange '" + item + "' not found."); + } + else + { + _tool.getState().setExchange(exchange); + } + + if (_tool.getState().getQueue() != null) + { + if (!exchange.isBound(_tool.getState().getQueue())) + { + _tool.getState().setQueue(null); + } + } + } + + if (type.equals("queue")) + { + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); + + if (queue == null) + { + _console.println("Queue '" + item + "' not found."); + } + else + { + _tool.getState().setQueue(queue); + + if (_tool.getState().getExchange() == null) + { + for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) + { + Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); + if (exchange.isBound(queue)) + { + _tool.getState().setExchange(exchange); + break; + } + } + } + + //remove the message selection + _tool.getState().setMessages((java.util.List) null); + } + } + + if (type.equals("msg")) + { + if (item.startsWith("id=")) + { + StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); + + java.util.List msgids = null; + + if (tok.hasMoreTokens()) + { + msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + msgids.add(l); + } + } + } + else + { + msgids.add(Long.parseLong(next)); + } + } + + _tool.getState().setMessages(msgids); + } + + } + + if (type.equals("show")) + { + _console.println(_tool.getState().toString()); + if (_tool.getState().getMessages() != null) + { + _console.print("Msgs:"); + for (Long l : _tool.getState().getMessages()) + { + _console.print(" " + l); + } + _console.println(""); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java new file mode 100644 index 0000000000..8487afba76 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -0,0 +1,512 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.List; + +public class Show extends AbstractCommand +{ + protected boolean _amqHeaders = false; + protected boolean _routing = false; + protected boolean _msgHeaders = false; + + public Show(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Shows the messages headers."; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; + } + + public String getCommand() + { + return "show"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 2) + { + parseArgs("all"); + } + else + { + parseArgs(args); + } + + performShow(); + } + + protected void parseArgs(String... args) + { + List msgids = null; + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); + _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); + _routing = arg.contains("routing") || arg.contains("all"); + } + + if (arg.startsWith("id=")) + { + _tool.getState().setMessages(msgids); + } + }//for args + }// if args > 2 + } + + protected void performShow() + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); + return; + } + + AMQQueue _queue = _tool.getState().getQueue(); + + List msgids = _tool.getState().getMessages(); + + if (_queue != null) + { + List messages = _queue.getMessagesOnTheQueue(); + if (messages == null || messages.size() == 0) + { + _console.println("No messages on queue"); + return; + } + + List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); + if (data != null) + { + _console.printMap(null, data); + } + else + { + String message = "No data to display."; + if (msgids != null) + { + message += " Is message selection correct? " + _tool.getState().printMessages(); + } + _console.println(message); + } + + } + else + { + _console.println("No Queue specified to show."); + } + } + + /** + * Create the list data for display from the messages. + * + * @param msgids The list of message ids to display + * @param messages A list of messages to format and display. + * @param showHeaders should the header info be shown + * @param showRouting show the routing info be shown + * @param showMessageHeaders show the msg headers be shown + * @return the formated data lists for printing + */ + protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + // Currenly exposed message properties +// //Printing the content Body +// msg.getContentBodyIterator(); +// //Print the Headers +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); +// +// //Print out all the property names +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); +// +// msg.getMessageId(); +// msg.getSize(); +// msg.getArrivalTime(); + +// msg.getDeliveredSubscription(); +// msg.getDeliveredToConsumer(); +// msg.getMessageHandle(); +// msg.getMessageId(); +// msg.getMessagePublishInfo(); +// msg.getPublisher(); + +// msg.getStoreContext(); +// msg.isAllContentReceived(); +// msg.isPersistent(); +// msg.isRedelivered(); +// msg.isRejectedBy(); +// msg.isTaken(); + + //Header setup + + List data = new LinkedList(); + + List id = new LinkedList(); + data.add(id); + id.add(Columns.ID.name()); + id.add(Console.ROW_DIVIDER); + + List exchange = new LinkedList(); + List routingkey = new LinkedList(); + List immediate = new LinkedList(); + List mandatory = new LinkedList(); + if (showRouting) + { + data.add(exchange); + exchange.add(Columns.Exchange.name()); + exchange.add(Console.ROW_DIVIDER); + + data.add(routingkey); + routingkey.add(Columns.RoutingKey.name()); + routingkey.add(Console.ROW_DIVIDER); + + data.add(immediate); + immediate.add(Columns.isImmediate.name()); + immediate.add(Console.ROW_DIVIDER); + + data.add(mandatory); + mandatory.add(Columns.isMandatory.name()); + mandatory.add(Console.ROW_DIVIDER); + } + + List size = new LinkedList(); + List appid = new LinkedList(); + List clusterid = new LinkedList(); + List contenttype = new LinkedList(); + List correlationid = new LinkedList(); + List deliverymode = new LinkedList(); + List encoding = new LinkedList(); + List arrival = new LinkedList(); + List expiration = new LinkedList(); + List priority = new LinkedList(); + List propertyflag = new LinkedList(); + List replyto = new LinkedList(); + List timestamp = new LinkedList(); + List type = new LinkedList(); + List userid = new LinkedList(); + List ispersitent = new LinkedList(); + List isredelivered = new LinkedList(); + List isdelivered = new LinkedList(); + + data.add(size); + size.add(Columns.Size.name()); + size.add(Console.ROW_DIVIDER); + + if (showHeaders) + { + data.add(ispersitent); + ispersitent.add(Columns.isPersistent.name()); + ispersitent.add(Console.ROW_DIVIDER); + + data.add(isredelivered); + isredelivered.add(Columns.isRedelivered.name()); + isredelivered.add(Console.ROW_DIVIDER); + + data.add(isdelivered); + isdelivered.add(Columns.isDelivered.name()); + isdelivered.add(Console.ROW_DIVIDER); + + data.add(appid); + appid.add(Columns.App_ID.name()); + appid.add(Console.ROW_DIVIDER); + + data.add(clusterid); + clusterid.add(Columns.Cluster_ID.name()); + clusterid.add(Console.ROW_DIVIDER); + + data.add(contenttype); + contenttype.add(Columns.Content_Type.name()); + contenttype.add(Console.ROW_DIVIDER); + + data.add(correlationid); + correlationid.add(Columns.Correlation_ID.name()); + correlationid.add(Console.ROW_DIVIDER); + + data.add(deliverymode); + deliverymode.add(Columns.Delivery_Mode.name()); + deliverymode.add(Console.ROW_DIVIDER); + + data.add(encoding); + encoding.add(Columns.Encoding.name()); + encoding.add(Console.ROW_DIVIDER); + + data.add(arrival); + expiration.add(Columns.Arrival.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(expiration); + expiration.add(Columns.Expiration.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(priority); + priority.add(Columns.Priority.name()); + priority.add(Console.ROW_DIVIDER); + + data.add(propertyflag); + propertyflag.add(Columns.Property_Flag.name()); + propertyflag.add(Console.ROW_DIVIDER); + + data.add(replyto); + replyto.add(Columns.ReplyTo.name()); + replyto.add(Console.ROW_DIVIDER); + + data.add(timestamp); + timestamp.add(Columns.Timestamp.name()); + timestamp.add(Console.ROW_DIVIDER); + + data.add(type); + type.add(Columns.Type.name()); + type.add(Console.ROW_DIVIDER); + + data.add(userid); + userid.add(Columns.UserID.name()); + userid.add(Console.ROW_DIVIDER); + } + + List msgHeaders = new LinkedList(); + if (showMessageHeaders) + { + data.add(msgHeaders); + msgHeaders.add(Columns.MsgHeaders.name()); + msgHeaders.add(Console.ROW_DIVIDER); + } + + //Add create the table of data + for (AMQMessage msg : messages) + { + if (!includeMsg(msg, msgids)) + { + continue; + } + + id.add("" + msg.getMessageId()); + + size.add("" + msg.getSize()); + + arrival.add("" + msg.getArrivalTime()); + + try + { + ispersitent.add(msg.isPersistent() ? "true" : "false"); + } + catch (AMQException e) + { + ispersitent.add("n/a"); + } + + isredelivered.add(msg.isRedelivered() ? "true" : "false"); + + isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + +// msg.getMessageHandle(); + + BasicContentHeaderProperties headers = null; + + try + { + headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + } + catch (AMQException e) + { + //ignore +// commandError("Unable to read properties for message: " + e.getMessage(), null); + } + + if (headers != null) + { + String appidS = headers.getAppIdAsString(); + appid.add(appidS == null ? "null" : appidS); + + String clusterS = headers.getClusterIdAsString(); + clusterid.add(clusterS == null ? "null" : clusterS); + + String contentS = headers.getContentTypeAsString(); + contenttype.add(contentS == null ? "null" : contentS); + + String correlationS = headers.getCorrelationIdAsString(); + correlationid.add(correlationS == null ? "null" : correlationS); + + deliverymode.add("" + headers.getDeliveryMode()); + + AMQShortString encodeSS = headers.getEncoding(); + encoding.add(encodeSS == null ? "null" : encodeSS.toString()); + + expiration.add("" + headers.getExpiration()); + + FieldTable headerFT = headers.getHeaders(); + msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); + + priority.add("" + headers.getPriority()); + propertyflag.add("" + headers.getPropertyFlags()); + + AMQShortString replytoSS = headers.getReplyTo(); + replyto.add(replytoSS == null ? "null" : replytoSS.toString()); + + timestamp.add("" + headers.getTimestamp()); + + AMQShortString typeSS = headers.getType(); + type.add(typeSS == null ? "null" : typeSS.toString()); + + AMQShortString useridSS = headers.getUserId(); + userid.add(useridSS == null ? "null" : useridSS.toString()); + + MessagePublishInfo info = null; + try + { + info = msg.getMessagePublishInfo(); + } + catch (AMQException e) + { + //ignore + } + + if (info != null) + { + AMQShortString exchangeSS = info.getExchange(); + exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); + + AMQShortString routingkeySS = info.getRoutingKey(); + routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); + + immediate.add(info.isImmediate() ? "true" : "false"); + mandatory.add(info.isMandatory() ? "true" : "false"); + } + +// msg.getPublisher(); -- only used in clustering +// msg.getStoreContext(); +// msg.isAllContentReceived(); + + }// if headers!=null + +// need to access internal map and do lookups. +// msg.isTaken(); +// msg.getDeliveredSubscription(); +// msg.isRejectedBy(); + + } + + // if id only had the header and the divider in it then we have no data to display + if (id.size() == 2) + { + return null; + } + return data; + } + + protected boolean includeMsg(AMQMessage msg, List msgids) + { + if (msgids == null) + { + return true; + } + + Long msgid = msg.getMessageId(); + + boolean found = false; + + if (msgids != null) + { + //check msgid is in msgids + for (Long l : msgids) + { + if (l.equals(msgid)) + { + found = true; + break; + } + } + } + return found; + } + + public enum Columns + { + ID, + Size, + Exchange, + RoutingKey, + isImmediate, + isMandatory, + isPersistent, + isRedelivered, + isDelivered, + App_ID, + Cluster_ID, + Content_Type, + Correlation_ID, + Delivery_Mode, + Encoding, + Arrival, + Expiration, + Priority, + Property_Flag, + ReplyTo, + Timestamp, + Type, + UserID, + MsgHeaders + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java new file mode 100644 index 0000000000..c27c52eb8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java new file mode 100644 index 0000000000..986fea32cc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +public interface CommandParser +{ + /** + * If there is more than one command received on the last parse request. + * + * Subsequent calls to parse will utilise this input rather than reading new data from the input source + * @return boolean + */ + boolean more(); + + /** + * True if the currently parsed command has been requested as a background operation + * + * @return boolean + */ + boolean isBackground(); + + /** + * Parses user commands, and groups tokens in the + * String[] format that all Java main's love. + * + * If more than one command is provided in one input line then the more() method will return true. + * A subsequent call to parse() will continue to parse that input line before reading new input. + * + * @return input split in args[] format; null if eof. + * @throws java.io.IOException if there is a problem reading from the input stream + */ + String[] parse() throws java.io.IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java new file mode 100644 index 0000000000..cf457d1ea5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.util.List; + +public interface Console +{ + public enum CellFormat + { + CENTRED, LEFT, RIGHT + } + + public static String ROW_DIVIDER = "*divider"; + + public void print(String... message); + + public void println(String... message); + + public String readln(); + + /** + * Reads and parses the command line. + * + * + * @return The next command or null + */ + public String[] readCommand(); + + public CommandParser getCommandParser(); + + public void setCommandParser(CommandParser parser); + + /** + * + * Prints the list of String nicely. + * + * +-------------+ + * | Heading | + * +-------------+ + * | Item 1 | + * | Item 2 | + * | Item 3 | + * +-------------+ + * + * @param hasTitle should list[0] be used as a heading + * @param list The list of Strings to display + */ + public void displayList(boolean hasTitle, String... list); + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * +----------------------------+ (*divider) + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + void printMap(String title, List entries); + + + public void close(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java new file mode 100644 index 0000000000..09444ccdd7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.StringTokenizer; + +public class SimpleCommandParser implements CommandParser +{ + private static final String COMMAND_SEPERATOR = ";"; + + /** Input source of commands */ + protected BufferedReader _reader; + + /** The next list of commands from the command line */ + private StringBuilder _nextCommand = null; + + public SimpleCommandParser(BufferedReader reader) + { + _reader = reader; + } + + public boolean more() + { + return _nextCommand != null; + } + + public boolean isBackground() + { + return false; + } + + public String[] parse() throws IOException + { + String[] commands = null; + + String input = null; + + if (_nextCommand == null) + { + input = _reader.readLine(); + } + else + { + input = _nextCommand.toString(); + _nextCommand = null; + } + + if (input == null) + { + return null; + } + + StringTokenizer tok = new StringTokenizer(input, " "); + + int tokenCount = tok.countTokens(); + int index = 0; + + if (tokenCount > 0) + { + commands = new String[tokenCount]; + boolean commandComplete = false; + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + + if (next.equals(COMMAND_SEPERATOR)) + { + commandComplete = true; + _nextCommand = new StringBuilder(); + continue; + } + + if (commandComplete) + { + _nextCommand.append(next); + _nextCommand.append(" "); + } + else + { + commands[index] = next; + index++; + } + } + + } + + //Reduce the String[] if not all the tokens were used in this command. + // i.e. there is more than one command on the line. + if (index != tokenCount) + { + String[] shortCommands = new String[index]; + System.arraycopy(commands, 0, shortCommands, 0, index); + return shortCommands; + } + else + { + return commands; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java new file mode 100644 index 0000000000..ec080a4611 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +public class SimpleConsole implements Console +{ + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); + + /** Console Writer. */ + protected static BufferedWriter _consoleWriter; + + /** Console Reader. */ + protected static BufferedReader _consoleReader; + + /** Parser for command-line input. */ + protected CommandParser _parser; + + public SimpleConsole(BufferedWriter writer, BufferedReader reader) + { + _consoleWriter = writer; + _consoleReader = reader; + _parser = new SimpleCommandParser(_consoleReader); + } + + public void print(String... message) + { + try + { + for (String s : message) + { + _consoleWriter.write(s); + } + _consoleWriter.flush(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); + } + + } + + public void println(String... message) + { + print(message); + print(System.getProperty("line.separator")); + } + + + public String readln() + { + try + { + return _consoleReader.readLine(); + } + catch (IOException e) + { + _devlog.debug("Unable to read input due to:" + e.getMessage()); + return null; + } + } + + public String[] readCommand() + { + try + { + return _parser.parse(); + } + catch (IOException e) + { + _devlog.error("Error reading command:" + e.getMessage()); + return new String[0]; + } + } + + public CommandParser getCommandParser() + { + return _parser; + } + + public void setCommandParser(CommandParser parser) + { + _parser = parser; + } + + public void displayList(boolean hasTitle, String... list) + { + java.util.List data = new LinkedList(); + + java.util.List values = new LinkedList(); + + data.add(values); + + for (String value : list) + { + values.add(value); + } + + if (hasTitle) + { + values.add(1, "*divider"); + } + + printMap(null, data); + } + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + public void printMap(String title, java.util.List entries) + { + try + { + int columns = entries.size(); + + int[] columnWidth = new int[columns]; + + // calculate row count + int rowMax = 0; + + //the longest item + int itemMax = 0; + + for (int i = 0; i < columns; i++) + { + int columnIRowMax = entries.get(i).size(); + + if (columnIRowMax > rowMax) + { + rowMax = columnIRowMax; + } + for (Object values : entries.get(i)) + { + if (values.toString().equals(Console.ROW_DIVIDER)) + { + continue; + } + + int itemLength = values.toString().length(); + + //note for single width + if (itemLength > itemMax) + { + itemMax = itemLength; + } + + //note for mulit width + if (itemLength > columnWidth[i]) + { + columnWidth[i] = itemLength; + } + + } + } + + int tableWidth = 0; + + + for (int i = 0; i < columns; i++) + { + // plus 2 for the space padding + columnWidth[i] += 2; + } + for (int size : columnWidth) + { + tableWidth += size; + } + tableWidth += (columns - 1); + + if (title != null) + { + if (title.length() > tableWidth) + { + tableWidth = title.length(); + } + + printCellRow("+", "-", tableWidth); + + printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); + _consoleWriter.newLine(); + + } + + //put top line | or bottom of title + printCellRow("+", "-", tableWidth); + + //print the table data + int row = 0; + + for (; row < rowMax; row++) + { + for (int i = 0; i < columns; i++) + { + java.util.List columnData = entries.get(i); + + String value; + // does this column have a value for this row + if (columnData.size() > row) + { + value = " " + columnData.get(row).toString() + " "; + } + else + { + value = " "; + } + + if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) + { + printCellRow("+", "-", tableWidth); + //move on to the next row + break; + } + else + { + printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); + } + + // if it is the last row then do a new line. + if (i == columns - 1) + { + _consoleWriter.newLine(); + } + } + } + + printCellRow("+", "-", tableWidth); + + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write."); + } + } + + public void close() + { + + try + { + _consoleReader.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); + } + + try + { + + _consoleWriter.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); + } + + } + + private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException + { + int pad = cellWidth - cell.length(); + + if (column == 0) + { + _consoleWriter.write(edge); + } + + switch (format) + { + case CENTRED: + printPad(" ", pad / 2); + break; + case RIGHT: + printPad(" ", pad); + break; + } + + _consoleWriter.write(cell); + + + switch (format) + { + case CENTRED: + // if pad isn't even put the extra one on the right + if (pad % 2 == 0) + { + printPad(" ", pad / 2); + } + else + { + printPad(" ", (pad / 2) + 1); + } + break; + case LEFT: + printPad(" ", pad); + break; + } + + + _consoleWriter.write(edge); + + } + + private void printCellRow(String edge, String mid, int cellWidth) throws IOException + { + _consoleWriter.write(edge); + + printPad(mid, cellWidth); + + _consoleWriter.write(edge); + _consoleWriter.newLine(); + } + + private void printPad(String padChar, int count) throws IOException + { + for (int i = 0; i < count; i++) + { + _consoleWriter.write(padChar); + } + } + + +} -- cgit v1.2.1 From 9cfc46c80e49f902f086d387c87aab33c337d77f Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Thu, 30 Aug 2007 19:21:49 +0000 Subject: fixed a race condition causing intermittant test failures in AMQBrokerManagerMBeanTest git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@571277 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ApplicationRegistry.java | 89 ++++++++++++---------- 1 file changed, 49 insertions(+), 40 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 89f0b7b39d..a70505ff6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -61,7 +61,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.info("Shutting down application registries..."); try { - synchronized (ApplicationRegistry.class) + synchronized (_instanceMap) { Iterator keyIterator = _instanceMap.values().iterator(); @@ -87,40 +87,46 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception { - if (instance != null) + synchronized (_instanceMap) { - _logger.info("Initialising Application Registry:" + instanceID); - _instanceMap.put(instanceID, instance); - - try + if (instance != null) { - instance.initialise(); + _logger.info("Initialising Application Registry:" + instanceID); + _instanceMap.put(instanceID, instance); + + try + { + instance.initialise(); + } + catch (Exception e) + { + _instanceMap.remove(instanceID); + throw e; + } } - catch (Exception e) + else { - _instanceMap.remove(instanceID); - throw e; + remove(instanceID); } } - else - { - remove(instanceID); - } } public static void remove(int instanceID) { - try - { - _instanceMap.get(instanceID).close(); - } - catch (Exception e) + synchronized (_instanceMap) { + try + { + _instanceMap.get(instanceID).close(); + } + catch (Exception e) + { - } - finally - { - _instanceMap.remove(instanceID); + } + finally + { + _instanceMap.remove(instanceID); + } } } @@ -137,29 +143,32 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public static IApplicationRegistry getInstance(int instanceID) { - IApplicationRegistry instance = _instanceMap.get(instanceID); - - if (instance == null) + synchronized (_instanceMap) { - try + IApplicationRegistry instance = _instanceMap.get(instanceID); + + if (instance == null) { - _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; + 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", e); + } } - catch (Exception e) + else { - _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", e); + return instance; } } - else - { - return instance; - } } public void close() throws Exception -- cgit v1.2.1 From 971ab329f242efbbb590405e924f28c21f1ff9f2 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 4 Sep 2007 17:40:36 +0000 Subject: added debugging utility method git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@572750 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/AMQMessage.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index d5100dc8e5..7fa028df29 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -1092,4 +1092,17 @@ public class AMQMessage implements StorableMessage return rejected; } } + + public String getBodyAsString() + { + StringBuilder b = new StringBuilder(); + for (Iterator it = getContentBodyIterator(); it.hasNext(); ) + { + ByteBuffer buf = it.next().getData(); + byte[] bytes = new byte[buf.remaining()]; + buf.duplicate().get(bytes); + b.append(new String(bytes)); + } + return b.toString(); + } } -- cgit v1.2.1 From c6d9d4d374608b260f60d91624127c007e23ca43 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Sep 2007 15:01:43 +0000 Subject: QPID-572 Applied test patch supplied by Aidan Skinner along with change to ConcurrentSelectorDeliveryManager that resolves the ordering problem. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@574982 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 0639243e02..f3b8f0de35 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -747,7 +747,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { Subscription s = _subscriptions.nextSubscriber(msg); - if (s == null) //no-one can take the message right now. + if (s == null || hasQueuedMessages()) //no-one can take the message right now or we're queueing { if (debugEnabled) { @@ -795,6 +795,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else { + + if (_messages.size() > 0) + { + _log.error("Direct delivery with queued msgs:" + _messages.size()); + } + //release lock now _lock.unlock(); synchronized (s.getSendLock()) -- cgit v1.2.1 From bc20549a8a418e84f600097023512942dee6cfba Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 00:08:07 +0000 Subject: Enabled the broker module again, and Commented out the offending class that had compilation errors due missing classes from the new mina version git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599216 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ThreadPoolFilter.java | 67 ++++++++++++---------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java index bdd27f2d1c..e6ee8891f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -31,11 +31,12 @@ import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoFilterAdapter; import org.apache.mina.common.IoHandler; import org.apache.mina.common.IoSession; -import org.apache.mina.util.BlockingQueue; -import org.apache.mina.util.ByteBufferUtil; -import org.apache.mina.util.IdentityHashSet; -import org.apache.mina.util.Queue; -import org.apache.mina.util.Stack; +//import org.apache.mina.util.BlockingQueue; +//import org.apache.mina.util.ByteBufferUtil; +//import org.apache.mina.util.IdentityHashSet; +//import org.apache.mina.util.Queue; +//import org.apache.mina.util.Stack; +//import org.apache.mina.util.IdentityHashSet; /** * A Thread-pooling filter. This filter forwards {@link IoHandler} events @@ -47,6 +48,7 @@ import org.apache.mina.util.Stack; */ public class ThreadPoolFilter extends IoFilterAdapter { + /** * Default maximum size of thread pool (2G). */ @@ -62,7 +64,7 @@ public class ThreadPoolFilter extends IoFilterAdapter * 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 final Queue threadIdReuseQueue = new Queue(); private static int threadId = 0; private static int acquireThreadId() @@ -87,16 +89,16 @@ public class ThreadPoolFilter extends IoFilterAdapter { threadIdReuseQueue.push(new Integer(id)); } - } + } */ - private final String threadNamePrefix; + private final String threadNamePrefix = ""; private final Map buffers = new IdentityHashMap(); - private final BlockingQueue unfetchedSessionBuffers = new BlockingQueue(); - private final Set allSessionBuffers = new IdentityHashSet(); + //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 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; @@ -131,20 +133,21 @@ public class ThreadPoolFilter extends IoFilterAdapter { throw new IllegalArgumentException("threadNamePrefix is empty."); } - this.threadNamePrefix = threadNamePrefix; + // this.threadNamePrefix = threadNamePrefix; } public String getThreadNamePrefix() { - return threadNamePrefix; + return null; // threadNamePrefix; } public int getPoolSize() { - synchronized (poolSizeLock) + /* synchronized (poolSizeLock) { return poolSize; - } + }*/ + return 0; } public int getMaximumPoolSize() @@ -171,7 +174,7 @@ public class ThreadPoolFilter extends IoFilterAdapter this.keepAliveTime = keepAliveTime; } - public void init() +/* public void init() { shuttingDown = false; leader = new Worker(); @@ -188,7 +191,7 @@ public class ThreadPoolFilter extends IoFilterAdapter List allWorkers; synchronized (poolSizeLock) { - allWorkers = new ArrayList(this.allWorkers); + // allWorkers = new ArrayList(this.allWorkers); } // You may not interrupt the current thread. @@ -216,10 +219,10 @@ public class ThreadPoolFilter extends IoFilterAdapter } } - this.allSessionBuffers.clear(); - this.unfetchedSessionBuffers.clear(); + // this.allSessionBuffers.clear(); + // this.unfetchedSessionBuffers.clear(); this.buffers.clear(); - this.followers.clear(); + // this.followers.clear(); this.leader = null; } @@ -228,7 +231,7 @@ public class ThreadPoolFilter extends IoFilterAdapter synchronized (poolSizeLock) { poolSize++; - allWorkers.add(worker); + //allWorkers.add(worker); } } @@ -237,13 +240,14 @@ public class ThreadPoolFilter extends IoFilterAdapter synchronized (poolSizeLock) { poolSize--; - allWorkers.remove(worker); + //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); @@ -264,6 +268,7 @@ public class ThreadPoolFilter extends IoFilterAdapter unfetchedSessionBuffers.push(buf); } } + */ } /** @@ -273,7 +278,7 @@ public class ThreadPoolFilter extends IoFilterAdapter * * @return A non-null {@link SessionBuffer} */ - protected SessionBuffer fetchSessionBuffer(Queue unfetchedSessionBuffers) + /* protected SessionBuffer fetchSessionBuffer(Queue unfetchedSessionBuffers) { return (SessionBuffer) unfetchedSessionBuffers.pop(); } @@ -311,7 +316,7 @@ public class ThreadPoolFilter extends IoFilterAdapter { private final IoSession session; - private final Queue eventQueue = new Queue(); + //private final Queue eventQueue = new Queue(); private SessionBuffer(IoSession session) { @@ -323,7 +328,7 @@ public class ThreadPoolFilter extends IoFilterAdapter return session; } - public Queue getEventQueue() + /* public Queue getEventQueue() { return eventQueue; } @@ -702,4 +707,6 @@ public class ThreadPoolFilter extends IoFilterAdapter { nextFilter.filterClose(session); } -} + + */ + -- cgit v1.2.1 From d8988a8acd974f58545bacb52496bb9dcc9fae6d Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 23 Apr 2008 23:50:34 +0000 Subject: Delete stuff that's just going to get synced from M2.x git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651111 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 1007 ----------- .../apache/qpid/configuration/Configuration.java | 188 -- .../apache/qpid/server/AMQBrokerManagerMBean.java | 256 --- .../java/org/apache/qpid/server/AMQChannel.java | 980 ----------- .../qpid/server/ConsumerTagNotUniqueException.java | 36 - .../src/main/java/org/apache/qpid/server/Main.java | 573 ------ .../org/apache/qpid/server/ManagedChannel.java | 68 - .../qpid/server/RequiredDeliveryException.java | 68 - .../java/org/apache/qpid/server/ack/TxAck.java | 139 -- .../qpid/server/ack/UnacknowledgedMessage.java | 79 - .../qpid/server/ack/UnacknowledgedMessageMap.java | 80 - .../server/ack/UnacknowledgedMessageMapImpl.java | 235 --- .../qpid/server/configuration/Configurator.java | 118 -- .../configuration/VirtualHostConfiguration.java | 290 --- .../server/exception/CommandInvalidException.java | 66 - .../server/exception/InternalErrorException.java | 68 - .../qpid/server/exception/InvalidXidException.java | 82 - .../exception/MessageAlreadyStagedException.java | 60 - .../exception/MessageDoesntExistException.java | 66 - .../server/exception/NotPreparedException.java | 67 - .../exception/QueueAlreadyExistsException.java | 65 - .../exception/QueueDoesntExistException.java | 65 - .../qpid/server/exception/UnknownXidException.java | 85 - .../qpid/server/exchange/AbstractExchange.java | 203 --- .../server/exchange/DefaultExchangeFactory.java | 101 -- .../server/exchange/DefaultExchangeRegistry.java | 155 -- .../qpid/server/exchange/DestNameExchange.java | 253 --- .../qpid/server/exchange/DestWildExchange.java | 453 ----- .../org/apache/qpid/server/exchange/Exchange.java | 94 - .../qpid/server/exchange/ExchangeFactory.java | 36 - .../server/exchange/ExchangeInUseException.java | 45 - .../qpid/server/exchange/ExchangeRegistry.java | 50 - .../apache/qpid/server/exchange/ExchangeType.java | 34 - .../qpid/server/exchange/FanoutExchange.java | 239 --- .../qpid/server/exchange/HeadersBinding.java | 219 --- .../qpid/server/exchange/HeadersExchange.java | 350 ---- .../org/apache/qpid/server/exchange/Index.java | 90 - .../qpid/server/exchange/ManagedExchange.java | 95 - .../apache/qpid/server/exchange/MessageRouter.java | 40 - .../qpid/server/exchange/NoRouteException.java | 48 - .../qpid/server/filter/ArithmeticExpression.java | 275 --- .../qpid/server/filter/BinaryExpression.java | 106 -- .../qpid/server/filter/BooleanExpression.java | 40 - .../qpid/server/filter/ComparisonExpression.java | 595 ------- .../qpid/server/filter/ConstantExpression.java | 210 --- .../org/apache/qpid/server/filter/Expression.java | 37 - .../apache/qpid/server/filter/FilterManager.java | 37 - .../qpid/server/filter/FilterManagerFactory.java | 77 - .../qpid/server/filter/JMSSelectorFilter.java | 68 - .../apache/qpid/server/filter/LogicExpression.java | 110 -- .../apache/qpid/server/filter/MessageFilter.java | 29 - .../qpid/server/filter/NoConsumerFilter.java | 42 - .../qpid/server/filter/PropertyExpression.java | 322 ---- .../qpid/server/filter/SimpleFilterManager.java | 76 - .../apache/qpid/server/filter/UnaryExpression.java | 337 ---- .../apache/qpid/server/filter/XPathExpression.java | 127 -- .../qpid/server/filter/XQueryExpression.java | 57 - .../qpid/server/filter/XalanXPathEvaluator.java | 102 -- .../qpid/server/handler/BasicAckMethodHandler.java | 67 - .../server/handler/BasicCancelMethodHandler.java | 79 - .../server/handler/BasicConsumeMethodHandler.java | 175 -- .../qpid/server/handler/BasicGetMethodHandler.java | 95 - .../server/handler/BasicPublishMethodHandler.java | 104 -- .../qpid/server/handler/BasicQosHandler.java | 58 - .../server/handler/BasicRecoverMethodHandler.java | 64 - .../server/handler/BasicRejectMethodHandler.java | 115 -- .../qpid/server/handler/ChannelCloseHandler.java | 78 - .../qpid/server/handler/ChannelCloseOkHandler.java | 53 - .../qpid/server/handler/ChannelFlowHandler.java | 72 - .../qpid/server/handler/ChannelOpenHandler.java | 62 - .../handler/ConnectionCloseMethodHandler.java | 71 - .../handler/ConnectionCloseOkMethodHandler.java | 63 - .../handler/ConnectionOpenMethodHandler.java | 118 -- .../handler/ConnectionSecureOkMethodHandler.java | 141 -- .../handler/ConnectionStartOkMethodHandler.java | 172 -- .../handler/ConnectionTuneOkMethodHandler.java | 54 - .../qpid/server/handler/ExchangeBoundHandler.java | 205 --- .../server/handler/ExchangeDeclareHandler.java | 114 -- .../qpid/server/handler/ExchangeDeleteHandler.java | 70 - .../server/handler/OnCurrentThreadExecutor.java | 34 - .../qpid/server/handler/QueueBindHandler.java | 135 -- .../qpid/server/handler/QueueDeclareHandler.java | 215 --- .../qpid/server/handler/QueueDeleteHandler.java | 132 -- .../qpid/server/handler/QueuePurgeHandler.java | 115 -- .../qpid/server/handler/TxCommitHandler.java | 77 - .../qpid/server/handler/TxRollbackHandler.java | 73 - .../qpid/server/handler/TxSelectHandler.java | 63 - .../org/apache/qpid/server/jms/JmsConsumer.java | 110 -- .../qpid/server/management/AMQManagedObject.java | 97 - .../server/management/DefaultManagedObject.java | 191 -- .../management/JMXManagedObjectRegistry.java | 283 --- .../qpid/server/management/MBeanAttribute.java | 41 - .../qpid/server/management/MBeanConstructor.java | 39 - .../qpid/server/management/MBeanDescription.java | 38 - .../qpid/server/management/MBeanIntrospector.java | 388 ---- .../management/MBeanInvocationHandlerImpl.java | 239 --- .../qpid/server/management/MBeanOperation.java | 43 - .../server/management/MBeanOperationParameter.java | 37 - .../apache/qpid/server/management/Managable.java | 34 - .../qpid/server/management/ManagedBroker.java | 98 -- .../qpid/server/management/ManagedObject.java | 58 - .../server/management/ManagedObjectRegistry.java | 48 - .../server/management/ManagementConfiguration.java | 30 - .../management/NoopManagedObjectRegistry.java | 60 - .../apache/qpid/server/messageStore/JDBCStore.java | 1861 -------------------- .../server/messageStore/MemoryMessageStore.java | 273 --- .../qpid/server/messageStore/MessageStore.java | 308 ---- .../org/apache/qpid/server/messageStore/Pool.java | 135 -- .../qpid/server/messageStore/StorableMessage.java | 116 -- .../qpid/server/messageStore/StorableQueue.java | 75 - .../server/output/ProtocolOutputConverter.java | 57 - .../output/ProtocolOutputConverterRegistry.java | 62 - .../amqp0_8/ProtocolOutputConverterImpl.java | 282 --- .../server/protocol/AMQMinaProtocolSession.java | 773 -------- .../protocol/AMQNoMethodHandlerException.java | 46 - .../server/protocol/AMQPFastProtocolHandler.java | 243 --- .../qpid/server/protocol/AMQPProtocolProvider.java | 52 - .../qpid/server/protocol/AMQProtocolSession.java | 175 -- .../server/protocol/AMQProtocolSessionMBean.java | 305 ---- .../qpid/server/protocol/ExchangeInitialiser.java | 49 - .../qpid/server/protocol/HeartbeatConfig.java | 67 - .../qpid/server/protocol/ManagedConnection.java | 135 -- .../protocol/UnknnownMessageTypeException.java | 46 - .../org/apache/qpid/server/queue/AMQMessage.java | 1108 ------------ .../apache/qpid/server/queue/AMQMessageHandle.java | 82 - .../org/apache/qpid/server/queue/AMQQueue.java | 1052 ----------- .../apache/qpid/server/queue/AMQQueueMBean.java | 471 ----- .../qpid/server/queue/AsyncDeliveryConfig.java | 56 - .../queue/ConcurrentSelectorDeliveryManager.java | 923 ---------- .../qpid/server/queue/DefaultQueueRegistry.java | 71 - .../apache/qpid/server/queue/DeliveryManager.java | 100 -- .../apache/qpid/server/queue/ExchangeBindings.java | 137 -- .../ExistingExclusiveSubscriptionException.java | 22 - ...tingSubscriptionPreventsExclusiveException.java | 22 - .../qpid/server/queue/FailedDequeueException.java | 45 - .../qpid/server/queue/InMemoryMessageHandle.java | 169 -- .../org/apache/qpid/server/queue/ManagedQueue.java | 245 --- .../qpid/server/queue/MessageCleanupException.java | 47 - .../qpid/server/queue/MessageHandleFactory.java | 48 - .../apache/qpid/server/queue/MessageMetaData.java | 92 - .../qpid/server/queue/NoConsumersException.java | 47 - .../qpid/server/queue/NotificationCheck.java | 138 -- .../server/queue/QueueNotificationListener.java | 26 - .../apache/qpid/server/queue/QueueRegistry.java | 43 - .../qpid/server/queue/StorableMessageHandle.java | 304 ---- .../org/apache/qpid/server/queue/Subscription.java | 63 - .../qpid/server/queue/SubscriptionFactory.java | 43 - .../apache/qpid/server/queue/SubscriptionImpl.java | 676 ------- .../qpid/server/queue/SubscriptionManager.java | 34 - .../apache/qpid/server/queue/SubscriptionSet.java | 229 --- .../qpid/server/queue/TransientMessageData.java | 121 -- .../server/queue/WeakReferenceMessageHandle.java | 232 --- .../server/queue/WeightedSubscriptionManager.java | 26 - .../qpid/server/registry/ApplicationRegistry.java | 219 --- .../ConfigurationFileApplicationRegistry.java | 176 -- .../qpid/server/registry/IApplicationRegistry.java | 71 - .../org/apache/qpid/server/security/Passwd.java | 81 - .../security/access/AMQUserManagementMBean.java | 467 ----- .../qpid/server/security/access/AccessManager.java | 34 - .../server/security/access/AccessManagerImpl.java | 155 -- .../qpid/server/security/access/AccessResult.java | 66 - .../qpid/server/security/access/AccessRights.java | 63 - .../qpid/server/security/access/Accessable.java | 27 - .../qpid/server/security/access/AllowAll.java | 42 - .../qpid/server/security/access/DenyAll.java | 41 - .../server/security/access/FileAccessManager.java | 183 -- .../access/PrincipalDatabaseAccessManager.java | 108 -- .../server/security/access/UserManagement.java | 118 -- .../server/security/access/VirtualHostAccess.java | 68 - .../server/security/auth/AuthenticationResult.java | 43 - .../Base64MD5PasswordFilePrincipalDatabase.java | 599 ------- .../ConfigurationFilePrincipalDatabaseManager.java | 238 --- .../PlainPasswordFilePrincipalDatabase.java | 240 --- .../PlainPasswordVhostFilePrincipalDatabase.java | 130 -- .../security/auth/database/PrincipalDatabase.java | 100 -- .../auth/database/PrincipalDatabaseManager.java | 34 - .../auth/database/PropertiesPrincipalDatabase.java | 160 -- .../PropertiesPrincipalDatabaseManager.java | 48 - .../auth/manager/AuthenticationManager.java | 37 - .../PrincipalDatabaseAuthenticationManager.java | 249 --- .../sasl/AuthenticationProviderInitialiser.java | 76 - .../server/security/auth/sasl/JCAProvider.java | 47 - .../auth/sasl/UsernamePasswordInitialiser.java | 123 -- .../security/auth/sasl/UsernamePrincipal.java | 44 - .../auth/sasl/amqplain/AmqPlainInitialiser.java | 38 - .../auth/sasl/amqplain/AmqPlainSaslServer.java | 129 -- .../sasl/amqplain/AmqPlainSaslServerFactory.java | 60 - .../sasl/crammd5/CRAMMD5HashedInitialiser.java | 50 - .../auth/sasl/crammd5/CRAMMD5HashedSaslServer.java | 105 -- .../sasl/crammd5/CRAMMD5HashedServerFactory.java | 61 - .../auth/sasl/crammd5/CRAMMD5Initialiser.java | 71 - .../security/auth/sasl/plain/PlainInitialiser.java | 38 - .../security/auth/sasl/plain/PlainSaslServer.java | 149 -- .../auth/sasl/plain/PlainSaslServerFactory.java | 60 - .../org/apache/qpid/server/state/AMQState.java | 36 - .../apache/qpid/server/state/AMQStateManager.java | 284 --- .../server/state/StateAwareMethodListener.java | 35 - .../apache/qpid/server/state/StateListener.java | 30 - .../qpid/server/store/MemoryMessageStore.java | 209 --- .../org/apache/qpid/server/store/MessageStore.java | 261 --- .../org/apache/qpid/server/store/StoreContext.java | 68 - .../server/transport/ConnectorConfiguration.java | 97 - .../qpid/server/transport/ThreadPoolFilter.java | 712 -------- .../qpid/server/txn/CleanupMessageOperation.java | 77 - .../org/apache/qpid/server/txn/DequeueRecord.java | 59 - .../txn/DistributedTransactionalContext.java | 267 --- .../org/apache/qpid/server/txn/EnqueueRecord.java | 72 - .../apache/qpid/server/txn/JDBCAbstractRecord.java | 93 - .../apache/qpid/server/txn/JDBCDequeueRecord.java | 85 - .../apache/qpid/server/txn/JDBCEnqueueRecord.java | 106 -- .../apache/qpid/server/txn/JDBCTransaction.java | 196 --- .../qpid/server/txn/JDBCTransactionManager.java | 554 ------ .../qpid/server/txn/LocalTransactionalContext.java | 262 --- .../qpid/server/txn/MemoryDequeueRecord.java | 82 - .../qpid/server/txn/MemoryEnqueueRecord.java | 82 - .../apache/qpid/server/txn/MemoryTransaction.java | 158 -- .../qpid/server/txn/MemoryTransactionManager.java | 321 ---- .../qpid/server/txn/NonTransactionalContext.java | 234 --- .../qpid/server/txn/StoreMessageOperation.java | 58 - .../org/apache/qpid/server/txn/Transaction.java | 49 - .../apache/qpid/server/txn/TransactionManager.java | 228 --- .../apache/qpid/server/txn/TransactionRecord.java | 72 - .../qpid/server/txn/TransactionalContext.java | 171 -- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 97 - .../java/org/apache/qpid/server/txn/TxnOp.java | 55 - .../java/org/apache/qpid/server/txn/XAFlag.java | 50 - .../java/org/apache/qpid/server/txn/XidImpl.java | 210 --- .../apache/qpid/server/util/CircularBuffer.java | 131 -- .../server/util/ConcurrentLinkedQueueNoSize.java | 38 - .../org/apache/qpid/server/util/LoggingProxy.java | 105 -- .../qpid/server/util/NullApplicationRegistry.java | 128 -- .../server/virtualhost/ManagedVirtualHost.java | 44 - .../qpid/server/virtualhost/VirtualHost.java | 289 --- .../server/virtualhost/VirtualHostRegistry.java | 70 - .../qpid/tools/messagestore/MessageStoreTool.java | 652 ------- .../messagestore/commands/AbstractCommand.java | 66 - .../qpid/tools/messagestore/commands/Clear.java | 85 - .../qpid/tools/messagestore/commands/Command.java | 36 - .../qpid/tools/messagestore/commands/Copy.java | 55 - .../qpid/tools/messagestore/commands/Dump.java | 299 ---- .../qpid/tools/messagestore/commands/Help.java | 98 -- .../qpid/tools/messagestore/commands/List.java | 314 ---- .../qpid/tools/messagestore/commands/Load.java | 94 - .../qpid/tools/messagestore/commands/Move.java | 205 --- .../qpid/tools/messagestore/commands/Purge.java | 68 - .../qpid/tools/messagestore/commands/Quit.java | 54 - .../qpid/tools/messagestore/commands/Select.java | 233 --- .../qpid/tools/messagestore/commands/Show.java | 512 ------ .../org/apache/qpid/tools/security/Passwd.java | 81 - .../org/apache/qpid/tools/utils/CommandParser.java | 51 - .../java/org/apache/qpid/tools/utils/Console.java | 90 - .../qpid/tools/utils/SimpleCommandParser.java | 121 -- .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 ---- 253 files changed, 40833 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java deleted file mode 100644 index 7e0c4defe1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.log4j; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.Writer; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.zip.GZIPOutputStream; - -import org.apache.log4j.helpers.CountingQuietWriter; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.helpers.OptionConverter; -import org.apache.log4j.spi.LoggingEvent; - -/** - *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either - * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is - * crossed at which time it rolls all of those files as per the DailyRollingFileAppender) based on the setting for - * rollingStyle.

      To use CompositeRollingAppender to roll log files as they reach a certain size - * (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      To use CompositeRollingAppender to roll log - * files at certain time intervals (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      To - * have CompositeRollingAppender roll log files at a certain size AND rename those according to time intervals, set - * rollingStyle=3 (@see config.composite)
      - * - *

      A of few additional optional features have been added:
      -- Attach date pattern for current log file (@see - * staticLogFileName)
      -- Backup number increments for newer files (@see countDirection)
      -- Infinite number of - * backups by file size (@see maxSizeRollBackups)

      A few notes and warnings: For large or infinite number of - * backups countDirection > 0 is highly recommended, with staticLogFileName = false if time based rolling is also used - * -- this will reduce the number of file renamings to few or none. Changing staticLogFileName or countDirection - * without clearing the directory could have nasty side effects. If Date/Time based rolling is enabled, - * CompositeRollingAppender will attempt to roll existing files in the directory without a date/time tag based on the - * last modified date of the base log files last modification.

      A maximum number of backups based on - * date/time boundries would be nice but is not yet implemented.
      - * - * @author Kevin Steppe - * @author Heinz Richter - * @author Eirik Lygre - * @author Ceki Gülcü - * @author Martin Ritchie - */ -public class QpidCompositeRollingAppender extends FileAppender -{ - // The code assumes that the following 'time' constants are in a increasing - // sequence. - static final int TOP_OF_TROUBLE = -1; - static final int TOP_OF_MINUTE = 0; - static final int TOP_OF_HOUR = 1; - static final int HALF_DAY = 2; - static final int TOP_OF_DAY = 3; - static final int TOP_OF_WEEK = 4; - static final int TOP_OF_MONTH = 5; - - /** Style of rolling to use */ - static final int BY_SIZE = 1; - static final int BY_DATE = 2; - static final int BY_COMPOSITE = 3; - - // Not currently used - static final String S_BY_SIZE = "Size"; - static final String S_BY_DATE = "Date"; - static final String S_BY_COMPOSITE = "Composite"; - - /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ - private String datePattern = "'.'yyyy-MM-dd"; - - /** - * The actual formatted filename that is currently being written to or will be the file transferred to on roll over - * (based on staticLogFileName). - */ - private String scheduledFilename = null; - - /** The timestamp when we shall next recompute the filename. */ - private long nextCheck = System.currentTimeMillis() - 1; - - /** Holds date of last roll over */ - Date now = new Date(); - - SimpleDateFormat sdf; - - /** Helper class to determine next rollover time */ - RollingCalendar rc = new RollingCalendar(); - - /** Current period for roll overs */ - int checkPeriod = TOP_OF_TROUBLE; - - /** The default maximum file size is 10MB. */ - protected long maxFileSize = 10 * 1024 * 1024; - - /** There is zero backup files by default. */ - protected int maxSizeRollBackups = 0; - /** How many sized based backups have been made so far */ - protected int curSizeRollBackups = 0; - - /** not yet implemented */ - protected int maxTimeRollBackups = -1; - protected int curTimeRollBackups = 0; - - /** - * By default newer files have lower numbers. (countDirection < 0) ie. log.1 is most recent, log.5 is the 5th - * backup, etc... countDirection > 0 does the opposite ie. log.1 is the first backup made, log.5 is the 5th backup - * made, etc. For infinite backups use countDirection > 0 to reduce rollOver costs. - */ - protected int countDirection = -1; - - /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ - protected int rollingStyle = BY_COMPOSITE; - protected boolean rollDate = true; - protected boolean rollSize = true; - - /** - * By default file.log is always the current file. Optionally file.log.yyyy-mm-dd for current formated datePattern - * can by the currently logging file (or file.log.curSizeRollBackup or even file.log.yyyy-mm-dd.curSizeRollBackup) - * This will make time based roll overs with a large number of backups much faster -- it won't have to rename all - * the backups! - */ - protected boolean staticLogFileName = true; - - /** FileName provided in configuration. Used for rolling properly */ - protected String baseFileName; - - /** Do we want to .gz our backup files. */ - protected boolean compress = false; - - /** Do we want to use a second thread when compressing our backup files. */ - protected boolean compressAsync = false; - - /** Do we want to start numbering files at zero. */ - protected boolean zeroBased = false; - - /** Path provided in configuration. Used for moving backup files to */ - protected String backupFilesToPath = null; - private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); - private AtomicBoolean _compressing = new AtomicBoolean(false); - - /** The default constructor does nothing. */ - public QpidCompositeRollingAppender() - { } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The - * opened filename will become the ouput destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern) throws IOException - { - this(layout, filename, datePattern, true); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the ouput destination for this appender. - * - *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by - * filename will be truncated before being opened. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) throws IOException - { - super(layout, filename, append); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the ouput destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern, boolean append) - throws IOException - { - super(layout, filename, append); - this.datePattern = datePattern; - activateOptions(); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the output destination for this appender. - * - *

      The file will be appended to. DatePattern is default. - */ - public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException - { - super(layout, filename); - } - - /** - * The DatePattern takes a string in the same format as expected by {@link java.text.SimpleDateFormat}. This - * options determines the rollover schedule. - */ - public void setDatePattern(String pattern) - { - datePattern = pattern; - } - - /** Returns the value of the DatePattern option. */ - public String getDatePattern() - { - return datePattern; - } - - /** Returns the value of the maxSizeRollBackups option. */ - public int getMaxSizeRollBackups() - { - return maxSizeRollBackups; - } - - /** - * Get the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - * @since 1.1 - */ - public long getMaximumFileSize() - { - return maxFileSize; - } - - /** - *

      Set the maximum number of backup files to keep around based on file size. - * - *

      The MaxSizeRollBackups option determines how many backup files are kept before the oldest is erased. - * This option takes an integer value. If set to zero, then there will be no backup files and the log file will be - * truncated when it reaches MaxFileSize. If a negative number is supplied then no deletions will be - * made. Note that this could result in very slow performance as a large number of files are rolled over unless - * {@link #setCountDirection} up is used. - * - *

      The maximum applys to -each- time based group of files and -not- the total. Using a daily roll the maximum - * total files would be (#days run) * (maxSizeRollBackups) - */ - public void setMaxSizeRollBackups(int maxBackups) - { - maxSizeRollBackups = maxBackups; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter - * taking a long argument from the setter taking a String argument by the JavaBeans {@link - * java.beans.Introspector Introspector}. - * - * @see #setMaxFileSize(String) - */ - public void setMaxFileSize(long maxFileSize) - { - this.maxFileSize = maxFileSize; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter - * taking a long argument from the setter taking a String argument by the JavaBeans {@link - * java.beans.Introspector Introspector}. - * - * @see #setMaxFileSize(String) - */ - public void setMaximumFileSize(long maxFileSize) - { - this.maxFileSize = maxFileSize; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      In configuration files, the MaxFileSize option takes an long integer in the range 0 - 2^63. You can - * specify the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed - * respectively in kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240. - */ - public void setMaxFileSize(String value) - { - maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); - } - - protected void setQWForFiles(Writer writer) - { - qw = new CountingQuietWriter(writer, errorHandler); - } - - // Taken verbatum from DailyRollingFileAppender - int computeCheckPeriod() - { - RollingCalendar c = new RollingCalendar(); - // set sate to 1970-01-01 00:00:00 GMT - Date epoch = new Date(0); - if (datePattern != null) - { - for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) - { - String r0 = sdf.format(epoch); - c.setType(i); - Date next = new Date(c.getNextCheckMillis(epoch)); - String r1 = sdf.format(next); - // LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); - if ((r0 != null) && (r1 != null) && !r0.equals(r1)) - { - return i; - } - } - } - - return TOP_OF_TROUBLE; // Deliberately head for trouble... - } - - // Now for the new stuff - /** - * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked - * first) or time (checked second) is need and then appends to the file last. - */ - protected void subAppend(LoggingEvent event) - { - - if (rollDate) - { - long n = System.currentTimeMillis(); - if (n >= nextCheck) - { - now.setTime(n); - nextCheck = rc.getNextCheckMillis(now); - - rollOverTime(); - } - } - - if (rollSize) - { - if ((fileName != null) && (((CountingQuietWriter) qw).getCount() >= maxFileSize)) - { - rollOverSize(); - } - } - - super.subAppend(event); - } - - public void setFile(String file) - { - baseFileName = file.trim(); - fileName = file.trim(); - } - - /** - * Creates and opens the file for logging. If staticLogFileName is false then the fully qualified name - * is determined and used. - */ - public synchronized void setFile(String fileName, boolean append) throws IOException - { - if (!staticLogFileName) - { - scheduledFilename = fileName = fileName.trim() + sdf.format(now); - if (countDirection > 0) - { - scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); - } - } - - super.setFile(fileName, append, bufferedIO, bufferSize); - - if (append) - { - File f = new File(fileName); - ((CountingQuietWriter) qw).setCount(f.length()); - } - } - - public int getCountDirection() - { - return countDirection; - } - - public void setCountDirection(int direction) - { - countDirection = direction; - } - - public int getRollingStyle() - { - return rollingStyle; - } - - public void setRollingStyle(int style) - { - rollingStyle = style; - switch (rollingStyle) - { - - case BY_SIZE: - rollDate = false; - rollSize = true; - break; - - case BY_DATE: - rollDate = true; - rollSize = false; - break; - - case BY_COMPOSITE: - rollDate = true; - rollSize = true; - break; - - default: - errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); - } - } - - /* - public void setRollingStyle(String style) { - if (style == S_BY_SIZE) { - rollingStyle = BY_SIZE; - } - else if (style == S_BY_DATE) { - rollingStyle = BY_DATE; - } - else if (style == S_BY_COMPOSITE) { - rollingStyle = BY_COMPOSITE; - } - } - */ - public boolean getStaticLogFileName() - { - return staticLogFileName; - } - - public void setStaticLogFileName(boolean s) - { - staticLogFileName = s; - } - - public void setStaticLogFileName(String value) - { - setStaticLogFileName(OptionConverter.toBoolean(value, true)); - } - - public boolean getCompressBackupFiles() - { - return compress; - } - - public void setCompressBackupFiles(boolean c) - { - compress = c; - } - - public boolean getCompressAsync() - { - return compressAsync; - } - - public void setCompressAsync(boolean c) - { - compressAsync = c; - if (compressAsync) - { - executor = Executors.newFixedThreadPool(1); - - compressor = new Compressor(); - } - } - - public boolean getZeroBased() - { - return zeroBased; - } - - public void setZeroBased(boolean z) - { - zeroBased = z; - } - - public String getBackupFilesToPath() - { - return backupFilesToPath; - } - - public void setbackupFilesToPath(String path) - { - File td = new File(path); - if (!td.exists()) - { - td.mkdirs(); - } - - backupFilesToPath = path; - } - - /** - * Initializes based on exisiting conditions at time of activateOptions. The following is done:
      - *
      A) determine curSizeRollBackups
      B) determine curTimeRollBackups (not implemented)
      C) initiates a - * roll over if needed for crossing a date boundary since the last run. - */ - protected void existingInit() - { - - if (zeroBased) - { - curSizeRollBackups = -1; - } - - curTimeRollBackups = 0; - - // part A starts here - String filter; - if (staticLogFileName || !rollDate) - { - filter = baseFileName + ".*"; - } - else - { - filter = scheduledFilename + ".*"; - } - - File f = new File(baseFileName); - f = f.getParentFile(); - if (f == null) - { - f = new File("."); - } - - LogLog.debug("Searching for existing files in: " + f); - String[] files = f.list(); - - if (files != null) - { - for (int i = 0; i < files.length; i++) - { - if (!files[i].startsWith(baseFileName)) - { - continue; - } - - int index = files[i].lastIndexOf("."); - - if (staticLogFileName) - { - int endLength = files[i].length() - index; - if ((baseFileName.length() + endLength) != files[i].length()) - { - // file is probably scheduledFilename + .x so I don't care - continue; - } - } - - try - { - int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); - LogLog.debug("From file: " + files[i] + " -> " + backup); - if (backup > curSizeRollBackups) - { - curSizeRollBackups = backup; - } - } - catch (Exception e) - { - // this happens when file.log -> file.log.yyyy-mm-dd which is normal - // when staticLogFileName == false - LogLog.debug("Encountered a backup file not ending in .x " + files[i]); - } - } - } - - LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); - // part A ends here - - // part B not yet implemented - - // part C - if (staticLogFileName && rollDate) - { - File old = new File(baseFileName); - if (old.exists()) - { - Date last = new Date(old.lastModified()); - if (!(sdf.format(last).equals(sdf.format(now)))) - { - scheduledFilename = baseFileName + sdf.format(last); - LogLog.debug("Initial roll over to: " + scheduledFilename); - rollOverTime(); - } - } - } - - LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); - // part C ends here - - } - - /** - * Sets initial conditions including date/time roll over information, first check, scheduledFilename, and calls - * existingInit to initialize the current # of backups. - */ - public void activateOptions() - { - - // REMOVE removed rollDate from boolean to enable Alex's change - if (datePattern != null) - { - now.setTime(System.currentTimeMillis()); - sdf = new SimpleDateFormat(datePattern); - int type = computeCheckPeriod(); - // printPeriodicity(type); - rc.setType(type); - // next line added as this removes the name check in rollOver - nextCheck = rc.getNextCheckMillis(now); - } - else - { - if (rollDate) - { - LogLog.error("Either DatePattern or rollingStyle options are not set for [" + name + "]."); - } - } - - existingInit(); - - if (rollDate && (fileName != null) && (scheduledFilename == null)) - { - scheduledFilename = fileName + sdf.format(now); - } - - try - { - this.setFile(fileName, true); - } - catch (IOException e) - { - errorHandler.error("Cannot set file name:" + fileName); - } - - super.activateOptions(); - } - - /** - * Rollover the file(s) to date/time tagged file(s). Opens the new file (through setFile) and resets - * curSizeRollBackups. - */ - protected void rollOverTime() - { - - curTimeRollBackups++; - - this.closeFile(); // keep windows happy. - - // delete the old stuff here - - if (staticLogFileName) - { - /* Compute filename, but only if datePattern is specified */ - if (datePattern == null) - { - errorHandler.error("Missing DatePattern option in rollOver()."); - - return; - } - - // is the new file name equivalent to the 'current' one - // something has gone wrong if we hit this -- we should only - // roll over if the new file will be different from the old - String dateFormat = sdf.format(now); - if (scheduledFilename.equals(fileName + dateFormat)) - { - errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); - - return; - } - - // close current file, and rename it to datedFilename - this.closeFile(); - - // we may have to roll over a large number of backups here - String from, to; - for (int i = 1; i <= curSizeRollBackups; i++) - { - from = fileName + '.' + i; - to = scheduledFilename + '.' + i; - rollFile(from, to, false); - } - - rollFile(fileName, scheduledFilename, compress); - } - else - { - if (compress) - { - compress(fileName); - } - } - - try - { - // This will also close the file. This is OK since multiple - // close operations are safe. - curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new - - // new scheduled name - scheduledFilename = fileName + sdf.format(now); - this.setFile(baseFileName, false); - } - catch (IOException e) - { - errorHandler.error("setFile(" + fileName + ", false) call failed."); - } - - } - - /** - * Renames file from to file to. It also checks for existence of target file and deletes - * if it does. - */ - protected void rollFile(String from, String to, boolean compress) - { - if (from.equals(to)) - { - if (compress) - { - LogLog.debug("Attempting to compress file with same output name."); - } - - return; - } - - File target = new File(to); - if (target.exists()) - { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } - - File file = new File(from); - if (compress) - { - compress(file, target); - } - else - { - if (!file.getPath().equals(target.getPath())) - { - file.renameTo(target); - } - } - - LogLog.debug(from + " -> " + to); - } - - protected void compress(String file) - { - File f = new File(file); - compress(f, f); - } - - private void compress(File from, File target) - { - if (compressAsync) - { - synchronized (_compress) - { - _compress.offer(new CompressJob(from, target)); - } - - startCompression(); - } - else - { - doCompress(from, target); - } - } - - private void startCompression() - { - if (_compressing.compareAndSet(false, true)) - { - executor.execute(compressor); - } - } - - /** Delete's the specified file if it exists */ - protected static void deleteFile(String fileName) - { - File file = new File(fileName); - if (file.exists()) - { - file.delete(); - } - } - - /** - * Implements roll overs base on file size. - * - *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If - * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} - * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is - * renamed File.1 and closed.
      - * - * A new file is created to receive further log output. - * - *

      If maxSizeRollBackups is equal to zero, then the File is truncated with no backup - * files created. - * - *

      If maxSizeRollBackups < 0, then File is renamed if needed and no files are deleted. - */ - - // synchronization not necessary since doAppend is alreasy synched - protected void rollOverSize() - { - File file; - - this.closeFile(); // keep windows happy. - - LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); - LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); - LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); - LogLog.debug("countDirection = " + countDirection); - - // If maxBackups <= 0, then there is no file renaming to be done. - if (maxSizeRollBackups != 0) - { - - if (countDirection < 0) - { - // Delete the oldest file, to keep Windows happy. - if (curSizeRollBackups == maxSizeRollBackups) - { - deleteFile(fileName + '.' + maxSizeRollBackups); - curSizeRollBackups--; - } - - // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} - for (int i = curSizeRollBackups; i >= 1; i--) - { - rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); - } - - curSizeRollBackups++; - // Rename fileName to fileName.1 - rollFile(fileName, fileName + ".1", compress); - - } // REMOVE This code branching for Alexander Cerna's request - else if (countDirection == 0) - { - // rollFile based on date pattern - curSizeRollBackups++; - now.setTime(System.currentTimeMillis()); - scheduledFilename = fileName + sdf.format(now); - rollFile(fileName, scheduledFilename, compress); - } - else - { // countDirection > 0 - if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) - { - // delete the first and keep counting up. - int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; - deleteFile(fileName + '.' + oldestFileIndex); - } - - if (staticLogFileName) - { - curSizeRollBackups++; - rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); - } - else - { - if (compress) - { - compress(fileName); - } - } - } - } - - try - { - // This will also close the file. This is OK since multiple - // close operations are safe. - this.setFile(baseFileName, false); - } - catch (IOException e) - { - LogLog.error("setFile(" + fileName + ", false) call failed.", e); - } - } - - protected synchronized void doCompress(File from, File to) - { - String toFile; - if (backupFilesToPath == null) - { - toFile = to.getPath() + ".gz"; - } - else - { - toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; - } - - File target = new File(toFile); - if (target.exists()) - { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } - - try - { - // Create the GZIP output stream - GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); - - // Open the input file - FileInputStream in = new FileInputStream(from); - - // Transfer bytes from the input file to the GZIP output stream - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) - { - out.write(buf, 0, len); - } - - in.close(); - - // Complete the GZIP file - out.finish(); - out.close(); - // Remove old file. - from.delete(); - } - catch (IOException e) - { - if (target.exists()) - { - target.delete(); - } - - rollFile(from.getPath(), to.getPath(), false); - } - } - - private class CompressJob - { - File _from, _to; - - CompressJob(File from, File to) - { - _from = from; - _to = to; - } - - File getFrom() - { - return _from; - } - - File getTo() - { - return _to; - } - } - - Compressor compressor = null; - - Executor executor; - - private class Compressor implements Runnable - { - public void run() - { - boolean running = true; - while (running) - { - CompressJob job = _compress.poll(); - - doCompress(job.getFrom(), job.getTo()); - - synchronized (_compress) - { - if (_compress.isEmpty()) - { - running = false; - _compressing.set(false); - } - } - } - - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java deleted file mode 100644 index 40ff590a0a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.configuration; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -public class Configuration -{ - public static final String QPID_HOME = "QPID_HOME"; - - final String QPIDHOME = System.getProperty(QPID_HOME); - - private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); - - public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - protected final Options _options = new Options(); - protected CommandLine _commandLine; - protected File _configFile; - - - public Configuration() - { - - } - - public void processCommandline(String[] args) throws InitException - { - try - { - _commandLine = new PosixParser().parse(_options, args); - } - catch (ParseException e) - { - throw new InitException("Unable to parse commmandline", e); - } - - final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); - setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); - } - - public void setConfig(File file) - { - _configFile = file; - } - - /** - * @param option The option to set. - */ - public void setOption(Option option) - { - _options.addOption(option); - } - - /** - * getOptionValue from the configuration - * @param option variable argument, first string is option to get, second if present is the default value. - * @return the String for the given option or null if not present (if default value not specified) - */ - public String getOptionValue(String... option) - { - if (option.length == 1) - { - return _commandLine.getOptionValue(option[0]); - } - else if (option.length == 2) - { - return _commandLine.getOptionValue(option[0], option[1]); - } - return null; - } - - public void loadConfig(File file) throws InitException - { - setConfig(file); - loadConfig(); - } - - private void loadConfig() throws InitException - { - 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, null); - } - else - { - _devlog.debug("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); -// } - } - - -// private void configureLogging(File logConfigFile, String logWatchConfig) -// { -// int logWatchTime = 0; -// try -// { -// logWatchTime = Integer.parseInt(logWatchConfig); -// } -// catch (NumberFormatException e) -// { -// _devlog.error("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()) -// { -// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); -// if (logWatchTime > 0) -// { -// _devlog.info("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(); -// } -// } - - public File getConfigFile() - { - return _configFile; - } - - - public class InitException extends Exception - { - InitException(String msg, Throwable cause) - { - super(msg, cause); - } - } -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java deleted file mode 100644 index 6d67686d1c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedBroker; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -/** - * This MBean 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") -public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBroker -{ - private final QueueRegistry _queueRegistry; - private final ExchangeRegistry _exchangeRegistry; - private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; - - private final VirtualHost.VirtualHostMBean _virtualHostMBean; - - @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException - { - super(ManagedBroker.class, ManagedBroker.TYPE); - - _virtualHostMBean = virtualHostMBean; - VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); - - _queueRegistry = virtualHost.getQueueRegistry(); - _exchangeRegistry = virtualHost.getExchangeRegistry(); - _messageStore = virtualHost.getMessageStore(); - _exchangeFactory = virtualHost.getExchangeFactory(); - } - - public String getObjectInstanceName() - { - return _virtualHostMBean.getVirtualHost().getName(); - } - - /** - * Creates new exchange and registers it with the registry. - * - * @param exchangeName - * @param type - * @param durable - * @throws JMException - */ - public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException - { - try - { - synchronized (_exchangeRegistry) - { - Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); - if (exchange == null) - { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), - new AMQShortString(type), durable, false, 0); - _exchangeRegistry.registerExchange(exchange); - } - else - { - throw new JMException("The exchange \"" + exchangeName + "\" already exists."); - } - } - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error in creating exchange " + exchangeName); - } - } - - /** - * Unregisters the exchange from registry. - * - * @param exchangeName - * @throws JMException - */ - public void unregisterExchange(String exchangeName) throws JMException - { - // TODO - // Check if the exchange is in use. - // boolean inUse = false; - // Check if there are queue-bindings with the exchange and unregister - // when there are no bindings. - try - { - _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); - } - } - - /** - * 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 - * @throws JMException - */ - public void createNewQueue(String queueName, String owner, boolean durable) throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue != null) - { - throw new JMException("The queue \"" + queueName + "\" already exists."); - } - - try - { - AMQShortString ownerShortString = null; - if (owner != null) - { - ownerShortString = new AMQShortString(owner); - } - - queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); - if (queue.isDurable() && !queue.isAutoDelete()) - { - //DTX MessageStore -// try -// { - _messageStore.createQueue(queue); -// } -// catch (Exception e) -// { -// JMException jme = new JMException("problem creating queue " + queue.getName()); -// jme.initCause(e); -// throw jme; -// } - } - - Configuration virtualHostDefaultQueueConfiguration = - VirtualHostConfiguration.getDefaultQueueConfiguration(queue); - if (virtualHostDefaultQueueConfiguration != null) - { - Configurator.configure(queue, virtualHostDefaultQueueConfiguration); - } - - _queueRegistry.registerQueue(queue); - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error in creating queue " + queueName); - } - } - - private VirtualHost getVirtualHost() - { - return _virtualHostMBean.getVirtualHost(); - } - - /** - * Deletes the queue from queue registry and persistant storage. - * - * @param queueName - * @throws JMException - */ - public void deleteQueue(String queueName) throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("The Queue " + queueName + " is not a registerd queue."); - } - - try - { - queue.delete(); - - //DTX MessageStore -// if (queue.isDurable()) -// { -// _messageStore.destroyQueue(queue); - _messageStore.removeQueue(queue.getName()); -// } - } - catch (Exception ex) - { - /*ex.printStackTrace(); - JMException jme = new JMException(ex.getMessage());*/ - throw new MBeanException(ex, "Error in deleting queue " + queueName); - } - } - - public ManagedObject getParentObject() - { - return _virtualHostMBean; - } - - // This will have a single instance for a virtual host, so not having the name property in the ObjectName - public ObjectName getObjectName() throws MalformedObjectNameException - { - return getObjectNameForSingleInstanceMBean(); - } -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java deleted file mode 100644 index bd93ae2f85..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ /dev/null @@ -1,980 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQShortString; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -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.exchange.NoRouteException; -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.queue.Subscription; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.txn.TransactionalContext; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -public class AMQChannel -{ - public static final int DEFAULT_PREFETCH = 5000; - - private static final Logger _log = Logger.getLogger(AMQChannel.class); - - private final int _channelId; - - // private boolean _transactional; - - private long _prefetch_HighWaterMark; - - private long _prefetch_LowWaterMark; - - private long _prefetchSize; - - /** - * 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 HashMap(); - - private final MessageStore _messageStore; - - private final TransactionManager _transactionManager; - - private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - - private final AtomicBoolean _suspended = new AtomicBoolean(false); - - private final MessageRouter _exchanges; - - private TransactionalContext _txnContext, _nonTransactedContext; - - /** - * A context used by the message store enabling it to track context for a given channel even across thread - * boundaries - */ - private final StoreContext _storeContext; - - private final List _returnMessages = new LinkedList(); - - private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); - - private Set _browsedAcks = new HashSet(); - - // Why do we need this reference ? - ritchiem - private final AMQProtocolSession _session; - private boolean _closing; - - public AMQChannel(AMQProtocolSession session, int channelId, TransactionManager transactionManager, - MessageStore messageStore, MessageRouter exchanges) throws AMQException - { - _session = session; - _channelId = channelId; - _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); - _prefetch_HighWaterMark = DEFAULT_PREFETCH; - _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; - _messageStore = messageStore; - _transactionManager = transactionManager; - _exchanges = exchanges; - // by default the session is non-transactional - _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); - } - - /** Sets this channel to be part of a local transaction */ - public void setLocalTransactional() - { - - _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); - - // Why is the LocalTransactionalContext always a DTX one? -// _txnContext = -// new DistributedTransactionalContext(_transactionManager, _messageStore, _storeContext, _returnMessages); - } - - public boolean isTransactional() - { - // this does not look great but there should only be one "non-transactional" - // transactional context, while there could be several transactional ones in - // theory - return !(_txnContext instanceof NonTransactionalContext); - } - - public int getChannelId() - { - return _channelId; - } - - public long getPrefetchCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - public long getPrefetchSize() - { - return _prefetchSize; - } - - public void setPrefetchSize(long prefetchSize) - { - _prefetchSize = prefetchSize; - } - - public long getPrefetchLowMarkCount() - { - return _prefetch_LowWaterMark; - } - - public void setPrefetchLowMarkCount(long prefetchCount) - { - _prefetch_LowWaterMark = prefetchCount; - } - - public long getPrefetchHighMarkCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchHighMarkCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher) throws AMQException - { - - _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); - _currentMessage.setPublisher(publisher); - } - - public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException(null, "Received content header without previously receiving a BasicPublish frame", null); - } - else - { - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "Content header received on channel " + _channelId); - } - - _currentMessage.setContentHeaderBody(contentHeaderBody); - _currentMessage.setExpiration(); - - routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); - - // check and deliver if header says body length is zero - if (contentHeaderBody.bodySize == 0) - { - _txnContext.messageProcessed(protocolSession); - _currentMessage = null; - } - } - } - - public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException(null, "Received content body without previously receiving a JmsPublishBody", null); - } - - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "Content body received on channel " + _channelId); - } - - try - { - - // returns true iff the message was delivered (i.e. if all data was - // received - if (_currentMessage.addContentBodyFrame(_storeContext, - protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody))) - { - // callback to allow the context to do any post message processing - // primary use is to allow message return processing in the non-tx case - _txnContext.messageProcessed(protocolSession); - _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 - { - try - { - _exchanges.routeContent(_currentMessage); - } - catch (NoRouteException e) - { - _returnMessages.add(e); - } - } - - 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 - * @param noLocal Flag stopping own messages being receivied. - * @param exclusive Flag requesting exclusive access to the queue - * @param acks Are acks enabled for this subscriber - * @param filters Filters to apply to this 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 AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException - { - if (tag == null) - { - tag = new AMQShortString("sgen_" + getNextConsumerTag()); - } - - if (_consumerTag2QueueMap.containsKey(tag)) - { - throw new ConsumerTagNotUniqueException(); - } - - queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive); - _consumerTag2QueueMap.put(tag, queue); - - return tag; - } - - public void unsubscribeConsumer(AMQProtocolSession session, final AMQShortString consumerTag) throws AMQException - { - final AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); - if (q != null) - { - q.unregisterProtocolSession(session, _channelId, consumerTag); - } - } - - /** - * Called from the protocol session to close this channel and clean up. T - * - * @param session The session to close - * - * @throws AMQException if there is an error during closure - */ - public void close(AMQProtocolSession session) throws AMQException - { - _txnContext.rollback(); - unsubscribeAllConsumers(session); - requeue(); - - setClosing(true); - } - - private void setClosing(boolean closing) - { - _closing = closing; - } - - private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException - { - if (_log.isInfoEnabled()) - { - if (!_consumerTag2QueueMap.isEmpty()) - { - _log.info("Unsubscribing all consumers on channel " + toString()); - } - else - { - _log.info("No consumers to unsubscribe on channel " + toString()); - } - } - - for (Map.Entry me : _consumerTag2QueueMap.entrySet()) - { - if (_log.isInfoEnabled()) - { - _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); - } - - 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 consumerTag The tag for the consumer that is to acknowledge this message. - * @param queue the queue from which the message was delivered - */ - public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, AMQShortString consumerTag, AMQQueue queue) - { - if (_log.isDebugEnabled()) - { - if (queue == null) - { - _log.debug("Adding unacked message with a null queue:" + message.debugIdentity()); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + " Adding unacked message(" + message.toString() + " DT:" + deliveryTag - + ") with a queue(" + queue + ") for " + consumerTag); - } - } - } - - synchronized (_unacknowledgedMessageMap.getLock()) - { - _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); - checkSuspension(); - } - } - - private final String id = "(" + System.identityHashCode(this) + ")"; - - public String debugIdentity() - { - return _channelId + id; - } - - /** - * Called to attempt re-delivery 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(); - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext = null; - - if (!messagesToBeDelivered.isEmpty()) - { - if (_log.isInfoEnabled()) - { - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); - } - - if (!(_txnContext instanceof NonTransactionalContext)) - { - // if (_nonTransactedContext == null) - { - _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); - } - - deliveryContext = _nonTransactedContext; - } - else - { - deliveryContext = _txnContext; - } - } - - for (UnacknowledgedMessage unacked : messagesToBeDelivered) - { - if (unacked.queue != null) - { - // Ensure message is released for redelivery - unacked.message.release(unacked.queue); - - // Mark message redelivered - unacked.message.setRedelivered(true); - - // Deliver Message - deliveryContext.deliver(unacked.message, unacked.queue, true); - - // Should we allow access To the DM to directy deliver the message? - // As we don't need to check for Consumers or worry about incrementing the message count? - // unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); - } - } - - } - - /** - * Requeue a single message - * - * @param deliveryTag The message to requeue - * - * @throws AMQException If something goes wrong. - */ - public void requeue(long deliveryTag) throws AMQException - { - UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); - - if (unacked != null) - { - - // Ensure message is released for redelivery - if (unacked.queue != null) - { - unacked.message.release(unacked.queue); - } - - // Mark message redelivered - unacked.message.setRedelivered(true); - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - // if (_nonTransactedContext == null) - { - _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); - } - - deliveryContext = _nonTransactedContext; - } - else - { - deliveryContext = _txnContext; - } - - if (unacked.queue != null) - { - // Redeliver the messages to the front of the queue - deliveryContext.deliver(unacked.message, unacked.queue, true); - // Deliver increments the message count but we have already deliverted this once so don't increment it again - // this was because deliver did an increment changed this. - } - else - { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.message.debugIdentity() - + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - // _log.error("Requested requeue of message:" + deliveryTag + - // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); - // - // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); - // - } - } - else - { - _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." - + _unacknowledgedMessageMap.size()); - - if (_log.isDebugEnabled()) - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - int count = 0; - - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - _log.debug( - (count++) + ": (" + message.message.debugIdentity() + ")" + "[" + message.deliveryTag + "]"); - - return false; // Continue - } - - public void visitComplete() - { - } - }); - } - } - - } - - /** - * Called to resend all outstanding unacknowledged messages to this same channel. - * - * @param requeue Are the messages to be requeued or dropped. - * - * @throws AMQException When something goes wrong. - */ - public void resend(final boolean requeue) throws AMQException - { - final List msgToRequeue = new LinkedList(); - final List msgToResend = new LinkedList(); - - if (_log.isDebugEnabled()) - { - _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); - } - - // Process the Unacked-Map. - // Marking messages who still have a consumer for to be resent - // and those that don't to be requeued. - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - AMQShortString consumerTag = message.consumerTag; - AMQMessage msg = message.message; - msg.setRedelivered(true); - if (consumerTag != null) - { - // Consumer exists - if (_consumerTag2QueueMap.containsKey(consumerTag)) - { - msgToResend.add(message); - } - else // consumer has gone - { - msgToRequeue.add(message); - } - } - else - { - // Message has no consumer tag, so was "delivered" to a GET - // or consumer no longer registered - // cannot resend, so re-queue. - if (message.queue != null) - { - if (requeue) - { - msgToRequeue.add(message); - } - else - { - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); - } - } - else - { - _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); - } - } - - // false means continue processing - return false; - } - - public void visitComplete() - { - } - }); - - // Process Messages to Resend - if (_log.isDebugEnabled()) - { - if (!msgToResend.isEmpty()) - { - _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); - } - else - { - _log.debug("No message to resend."); - } - } - - for (UnacknowledgedMessage message : msgToResend) - { - AMQMessage msg = message.message; - - // Our Java Client will always suspend the channel when resending! - // If the client has requested the messages be resent then it is - // their responsibility to ensure that thay are capable of receiving them - // i.e. The channel hasn't been server side suspended. - // if (isSuspended()) - // { - // _log.info("Channel is suspended so requeuing"); - // //move this message to requeue - // msgToRequeue.add(message); - // } - // else - // { - // release to allow it to be delivered - msg.release(message.queue); - - // Without any details from the client about what has been processed we have to mark - // all messages in the unacked map as redelivered. - msg.setRedelivered(true); - - Subscription sub = msg.getDeliveredSubscription(message.queue); - - if (sub != null) - { - // Get the lock so we can tell if the sub scription has closed. - // will stop delivery to this subscription until the lock is released. - // note: this approach would allow the use of a single queue if the - // PreDeliveryQueue would allow head additions. - // In the Java Qpid client we are suspended whilst doing this so it is all rather Mute.. - // needs guidance from AMQP WG Model SIG - synchronized (sub.getSendLock()) - { - if (sub.isClosed()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Subscription(" + System.identityHashCode(sub) - + ") closed during resend so requeuing message"); - } - // move this message to requeue - msgToRequeue.add(message); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" - + System.identityHashCode(sub)); - } - - sub.addToResendQueue(msg); - _unacknowledgedMessageMap.remove(message.deliveryTag); - } - } // sync(sub.getSendLock) - } - else - { - - if (_log.isInfoEnabled()) - { - _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() - + ")to prevent loss"); - } - // move this message to requeue - msgToRequeue.add(message); - } - } // for all messages - // } else !isSuspend - - if (_log.isInfoEnabled()) - { - if (!msgToRequeue.isEmpty()) - { - _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); - } - } - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - if (_nonTransactedContext == null) - { - _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages, _browsedAcks); - } - - deliveryContext = _nonTransactedContext; - } - else - { - deliveryContext = _txnContext; - } - - // Process Messages to Requeue at the front of the queue - for (UnacknowledgedMessage message : msgToRequeue) - { - message.message.release(message.queue); - message.message.setRedelivered(true); - - deliveryContext.deliver(message.message, message.queue, true); - - _unacknowledgedMessageMap.remove(message.deliveryTag); - } - } - - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to - * remove the queue reference and also decrement any message reference counts, without actually removing the item - * since we may get an ack for a delivery tag that was generated from the deleted queue. - * - * @param queue the queue that has been deleted - * - * @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) - { - try - { - message.discard(_storeContext); - message.queue = null; - } - 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 - { - synchronized (_unacknowledgedMessageMap.getLock()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Unacked (PreAck) Size:" + _unacknowledgedMessageMap.size()); - } - - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); - - if (_log.isDebugEnabled()) - { - _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size()); - } - - } - - checkSuspension(); - } - - /** - * Used only for testing purposes. - * - * @return the map of unacknowledged messages - */ - public UnacknowledgedMessageMap getUnacknowledgedMessageMap() - { - return _unacknowledgedMessageMap; - } - - private void checkSuspension() - { - boolean suspend; - - suspend = - ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) - || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); - - setSuspended(suspend); - } - - public void setSuspended(boolean suspended) - { - boolean isSuspended = _suspended.get(); - - if (isSuspended && !suspended) - { - // Continue being suspended if we are above the _prefetch_LowWaterMark - suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; - } - - boolean wasSuspended = _suspended.getAndSet(suspended); - if (wasSuspended != suspended) - { - if (wasSuspended) - { - _log.debug("Unsuspending channel " + this); - // may need to deliver queued messages - for (AMQQueue q : _consumerTag2QueueMap.values()) - { - q.deliverAsync(); - } - } - else - { - _log.debug("Suspending channel " + this); - } - } - } - - public boolean isSuspended() - { - return _suspended.get(); - } - - public void commit() throws AMQException - { - if (!isTransactional()) - { - throw new AMQException(null, "Fatal error: commit called on non-transactional channel", null); - } - - _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 mode: ").append(isTransactional()); - sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); - sb.append("/").append(_prefetch_HighWaterMark); - - return sb.toString(); - } - - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } - - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void processReturns(AMQProtocolSession session) throws AMQException - { - for (RequiredDeliveryException bouncedMessage : _returnMessages) - { - AMQMessage message = bouncedMessage.getAMQMessage(); - session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); - } - - _returnMessages.clear(); - } - - public boolean wouldSuspend(AMQMessage msg) - { - if (isSuspended()) - { - return true; - } - else - { - boolean willSuspend = - ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); - if (!willSuspend) - { - final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); - - willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < (msg.getSize() + unackedSize)); - } - - if (willSuspend) - { - setSuspended(true); - } - - return willSuspend; - } - - } - - public TransactionalContext getTransactionalContext() - { - return _txnContext; - } - - public boolean isClosing() - { - return _closing; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java deleted file mode 100644 index 3dc2654bd5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -/** - * ConsumerTagNotUniqueException indicates that a client has attempted to connect with a consumer tag that is already - * used. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents error when clients connects with a non-unique tag. - *
      - * - * @todo Consider replacing with an AMQNotAllowedException, as this is the status code returned when this happens. - */ -public class ConsumerTagNotUniqueException extends Exception -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java deleted file mode 100644 index 8932dd25f0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.commons.cli.CommandLine; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.common.SimpleByteBufferAllocator; -import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; -import org.apache.mina.transport.socket.nio.SocketSessionConfig; -import org.apache.qpid.AMQException; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; -import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; -import org.apache.qpid.server.protocol.AMQPProtocolProvider; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.transport.ConnectorConfiguration; -import org.apache.qpid.url.URLSyntaxException; - -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.List; - -/** - * Main entry point for AMQPD. - * - */ -@SuppressWarnings({"AccessStaticViaInstance"}) -public class Main -{ - /** Used for debugging. */ - private static final Logger _logger = Logger.getLogger(Main.class); - - /** Used for logging operator messages. */ - public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); - - private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - public static final String QPID_HOME = "QPID_HOME"; - private static final int IPV4_ADDRESS_LENGTH = 4; - - private static final char IPV4_LITERAL_SEPARATOR = '.'; - - protected static class InitException extends Exception - { - InitException(String msg, Throwable cause) - { - super(msg, cause); - } - } - - protected final Options options = new Options(); - protected CommandLine commandLine; - - /** - * @todo Side-effecting constructor; eliminate. Put the processing sequence in the main method. - */ - 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; - } - } - - /** - * Sets up the command line options, with usage help, ready for parsing the command line against. - * - * @param options The object to store the configured command line options in. - */ - 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 mport = - OptionBuilder.withArgName("mport").hasArg() - .withDescription("listen on the specified management port. Overrides any value in the config file") - .withLongOpt("mport").create("m"); - - - 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(mport); - options.addOption(bind); - } - - /** - * @todo Handles command line, but there is already a parse command line method. Put all command line handling - * in a single flow of control. Also part implements the top-level handler, which would more neatly be kept - * together in one place. - */ - 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 = QpidProperties.getVersionString(); - - StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: "); - - boolean first = true; - for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) - { - if (first) - { - first = false; - } - else - { - protocol.append(", "); - } - - protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); - - } - - System.out.println(ver + " (" + protocol + ")"); - } - else - { - try - { - startup(); - } - catch (InitException e) - { - System.out.println(e.getMessage()); - _brokerLogger.error("Initialisation Error : " + e.getMessage()); - - } - catch (ConfigurationException e) - { - System.out.println("Error configuring message broker: " + e); - _brokerLogger.error("Error configuring message broker: " + e); - e.printStackTrace(); - } - catch (Exception e) - { - System.out.println("Error intialising message broker: " + e); - _brokerLogger.error("Error intialising message broker: " + e); - e.printStackTrace(); - } - } - } - - /** - * Reads the configuration file and performs configuration specified in it. Then hands over to bind to do the - * actual broker start-up. - * - * @todo A bit confusing, seperate out configuration from start-up. Call config method to handle the configuration - * from the config file, in the main flow of control (possibly #main method). Then call #startup or #bind - * to start the broker. - */ - 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, null); - } - 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); - } - - ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); - - - updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); - - - - ApplicationRegistry.initialise(config); - - - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues - // that are causing the broker build to pick up the wrong properties file and hence say - // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - - ConnectorConfiguration connectorConfig = - ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); - - ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); - - // the MINA default is currently to use the pooled allocator although this may change in future - // once more testing of the performance of the simple allocator has been done - if (!connectorConfig.enablePooledAllocator) - { - ByteBuffer.setAllocator(new 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, e); - } - } - - 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); - - } - - /** - * Update the configuration data with the management port. - * @param configuration - * @param managementPort The string from the command line - */ - private void updateManagementPort(Configuration configuration, String managementPort) - { - if (managementPort != null) - { - int mport; - int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); - try - { - mport = Integer.parseInt(managementPort); - configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); - } - catch (NumberFormatException e) - { - _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); - } - } - } - - 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(); - } - } - } - } - - /** - * Assembles/configures the components that Mina needs, then start Mina running to accept connections. - * - * @todo Partially implements top-level error handler. Better to let these errors fall through to a single - * top-level handler. - */ - protected void bind(int port, ConnectorConfiguration connectorConfig) throws BindException - { - 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(ReadWriteThreadModel.getInstance()); - } - - if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) - { - 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); - // fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); - } - - if (connectorConfig.enableSSL) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - try - { - - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); - // fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); - - } - catch (IOException e) - { - _brokerLogger.error("Unable to listen on SSL port: " + e, e); - } - } - - // fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - } - catch (Exception e) - { - _logger.error("Unable to bind service to registry: " + e, e); - //fixme this need tidying up - throw new BindException(e.getMessage()); - } - } - - /** - * Processes the command line and starts the broker running. This method acts as a top-level error handler for - * any exceptions that fall out of the code below this point. These exceptions are logged before System.exit is - * called with an error code. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - // Use a try block so that any exceptions that fall through to the top-level are logged before the application - // exits with an error code. - // try - { - // Parse the command line. - - // Create an instance of the Main broker entry point class and start it running. - } - // catch () - { - // Log the exception as an error. - - // Exit with an error code. - } - - new Main(args); - } - - private byte[] parseIP(String address) throws Exception - { - char[] literalBuffer = address.toCharArray(); - int byteCount = 0; - int currByte = 0; - byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; - for (int i = 0; i < literalBuffer.length; i++) - { - char currChar = literalBuffer[i]; - if ((currChar >= '0') && (currChar <= '9')) - { - currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); - } - - if ((currChar == IPV4_LITERAL_SEPARATOR) || ((i + 1) == literalBuffer.length)) - { - ip[byteCount++] = (byte) currByte; - currByte = 0; - } - } - - if (byteCount != 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(); - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java deleted file mode 100644 index e76f9c3f6c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server; - -import java.io.IOException; - -import javax.management.JMException; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java deleted file mode 100644 index 37c5f38ea3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the - * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. - * - *

      The failed message is associated with this error condition, by taking a reference to it. This enables the - * correct compensating action to be taken against the message, for example, bouncing it back to the sender. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      Associate the failed message with the error condition. {@link AMQMessage} - *
      - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private final AMQMessage _amqMessage; - - public RequiredDeliveryException(String message, AMQMessage payload, Throwable cause) - { - super(null, message, cause); - - // Increment the reference as this message is in the routing phase - // and so will have the ref decremented as routing fails. - // we need to keep this message around so we can return it in the - // handler. So increment here. - _amqMessage = payload.takeReference(); - - // payload.incrementReference(); - } - - public AMQMessage getAMQMessage() - { - return _amqMessage; - } - - public AMQConstant getErrorCode() - { - return getReplyCode(); - } - - public abstract AMQConstant getReplyCode(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java deleted file mode 100644 index 5ca8d57f7c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TxnOp; - -/** - * 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(StoreContext storeContext) throws AMQException - { - //make persistent changes, i.e. dequeue and decrementReference - for (UnacknowledgedMessage msg : _unacked) - { - msg.restoreTransientMessageData(); - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(storeContext); - } - } - - public void undoPrepare() - { - //decrementReference is annoyingly untransactional (due to - //in memory counter) so if we failed in prepare for full - //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for (UnacknowledgedMessage msg : _unacked) - { - msg.clearTransientMessageData(); - msg.message.takeReference(); - } - } - - public void commit(StoreContext storeContext) - { - //remove the unacked messages from the channels map - _map.remove(_unacked); - for (UnacknowledgedMessage msg : _unacked) - { - msg.clearTransientMessageData(); - } - - } - - public void rollback(StoreContext storeContext) - { - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java deleted file mode 100644 index b8c5e821f7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -public class UnacknowledgedMessage -{ - public final AMQMessage message; - public final AMQShortString consumerTag; - public final long deliveryTag; - public AMQQueue queue; - - public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, AMQShortString consumerTag, long deliveryTag) - { - this.queue = queue; - this.message = message; - this.consumerTag = consumerTag; - this.deliveryTag = deliveryTag; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("Q:"); - sb.append(queue); - sb.append(" M:"); - sb.append(message); - sb.append(" CT:"); - sb.append(consumerTag); - sb.append(" DT:"); - sb.append(deliveryTag); - - return sb.toString(); - } - - public void discard(StoreContext storeContext) throws AMQException - { - if (queue != null) - { - message.dequeue(storeContext, queue); - } - //if the queue is null then the message is waiting to be acked, but has been removed. - message.decrementReference(storeContext); - } - - public void restoreTransientMessageData() throws AMQException - { - message.restoreTransientMessageData(); - } - - public void clearTransientMessageData() - { - message.clearTransientMessageData(); - } -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java deleted file mode 100644 index b69a917081..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TransactionalContext; - -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; - - Object getLock(); - - 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(); - - UnacknowledgedMessage get(long deliveryTag); - - /** - * Get the set of delivery tags that are outstanding. - * - * @return a set of delivery tags - */ - Set getDeliveryTags(); - - public long getUnacknowledgeBytes(); -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java deleted file mode 100644 index 1604d94539..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.txn.TransactionalContext; - -public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap -{ - private final Object _lock = new Object(); - - private long _unackedSize; - - 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) - { - remove(msg.deliveryTag); - } - } - } - - public UnacknowledgedMessage remove(long deliveryTag) - { - synchronized (_lock) - { - - UnacknowledgedMessage message = _map.remove(deliveryTag); - if(message != null) - { - _unackedSize -= message.message.getSize(); - } - - return message; - } - } - - public void visit(Visitor visitor) throws AMQException - { - synchronized (_lock) - { - Collection currentEntries = _map.values(); - for (UnacknowledgedMessage msg : currentEntries) - { - visitor.callback(msg); - } - visitor.visitComplete(); - } - } - - public Object getLock() - { - return _lock; - } - - public void add(long deliveryTag, UnacknowledgedMessage message) - { - synchronized (_lock) - { - _map.put(deliveryTag, message); - _unackedSize += message.message.getSize(); - _lastDeliveryTag = deliveryTag; - } - } - - public Collection cancelAllMessages() - { - synchronized (_lock) - { - Collection currentEntries = _map.values(); - _map = new LinkedHashMap(_prefetchLimit); - _unackedSize = 0l; - 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(); - _unackedSize = 0l; - } - } - - 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(null, "UnacknowledgedMessageMap is out of order:" + unacked.getKey() + - " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString(), null); - } - - it.remove(); - _unackedSize -= unacked.getValue().message.getSize(); - - destination.add(unacked.getValue()); - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - } - - public UnacknowledgedMessage get(long key) - { - synchronized (_lock) - { - return _map.get(key); - } - } - - public Set getDeliveryTags() - { - synchronized (_lock) - { - return _map.keySet(); - } - } - - private void collect(long key, List msgs) - { - synchronized (_lock) - { - for (Map.Entry entry : _map.entrySet()) - { - msgs.add(entry.getValue()); - if (entry.getKey() == key) - { - break; - } - } - } - } - - public long getUnacknowledgeBytes() - { - return _unackedSize; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java deleted file mode 100644 index 31c1b61a21..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import java.lang.reflect.Field; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.configuration.PropertyException; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.server.registry.ApplicationRegistry; - -/** - * This class contains utilities for populating classes automatically from values pulled from configuration - * files. - */ -public class Configurator -{ - private static final Logger _logger = Logger.getLogger(Configurator.class); - - - /** - * Configure a given instance using the supplied configuration. Note that superclasses are not - * currently configured but this could easily be added if required. - * @param instance the instance to configure - * @param config the configuration to use to configure the object - */ - public static void configure(Object instance, Configuration config) - { - - for (Field f : instance.getClass().getDeclaredFields()) - { - Configured annotation = f.getAnnotation(Configured.class); - if (annotation != null) - { - setValueInField(f, instance, config, annotation); - } - } - } - - - - /** - * Configure a given instance using the application configuration. Note that superclasses are not - * currently configured but this could easily be added if required. - * @param instance the instance to configure - */ - public static void configure(Object instance) - { - configure(instance, ApplicationRegistry.getInstance().getConfiguration()); - } - - private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) - { - Class fieldClass = f.getType(); - String configPath = annotation.path(); - try - { - if (fieldClass == String.class) - { - String val = config.getString(configPath, annotation.defaultValue()); - val = PropertyUtils.replaceProperties(val); - f.set(instance, val); - } - else if (fieldClass == int.class) - { - int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue())); - f.setInt(instance, val); - } - else if (fieldClass == long.class) - { - long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue())); - f.setLong(instance, val); - } - else if (fieldClass == double.class) - { - double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue())); - f.setDouble(instance, val); - } - else if (fieldClass == boolean.class) - { - boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue())); - f.setBoolean(instance, val); - } - else - { - _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value"); - } - } - catch (PropertyException e) - { - _logger.error("Unable to expand property: " + e + " INGORING field " + f, e); - } - catch (IllegalAccessException e) - { - _logger.error("Unable to access field " + f + " IGNORING configured value"); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java deleted file mode 100644 index d1589092e9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import java.util.Collections; -import java.util.List; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; - -public class VirtualHostConfiguration -{ - private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); - - private static XMLConfiguration _config; - - private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; - - - public VirtualHostConfiguration(String configFile) - throws - ConfigurationException - { - _logger.info("Loading Config file:" + configFile); - - _config = new XMLConfiguration(configFile); - - } - - - private void configureVirtualHost(String virtualHostName, Configuration configuration) - throws - ConfigurationException, - AMQException - { - _logger.debug("Loding configuration for virtaulhost: " + virtualHostName); - - - VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); - - - if (virtualHost == null) - { - throw new ConfigurationException("Unknown virtual host: " + virtualHostName); - } - - List exchangeNames = configuration.getList("exchanges.exchange.name"); - - for (Object exchangeNameObj : exchangeNames) - { - String exchangeName = String.valueOf(exchangeNameObj); - configureExchange(virtualHost, exchangeName, configuration); - } - - - List queueNames = configuration.getList("queues.queue.name"); - - for (Object queueNameObj : queueNames) - { - String queueName = String.valueOf(queueNameObj); - configureQueue(virtualHost, queueName, configuration); - } - - } - - private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) - throws - AMQException - { - - CompositeConfiguration exchangeConfiguration = new CompositeConfiguration(); - - exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange." + exchangeNameString)); - exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); - - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore messageStore = virtualHost.getMessageStore(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); - - AMQShortString exchangeName = new AMQShortString(exchangeNameString); - - - Exchange exchange; - - - synchronized (exchangeRegistry) - { - exchange = exchangeRegistry.getExchange(exchangeName); - if (exchange == null) - { - - AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type", "direct")); - boolean durable = exchangeConfiguration.getBoolean("durable", false); - boolean autodelete = exchangeConfiguration.getBoolean("autodelete", false); - - Exchange newExchange = exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); - exchangeRegistry.registerExchange(newExchange); - } - - } - } - - public static CompositeConfiguration getDefaultQueueConfiguration(AMQQueue queue) - { - CompositeConfiguration queueConfiguration = null; - if (_config == null) - return null; - - Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + queue.getVirtualHost().getName()); - - if (vHostConfiguration == null) - return null; - - Configuration defaultQueueConfiguration = vHostConfiguration.subset("queues"); - if (defaultQueueConfiguration != null) - { - queueConfiguration = new CompositeConfiguration(); - queueConfiguration.addConfiguration(defaultQueueConfiguration); - } - - return queueConfiguration; - } - - private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) - throws - AMQException, - ConfigurationException - { - CompositeConfiguration queueConfiguration = new CompositeConfiguration(); - - queueConfiguration.addConfiguration(configuration.subset("queues.queue." + queueNameString)); - queueConfiguration.addConfiguration(configuration.subset("queues")); - - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore messageStore = virtualHost.getMessageStore(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - - - AMQShortString queueName = new AMQShortString(queueNameString); - - AMQQueue queue; - - synchronized (queueRegistry) - { - queue = queueRegistry.getQueue(queueName); - - if (queue == null) - { - _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName()); - - boolean durable = queueConfiguration.getBoolean("durable", false); - boolean autodelete = queueConfiguration.getBoolean("autodelete", false); - String owner = queueConfiguration.getString("owner", null); - - queue = new AMQQueue(queueName, - durable, - owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, - autodelete /* Therefore autodelete makes no sence */, virtualHost); - - if (queue.isDurable()) - { - - messageStore.createQueue(queue); - //DTX MessageStore -// try -// { -// messageStore.createQueue(queue); -// } catch (InternalErrorException e) -// { -// _logger.error("Problem when creating Queue '" + queueNameString -// + "' on virtual host " + virtualHost.getName() + ", not creating."); -// -// } catch (QueueAlreadyExistsException e) -// { -// _logger.error("Queue '" + queueNameString -// + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); -// } - } - - queueRegistry.registerQueue(queue); - } else - { - _logger.info("Queue '" + queueNameString + "' already exists on virtual host " + virtualHost.getName() + ", not creating."); - } - - String exchangeName = queueConfiguration.getString("exchange", null); - - Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - - if (exchange == null) - { - exchange = virtualHost.getExchangeRegistry().getDefaultExchange(); - } - - if (exchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); - } - - synchronized (exchange) - { - List routingKeys = queueConfiguration.getList("routingKey"); - if (routingKeys == null || routingKeys.isEmpty()) - { - routingKeys = Collections.singletonList(queue.getName()); - } - - for (Object routingKeyNameObj : routingKeys) - { - AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - - - queue.bind(routingKey, null, exchange); - - - _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); - } - - if (exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) - { - queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); - } - } - - } - - - Configurator.configure(queue, queueConfiguration); - } - - - public void performBindings() throws AMQException, ConfigurationException - { - List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); - String defaultVirtualHostName = _config.getString("default"); - if (defaultVirtualHostName != null) - { - ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); - } - _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); - - for (Object nameObject : virtualHostNames) - { - String name = String.valueOf(nameObject); - configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name)); - } - - if (virtualHostNames == null || virtualHostNames.isEmpty()) - { - throw new ConfigurationException( - "Virtualhost Configuration document does not contain a valid virtualhost."); - } - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java deleted file mode 100644 index 2b5fbf9795..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/CommandInvalidException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * CommandInvalidException indicates that an innapropriate request has been made to a transaction manager. For example, - * calling prepare on an already prepared transaction. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents an error due to an innapropriate request to a transction manager. - *
      - */ -public class CommandInvalidException extends Exception -{ - /** - * Constructs a new CommandInvalidException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - */ - public CommandInvalidException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new CommandInvalidException with the specified detail message. - * - * @param message the detail message. - * - * @deprected - */ - public CommandInvalidException(String message) - { - super(message); - } - - /** - * Constructs a new CommandInvalidException with the specified cause. - * - * @param cause the cause - * - * @deprected - */ - public CommandInvalidException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java deleted file mode 100644 index 60e1514d2b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InternalErrorException.java +++ /dev/null @@ -1,68 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * General purpose exception for non-specifc error cases. Do not use. - * - * @deprected Far too broad to be a checked exception. Will be abused as a "don't know what to do with it" exception - * when Runtimes should be used. If this has a specific meaning within transaction managers, it should - * be renamed to something like TxManagerException, for example. At the moment, transaction managers are not - * catching this exception and taking some action, so it is clear that it is being used for errors that are - * not recoverable/handleable from; use runtimes. So far, it is only caught to be rethrown as AMQException, - * which is the other catch-all exception case to be eliminated. There are sequences in the code where - * AMQException is caught and rethrown as InternalErrorException, which is cause and rethrown as AMQException. - */ -public class InternalErrorException extends Exception -{ - /** - * Constructs a new InternalErrorException with the specified detail message. - * - * @param message the detail message. - * - * @deprected - */ - public InternalErrorException(String message) - { - super(message); - } - - /** - * Constructs a new InternalErrorException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - */ - public InternalErrorException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new InternalErrorException with the specified cause. - * - * @param cause the cause - * - * @deprected - */ - public InternalErrorException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java deleted file mode 100644 index 277614afff..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/InvalidXidException.java +++ /dev/null @@ -1,82 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -import javax.transaction.xa.Xid; - -/** - * InvalidXidException indicates that an Xid under which to conduct a transaction is invalid. This may be because it - * has an incorrect format, is null, or a transcaction with the same Xid is already running. - * - *

      - * - *
      CRC Card
      Responsibilities Collaborations - *
      Represents an invalid Xid for a transaction. - *
      - */ -public class InvalidXidException extends Exception -{ - /** - * Constructs a newr InvalidXidException with a standard message - * - * @param xid The invalid xid. - * - * @deprected - */ - public InvalidXidException(Xid xid) - { - super("The Xid: " + xid + " is invalid"); - } - - /** - * Constructs a newr InvalidXidException with a cause - * - * @param xid The invalid xid. - * @param cause The casue for the xid to be invalid - * - * @deprected - */ - public InvalidXidException(Xid xid, Throwable cause) - { - super("The Xid: " + xid + " is invalid", cause); - } - - /** - * Constructs a newr InvalidXidException with a reason message - * - * @param reason The reason why the xid is invalid - * @param xid The invalid xid. - */ - public InvalidXidException(Xid xid, String reason) - { - super("The Xid: " + xid + " is invalid, The reason is: " + reason); - } - - /** - * Constructs a newr InvalidXidException with a reason message and cause - * - * @param reason The reason why the xid is invalid - * @param xid The invalid xid. - * @param cause The casue for the xid to be invalid - * - * @deprected - */ - public InvalidXidException(Xid xid, String reason, Throwable cause) - { - super("The Xid: " + xid + " is invalid, The reason is: " + reason, cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java deleted file mode 100644 index 336f5fdf64..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageAlreadyStagedException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * @todo Need to understand what message staging is to document properly. - */ -public class MessageAlreadyStagedException extends Exception -{ - /** - * Constructs a new MessageAlreadyStagedException with the specified detail message. - * - * @param message the detail message. - */ - public MessageAlreadyStagedException(String message) - { - super(message); - } - - /** - * Constructs a new MessageAlreadyStagedException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - * - * @deprected - */ - public MessageAlreadyStagedException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new MessageAlreadyStagedException with the specified cause. - * - * @param cause the cause - * - * @deprected - */ - public MessageAlreadyStagedException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java deleted file mode 100644 index 544d669d4b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/MessageDoesntExistException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * MessageDoesntExistException indicates that a message store cannot find a message looked up by its id. This may - * indicate message loss. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure of message store to find a message. - *
      - */ -public class MessageDoesntExistException extends Exception -{ - /** - * Constructs a new MessageDoesntExistException with the specified detail message. - * - * @param message the detail message. - */ - public MessageDoesntExistException(String message) - { - super(message); - } - - /** - * Constructs a new MessageDoesntExistException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - * - * @deprected - */ - public MessageDoesntExistException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new MessageDoesntExistException with the specified cause. - * - * @param cause the cause - * - * @deprected - */ - public MessageDoesntExistException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java deleted file mode 100644 index ab288748f5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/NotPreparedException.java +++ /dev/null @@ -1,67 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * NotPreparedException indicates a failure to commit a transaction that has not been prepared. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to commit an unprepared transaction. - *
      - * - * @todo There is already a CommandInvalidException which would seem to cover this too. Use it instead? - */ -public class NotPreparedException extends Exception -{ - /** - * Constructs a new NotPreparedException with the specified detail message. - * - * @param message the detail message. - */ - public NotPreparedException(String message) - { - super(message); - } - - /** - * Constructs a new NotPreparedException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - * - * @deprecated - */ - public NotPreparedException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new NotPreparedException with the specified cause. - * - * @param cause the cause - * - * @deprected - */ - public NotPreparedException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java deleted file mode 100644 index 3635d2c19d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueAlreadyExistsException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * QueueAlreadyExistsException inidicates failure of a message store to create a queue that already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to create a queue that already exists. - *
      - */ -public class QueueAlreadyExistsException extends Exception -{ - /** - * Constructs a new QueueAlreadyExistsException with the specified detail message. - * - * @param message the detail message. - */ - public QueueAlreadyExistsException(String message) - { - super(message); - } - - /** - * Constructs a new QueueAlreadyExistsException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - * - * @deprecated - */ - public QueueAlreadyExistsException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new QueueDoesntExistException with the specified cause. - * - * @param cause the cause - * - * @deprecated - */ - public QueueAlreadyExistsException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java deleted file mode 100644 index d05c152228..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/QueueDoesntExistException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -/** - * MessageDoesntExistException indicates that a message store cannot find a queue. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to find a queue on a message store. - *
      - */ -public class QueueDoesntExistException extends Exception -{ - /** - * Constructs a new QueueDoesntExistException with the specified detail message. - * - * @param message the detail message. - */ - public QueueDoesntExistException(String message) - { - super(message); - } - - /** - * Constructs a new QueueDoesntExistException with the specified detail message and - * cause. - * - * @param message the detail message . - * @param cause the cause. - * - * @deprecated - */ - public QueueDoesntExistException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructs a new QueueDoesntExistException with the specified cause. - * - * @param cause the cause - * - * @deprecated - */ - public QueueDoesntExistException(Throwable cause) - { - super(cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java deleted file mode 100644 index e4a5de8ecb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exception/UnknownXidException.java +++ /dev/null @@ -1,85 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.exception; - -import javax.transaction.xa.Xid; - -/** - * UnknownXidException indicates that an Xid under which a transactional operation is to be run is not known. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure of a transaction manager to recognize an Xid. - *
      - * - * @todo Already have an InvalidXidException, this might be splitting things too far? There are cases where invalid is - * caught and rethrown as unknown. What is unknown specifically used for that invalid is not? For example, when - * recovering, is it important to distinguish between invalid and unknown? - */ -public class UnknownXidException extends Exception -{ - /** - * Constructs a newr UnknownXidException with a standard message - * - * @param xid The unknown xid. - * - * @deprecated - */ - public UnknownXidException(Xid xid) - { - super("The Xid: " + xid + " is unknown"); - } - - /** - * Constructs a newr UnknownXidException with a cause - * - * @param xid The unknown xid. - * @param cause The casue for the xid to be unknown - */ - public UnknownXidException(Xid xid, Throwable cause) - { - super("The Xid: " + xid + " is unknown", cause); - } - - /** - * Constructs a newr UnknownXidException with a reason message - * - * @param reason The reason why the xid is unknown - * @param xid The unknown xid. - * - * @deprecated - */ - /*public UnknownXidException(Xid xid, String reason) - { - super("The Xid: " + xid + " is unknown, The reason is: " + reason); - }*/ - - /** - * Constructs a newr UnknownXidException with a reason message and cause - * - * @param reason The reason why the xid is unknown - * @param xid The unknown xid. - * @param cause The casue for the xid to be unknown - * - * @deprected - */ - public UnknownXidException(Xid xid, String reason, Throwable cause) - { - super("The Xid: " + xid + " is unknown, The reason is: " + reason, cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java deleted file mode 100644 index 0558906fb6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.ArrayType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.List; -import java.util.Map; - -public abstract class AbstractExchange implements Exchange, Managable -{ - private AMQShortString _name; - - protected boolean _durable; - protected String _exchangeType; - - private VirtualHost _virtualHost; - - 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 - { - // open mbean data types for representing exchange bindings - protected String[] _bindingItemNames; - protected String[] _bindingItemIndexNames; - protected OpenType[] _bindingItemTypes; - protected CompositeType _bindingDataType; - protected TabularType _bindinglistDataType; - protected TabularDataSupport _bindingList; - - public ExchangeMBean() throws NotCompliantMBeanException - { - super(ManagedExchange.class, ManagedExchange.TYPE); - } - - protected void init() throws OpenDataException - { - _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; - - _bindingItemTypes = new OpenType[2]; - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - - public ManagedObject getParentObject() - { - return _virtualHost.getManagedObject(); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public String getExchangeType() - { - return _exchangeType; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - // Added exchangetype in the object name lets maangement apps to do any customization required - public ObjectName getObjectName() throws MalformedObjectNameException - { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + _exchangeType; - return new ObjectName(objNameString); - } - - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - } // End of MBean class - - public AMQShortString 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(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException - { - _virtualHost = host; - _name = name; - _durable = durable; - _autoDelete = autoDelete; - _exchangeMbean = createMBean(); - _exchangeMbean.register(); - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - public void close() throws AMQException - { - if (_exchangeMbean != null) - { - _exchangeMbean.unregister(); - } - } - - abstract public Map> getBindings(); - - public String toString() - { - return getClass().getName() + "[" + getName() +"]"; - } - - public ManagedObject getManagedObject() - { - return _exchangeMbean; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public QueueRegistry getQueueRegistry() - { - return getVirtualHost().getQueueRegistry(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java deleted file mode 100644 index e3b715d45f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; - -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class DefaultExchangeFactory implements ExchangeFactory -{ - private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); - - private Map> _exchangeClassMap = new HashMap>(); - private final VirtualHost _host; - - public DefaultExchangeFactory(VirtualHost host) - { - _host = host; - registerExchangeType(DestNameExchange.TYPE); - registerExchangeType(DestWildExchange.TYPE); - registerExchangeType(HeadersExchange.TYPE); - registerExchangeType(FanoutExchange.TYPE); - - } - - public void registerExchangeType(ExchangeType type) - { - _exchangeClassMap.put(type.getName(), type); - } - - public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException - { - ExchangeType exchType = _exchangeClassMap.get(type); - if (exchType == null) - { - - throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null); - } - Exchange e = exchType.newInstance(_host, exchange, durable, autoDelete); - return e; - } - - public void initialise(Configuration hostConfig) - { - for(Object className : hostConfig.getList("custom-exchanges.class-name")) - { - try - { - Class exchangeTypeClass = (Class) Class.forName(String.valueOf(className)); - ExchangeType type = exchangeTypeClass.newInstance(); - registerExchangeType(type); - - } - catch (ClassNotFoundException e) - { - _logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\""); - } - catch (ClassCastException classCastEx) - { - _logger.error("No custom exchange class: \""+String.valueOf(className)+"\" cannot be registered as it does not extend class \""+ExchangeType.class+"\""); - } - catch (IllegalAccessException e) - { - _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); - } - catch (InstantiationException e) - { - _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); - } - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java deleted file mode 100644 index 23a4bec6bd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Collection; -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(); - - private Exchange _defaultExchange; - private VirtualHost _host; - - public DefaultExchangeRegistry(VirtualHost host) - { - //create 'standard' exchanges: - _host = host; - - } - - public void initialise() throws AMQException - { - new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); - } - - public MessageStore getMessageStore() - { - return _host.getMessageStore(); - } - - public void registerExchange(Exchange exchange) throws AMQException - { - _exchangeMap.put(exchange.getName(), exchange); - if(exchange.isDurable()) - { - getMessageStore().createExchange(exchange); - //DTX MessageStore -// try -// { -// getMessageStore().createExchange(exchange); -// } catch (InternalErrorException e) -// { -// throw new AMQException(null, "problem registering excahgne " + exchange, e); -// } - } - } - - public void setDefaultExchange(Exchange exchange) - { - _defaultExchange = exchange; - } - - public Exchange getDefaultExchange() - { - return _defaultExchange; - } - - public Collection getExchangeNames() - { - return _exchangeMap.keySet(); - } - - public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException - { - // TODO: check inUse argument - Exchange e = _exchangeMap.remove(name); - if (e != null) - { - if (e.isDurable()) - { - getMessageStore().removeExchange(e); - //DTX MessageStore -// try -// { -// getMessageStore().removeExchange(e); -// } catch (InternalErrorException e1) -// { -// throw new AMQException(null, "Problem unregistering Exchange " + name, e1); -// } - } - e.close(); - } - else - { - throw new AMQException(null, "Unknown exchange " + name, null); - } - } - - public Exchange getExchange(AMQShortString name) - { - if((name == null) || name.length() == 0) - { - return getDefaultExchange(); - } - else - { - 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 AMQShortString exchange = payload.getMessagePublishInfo().getExchange(); - final Exchange exch = getExchange(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(null, "Exchange '" + exchange + "' does not exist", null); - } - exch.route(payload); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java deleted file mode 100644 index d1cc9b892f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -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(); - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return DestNameExchange.class; - } - - public DestNameExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - DestNameExchange exch = new DestNameExchange(); - exch.initialise(host, name, durable, autoDelete); - return exch; - } - }; - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DestNameExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DestNameExchangeMBean() throws JMException - { - super(); - _exchangeType = "direct"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - Map> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : bindings.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, DestNameExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - }// End of MBean class - - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestNameExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex); - } - } - - public AMQShortString getType() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that routing key", null); - } - } - - public void route(AMQMessage payload) throws AMQException - { - final MessagePublishInfo info = payload.getMessagePublishInfo(); - final AMQShortString routingKey = info.getRoutingKey(); - final List queues = (routingKey == null) ? null : _index.get(routingKey); - if (queues == null || queues.isEmpty()) - { - String msg = "Routing key " + routingKey + " is not known to " + this; - if (info.isMandatory() || info.isImmediate()) - { - throw new NoRouteException(msg, payload, null); - } - else - { - _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); - _logger.warn(msg); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + queues); - } - - for (AMQQueue q : queues) - { - payload.enqueue(q); - } - } - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - final List queues = _index.get(routingKey); - return queues != null && queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - final List queues = _index.get(routingKey); - return queues != null && !queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - Map> bindings = _index.getBindingsMap(); - for (List queues : bindings.values()) - { - if (queues.contains(queue)) - { - return true; - } - } - return false; - } - - public boolean hasBindings() - { - return !_index.getBindingsMap().isEmpty(); - } - - public Map> getBindings() - { - return _index.getBindingsMap(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java deleted file mode 100644 index 25dc32fd41..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -public class DestWildExchange extends AbstractExchange -{ - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return DestWildExchange.class; - } - - public DestWildExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - DestWildExchange exch = new DestWildExchange(); - exch.initialise(host, name, durable, autoDelete); - return exch; - } - }; - - - private static final Logger _logger = Logger.getLogger(DestWildExchange.class); - - private ConcurrentHashMap> _routingKey2queues = - new ConcurrentHashMap>(); - // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); - private static final String TOPIC_SEPARATOR = "."; - private static final String AMQP_STAR = "*"; - private static final String AMQP_HASH = "#"; - - /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class DestWildExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public DestWildExchangeMBean() throws JMException - { - super(); - _exchangeType = "topic"; - init(); - } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Map.Entry> entry : _routingKey2queues.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = getMatchedQueues(key); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, DestWildExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - AMQShortString routingKey = normalize(rKey); - - _logger.debug("Registering queue " + queue.getName() + " with routing key " + routingKey); - // 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); - } - - } - - private AMQShortString normalize(AMQShortString routingKey) - { - StringTokenizer routingTokens = new StringTokenizer(routingKey.toString(), TOPIC_SEPARATOR); - List _subscription = new ArrayList(); - - while (routingTokens.hasMoreTokens()) - { - _subscription.add(routingTokens.nextToken()); - } - - int size = _subscription.size(); - - for (int index = 0; index < size; index++) - { - // if there are more levels - if ((index + 1) < size) - { - if (_subscription.get(index).equals(AMQP_HASH)) - { - if (_subscription.get(index + 1).equals(AMQP_HASH)) - { - // we don't need #.# delete this one - _subscription.remove(index); - size--; - // redo this normalisation - index--; - } - - if (_subscription.get(index + 1).equals(AMQP_STAR)) - { - // we don't want #.* swap to *.# - // remove it and put it in at index + 1 - _subscription.add(index + 1, _subscription.remove(index)); - } - } - } // if we have more levels - } - - StringBuilder sb = new StringBuilder(); - - for (String s : _subscription) - { - sb.append(s); - sb.append(TOPIC_SEPARATOR); - } - - sb.deleteCharAt(sb.length() - 1); - - return new AMQShortString(sb.toString()); - } - - public void route(AMQMessage payload) throws AMQException - { - MessagePublishInfo info = payload.getMessagePublishInfo(); - - final AMQShortString routingKey = normalize(info.getRoutingKey()); - - List queues = getMatchedQueues(routingKey); - // if we have no registered queues we have nothing to do - // TODO: add support for the immediate flag - if ((queues == null) || queues.isEmpty()) - { - if (info.isMandatory() || info.isImmediate()) - { - String msg = "Topic " + routingKey + " is not known to " + this; - throw new NoRouteException(msg, payload, null); - } - else - { - _logger.warn("No queues found for routing key " + routingKey); - _logger.warn("Routing map contains: " + _routingKey2queues); - - 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 boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - List queues = _routingKey2queues.get(normalize(routingKey)); - - return (queues != null) && queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - List queues = _routingKey2queues.get(normalize(routingKey)); - - return (queues != null) && !queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - for (List queues : _routingKey2queues.values()) - { - if (queues.contains(queue)) - { - return true; - } - } - - return false; - } - - public boolean hasBindings() - { - return !_routingKey2queues.isEmpty(); - } - - public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - AMQShortString routingKey = normalize(rKey); - - List queues = _routingKey2queues.get(routingKey); - if (queues == null) - { - throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that routing key", null); - - } - - boolean removedQ = queues.remove(queue); - if (!removedQ) - { - throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey, null); - } - - if (queues.isEmpty()) - { - _routingKey2queues.remove(routingKey); - } - } - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestWildExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException(null, "Exception occured in creating the topic exchenge mbean", ex); - } - } - - public Map> getBindings() - { - return _routingKey2queues; - } - - private List getMatchedQueues(AMQShortString routingKey) - { - List list = new LinkedList(); - StringTokenizer routingTokens = new StringTokenizer(routingKey.toString(), TOPIC_SEPARATOR); - - ArrayList routingkeyList = new ArrayList(); - - while (routingTokens.hasMoreTokens()) - { - String next = routingTokens.nextToken(); - if (next.equals(AMQP_HASH) && routingkeyList.get(routingkeyList.size() - 1).equals(AMQP_HASH)) - { - continue; - } - - routingkeyList.add(next); - } - - for (AMQShortString queue : _routingKey2queues.keySet()) - { - StringTokenizer queTok = new StringTokenizer(queue.toString(), TOPIC_SEPARATOR); - - ArrayList queueList = new ArrayList(); - - while (queTok.hasMoreTokens()) - { - queueList.add(queTok.nextToken()); - } - - int depth = 0; - boolean matching = true; - boolean done = false; - int routingskip = 0; - int queueskip = 0; - - while (matching && !done) - { - if ((queueList.size() == (depth + queueskip)) || (routingkeyList.size() == (depth + routingskip))) - { - done = true; - - // if it was the routing key that ran out of digits - if (routingkeyList.size() == (depth + routingskip)) - { - if (queueList.size() > (depth + queueskip)) - { // a hash and it is the last entry - matching = - queueList.get(depth + queueskip).equals(AMQP_HASH) - && (queueList.size() == (depth + queueskip + 1)); - } - } - else if (routingkeyList.size() > (depth + routingskip)) - { - // There is still more routing key to check - matching = false; - } - - continue; - } - - // if the values on the two topics don't match - if (!queueList.get(depth + queueskip).equals(routingkeyList.get(depth + routingskip))) - { - if (queueList.get(depth + queueskip).equals(AMQP_STAR)) - { - depth++; - - continue; - } - else if (queueList.get(depth + queueskip).equals(AMQP_HASH)) - { - // Is this a # at the end - if (queueList.size() == (depth + queueskip + 1)) - { - done = true; - - continue; - } - - // otherwise # in the middle - while (routingkeyList.size() > (depth + routingskip)) - { - if (routingkeyList.get(depth + routingskip).equals(queueList.get(depth + queueskip + 1))) - { - queueskip++; - depth++; - - break; - } - - routingskip++; - } - - continue; - } - - matching = false; - } - - depth++; - } - - if (matching) - { - list.addAll(_routingKey2queues.get(queue)); - } - } - - return list; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java deleted file mode 100644 index 78749de612..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.List; -import java.util.Map; - -public interface Exchange -{ - AMQShortString getName(); - AMQShortString getType(); - - void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException; - - boolean isDurable(); - - /** - * @return true if the exchange will be deleted after all queues have been detached - */ - boolean isAutoDelete(); - - void close() throws AMQException; - - void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - void route(AMQMessage message) throws AMQException; - - - /** - * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments - * @param routingKey - * @param arguments - * @param queue - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); - - /** - * Determines whether a message would be isBound to a particular queue using a specific routing key - * @param routingKey - * @param queue - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey, AMQQueue queue); - - /** - * Determines whether a message is routing to any queue using a specific routing key - * @param routingKey - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey); - - boolean isBound(AMQQueue queue); - - /** - * Returns true if this exchange has at least one binding associated with it. - * @return - * @throws AMQException - */ - boolean hasBindings(); - - Map> getBindings(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java deleted file mode 100644 index b7b88b9157..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.commons.configuration.Configuration; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; - - -public interface ExchangeFactory -{ - Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException; - - void initialise(Configuration hostConfig); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java deleted file mode 100644 index 07550dd808..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; - -/** - * ExchangeInUseRegistry indicates that an exchange cannot be unregistered because it is currently being used. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to unregister exchange that is in use. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo This exception is not used. However, it is part of the ExchangeRegistry interface, and looks like code is - * going to need to be added to throw/deal with this. Alternatively ExchangeResitries may be able to handle the - * issue internally. - */ -public class ExchangeInUseException extends AMQException -{ - public ExchangeInUseException(String exchangeName, Throwable cause) - { - super(null, "Exchange " + exchangeName + " is currently in use", cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java deleted file mode 100644 index 2e101beb84..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; - -import java.util.Collection; - -public interface ExchangeRegistry extends MessageRouter -{ - void registerExchange(Exchange exchange) throws AMQException; - - /** - * 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(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; - - Exchange getExchange(AMQShortString name); - - void setDefaultExchange(Exchange exchange); - - Exchange getDefaultExchange(); - - Collection getExchangeNames(); - - void initialise() throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java deleted file mode 100644 index 472de2da5c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.virtualhost.VirtualHost; - - -public interface ExchangeType -{ - public AMQShortString getName(); - public Class getExchangeClass(); - public T newInstance(VirtualHost host, AMQShortString name, - boolean durable, boolean autoDelete) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java deleted file mode 100644 index 77590ea54d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -public class FanoutExchange extends AbstractExchange -{ - - - private static final Logger _logger = Logger.getLogger(FanoutExchange.class); - - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return FanoutExchange.class; - } - - public FanoutExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - FanoutExchange exch = new FanoutExchange(); - exch.initialise(host, name, durable, autoDelete); - return exch; - } - }; - - - /** - * Maps from queue name to queue instances - */ - private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Fanout Exchange") - private final class FanoutExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException - { - super(); - _exchangeType = "fanout"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (AMQQueue queue : _queues) - { - String queueName = queue.getName().toString(); - - Object[] bindingItemValues = {queueName, new String[]{queueName}}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, FanoutExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new FanoutExchange.FanoutExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex); - } - } - - public Map> getBindings() - { - return null; - } - - public AMQShortString getType() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (_queues.contains(queue)) - { - _logger.debug("Queue " + queue + " is already registered"); - } - else - { - _queues.add(queue); - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); - } - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (!_queues.remove(queue)) - { - throw new AMQException(null, "Queue " + queue + " was not registered with exchange " + this.getName() + - ". ", null); - } - } - - public void route(AMQMessage payload) throws AMQException - { - final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); - final AMQShortString routingKey = publishInfo.getRoutingKey(); - if ((_queues == null) || _queues.isEmpty()) - { - String msg = "No queues bound to " + this; - if (publishInfo.isMandatory() || publishInfo.isImmediate()) - { - throw new NoRouteException(msg, payload, null); - } - else - { - _logger.warn(msg); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + _queues); - } - - for (AMQQueue q : _queues) - { - payload.enqueue(q); - } - } - } - - public boolean isBound(AMQShortString routingKey, FieldTable fieldtable, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return _queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - - return (_queues != null) && !_queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - - return _queues.contains(queue); - } - - public boolean hasBindings() - { - return !_queues.isEmpty(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java deleted file mode 100644 index 2b7df4361a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.log4j.Logger; -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.FieldTable; - -/** - * Defines binding and matching based on a set of headers. - */ -class HeadersBinding -{ - private static final Logger _logger = Logger.getLogger(HeadersBinding.class); - - private final FieldTable _mappings; - private final Set required = new HashSet(); - private final Map matches = new HashMap(); - private boolean matchAny; - - private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor - { - private Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor - { - Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if(required.contains(propertyName)) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - - - /** - * 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(FieldTable mappings) - { - _mappings = mappings; - initMappings(); - } - - private void initMappings() - { - - _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if (isSpecial(propertyName)) - { - processSpecial(propertyName, value.getValue()); - } - else if (value.getValue() == null || value.getValue().equals("")) - { - required.add(propertyName); - } - else - { - matches.put(propertyName,value.getValue()); - } - - return true; - } - - public Object getResult() - { - return null; - } - }); - } - - protected FieldTable 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(FieldTable headers) - { - if(headers == null) - { - return required.isEmpty() && matches.isEmpty(); - } - else - { - return matchAny ? or(headers) : and(headers); - } - } - - private boolean and(FieldTable headers) - { - if(headers.keys().containsAll(required)) - { - for(Map.Entry e : matches.entrySet()) - { - if(!e.getValue().equals(headers.getObject(e.getKey()))) - { - return false; - } - } - return true; - } - else - { - return false; - } - } - - - private boolean or(final FieldTable headers) - { - if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) - { - return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) - || (required.isEmpty() && matches.isEmpty()); - } - else - { - return true; - } - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java deleted file mode 100644 index 426cd090c1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * An exchange that binds queues based on a set of required headers and header values - * and routes messages to these queues by matching the headers of the message against - * those with which the queues were bound. - *

      - *

      - * The Headers Exchange
      - *
      - *  Routes messages according to the value/presence of fields in the message header table.
      - *  (Basic and JMS content has a content header field called "headers" that is a table of
      - *   message header fields).
      - *
      - *  class = "headers"
      - *  routing key is not used
      - *
      - *  Has the following binding arguments:
      - *
      - *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
      - *  other fields prefixed with "X-" are ignored (and generate a console warning message).
      - *  a field with no value or empty value indicates a match on presence only.
      - *  a field with a value indicates match on field presence and specific value.
      - *
      - *  Standard instances:
      - *
      - *  amq.match - pub/sub on field content/value
      - *  
      - */ -public class HeadersExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return HeadersExchange.class; - } - - public HeadersExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - boolean autoDelete) throws AMQException - { - HeadersExchange exch = new HeadersExchange(); - exch.initialise(host, name, durable, autoDelete); - return exch; - } - }; - - - 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 - { - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException - { - super(); - _exchangeType = "headers"; - init(); - } - - /** - * initialises the OpenType objects. - */ - protected void init() throws OpenDataException - { - _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; - - _bindingItemTypes = new OpenType[3]; - _bindingItemTypes[0] = SimpleType.INTEGER; - _bindingItemTypes[1] = SimpleType.STRING; - _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - int count = 1; - for (Iterator itr = _bindings.iterator(); itr.hasNext();) - { - Registration registration = itr.next(); - String queueName = registration.queue.getName().toString(); - - HeadersBinding headers = registration.binding; - FieldTable headerMappings = headers.getMappings(); - final List mappingList = new ArrayList(); - - headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - mappingList.add(propertyName + "=" + value.getValue()); - return true; - } - - public Object getResult() - { - return mappingList; - } - }); - - - Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - /** - * Creates bindings. Binding pattern is as follows- - * =,=,... - * @param queueName - * @param binding - * @throws javax.management.JMException - */ - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - String[] bindings = binding.split(","); - FieldTable bindingMap = new FieldTable(); - for (int i = 0; i < bindings.length; i++) - { - String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length < 2) - { - throw new JMException("Format for headers binding should be \"=,=\" "); - } - bindingMap.setString(keyAndValue[0], keyAndValue[1]); - } - - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); - _bindings.add(new Registration(new HeadersBinding(args), queue)); - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - _bindings.remove(new Registration(new HeadersBinding(args), queue)); - } - - public void route(AMQMessage payload) throws AMQException - { - FieldTable 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) - { - - String msg = "Exchange " + getName() + ": message not routable."; - - if (payload.getMessagePublishInfo().isMandatory() || payload.getMessagePublishInfo().isImmediate()) - { - throw new NoRouteException(msg, payload, null); - } - else - { - _logger.warn(msg); - } - - } - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - //fixme isBound here should take the arguements in to consideration. - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return isBound(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - return hasBindings(); - } - - public boolean isBound(AMQQueue queue) - { - for (Registration r : _bindings) - { - if (r.queue.equals(queue)) - { - return true; - } - } - return false; - } - - public boolean hasBindings() - { - return !_bindings.isEmpty(); - } - - protected FieldTable 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 (JMException ex) - { - _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException(null, "Exception occured in creating the HeadersExchangeMBean", ex); - } - } - - public Map> getBindings() - { - return null; - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java deleted file mode 100644 index eacdad8a8e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * 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>(); - - synchronized boolean add(AMQShortString 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); - } - } - - synchronized boolean remove(AMQShortString 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(AMQShortString key) - { - return _index.get(key); - } - - Map> getBindingsMap() - { - return new HashMap>(_index); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java deleted file mode 100644 index bb33341aef..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The management interface exposed to allow management of an Exchange. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedExchange -{ - static final String TYPE = "Exchange"; - - /** - * Returns the name of the managed exchange. - * @return the name of the exchange. - * @throws IOException - */ - @MBeanAttribute(name="Name", description=TYPE + " Name") - String getName() throws IOException; - - @MBeanAttribute(name="ExchangeType", description="Exchange Type") - String getExchangeType() throws IOException; - - /** - * Tells if the exchange is durable or not. - * @return true if the exchange is durable. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description="true if Exchange is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the exchange is set for autodelete or not. - * @return true if the exchange is set as autodelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") - boolean isAutoDelete() throws IOException; - - // Operations - - /** - * Returns all the bindings this exchange has with the queues. - * @return the bindings with the exchange. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") - TabularData bindings() throws IOException, JMException; - - /** - * Creates new binding with the given queue and binding. - * @param queueName - * @param binding - * @throws JMException - */ - @MBeanOperation(name="createNewBinding", - description="create a new binding with this exchange", - impact= MBeanOperationInfo.ACTION) - void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, - @MBeanOperationParameter(name="Binding", description="New binding")String binding) - throws JMException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java deleted file mode 100644 index 7508e80f7f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java deleted file mode 100644 index c787103c00..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message - * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report - * this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoRouteException extends RequiredDeliveryException -{ - public NoRouteException(String msg, AMQMessage message, Throwable cause) - { - super(msg, message, cause); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_ROUTE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java deleted file mode 100644 index fb5220f4da..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ /dev/null @@ -1,275 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * An expression which performs an operation on two expression values - */ -public abstract class ArithmeticExpression extends BinaryExpression -{ - - protected static final int INTEGER = 1; - protected static final int LONG = 2; - protected static final int DOUBLE = 3; - - /** - * @param left - * @param right - */ - public ArithmeticExpression(Expression left, Expression right) - { - super(left, right); - } - - public static Expression createPlus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof String) - { - String text = (String) lvalue; - String answer = text + rvalue; - - return answer; - } - else if (lvalue instanceof Number) - { - return plus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "+"; - } - }; - } - - public static Expression createMinus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return minus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "-"; - } - }; - } - - public static Expression createMultiply(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return multiply((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "*"; - } - }; - } - - public static Expression createDivide(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return divide((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "/"; - } - }; - } - - public static Expression createMod(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return mod((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "%"; - } - }; - } - - protected Number plus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() + right.intValue()); - - case LONG: - return new Long(left.longValue() + right.longValue()); - - default: - return new Double(left.doubleValue() + right.doubleValue()); - } - } - - protected Number minus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() - right.intValue()); - - case LONG: - return new Long(left.longValue() - right.longValue()); - - default: - return new Double(left.doubleValue() - right.doubleValue()); - } - } - - protected Number multiply(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() * right.intValue()); - - case LONG: - return new Long(left.longValue() * right.longValue()); - - default: - return new Double(left.doubleValue() * right.doubleValue()); - } - } - - protected Number divide(Number left, Number right) - { - return new Double(left.doubleValue() / right.doubleValue()); - } - - protected Number mod(Number left, Number right) - { - return new Double(left.doubleValue() % right.doubleValue()); - } - - private int numberType(Number left, Number right) - { - if (isDouble(left) || isDouble(right)) - { - return DOUBLE; - } - else if ((left instanceof Long) || (right instanceof Long)) - { - return LONG; - } - else - { - return INTEGER; - } - } - - private boolean isDouble(Number n) - { - return (n instanceof Float) || (n instanceof Double); - } - - protected Number asNumber(Object value) - { - if (value instanceof Number) - { - return (Number) value; - } - else - { - throw new RuntimeException("Cannot convert value: " + value + " into a number"); - } - } - - public Object evaluate(AMQMessage message) throws AMQException - { - Object lvalue = left.evaluate(message); - if (lvalue == null) - { - return null; - } - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - return evaluate(lvalue, rvalue); - } - - /** - * @param lvalue - * @param rvalue - * @return - */ - protected abstract Object evaluate(Object lvalue, Object rvalue); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java deleted file mode 100644 index 024257bea9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -/** - * An expression which performs an operation on two expression values. - */ -public abstract class BinaryExpression implements Expression -{ - protected Expression left; - protected Expression right; - - public BinaryExpression(Expression left, Expression right) - { - this.left = left; - this.right = right; - } - - public Expression getLeft() - { - return left; - } - - public Expression getRight() - { - return right; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - - /** - * @param expression - */ - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @param expression - */ - public void setLeft(Expression expression) - { - left = expression; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java deleted file mode 100644 index e28ff79820..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * A BooleanExpression is an expression that always - * produces a Boolean result. - */ -public interface BooleanExpression extends Expression -{ - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException - */ - public boolean matches(AMQMessage message) throws AMQException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java deleted file mode 100644 index 72a9ef7969..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ /dev/null @@ -1,595 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.util.HashSet; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * A filter performing a comparison of two objects - */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); - } - - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); - } - - private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); - - static - { - REGEXP_CONTROL_CHARS.add(new Character('.')); - REGEXP_CONTROL_CHARS.add(new Character('\\')); - REGEXP_CONTROL_CHARS.add(new Character('[')); - REGEXP_CONTROL_CHARS.add(new Character(']')); - REGEXP_CONTROL_CHARS.add(new Character('^')); - REGEXP_CONTROL_CHARS.add(new Character('$')); - REGEXP_CONTROL_CHARS.add(new Character('?')); - REGEXP_CONTROL_CHARS.add(new Character('*')); - REGEXP_CONTROL_CHARS.add(new Character('+')); - REGEXP_CONTROL_CHARS.add(new Character('{')); - REGEXP_CONTROL_CHARS.add(new Character('}')); - REGEXP_CONTROL_CHARS.add(new Character('|')); - REGEXP_CONTROL_CHARS.add(new Character('(')); - REGEXP_CONTROL_CHARS.add(new Character(')')); - REGEXP_CONTROL_CHARS.add(new Character(':')); - REGEXP_CONTROL_CHARS.add(new Character('&')); - REGEXP_CONTROL_CHARS.add(new Character('<')); - REGEXP_CONTROL_CHARS.add(new Character('>')); - REGEXP_CONTROL_CHARS.add(new Character('=')); - REGEXP_CONTROL_CHARS.add(new Character('!')); - } - - static class LikeExpression extends UnaryExpression implements BooleanExpression - { - - Pattern likePattern; - - /** - * @param right - */ - public LikeExpression(Expression right, String like, int escape) - { - super(right); - - StringBuffer regexp = new StringBuffer(like.length() * 2); - regexp.append("\\A"); // The beginning of the input - for (int i = 0; i < like.length(); i++) - { - char c = like.charAt(i); - if (escape == (0xFFFF & c)) - { - i++; - if (i >= like.length()) - { - // nothing left to escape... - break; - } - - char t = like.charAt(i); - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & t)); - } - else if (c == '%') - { - regexp.append(".*?"); // Do a non-greedy match - } - else if (c == '_') - { - regexp.append("."); // match one - } - else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) - { - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & c)); - } - else - { - regexp.append(c); - } - } - - regexp.append("\\z"); // The end of the input - - likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); - } - - /** - * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() - */ - public String getExpressionSymbol() - { - return "LIKE"; - } - - /** - * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) - */ - public Object evaluate(AMQMessage message) throws AMQException - { - - Object rv = this.getRight().evaluate(message); - - if (rv == null) - { - return null; - } - - if (!(rv instanceof String)) - { - return - Boolean.FALSE; - // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); - } - - return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; - } - - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static BooleanExpression createLike(Expression left, String right, String escape) - { - if ((escape != null) && (escape.length() != 1)) - { - throw new RuntimeException( - "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); - } - - int c = -1; - if (escape != null) - { - c = 0xFFFF & escape.charAt(0); - } - - return new LikeExpression(left, right, c); - } - - public static BooleanExpression createNotLike(Expression left, String right, String escape) - { - return UnaryExpression.createNOT(createLike(left, right, escape)); - } - - public static BooleanExpression createInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); - - } - - public static BooleanExpression createNotInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); - - } - - public static BooleanExpression createIsNull(Expression left) - { - return doCreateEqual(left, ConstantExpression.NULL); - } - - public static BooleanExpression createIsNotNull(Expression left) - { - return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); - } - - public static BooleanExpression createNotEqual(Expression left, Expression right) - { - return UnaryExpression.createNOT(createEqual(left, right)); - } - - public static BooleanExpression createEqual(Expression left, Expression right) - { - checkEqualOperand(left); - checkEqualOperand(right); - checkEqualOperandCompatability(left, right); - - return doCreateEqual(left, right); - } - - private static BooleanExpression doCreateEqual(Expression left, Expression right) - { - return new ComparisonExpression(left, right) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - Object lv = left.evaluate(message); - Object rv = right.evaluate(message); - - // Iff one of the values is null - if ((lv == null) ^ (rv == null)) - { - return Boolean.FALSE; - } - - if ((lv == rv) || lv.equals(rv)) - { - return Boolean.TRUE; - } - - if ((lv instanceof Comparable) && (rv instanceof Comparable)) - { - return compare((Comparable) lv, (Comparable) rv); - } - - return Boolean.FALSE; - } - - protected boolean asBoolean(int answer) - { - return answer == 0; - } - - public String getExpressionSymbol() - { - return "="; - } - }; - } - - public static BooleanExpression createGreaterThan(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer > 0; - } - - public String getExpressionSymbol() - { - return ">"; - } - }; - } - - public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer >= 0; - } - - public String getExpressionSymbol() - { - return ">="; - } - }; - } - - public static BooleanExpression createLessThan(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer < 0; - } - - public String getExpressionSymbol() - { - return "<"; - } - - }; - } - - public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer <= 0; - } - - public String getExpressionSymbol() - { - return "<="; - } - }; - } - - /** - * Only Numeric expressions can be used in >, >=, < or <= expressions.s - * - * @param expr - */ - public static void checkLessThanOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value instanceof Number) - { - return; - } - - // Else it's boolean or a String.. - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - - if (expr instanceof BooleanExpression) - { - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - } - - /** - * Validates that the expression can be used in == or <> expression. - * Cannot not be NULL TRUE or FALSE litterals. - * - * @param expr - */ - public static void checkEqualOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value == null) - { - throw new RuntimeException("'" + expr + "' cannot be compared."); - } - } - } - - /** - * - * @param left - * @param right - */ - private static void checkEqualOperandCompatability(Expression left, Expression right) - { - if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) - { - if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) - { - throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); - } - } - } - - /** - * @param left - * @param right - */ - public ComparisonExpression(Expression left, Expression right) - { - super(left, right); - } - - public Object evaluate(AMQMessage message) throws AMQException - { - Comparable lv = (Comparable) left.evaluate(message); - if (lv == null) - { - return null; - } - - Comparable rv = (Comparable) right.evaluate(message); - if (rv == null) - { - return null; - } - - return compare(lv, rv); - } - - protected Boolean compare(Comparable lv, Comparable rv) - { - Class lc = lv.getClass(); - Class rc = rv.getClass(); - // If the the objects are not of the same type, - // try to convert up to allow the comparison. - if (lc != rc) - { - if (lc == Byte.class) - { - if (rc == Short.class) - { - lv = new Short(((Number) lv).shortValue()); - } - else if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Short.class) - { - if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Integer.class) - { - if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Long.class) - { - if (rc == Integer.class) - { - rv = new Long(((Number) rv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Float.class) - { - if (rc == Integer.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Long.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Double.class) - { - if (rc == Integer.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Long.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Float.class) - { - rv = new Float(((Number) rv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else - { - return Boolean.FALSE; - } - } - - return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; - } - - protected abstract boolean asBoolean(int answer); - - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java deleted file mode 100644 index 0e729cc521..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.math.BigDecimal; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Represents a constant expression - */ -public class ConstantExpression implements Expression -{ - - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression - { - public BooleanConstantExpression(Object value) - { - super(value); - } - - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); - public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); - public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); - - private Object value; - - public static ConstantExpression createFromDecimal(String text) - { - - // Strip off the 'l' or 'L' if needed. - if (text.endsWith("l") || text.endsWith("L")) - { - text = text.substring(0, text.length() - 1); - } - - Number value; - try - { - value = new Long(text); - } - catch (NumberFormatException e) - { - // The number may be too big to fit in a long. - value = new BigDecimal(text); - } - - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromHex(String text) - { - Number value = new Long(Long.parseLong(text.substring(2), 16)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromOctal(String text) - { - Number value = new Long(Long.parseLong(text, 8)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFloat(String text) - { - Number value = new Double(text); - - return new ConstantExpression(value); - } - - public ConstantExpression(Object value) - { - this.value = value; - } - - public Object evaluate(AMQMessage message) throws AMQException - { - return value; - } - - public Object getValue() - { - return value; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - if (value == null) - { - return "NULL"; - } - - if (value instanceof Boolean) - { - return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; - } - - if (value instanceof String) - { - return encodeString((String) value); - } - - return value.toString(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Encodes the value of string so that it looks like it would look like - * when it was provided in a selector. - * - * @param s - * @return - */ - public static String encodeString(String s) - { - StringBuffer b = new StringBuffer(); - b.append('\''); - for (int i = 0; i < s.length(); i++) - { - char c = s.charAt(i); - if (c == '\'') - { - b.append(c); - } - - b.append(c); - } - - b.append('\''); - - return b.toString(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java deleted file mode 100644 index 5f646c15db..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Represents an expression - */ -public interface Expression -{ - - /** - * @return the value of this expression - */ - public Object evaluate(AMQMessage message) throws AMQException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java deleted file mode 100644 index c82de9fa15..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.server.queue.AMQMessage; - -public interface FilterManager -{ - void add(MessageFilter filter); - - void remove(MessageFilter filter); - - boolean allAllow(AMQMessage msg); - - boolean hasFilters(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java deleted file mode 100644 index 311f0680ec..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.AMQException; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.framing.FieldTable; - - -public class FilterManagerFactory -{ - //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); - private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); - - //fixme move to a common class so it can be refered to from client code. - - public static FilterManager createManager(FieldTable filters) throws AMQException - { - FilterManager manager = null; - - if (filters != null) - { - - manager = new SimpleFilterManager(); - - if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) - { - String selector = filters.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - - if (selector != null && !selector.equals("")) - { - manager.add(new JMSSelectorFilter(selector)); - } - - } - - if (filters.containsKey(AMQPFilterTypes.NO_CONSUME.getValue())) - { - manager.add(new NoConsumerFilter()); - } - - - - //If we added no filters don't bear the overhead of having an filter manager - if (!manager.hasFilters()) - { - manager = null; - } - } - else - { - _logger.debug("No Filters found."); - } - - - return manager; - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java deleted file mode 100644 index 2061803d65..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.filter.jms.selector.SelectorParser; -import org.apache.qpid.server.queue.AMQMessage; - - - -public class JMSSelectorFilter implements MessageFilter -{ - private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); - - private String _selector; - private BooleanExpression _matcher; - - public JMSSelectorFilter(String selector) throws AMQException - { - _selector = selector; - _logger.info("Created JMSSelectorFilter with selector:" + _selector); - - - _matcher = new SelectorParser().parse(selector); - - - } - - public boolean matches(AMQMessage message) - { - try - { - boolean match = _matcher.matches(message); - _logger.info(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); - return match; - } - catch (AMQException e) - { - //fixme this needs to be sorted.. it shouldn't happen - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - return false; - } - - public String getSelector() - { - return _selector; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java deleted file mode 100644 index c8cbdb2125..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * A filter performing a comparison of two objects - */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - - Boolean lv = (Boolean) left.evaluate(message); - // Can we do an OR shortcut?? - if ((lv != null) && lv.booleanValue()) - { - return Boolean.TRUE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "OR"; - } - }; - } - - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - - Boolean lv = (Boolean) left.evaluate(message); - - // Can we do an AND shortcut?? - if (lv == null) - { - return null; - } - - if (!lv.booleanValue()) - { - return Boolean.FALSE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "AND"; - } - }; - } - - /** - * @param left - * @param right - */ - public LogicExpression(BooleanExpression left, BooleanExpression right) - { - super(left, right); - } - - public abstract Object evaluate(AMQMessage message) throws AMQException; - - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java deleted file mode 100644 index e6bfe974d5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -public interface MessageFilter -{ - boolean matches(AMQMessage message) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java deleted file mode 100644 index 47ca930d12..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -public class NoConsumerFilter implements MessageFilter -{ - private final static Logger _logger = org.apache.log4j.Logger.getLogger(NoConsumerFilter.class); - - - public NoConsumerFilter() throws AMQException - { - _logger.info("Created NoConsumerFilter"); - } - - public boolean matches(AMQMessage message) - { - return true; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java deleted file mode 100644 index 5ab360ca19..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.util.HashMap; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Represents a property expression - */ -public class PropertyExpression implements Expression -{ - // Constants - defined the same as JMS - private static final int NON_PERSISTENT = 1; - private static final int PERSISTENT = 2; - private static final int DEFAULT_PRIORITY = 4; - - private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - - private static final HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); - - static - { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() - { - public Object evaluate(AMQMessage message) - { - //TODO - return null; - } - }); - JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - - return (replyTo == null) ? null : replyTo.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - - return (type == null) ? null : type.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; - if (_logger.isDebugEnabled()) - { - _logger.debug("JMSDeliveryMode is :" + mode); - } - - return mode; - } - catch (AMQException e) - { - _logger.warn(e); - } - - return NON_PERSISTENT; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return (int) _properties.getPriority(); - } - catch (AMQException e) - { - _logger.warn(e); - } - - return DEFAULT_PRIORITY; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); - - return (messageId == null) ? null : messageId; - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getTimestamp(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - - return (correlationId == null) ? null : correlationId.toString(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getExpiration(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() - { - public Object evaluate(AMQMessage message) - { - return message.isRedelivered(); - } - }); - - } - - private final String name; - private final Expression jmsPropertyExpression; - - public PropertyExpression(String name) - { - this.name = name; - jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); - } - - public Object evaluate(AMQMessage message) throws AMQException - { - - if (jmsPropertyExpression != null) - { - return jmsPropertyExpression.evaluate(message); - } - else - { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking up property:" + name); - _logger.debug("Properties are:" + _properties.getHeaders().keySet()); - } - - return _properties.getHeaders().getObject(name); - } - } - - public String getName() - { - return name; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return name; - } - - /** - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return name.hashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return name.equals(((PropertyExpression) o).name); - - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java deleted file mode 100644 index 62a45f5420..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -public class SimpleFilterManager implements FilterManager -{ - private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - - private final ConcurrentLinkedQueue _filters; - - public SimpleFilterManager() - { - _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue(); - } - - public void add(MessageFilter filter) - { - _filters.add(filter); - } - - public void remove(MessageFilter filter) - { - _filters.remove(filter); - } - - public boolean allAllow(AMQMessage msg) - { - for (MessageFilter filter : _filters) - { - try - { - if (!filter.matches(msg)) - { - return false; - } - } - catch (AMQException e) - { - //fixme - e.printStackTrace(); - return false; - } - } - return true; - } - - public boolean hasFilters() - { - return !_filters.isEmpty(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java deleted file mode 100644 index 83b4ed5358..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * An expression which performs an operation on two expression values - */ -public abstract class UnaryExpression implements Expression -{ - - private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression right; - - public static Expression createNegate(Expression left) - { - return new UnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue instanceof Number) - { - return negate((Number) rvalue); - } - - return null; - } - - public String getExpressionSymbol() - { - return "-"; - } - }; - } - - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) - { - - // Use a HashSet if there are many elements. - Collection t; - if (elements.size() == 0) - { - t = null; - } - else if (elements.size() < 5) - { - t = elements; - } - else - { - t = new HashSet(elements); - } - - final Collection inList = t; - - return new BooleanUnaryExpression(right) - { - public Object evaluate(AMQMessage message) throws AMQException - { - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue.getClass() != String.class) - { - return null; - } - - if (((inList != null) && inList.contains(rvalue)) ^ not) - { - return Boolean.TRUE; - } - else - { - return Boolean.FALSE; - } - - } - - public String toString() - { - StringBuffer answer = new StringBuffer(); - answer.append(right); - answer.append(" "); - answer.append(getExpressionSymbol()); - answer.append(" ( "); - - int count = 0; - for (Iterator i = inList.iterator(); i.hasNext();) - { - Object o = (Object) i.next(); - if (count != 0) - { - answer.append(", "); - } - - answer.append(o); - count++; - } - - answer.append(" )"); - - return answer.toString(); - } - - public String getExpressionSymbol() - { - if (not) - { - return "NOT IN"; - } - else - { - return "IN"; - } - } - }; - } - - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression - { - public BooleanUnaryExpression(Expression left) - { - super(left); - } - - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - ; - - public static BooleanExpression createNOT(BooleanExpression left) - { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) - { - return null; - } - - return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - - public String getExpressionSymbol() - { - return "NOT"; - } - }; - } - - public static BooleanExpression createXPath(final String xpath) - { - return new XPathExpression(xpath); - } - - public static BooleanExpression createXQuery(final String xpath) - { - return new XQueryExpression(xpath); - } - - public static BooleanExpression createBooleanCast(Expression left) - { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (!rvalue.getClass().equals(Boolean.class)) - { - return Boolean.FALSE; - } - - return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; - } - - public String toString() - { - return right.toString(); - } - - public String getExpressionSymbol() - { - return ""; - } - }; - } - - private static Number negate(Number left) - { - Class clazz = left.getClass(); - if (clazz == Integer.class) - { - return new Integer(-left.intValue()); - } - else if (clazz == Long.class) - { - return new Long(-left.longValue()); - } - else if (clazz == Float.class) - { - return new Float(-left.floatValue()); - } - else if (clazz == Double.class) - { - return new Double(-left.doubleValue()); - } - else if (clazz == BigDecimal.class) - { - // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the - // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it - // as a Big decimal. But it gets Negated right away.. to here we try to covert it back - // to a Long. - BigDecimal bd = (BigDecimal) left; - bd = bd.negate(); - - if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) - { - return new Long(Long.MIN_VALUE); - } - - return bd; - } - else - { - throw new RuntimeException("Don't know how to negate: " + left); - } - } - - public UnaryExpression(Expression left) - { - this.right = left; - } - - public Expression getRight() - { - return right; - } - - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return "(" + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java deleted file mode 100644 index 2fdea208f2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Used to evaluate an XPath Expression in a JMS selector. - */ -public final class XPathExpression implements BooleanExpression { - - private static final Log log = LogFactory.getLog(XPathExpression.class); - private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.qpid.server.filter.XPathEvaluatorClassName"; - private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName(); - - private static final Constructor EVALUATOR_CONSTRUCTOR; - - static { - String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); - Constructor m = null; - try { - try { - m = getXPathEvaluatorConstructor(cn); - } catch (Throwable e) { - log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e); - cn = DEFAULT_EVALUATOR_CLASS_NAME; - try { - m = getXPathEvaluatorConstructor(cn); - } catch (Throwable e2) { - log.error("Default XPath evaluator could not be loaded",e); - } - } - } finally { - EVALUATOR_CONSTRUCTOR = m; - } - } - - private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { - Class c = XPathExpression.class.getClassLoader().loadClass(cn); - if( !XPathEvaluator.class.isAssignableFrom(c) ) { - throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class); - } - return c.getConstructor(new Class[]{String.class}); - } - - private final String xpath; - private final XPathEvaluator evaluator; - - static public interface XPathEvaluator { - public boolean evaluate(AMQMessage message) throws AMQException; - } - - XPathExpression(String xpath) { - this.xpath = xpath; - this.evaluator = createEvaluator(xpath); - } - - private XPathEvaluator createEvaluator(String xpath2) { - try { - return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath}); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if( cause instanceof RuntimeException ) { - throw (RuntimeException)cause; - } - throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); - } catch (Throwable e) { - throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); - } - } - - public Object evaluate(AMQMessage message) throws AMQException { -// try { -//FIXME this is flow to disk work -// if( message.isDropped() ) -// return null; - return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE; -// } catch (IOException e) { -// -// JMSException exception = new JMSException(e.getMessage()); -// exception.initCause(e); -// throw exception; -// -// } - - } - - public String toString() { - return "XPATH "+ConstantExpression.encodeString(xpath); - } - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException - */ - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java deleted file mode 100644 index f5debb607a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -/** - * Used to evaluate an XQuery Expression in a JMS selector. - */ -public final class XQueryExpression implements BooleanExpression { - private final String xpath; - - XQueryExpression(String xpath) { - super(); - this.xpath = xpath; - } - - public Object evaluate(AMQMessage message) throws AMQException { - return Boolean.FALSE; - } - - public String toString() { - return "XQUERY "+ConstantExpression.encodeString(xpath); - } - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException - */ - public boolean matches(AMQMessage message) throws AMQException - { - Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java deleted file mode 100644 index 35d770fd5d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.io.ByteArrayInputStream; -import java.io.StringReader; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.xpath.CachedXPathAPI; -import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; -import org.xml.sax.InputSource; - -public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { - - private final String xpath; - - public XalanXPathEvaluator(String xpath) { - this.xpath = xpath; - } - - public boolean evaluate(AMQMessage m) throws AMQException - { - // TODO - we would have to check the content type and then evaluate the content - // here... is this really a feature we wish to implement? - RobG - /* - - if( m instanceof TextMessage ) { - String text = ((TextMessage)m).getText(); - return evaluate(text); - } else if ( m instanceof BytesMessage ) { - BytesMessage bm = (BytesMessage) m; - byte data[] = new byte[(int) bm.getBodyLength()]; - bm.readBytes(data); - return evaluate(data); - } - */ - return false; - - } - - private boolean evaluate(byte[] data) { - try { - - InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder dbuilder = factory.newDocumentBuilder(); - Document doc = dbuilder.parse(inputSource); - - CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); - NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); - return iterator.nextNode()!=null; - - } catch (Throwable e) { - return false; - } - } - - private boolean evaluate(String text) { - try { - InputSource inputSource = new InputSource(new StringReader(text)); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder dbuilder = factory.newDocumentBuilder(); - Document doc = dbuilder.parse(inputSource); - - // We should associated the cachedXPathAPI object with the message being evaluated - // since that should speedup subsequent xpath expressions. - CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); - NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); - return iterator.nextNode()!=null; - } catch (Throwable e) { - return false; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java deleted file mode 100644 index a6972475a6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicAckBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class BasicAckMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicAckMethodHandler.class); - - private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); - - public static BasicAckMethodHandler getInstance() - { - return _instance; - } - - private BasicAckMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession protocolSession = stateManager.getProtocolSession(); - BasicAckBody body = evt.getMethod(); - - if (_log.isDebugEnabled()) - { - _log.debug("Ack(Tag:" + body.deliveryTag + ":Mult:" + body.multiple + ") received on channel " + evt.getChannelId()); - } - - final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - // this method throws an AMQException if the delivery tag is not known - channel.acknowledgeMessage(body.deliveryTag, body.multiple); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java deleted file mode 100644 index 8bab96a11b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicCancelBody; -import org.apache.qpid.framing.BasicCancelOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; - -public class BasicCancelMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicCancelMethodHandler.class); - - private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); - - public static BasicCancelMethodHandler getInstance() - { - return _instance; - } - - private BasicCancelMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession protocolSession = stateManager.getProtocolSession(); - - final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - final BasicCancelBody body = evt.getMethod(); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - if (_log.isDebugEnabled()) - { - _log.debug("BasicCancel: for:" + body.consumerTag + - " nowait:" + body.nowait); - } - - channel.unsubscribeConsumer(protocolSession, body.consumerTag); - if (!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - final AMQFrame responseFrame = BasicCancelOkBody.createAMQFrame(evt.getChannelId(), - (byte) 8, (byte) 0, // AMQP version (major, minor) - body.consumerTag); // consumerTag - protocolSession.writeFrame(responseFrame); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java deleted file mode 100644 index ab4f2c4e64..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQShortString; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicConsumeOkBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.ExistingExclusiveSubscriptionException; -import org.apache.qpid.server.queue.ExistingSubscriptionPreventsExclusiveException; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - BasicConsumeBody body = evt.getMethod(); - final int channelId = evt.getChannelId(); - - AMQChannel channel = session.getChannel(channelId); - - VirtualHost vHost = session.getVirtualHost(); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug("BasicConsume: from '" + body.queue + - "' for:" + body.consumerTag + - " nowait:" + body.nowait + - " args:" + body.arguments); - } - - AMQQueue queue = body.queue == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.queue); - - if (queue == null) - { - if (_log.isTraceEnabled()) - { - _log.trace("No queue for '" + body.queue + "'"); - } - if (body.queue != null) - { - String msg = "No such queue, '" + body.queue + "'"; - throw body.getChannelException(AMQConstant.NOT_FOUND, msg); - } - else - { - String msg = "No queue name provided, no default queue defined."; - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg); - } - } - else - { - - if (body.consumerTag != null) - { - body.consumerTag = body.consumerTag.intern(); - } - - try - { - AMQShortString consumerTag = channel.subscribeToQueue(body.consumerTag, queue, session, !body.noAck, - body.arguments, body.noLocal, body.exclusive); - if (!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(BasicConsumeOkBody.createAMQFrame(channelId, - (byte) 8, (byte) 0, // AMQP version (major, minor) - consumerTag)); // consumerTag - } - - //now allow queue to start async processing of any backlog of messages - queue.deliverAsync(); - } - catch (org.apache.qpid.AMQInvalidArgumentException ise) - { - _log.debug("Closing connection due to invalid selector"); - // Why doesn't this ChannelException work. -// throw body.getChannelException(AMQConstant.INVALID_ARGUMENT, ise.getMessage()); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(ChannelCloseBody.createAMQFrame(channelId, - (byte) 8, (byte) 0, // AMQP version (major, minor) - BasicConsumeBody.getClazz((byte) 8, (byte) 0), // classId - BasicConsumeBody.getMethod((byte) 8, (byte) 0), // methodId - AMQConstant.INVALID_ARGUMENT.getCode(), // replyCode - new AMQShortString(ise.getMessage()))); // replyText - } - catch (ConsumerTagNotUniqueException e) - { - AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.consumerTag + "'"); - // If the above doesn't work then perhaps this is wrong too. -// throw body.getConnectionException(AMQConstant.NOT_ALLOWED, -// "Non-unique consumer tag, '" + body.consumerTag + "'"); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(ConnectionCloseBody.createAMQFrame(channelId, - (byte) 8, (byte) 0, // AMQP version (major, minor) - BasicConsumeBody.getClazz((byte) 8, (byte) 0), // classId - BasicConsumeBody.getMethod((byte) 8, (byte) 0), // methodId - AMQConstant.NOT_ALLOWED.getCode(), // replyCode - msg)); // replyText - } - catch (ExistingExclusiveSubscriptionException e) - { - throw body.getChannelException(AMQConstant.ACCESS_REFUSED, - "Cannot subscribe to queue " - + queue.getName() - + " as it already has an existing exclusive consumer"); - } - catch (ExistingSubscriptionPreventsExclusiveException e) - { - throw body.getChannelException(AMQConstant.ACCESS_REFUSED, - "Cannot subscribe to queue " - + queue.getName() - + " exclusively as it already has a consumer"); - } - - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java deleted file mode 100644 index 782a89c704..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicGetBody; -import org.apache.qpid.framing.BasicGetEmptyBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicGetMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); - - private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); - - public static BasicGetMethodHandler getInstance() - { - return _instance; - } - - private BasicGetMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - BasicGetBody body = evt.getMethod(); - final int channelId = evt.getChannelId(); - VirtualHost vHost = session.getVirtualHost(); - - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - else - { - AMQQueue queue = body.queue == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.queue); - - if (queue == null) - { - _log.info("No queue for '" + body.queue + "'"); - if(body.queue!=null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, - "No such queue, '" + body.queue + "'"); - } - else - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "No queue name provided, no default queue defined."); - } - } - else - { - if(!queue.performGet(session, channel, !body.noAck)) - { - - - // TODO - set clusterId - session.writeFrame(BasicGetEmptyBody.createAMQFrame(channelId, body.getMajor(), body.getMinor(), null)); - } - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java deleted file mode 100644 index 541d2afaf4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicPublishMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicPublishMethodHandler.class); - - private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); - - - public static BasicPublishMethodHandler getInstance() - { - return _instance; - } - - private BasicPublishMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - final BasicPublishBody body = evt.getMethod(); - - if (_log.isDebugEnabled()) - { - _log.debug("Publish received on channel " + evt.getChannelId()); - } - - // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? - if (body.exchange == null) - { - body.exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; - - } - else - { - body.exchange = body.exchange.intern(); - } - VirtualHost vHost = session.getVirtualHost(); - Exchange e = vHost.getExchangeRegistry().getExchange(body.exchange); - // if the exchange does not exist we raise a channel exception - if (e == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name"); - } - 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 = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - if(body.routingKey != null) - { - body.routingKey = body.routingKey.intern(); - } - - MessagePublishInfo info = session.getRegistry().getProtocolVersionMethodConverter().convertToInfo(body); - channel.setPublishFrame(info, session); - } - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java deleted file mode 100644 index 3cd6a87f64..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicQosBody; -import org.apache.qpid.framing.BasicQosOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class BasicQosHandler implements StateAwareMethodListener -{ - private static final BasicQosHandler _instance = new BasicQosHandler(); - - public static BasicQosHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - AMQChannel channel = session.getChannel(evt.getChannelId()); - if (channel == null) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - - channel.setPrefetchCount(evt.getMethod().prefetchCount); - channel.setPrefetchSize(evt.getMethod().prefetchSize); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(BasicQosOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java deleted file mode 100644 index a436c35473..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.BasicRecoverOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.debug("Recover received on protocol session " + session + " and channel " + evt.getChannelId()); - AMQChannel channel = session.getChannel(evt.getChannelId()); - BasicRecoverBody body = evt.getMethod(); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - channel.resend(body.requeue); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(BasicRecoverOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java deleted file mode 100644 index 32c840106f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.BasicRejectBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ack.UnacknowledgedMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class BasicRejectMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRejectMethodHandler.class); - - private static BasicRejectMethodHandler _instance = new BasicRejectMethodHandler(); - - public static BasicRejectMethodHandler getInstance() - { - return _instance; - } - - private BasicRejectMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - int channelId = evt.getChannelId(); - -// if (_logger.isDebugEnabled()) -// { -// _logger.debug("Rejecting:" + evt.getMethod().deliveryTag + -// ": Requeue:" + evt.getMethod().requeue + -//// ": Resend:" + evt.getMethod().resend + -// " on channel:" + channelId); -// } - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw evt.getMethod().getChannelNotFoundException(channelId); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Rejecting:" + evt.getMethod().deliveryTag + - ": Requeue:" + evt.getMethod().requeue + - //": Resend:" + evt.getMethod().resend + - " on channel:" + channel.debugIdentity()); - } - - long deliveryTag = evt.getMethod().deliveryTag; - - UnacknowledgedMessage message = channel.getUnacknowledgedMessageMap().get(deliveryTag); - - if (message == null) - { - _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag); -// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known"); - } - else - { - - if (_logger.isTraceEnabled()) - { - _logger.trace("Rejecting: DT:" + deliveryTag + "-" + message.message.debugIdentity() + - ": Requeue:" + evt.getMethod().requeue + - //": Resend:" + evt.getMethod().resend + - " on channel:" + channel.debugIdentity()); - } - - // If we haven't requested message to be resent to this consumer then reject it from ever getting it. -// if (!evt.getMethod().resend) - { - message.message.reject(message.message.getDeliveredSubscription(message.queue)); - } - - if (evt.getMethod().requeue) - { - channel.requeue(deliveryTag); - } - else - { - _logger.warn("Dropping message as requeue not required and there is no dead letter queue"); -// message.queue = channel.getDefaultDeadLetterQueue(); -// channel.requeue(deliveryTag); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java deleted file mode 100644 index 1f4f1f9221..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - ChannelCloseBody body = evt.getMethod(); - if (_logger.isInfoEnabled()) - { - _logger.info("Received channel close for id " + evt.getChannelId() + " citing class " + body.classId + - " and method " + body.methodId); - } - int channelId = evt.getChannelId(); - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel"); - } - - session.closeChannel(channelId); - // Client requested closure so we don't wait for ok we send it - stateManager.getProtocolSession().closeChannelOk(channelId); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ChannelCloseOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0); - session.writeFrame(response); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java deleted file mode 100644 index ad5604e7ea..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - int channelId = evt.getChannelId(); - _logger.info("Received channel-close-ok for channel-id " + channelId); - - // Let the Protocol Session know the channel is now closed. - stateManager.getProtocolSession().closeChannelOk(channelId); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java deleted file mode 100644 index bfa170cfc5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.ChannelFlowBody; -import org.apache.qpid.framing.ChannelFlowOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - ChannelFlowBody body = evt.getMethod(); - - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - channel.setSuspended(!body.active); - _logger.debug("Channel.Flow for channel " + evt.getChannelId() + ", active=" + body.active); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ChannelFlowOkBody.createAMQFrame(evt.getChannelId(), - (byte)8, (byte)0, // AMQP version (major, minor) - body.active); // active - session.writeFrame(response); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java deleted file mode 100644 index e4abae4f28..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ChannelOpenBody; -import org.apache.qpid.framing.ChannelOpenOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class ChannelOpenHandler implements StateAwareMethodListener -{ - private static ChannelOpenHandler _instance = new ChannelOpenHandler(); - - public static ChannelOpenHandler getInstance() - { - return _instance; - } - - private ChannelOpenHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - - final AMQChannel channel = new AMQChannel(session,evt.getChannelId(), virtualHost.getTransactionManager(), - virtualHost.getMessageStore(), - virtualHost.getExchangeRegistry()); - session.addChannel(channel); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ChannelOpenOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - session.writeFrame(response); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java deleted file mode 100644 index b086cad67f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - final ConnectionCloseBody body = evt.getMethod(); - if (_logger.isInfoEnabled()) - { - _logger.info("ConnectionClose received with reply code/reply text " + body.replyCode + "/" + - body.replyText + " for " + session); - } - try - { - session.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = ConnectionCloseOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0); - session.writeFrame(response); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java deleted file mode 100644 index 853f4df435..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.ConnectionCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - //todo should this not do more than just log the method? - _logger.info("Received Connection-close-ok"); - - try - { - stateManager.changeState(AMQState.CONNECTION_CLOSED); - session.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java deleted file mode 100644 index 30a40c5a75..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionOpenBody; -import org.apache.qpid.framing.ConnectionOpenOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -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.virtualhost.VirtualHost; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.AccessRights; -import org.apache.log4j.Logger; - -public class ConnectionOpenMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); - - private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); - - public static ConnectionOpenMethodHandler getInstance() - { - return _instance; - } - - private ConnectionOpenMethodHandler() - { - } - - private static AMQShortString generateClientID() - { - return new AMQShortString(Long.toString(System.currentTimeMillis())); - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - ConnectionOpenBody body = evt.getMethod(); - - //ignore leading '/' - String virtualHostName; - if ((body.virtualHost != null) && body.virtualHost.charAt(0) == '/') - { - virtualHostName = new StringBuilder(body.virtualHost.subSequence(1, body.virtualHost.length())).toString(); - } - else - { - virtualHostName = body.virtualHost == null ? null : String.valueOf(body.virtualHost); - } - - VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); - - if (virtualHost == null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'"); - } - else - { - session.setVirtualHost(virtualHost); - - AccessResult result = virtualHost.getAccessManager().isAuthorized(virtualHost, session.getAuthorizedID(), AccessRights.Rights.ANY); - - switch (result.getStatus()) - { - default: - case REFUSED: - String error = "Any access denied to vHost '" + virtualHostName + "' by " - + result.getAuthorizer(); - - _logger.warn(error); - - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, error); - case GRANTED: - _logger.info("Granted any access to vHost '" + virtualHostName + "' for " + session.getAuthorizedID() - + " by '" + result.getAuthorizer() + "'"); - } - - // See Spec (0.8.2). Section 3.1.2 Virtual Hosts - if (session.getContextKey() == null) - { - session.setContextKey(generateClientID()); - } - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short) 0, - (byte) 8, (byte) 0, // AMQP version (major, minor) - body.virtualHost); - stateManager.changeState(AMQState.CONNECTION_OPEN); - session.writeFrame(response); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java deleted file mode 100644 index 43986adea7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionSecureBody; -import org.apache.qpid.framing.ConnectionSecureOkBody; -import org.apache.qpid.framing.ConnectionTuneBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - ConnectionSecureOkBody body = evt.getMethod(); - - //fixme Vhost not defined yet - //session.getVirtualHost().getAuthenticationManager(); - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); - - SaslServer ss = session.getSaslServer(); - if (ss == null) - { - throw new AMQException(null, "No SASL context set up in session", null); - } - - 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); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame close = ConnectionCloseBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) - ConnectionCloseBody.getClazz((byte)8, (byte)0), // classId - ConnectionCloseBody.getMethod((byte)8, (byte)0), // methodId - AMQConstant.NOT_ALLOWED.getCode(), // replyCode - AMQConstant.NOT_ALLOWED.getName()); // replyText - session.writeFrame(close); - disposeSaslServer(session); - break; - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - // TODO: Check the value of channelMax here: This should be the max - // value of a 2-byte unsigned integer (as channel is only 2 bytes on the wire), - // not Integer.MAX_VALUE (which is signed 4 bytes). - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) - Integer.MAX_VALUE, // channelMax - ConnectionStartOkMethodHandler.getConfiguredFrameSize(), // frameMax - HeartbeatConfig.getInstance().getDelay()); // heartbeat - session.writeFrame(tune); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); - disposeSaslServer(session); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) - authResult.challenge); // challenge - session.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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java deleted file mode 100644 index 5dbd1b18de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionSecureBody; -import org.apache.qpid.framing.ConnectionStartOkBody; -import org.apache.qpid.framing.ConnectionTuneBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - final ConnectionStartOkBody body = evt.getMethod(); - _logger.info("SASL Mechanism selected: " + body.mechanism); - _logger.info("Locale selected: " + body.locale); - - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); - - SaslServer ss = null; - try - { - ss = authMgr.createSaslServer(String.valueOf(body.mechanism), session.getLocalFQDN()); - - if (ss == null) - { - throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.mechanism - ); - } - - session.setSaslServer(ss); - - AuthenticationResult authResult = authMgr.authenticate(ss, body.response); - - //save clientProperties - if (session.getClientProperties() == null) - { - session.setClientProperties(body.clientProperties); - } - - switch (authResult.status) - { - case ERROR: - _logger.info("Authentication failed"); - stateManager.changeState(AMQState.CONNECTION_CLOSING); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame close = ConnectionCloseBody.createAMQFrame(0, - (byte) 8, (byte) 0, // AMQP version (major, minor) - ConnectionCloseBody.getClazz((byte) 8, (byte) 0), // classId - ConnectionCloseBody.getMethod((byte) 8, (byte) 0), // methodId - AMQConstant.NOT_ALLOWED.getCode(), // replyCode - AMQConstant.NOT_ALLOWED.getName()); // replyText - session.writeFrame(close); - disposeSaslServer(session); - break; - - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); - - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, - (byte) 8, (byte) 0, // AMQP version (major, minor) - Integer.MAX_VALUE, // channelMax - getConfiguredFrameSize(), // frameMax - HeartbeatConfig.getInstance().getDelay()); // heartbeat - session.writeFrame(tune); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, - (byte) 8, (byte) 0, // AMQP version (major, minor) - authResult.challenge); // challenge - session.writeFrame(challenge); - } - } - catch (SaslException e) - { - disposeSaslServer(session); - throw new AMQException(null, "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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java deleted file mode 100644 index ab7695955c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionTuneOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - ConnectionTuneOkBody body = evt.getMethod(); - if (_logger.isDebugEnabled()) - { - _logger.debug(body); - } - stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); - session.initHeartbeats(body.heartbeat); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java deleted file mode 100644 index 0ff19bdf9e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQShortString; -import org.apache.qpid.framing.ExchangeBoundBody; -import org.apache.qpid.framing.ExchangeBoundOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.exchange.Exchange; -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.virtualhost.VirtualHost; - -/** - * @author Apache Software Foundation - */ -public class ExchangeBoundHandler implements StateAwareMethodListener -{ - private static final ExchangeBoundHandler _instance = new ExchangeBoundHandler(); - - public static final int OK = 0; - - public static final int EXCHANGE_NOT_FOUND = 1; - - public static final int QUEUE_NOT_FOUND = 2; - - public static final int NO_BINDINGS = 3; - - public static final int QUEUE_NOT_BOUND = 4; - - public static final int NO_QUEUE_BOUND_WITH_RK = 5; - - public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; - - public static ExchangeBoundHandler getInstance() - { - return _instance; - } - - private ExchangeBoundHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - byte major = (byte)8; - byte minor = (byte)0; - - ExchangeBoundBody body = evt.getMethod(); - - AMQShortString exchangeName = body.exchange; - AMQShortString queueName = body.queue; - AMQShortString routingKey = body.routingKey; - if (exchangeName == null) - { - throw new AMQException(null, "Exchange exchange must not be null", null); - } - Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); - AMQFrame response; - if (exchange == null) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - EXCHANGE_NOT_FOUND, // replyCode - new AMQShortString("Exchange " + exchangeName + " not found")); // replyText - } - else if (routingKey == null) - { - if (queueName == null) - { - if (exchange.hasBindings()) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - OK, // replyCode - null); // replyText - } - else - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - NO_BINDINGS, // replyCode - null); // replyText - } - } - else - { - - AMQQueue queue = queueRegistry.getQueue(queueName); - if (queue == null) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - QUEUE_NOT_FOUND, // replyCode - new AMQShortString("Queue " + queueName + " not found")); // replyText - } - else - { - if (exchange.isBound(queue)) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - OK, // replyCode - null); // replyText - } - else - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - QUEUE_NOT_BOUND, // replyCode - new AMQShortString("Queue " + queueName + " not bound to exchange " + exchangeName)); // replyText - } - } - } - } - else if (queueName != null) - { - AMQQueue queue = queueRegistry.getQueue(queueName); - if (queue == null) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - QUEUE_NOT_FOUND, // replyCode - new AMQShortString("Queue " + queueName + " not found")); // replyText - } - else - { - if (exchange.isBound(body.routingKey, queue)) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - OK, // replyCode - null); // replyText - } - else - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode - new AMQShortString("Queue " + queueName + " not bound with routing key " + - body.routingKey + " to exchange " + exchangeName)); // replyText - } - } - } - else - { - if (exchange.isBound(body.routingKey)) - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - OK, // replyCode - null); // replyText - } - else - { - // AMQP version change: Be aware of possible changes to parameter order as versions change. - response = ExchangeBoundOkBody.createAMQFrame(evt.getChannelId(), - major, minor, // AMQP version (major, minor) - NO_QUEUE_BOUND_WITH_RK, // replyCode - new AMQShortString("No queue bound with routing key " + body.routingKey + - " to exchange " + exchangeName)); // replyText - } - } - session.writeFrame(response); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java deleted file mode 100644 index f0f6fde08c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQConnectionException; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ExchangeDeclareBody; -import org.apache.qpid.framing.ExchangeDeclareOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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 ExchangeDeclareHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); - - 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) - { - if(body.passive && ((body.type == null) || body.type.length() ==0)) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + body.exchange); - } - else - { - try - { - - exchange = exchangeFactory.createExchange(body.exchange == null ? null : body.exchange.intern(), - body.type == null ? null : body.type.intern(), - body.durable, - body.passive, body.ticket); - exchangeRegistry.registerExchange(exchange); - } - catch(AMQUnknownExchangeType e) - { - throw body.getConnectionException(AMQConstant.COMMAND_INVALID, "Unknown exchange: " + body.exchange,e); - } - } - } - else if (!exchange.getType().equals(body.type)) - { - - throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.exchange + " of type " + exchange.getType() + " to " + body.type +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(), null); - } - - } - if(!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ExchangeDeclareOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - session.writeFrame(response); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java deleted file mode 100644 index f9926c399c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.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.protocol.AMQMethodEvent; -import org.apache.qpid.server.exchange.ExchangeInUseException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - - ExchangeDeleteBody body = evt.getMethod(); - try - { - exchangeRegistry.unregisterExchange(body.exchange, body.ifUnused); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ExchangeDeleteOkBody.createAMQFrame(evt.getChannelId(), (byte)8, (byte)0); - session.writeFrame(response); - } - catch (ExchangeInUseException e) - { - // TODO: sort out consistent channel close mechanism that does all clean up etc. - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java deleted file mode 100644 index ac516b6133..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import java.util.concurrent.Executor; - -/** - * An executor that executes the task on the current thread. - */ -public class OnCurrentThreadExecutor implements Executor -{ - public void execute(Runnable command) - { - command.run(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java deleted file mode 100644 index 3e68069838..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.QueueBindBody; -import org.apache.qpid.framing.QueueBindOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.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.virtualhost.VirtualHost; - -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, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - final QueueBindBody body = evt.getMethod(); - final AMQQueue queue; - if (body.queue == null) - { - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - queue = channel.getDefaultQueue(); - - if (queue == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "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, "Queue " + body.queue + " does not exist."); - } - final Exchange exch = exchangeRegistry.getExchange(body.exchange); - if (exch == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.exchange + " does not exist."); - } - - if (body.routingKey != null) - { - body.routingKey = body.routingKey.intern(); - } - - try - { - if (!exch.isBound(body.routingKey, body.arguments, queue)) - { - queue.bind(body.routingKey, body.arguments, exch); - } - } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, body.routingKey.toString()); - } - catch (AMQException e) - { - throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); - } - - if (_log.isInfoEnabled()) - { - _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + body.routingKey); - } - if (!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0); - session.writeFrame(response); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java deleted file mode 100644 index 9be0dabb68..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.text.MessageFormat; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.QueueDeclareOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.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.store.MessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.commons.configuration.Configuration; - -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(); - - - protected QueueDeclareHandler() - { - Configurator.configure(this); - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore store = virtualHost.getMessageStore(); - - 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(); - } - - AMQQueue queue; - //TODO: do we need to check that the queue already exists with exactly the same "configuration"? - - synchronized (queueRegistry) - { - - if (((queue = queueRegistry.getQueue(body.queue)) == null)) - { - if(body.queue != null) - { - body.queue = body.queue.intern(); - } - - if (body.passive) - { - String msg = "Queue: " + body.queue + " not found on VirtualHost(" + virtualHost + ")."; - throw body.getChannelException(AMQConstant.NOT_FOUND, msg); - } - else - { - queue = createQueue(body, virtualHost, session); - if (queue.isDurable() && !queue.isAutoDelete()) - { - //DTX MessageStore -// try -// { - store.createQueue(queue); -// } catch (Exception e) -// { -// throw new AMQException(null, "Problem when creating queue " + queue, e); -// } - } - queueRegistry.registerQueue(queue); - if (autoRegister) - { - Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); - - queue.bind(body.queue, null, defaultExchange); - _log.info("Queue " + body.queue + " bound to default exchange(" + defaultExchange.getName() + ")"); - } - } - } - else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) - { - throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + body.queue + "')," - + " as exclusive queue with same name " - + "declared on another client ID('" - + queue.getOwner() + "')"); - } - - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - //set this as the default queue on the channel: - channel.setDefaultQueue(queue); - } - - if (!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - AMQFrame response = QueueDeclareOkBody.createAMQFrame(evt.getChannelId(), - (byte) 8, (byte) 0, // AMQP version (major, minor) - queue.getConsumerCount(), // consumerCount - queue.getMessageCount(), // messageCount - body.queue); // queue - _log.info("Queue " + body.queue + " declared successfully"); - session.writeFrame(response); - } - } - - protected AMQShortString createName() - { - return new AMQShortString("tmp_" + pad(_counter.incrementAndGet())); - } - - protected static String pad(int value) - { - return MessageFormat.format("{0,number,0000000000000}", value); - } - - protected AMQQueue createQueue(QueueDeclareBody body, VirtualHost virtualHost, final AMQProtocolSession session) - throws AMQException - { - final QueueRegistry registry = virtualHost.getQueueRegistry(); - AMQShortString owner = body.exclusive ? session.getContextKey() : null; - final AMQQueue queue = new AMQQueue(body.queue, body.durable, owner, body.autoDelete, virtualHost); - final AMQShortString queueName = queue.getName(); - - if (body.exclusive && !body.durable) - { - final AMQProtocolSession.Task deleteQueueTask = - new AMQProtocolSession.Task() - { - public void doTask(AMQProtocolSession session) throws AMQException - { - if (registry.getQueue(queueName) == queue) - { - queue.delete(); - } - } - }; - - session.addSessionCloseTask(deleteQueueTask); - - queue.addQueueDeleteTask(new AMQQueue.Task() - { - public void doTask(AMQQueue queue) - { - session.removeSessionCloseTask(deleteQueueTask); - } - }); - }// if exclusive and not durable - - Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); - if (virtualHostDefaultQueueConfiguration != null) - { - Configurator.configure(queue, virtualHostDefaultQueueConfiguration); - } - - return queue; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java deleted file mode 100644 index edeb6f1f48..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.QueueDeleteBody; -import org.apache.qpid.framing.QueueDeleteOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQConstant; -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.store.MessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.QueueDoesntExistException; - -public class QueueDeleteHandler implements StateAwareMethodListener -{ - private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); - - public static QueueDeleteHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueueDeleteHandler() - { - this(true); - } - - public QueueDeleteHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore store = virtualHost.getMessageStore(); - - QueueDeleteBody body = evt.getMethod(); - AMQQueue queue; - if (body.queue == null) - { - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - } - else - { - queue = queueRegistry.getQueue(body.queue); - } - - if (queue == null) - { - if (_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.queue + " does not exist."); - } - } - else - { - if (body.ifEmpty && !queue.isEmpty()) - { - throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.queue + " is not empty."); - } - else if (body.ifUnused && !queue.isUnused()) - { - // TODO - Error code - throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.queue + " is still used."); - - } - else - { - int purged = queue.delete(body.ifUnused, body.ifEmpty); - - if (queue.isDurable()) - { - try - { - //DTX MessageStore -// store.destroyQueue(queue); - store.removeQueue(queue.getName()); - } catch (Exception e) - { - throw new AMQException(null, "problem when destroying queue " + queue, e); - } - } - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(QueueDeleteOkBody.createAMQFrame(evt.getChannelId(), - (byte) 8, (byte) 0, // AMQP version (major, minor) - purged)); // messageCount - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java deleted file mode 100644 index 3e1937bb43..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.QueuePurgeBody; -import org.apache.qpid.framing.QueuePurgeOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.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.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; - -public class QueuePurgeHandler implements StateAwareMethodListener -{ - private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); - - public static QueuePurgeHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueuePurgeHandler() - { - this(true); - } - - public QueuePurgeHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - AMQChannel channel = session.getChannel(evt.getChannelId()); - - QueuePurgeBody body = evt.getMethod(); - AMQQueue queue; - if(body.queue == null) - { - - if (channel == null) - { - throw body.getChannelNotFoundException(evt.getChannelId()); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); - } - } - } - else - { - queue = queueRegistry.getQueue(body.queue); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.queue + " does not exist."); - } - } - else - { - long purged = queue.clearQueue(channel.getStoreContext()); - - - if(!body.nowait) - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(QueuePurgeOkBody.createAMQFrame(evt.getChannelId(), - (byte)8, (byte)0, // AMQP version (major, minor) - purged)); // messageCount - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java deleted file mode 100644 index 3d7ec286f9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxCommitBody; -import org.apache.qpid.framing.TxCommitOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxCommitHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(TxCommitHandler.class); - - private static TxCommitHandler _instance = new TxCommitHandler(); - - public static TxCommitHandler getInstance() - { - return _instance; - } - - private TxCommitHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - try - { - if (_log.isDebugEnabled()) - { - _log.debug("Commit received on channel " + evt.getChannelId()); - } - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - - channel.commit(); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); - channel.processReturns(session); - } - catch (AMQException e) - { - throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java deleted file mode 100644 index f747f7a840..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxRollbackBody; -import org.apache.qpid.framing.TxRollbackOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxRollbackHandler implements StateAwareMethodListener -{ - private static TxRollbackHandler _instance = new TxRollbackHandler(); - - public static TxRollbackHandler getInstance() - { - return _instance; - } - - private TxRollbackHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - try - { - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - - channel.rollback(); - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); - //Now resend all the unacknowledged messages back to the original subscribers. - //(Must be done after the TxnRollback-ok response). - // Why, are we not allowed to send messages back to client before the ok method? - channel.resend(false); - } - catch (AMQException e) - { - throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java deleted file mode 100644 index a9e478e301..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class TxSelectHandler implements StateAwareMethodListener -{ - private static TxSelectHandler _instance = new TxSelectHandler(); - - public static TxSelectHandler getInstance() - { - return _instance; - } - - private TxSelectHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AMQMethodEvent evt) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - AMQChannel channel = session.getChannel(evt.getChannelId()); - - if (channel == null) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - - channel.setLocalTransactional(); - - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - session.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId(), (byte) 8, (byte) 0)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java deleted file mode 100644 index c08fae4e4e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.jms; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -public class JmsConsumer -{ - private int _prefetchValue; - - private PrefetchUnits _prefetchUnits; - - private boolean _noLocal; - - private boolean _autoAck; - - private boolean _exclusive; - - private AMQProtocolSession _protocolSession; - - public enum PrefetchUnits - { - OCTETS, - MESSAGES - } - - public int getPrefetchValue() - { - return _prefetchValue; - } - - public void setPrefetchValue(int prefetchValue) - { - _prefetchValue = prefetchValue; - } - - public PrefetchUnits getPrefetchUnits() - { - return _prefetchUnits; - } - - public void setPrefetchUnits(PrefetchUnits prefetchUnits) - { - _prefetchUnits = prefetchUnits; - } - - public boolean isNoLocal() - { - return _noLocal; - } - - public void setNoLocal(boolean noLocal) - { - _noLocal = noLocal; - } - - public boolean isAutoAck() - { - return _autoAck; - } - - public void setAutoAck(boolean autoAck) - { - _autoAck = autoAck; - } - - public boolean isExclusive() - { - return _exclusive; - } - - public void setExclusive(boolean exclusive) - { - _exclusive = exclusive; - } - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void setProtocolSession(AMQProtocolSession protocolSession) - { - _protocolSession = protocolSession; - } - - public void deliverMessage() throws AMQException - { - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java deleted file mode 100644 index a2c2bd62a2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.ListenerNotFoundException; -import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; - -/** - * This class provides additinal feature of Notification Broadcaster to the - * DefaultManagedObject. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public abstract class AMQManagedObject extends DefaultManagedObject - implements NotificationBroadcaster -{ - /** - * broadcaster support class - */ - protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); - - /** - * sequence number for notifications - */ - protected long _notificationSequenceNumber = 0; - - protected MBeanInfo _mbeanInfo; - - protected AMQManagedObject(Class managementInterface, String typeName) - throws NotCompliantMBeanException - { - super(managementInterface, typeName); - buildMBeanInfo(); - } - - @Override - public MBeanInfo getMBeanInfo() - { - return _mbeanInfo; - } - - private void buildMBeanInfo() throws NotCompliantMBeanException - { - _mbeanInfo = new MBeanInfo(this.getClass().getName(), - MBeanIntrospector.getMBeanDescription(this.getClass()), - MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()), - MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()), - MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()), - this.getNotificationInfo()); - } - - - - // notification broadcaster implementation - - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - { - _broadcaster.addNotificationListener(listener, filter, handback); - } - - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException - { - _broadcaster.removeNotificationListener(listener); - } - - public MBeanNotificationInfo[] getNotificationInfo() - { - return null; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java deleted file mode 100644 index 31313cf024..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.StandardMBean; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; - -/** - * 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 - { - getManagedObjectRegistry().registerObject(this); - } - catch (JMException e) - { - throw new AMQException(null, "Error registering managed object " + this + ": " + e, e); - } - } - - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - - public void unregister() throws AMQException - { - try - { - getManagedObjectRegistry().unregisterObject(this); - } - catch (JMException e) - { - throw new AMQException(null, "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()); - } - - protected ObjectName getObjectNameForSingleInstanceMBean() throws MalformedObjectNameException - { - StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); - - objectName.append(":type="); - objectName.append(getHierarchicalType(this)); - - String hierarchyName = getHierarchicalName(this); - if (hierarchyName != null) - { - objectName.append(","); - objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); - } - - return new ObjectName(objectName.toString()); - } - - protected String getHierarchicalType(ManagedObject obj) - { - if (obj.getParentObject() != null) - { - String parentType = getHierarchicalType(obj.getParentObject()).toString(); - return parentType + "." + obj.getType(); - } - else - return obj.getType(); - } - - protected String getHierarchicalName(ManagedObject obj) - { - if (obj.getParentObject() != null) - { - String 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; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java deleted file mode 100644 index 9dce752021..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; - -import javax.management.JMException; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.MBeanServerForwarder; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.UnicastRemoteObject; -import java.util.HashMap; -import java.util.Map; - -/** - * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features - * implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env - * variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be - * used, which again doesn't have user authentication. - */ -public class JMXManagedObjectRegistry implements ManagedObjectRegistry -{ - private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); - - private final MBeanServer _mbeanServer; - private Registry _rmiRegistry; - private JMXServiceURL _jmxURL; - - public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; - public static final int MANAGEMENT_PORT_DEFAULT = 8999; - - public JMXManagedObjectRegistry() throws AMQException - { - _log.info("Initialising managed object registry using platform MBean server"); - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - - // Retrieve the config parameters - boolean platformServer = appRegistry.getConfiguration().getBoolean("management.platform-mbeanserver", true); - - _mbeanServer = - platformServer ? ManagementFactory.getPlatformMBeanServer() - : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); - } - - - public void start() throws IOException - { - // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent - if (areOutOfTheBoxJMXOptionsSet()) - { - _log.info("JMX: Using the out of the box JMX Agent"); - return; - } - - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - - boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); - int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT); - - if (security) - { - // For SASL using JMXMP - _jmxURL = new JMXServiceURL("jmxmp", null, port); - - Map env = new HashMap(); - Map map = appRegistry.getDatabaseManager().getDatabases(); - PrincipalDatabase db = null; - - for (Map.Entry entry : map.entrySet()) - { - if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) - { - db = entry.getValue(); - break; - } - else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) - { - db = entry.getValue(); - } - } - - if (db instanceof Base64MD5PasswordFilePrincipalDatabase) - { - env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); - CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); - initialiser.initialise(db); - env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); - } - else if (db instanceof PlainPasswordFilePrincipalDatabase) - { - env.put("jmx.remote.profiles", "SASL/PLAIN"); - env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); - } - - // Enable the SSL security and server authentication - /* - SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); - SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); - env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); - env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); - */ - - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - cs.start(); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL"); - - } - else - { - startJMXConnectorServer(port); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled"); - } - } - - /** - * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it. - * - * @param port - * - * @throws IOException - */ - private void startJMXConnectorServer(int port) throws IOException - { - startRMIRegistry(port); - _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); - cs.start(); - } - - public void registerObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.unregisterMBean(managedObject.getObjectName()); - } - - /** - * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent. - * - * @return - */ - private boolean areOutOfTheBoxJMXOptionsSet() - { - if (System.getProperty("com.sun.management.jmxremote") != null) - { - return true; - } - - if (System.getProperty("com.sun.management.jmxremote.port") != null) - { - return true; - } - - return false; - } - - /** - * Starts the rmi registry at given port - * - * @param port - * - * @throws RemoteException - */ - private void startRMIRegistry(int port) throws RemoteException - { - System.setProperty("java.rmi.server.randomIDs", "true"); - _rmiRegistry = LocateRegistry.createRegistry(port); - } - - // stops the RMIRegistry, if it was running and bound to a port - public void close() throws RemoteException - { - if (_rmiRegistry != null) - { - // Stopping the RMI registry - UnicastRemoteObject.unexportObject(_rmiRegistry, true); - } - } - - /** This class is used for SASL enabled JMXConnector for performing user authentication. */ - private class UserCallbackHandler implements CallbackHandler - { - private final PrincipalDatabase _principalDatabase; - - protected UserCallbackHandler(PrincipalDatabase database) - { - _principalDatabase = database; - } - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - // Retrieve callbacks - NameCallback ncb = null; - PasswordCallback pcb = null; - for (int i = 0; i < callbacks.length; i++) - { - if (callbacks[i] instanceof NameCallback) - { - ncb = (NameCallback) callbacks[i]; - } - else if (callbacks[i] instanceof PasswordCallback) - { - pcb = (PasswordCallback) callbacks[i]; - } - else if (callbacks[i] instanceof AuthorizeCallback) - { - ((AuthorizeCallback) callbacks[i]).setAuthorized(true); - } - else - { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - - boolean authorized = false; - // Process retrieval of password; can get password if username is available in NameCallback - if ((ncb != null) && (pcb != null)) - { - String username = ncb.getDefaultName(); - try - { - authorized = _principalDatabase.verifyPassword(username, pcb.getPassword()); - } - catch (AccountNotFoundException e) - { - IOException ioe = new IOException("User not authorized. " + e); - ioe.initCause(e); - throw ioe; - } - } - - if (!authorized) - { - throw new IOException("User not authorized."); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java deleted file mode 100644 index 7d42297699..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean attributes. This should be used with getter or setter - * methods of attributes. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanAttribute -{ - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java deleted file mode 100644 index 9138e03085..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean constructors. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.CONSTRUCTOR) -@Inherited -public @interface MBeanConstructor -{ - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java deleted file mode 100644 index 448fed3280..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean class. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -public @interface MBeanDescription { - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java deleted file mode 100644 index 0c2ec2aebd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanConstructorInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.NotCompliantMBeanException; - -/** - * 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()) - { - 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; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java deleted file mode 100644 index 4fb260472d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.server.security.access.UserManagement; -import org.apache.log4j.Logger; - -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.JMXPrincipal; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.JMException; -import javax.security.auth.Subject; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.Principal; -import java.security.AccessControlContext; -import java.util.Set; -import java.util.Properties; - -/** - * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements - * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite - * and admin users. - */ -public class MBeanInvocationHandlerImpl implements InvocationHandler -{ - private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); - - public final static String ADMIN = "admin"; - public final static String READWRITE = "readwrite"; - public final static String READONLY = "readonly"; - private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; - private MBeanServer mbs; - private static Properties _userRoles = new Properties(); - - public static MBeanServerForwarder newProxyInstance() - { - final InvocationHandler handler = new MBeanInvocationHandlerImpl(); - final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; - - Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); - return MBeanServerForwarder.class.cast(proxy); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - final String methodName = method.getName(); - - if (methodName.equals("getMBeanServer")) - { - return mbs; - } - - if (methodName.equals("setMBeanServer")) - { - if (args[0] == null) - { - throw new IllegalArgumentException("Null MBeanServer"); - } - if (mbs != null) - { - throw new IllegalArgumentException("MBeanServer object already initialized"); - } - mbs = (MBeanServer) args[0]; - return null; - } - - // Retrieve Subject from current AccessControlContext - AccessControlContext acc = AccessController.getContext(); - Subject subject = Subject.getSubject(acc); - - // Allow operations performed locally on behalf of the connector server itself - if (subject == null) - { - return method.invoke(mbs, args); - } - - if (args == null || DELEGATE.equals(args[0])) - { - return method.invoke(mbs, args); - } - - // Restrict access to "createMBean" and "unregisterMBean" to any user - if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) - { - _logger.debug("User trying to create or unregister an MBean"); - throw new SecurityException("Access denied"); - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - throw new SecurityException("Access denied"); - } - - Principal principal = principals.iterator().next(); - String identity = principal.getName(); - - if (isAdminMethod(args)) - { - if (isAdmin(identity)) - { - return method.invoke(mbs, args); - } - else - { - throw new SecurityException("Access denied"); - } - } - - // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAllowedToModify(identity)) - { - return method.invoke(mbs, args); - } - - // These users can only call "getAttribute" on the MBeanServerDelegate MBean - // Here we can add other fine grained permissions like specific method for a particular mbean - if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) - { - return method.invoke(mbs, args); - } - - throw new SecurityException("Access denied"); - } - - private boolean isAdminMethod(Object[] args) - { - if (args[0] instanceof ObjectName) - { - ObjectName object = (ObjectName) args[0]; - return UserManagement.TYPE.equals(object.getKeyProperty("type")); - } - - return false; - } - - // Initialises the user roles - public static void setAccessRights(Properties accessRights) - { - _userRoles = accessRights; - } - - private boolean isAdmin(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isAllowedToModify(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName)) - || READWRITE.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isReadOnlyUser(String userName) - { - if (READONLY.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isReadOnlyMethod(Method method, Object[] args) - { - String methodName = method.getName(); - if (methodName.startsWith("query") || methodName.startsWith("get")) - { - return true; - } - else if (methodName.startsWith("set")) - { - return false; - } - - if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) - { - String mbeanMethod = (args.length > 1) ? (String) args[1] : null; - if (mbeanMethod == null) - { - return false; - } - - try - { - MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); - if (mbeanInfo != null) - { - MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); - for (MBeanOperationInfo opInfo : opInfos) - { - if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) - { - return true; - } - } - } - } - catch (JMException ex) - { - ex.printStackTrace(); - } - } - - return false; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java deleted file mode 100644 index a2dca3e51d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.management.MBeanOperationInfo; - -/** - * Annotation for MBean operations. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanOperation -{ - String name(); - String description(); - int impact() default MBeanOperationInfo.INFO; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java deleted file mode 100644 index aba5ec70d8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean operation parameters. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface MBeanOperationParameter { - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java deleted file mode 100644 index 166a2a376d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -/** - * Any object that can return a related MBean should implement this interface. - * - * This enables other classes to get the managed object, which in turn is useful when - * constructing relationships between managed objects without having to maintain - * separate data structures containing MBeans. - * - */ -public interface Managable -{ - ManagedObject getManagedObject(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java deleted file mode 100644 index 45e2e91ed7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.management; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; - -import org.apache.qpid.server.exchange.ManagedExchange; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The ManagedBroker is the management interface to expose management - * features of the Broker. - * - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedBroker -{ - static final String TYPE = "VirtualHostManager"; - - /** - * Creates a new Exchange. - * @param name - * @param type - * @param durable - * @param passive - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) - void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, - @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) - throws IOException, JMException; - - /** - * unregisters all the channels, queuebindings etc and unregisters - * this exchange from managed objects. - * @param exchange - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="unregisterExchange", - description="Unregisters all the related channels and queuebindings of this exchange", - impact= MBeanOperationInfo.ACTION) - void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) - throws IOException, JMException; - - /** - * Create a new Queue on the Broker server - * @param queueName - * @param durable - * @param owner - * @param autoDelete - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) - void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, - @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) - throws IOException, JMException; - - /** - * Unregisters the Queue bindings, removes the subscriptions and unregisters - * from the managed objects. - * @param queueName - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteQueue", - description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", - impact= MBeanOperationInfo.ACTION) - void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) - throws IOException, JMException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java deleted file mode 100644 index 42ea8921a4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.apache.qpid.AMQException; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java deleted file mode 100644 index d8d87ef881..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; -import java.rmi.RemoteException; -import java.io.IOException; - -/** - * 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 start() throws IOException; - - void registerObject(ManagedObject managedObject) throws JMException; - - void unregisterObject(ManagedObject managedObject) throws JMException; - - void close() throws RemoteException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java deleted file mode 100644 index 042f626e8b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.qpid.configuration.Configured; - -public class ManagementConfiguration -{ - @Configured(path = "management.enabled", - defaultValue = "true") - public boolean enabled; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java deleted file mode 100644 index b4fbed6948..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; - -import org.apache.log4j.Logger; - -import java.rmi.RemoteException; - -/** - * 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 start() - { - //no-op - } - - public void registerObject(ManagedObject managedObject) throws JMException - { - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - } - - public void close() throws RemoteException - { - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java deleted file mode 100644 index 8c13473488..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/JDBCStore.java +++ /dev/null @@ -1,1861 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.InvalidXidException; -import org.apache.qpid.server.exception.MessageAlreadyStagedException; -import org.apache.qpid.server.exception.MessageDoesntExistException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; -import org.apache.qpid.server.exception.QueueDoesntExistException; -import org.apache.qpid.server.exception.UnknownXidException; -import org.apache.qpid.server.exchange.Exchange; -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.StoreContext; -import org.apache.qpid.server.txn.JDBCAbstractRecord; -import org.apache.qpid.server.txn.JDBCDequeueRecord; -import org.apache.qpid.server.txn.JDBCEnqueueRecord; -import org.apache.qpid.server.txn.JDBCTransaction; -import org.apache.qpid.server.txn.JDBCTransactionManager; -import org.apache.qpid.server.txn.Transaction; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.txn.TransactionRecord; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.txn.XidImpl; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.transaction.xa.Xid; -import java.sql.Blob; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * Created by Arnaud Simon - * Date: 15-May-2007 - * Time: 09:59:12 - */ -public class JDBCStore implements MessageStore -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCStore.class); - // the database connection pool - public static ConnectionPool _connectionPool = null; - // the prepared statements - //==== IMPORTANT: remember to update if we add more prepared statements! - private static final int CREATE_EXCHANGE = 0; - private static final int DELETE_EXCHANGE = 1; - private static final int BIND_QUEUE = 2; - private static final int UNBIND_QUEUE = 3; - private static final int CREATE_QUEUE = 4; - private static final int DELETE_QUEUE = 5; - private static final int STAGE_MESSAGE = 6; - private static final int UPDATE_MESSAGE_PAYLOAD = 7; - private static final int SELECT_MESSAGE_PAYLOAD = 8; - private static final int DELETE_MESSAGE = 9; - private static final int ENQUEUE = 10; - private static final int DEQUEUE = 11; - private static final int GET_ALL_QUEUES = 12; - private static final int GET_ALL_MESSAGES = 13; - private static final int SAVE_RECORD = 14; - private static final int SAVE_XID = 15; - private static final int DELETE_RECORD = 16; - private static final int DELETE_XID = 17; - private static final int UPDATE_QMR = 18; - private static final int GET_CONTENT_HEADER = 19; - private static final int GET_MESSAGE_INFO = 20; - //==== size: - private static final int STATEMENT_SIZE = 21; - //======================================================================== - // field properties - //======================================================================== - //The default URL - protected String _connectionURL = "jdbc:derby:derbyDB;create=true"; - // The default driver - private String _driver = "org.apache.derby.jdbc.EmbeddedDriver"; - // The pool max size - private int _maxSize = 40; - // The tables - // the table containing the messages - private String _tableNameMessage = "MessageTable"; - private String _tableNameQueue = "QueueTable"; - private String _tableNameQueueMessageRelation = "QeueMessageRelation"; - private String _tableNameExchange = "Exchange"; - private String _tableNameExchangeQueueRelation = "ExchangeQueueRelation"; - private String _tableNameTransaction = "TransactionTable"; - private String _tableNameRecord = "RecordTable"; - - // The transaction maanger - private JDBCTransactionManager _tm; - // the message ID - private long _messageID = 0; - // the virtual host - private VirtualHost _virtualHost; - // indicate whether this store is recovering - private boolean _recovering = false; - // the recovered queues - private HashMap _queueMap; - - //======================================================================== - // Interface MessageStore - //======================================================================== - public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws - InternalErrorException, - IllegalArgumentException - { - _log.info("Configuring Derby message store"); - // the virtual host - _virtualHost = virtualHost; - // Specify that the tables must be dropped. - // If true then this means that recovery is not possible. - boolean dropTables = true; - if (config != null) - { - dropTables = config.getBoolean(base + "dropTables", false); - _driver = config.getString(base + "driver", _driver); - _connectionURL = config.getString(base + "connectionURL", _connectionURL); - _maxSize = config.getInt(base + "connectionPoolSize", 20); - } - if (dropTables) - { - _log.info("Dropping table of Derby message store"); - } - if (!setupStore(dropTables)) - { - _log.error("Error configuration of Derby store failed"); - throw new InternalErrorException("Error configuration of Derby store failed"); - } - // recovery - _recovering = true; - _queueMap = recover(); //==> recover the queues and the messages - // recreate the excahnges and bind the queues - recoverExchanges(_queueMap); - _recovering = false; - _tm = (JDBCTransactionManager) tm; - _tm.configure(this, "txn", config); - _queueMap.clear(); - _queueMap = null; - } - - public void close() - throws - InternalErrorException - { - // nothing has to be done - } - - public void createExchange(Exchange exchange) - throws - InternalErrorException - { - if (!_recovering) - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[CREATE_EXCHANGE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameExchange + - " (Name,Type) VALUES (?,?)"); - connection.getStatements()[CREATE_EXCHANGE] = pstmt; - } - pstmt.setString(1, exchange.getName().asString()); - pstmt.setString(2, exchange.getType().asString()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot create Exchange: " + exchange, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Exchange: " + exchange, e); - } - } - } - } - } - - public void removeExchange(Exchange exchange) - throws - InternalErrorException - { - if (!_recovering) - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[DELETE_EXCHANGE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameExchange + - " WHERE Name = ?"); - connection.getStatements()[DELETE_EXCHANGE] = pstmt; - } - pstmt.setString(1, exchange.getName().asString()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); - } - } - } - } - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException - { - if (!_recovering) - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[BIND_QUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameExchangeQueueRelation + - " (QueueID,Name,RoutingKey,fieldTable) VALUES (?,?,?,?)"); - connection.getStatements()[BIND_QUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.setString(2, exchange.getName().asString()); - pstmt.setString(3, routingKey.asString()); - if (args != null) - { - pstmt.setBytes(4, args.getDataAsBytes()); - } - else - { - pstmt.setBytes(4, null); - } - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot create Exchange: " + exchange, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Exchange: " + exchange, e); - } - } - } - } - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws - InternalErrorException - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[UNBIND_QUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameExchangeQueueRelation + - " WHERE QueueID = ? AND NAME = ? AND RoutingKey = ?"); - connection.getStatements()[UNBIND_QUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.setString(2, exchange.getName().asString()); - pstmt.setString(3, routingKey.asString()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Exchange: " + exchange, e); - } - } - } - } - - public void createQueue(StorableQueue queue) - throws - InternalErrorException, - QueueAlreadyExistsException - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[CREATE_QUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameQueue + - " (QueueID,Name,Owner) VALUES (?,?,?)"); - connection.getStatements()[CREATE_QUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.setString(2, queue.getName().asString()); - if (queue.getOwner() != null) - { - pstmt.setString(3, queue.getOwner().asString()); - } - else - { - pstmt.setString(3, null); - } - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot create Queue: " + queue, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot create Queue: " + queue, e); - } - } - } - } - - public void destroyQueue(StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[DELETE_QUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameQueue + - " WHERE QueueID = ?"); - connection.getStatements()[DELETE_QUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot remove Queue: " + queue, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot remove Queue: " + queue, e); - } - } - } - } - - public void stage(StorableMessage m) - throws - InternalErrorException, - MessageAlreadyStagedException - { - if (m.isStaged() || m.isEnqueued()) - { - _log.error("Message with Id " + m.getMessageId() + " is already staged"); - throw new MessageAlreadyStagedException("Message eith Id " + m.getMessageId() + " is already staged"); - } - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - stage(connection, m); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot stage Message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot stage Message: " + m, e); - } - } - } - } - - public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException - { - // The message must have been staged - if (!m.isStaged()) - { - _log.error("Cannot append content of message Id " - + m.getMessageId() + " as it has not been staged"); - throw new MessageDoesntExistException("Cannot append content of message Id " - + m.getMessageId() + " as it has not been staged"); - } - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - appendContent(connection, m, data, offset, size); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot stage Message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot stage Message: " + m, e); - } - } - } - } - - public byte[] loadContent(StorableMessage m, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException - { - MyConnection connection = null; - try - { - byte[] result; - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[SELECT_MESSAGE_PAYLOAD]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT Payload FROM " + _tableNameMessage + - " WHERE MessageID = ? "); - connection.getStatements()[SELECT_MESSAGE_PAYLOAD] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - ResultSet rs = pstmt.executeQuery(); - if (!rs.next()) - { - throw new MessageDoesntExistException("Cannot load content of message Id " - + m.getMessageId() + " as it has not been found"); - } - Blob myBlob = rs.getBlob(1); - - if (myBlob.length() > 0) - { - if (size == 0) - { - result = myBlob.getBytes(offset, (int) myBlob.length()); - } - else - { - result = myBlob.getBytes(offset, size); - } - } - else - { - throw new MessageDoesntExistException("Cannot load content of message Id " - + m.getMessageId() + " as it has not been found"); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot load Message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot load Message: " + m, e); - } - } - } - } - - public void destroy(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - destroy(connection, m); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot destroy message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot destroy message: " + m, e); - } - } - } - } - - public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - MyConnection connection = null; - // Get the current tx - JDBCTransaction tx = getTx(xid); - // If this operation is transacted then we need to add a record - if (tx != null && !tx.isPrepared()) - { - // add an enqueue record - tx.addRecord(new JDBCEnqueueRecord(m, queue)); - } - else - { - try - { - if (tx != null) - { - connection = tx.getConnection(); - } - else - { - connection = (MyConnection) _connectionPool.acquireInstance(); - } - if (!m.isStaged() && !m.isEnqueued()) - { - //This is the first time this message is enqueued and it has not been staged. - stage(connection, m); - appendContent(connection, m, m.getData(), 0, m.getData().length); - } - PreparedStatement pstmt = connection.getStatements()[ENQUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameQueueMessageRelation + - " (QueueID,MessageID,Prepared) VALUES (?,?,0)"); - connection.getStatements()[ENQUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.setLong(2, m.getMessageId()); - pstmt.executeUpdate(); - m.enqueue(queue); - queue.enqueue(m); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); - } - finally - { - if (tx == null && connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); - } - } - } - } - } - - public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException - { - MyConnection connection = null; - // Get the current tx - JDBCTransaction tx = getTx(xid); - // If this operation is transacted then we need to add a record - if (tx != null && !tx.isPrepared()) - { - // add an dequeue record - tx.addRecord(new JDBCDequeueRecord(m, queue)); - } - else - { - try - { - if (tx != null) - { - connection = tx.getConnection(); - } - else - { - connection = (MyConnection) _connectionPool.acquireInstance(); - } - PreparedStatement pstmt = connection.getStatements()[DEQUEUE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameQueueMessageRelation + - " WHERE QueueID = ? AND MessageID = ?"); - connection.getStatements()[DEQUEUE] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - pstmt.setLong(2, m.getMessageId()); - pstmt.executeUpdate(); - m.dequeue(queue); - if (!m.isEnqueued()) - { - // delete this message from persistence store - destroy(connection, m); - } - queue.dequeue(m); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); - } - finally - { - if (tx == null && connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot enqueue message : " + m + " in queue: " + queue, e); - } - } - } - } - } - - public Collection getAllQueues() - throws - InternalErrorException - { - MyConnection connection = null; - List result = new ArrayList(); - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[GET_ALL_QUEUES]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT * FROM " + _tableNameQueue); - connection.getStatements()[GET_ALL_QUEUES] = pstmt; - } - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) - { - //the queue owner may be null - AMQShortString queueOwner = null; - if (rs.getString(3) != null) - { - queueOwner = new AMQShortString(rs.getString(3)); - } - result.add(new AMQQueue(new AMQShortString(rs.getString(2)), true, queueOwner, - false, _virtualHost)); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot get all queues", e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get all queues", e); - } - } - } - } - - public Collection getAllMessages(StorableQueue queue) - throws - InternalErrorException - { - MyConnection connection = null; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - return getAllMessages(connection, queue); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot get all queues", e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get all queues", e); - } - } - } - } - - public HashMap getAllInddoubt() - throws - InternalErrorException - { - MyConnection connection = null; - HashMap result = new HashMap(); - try - { - //TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); - // re-create all the tx - connection = (MyConnection) _connectionPool.acquireInstance(); - Statement stmt = connection.getConnection().createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameTransaction); - JDBCTransaction foundTx; - Xid foundXid; - long foundXIDID; - while (rs.next()) - { - // set the XID_ID - foundXIDID = rs.getLong(1); - if (foundXIDID > JDBCTransaction._xidId) - { - JDBCTransaction._xidId = foundXIDID; - } - foundTx = new JDBCTransaction(); - foundXid = new XidImpl(rs.getBlob(3).getBytes(1, (int) rs.getBlob(3).length()), - rs.getInt(2), rs.getBlob(4).getBytes(1, (int) rs.getBlob(4).length())); - // get all the records - Statement stmtr = connection.getConnection().createStatement(); - ResultSet rsr = stmtr.executeQuery("SELECT * FROM " + _tableNameRecord + - " WHERE XID_ID = " + rs.getLong(1)); - int foundType; - AMQQueue foundQueue; - StorableMessage foundMessage; - TransactionRecord foundRecord; - while (rsr.next()) - { - // those messages were not recovered before so they need to be recreated - foundType = rsr.getInt(2); - foundQueue = _queueMap.get(new Integer(rsr.getInt(4))); - - //DTX MessageStore - this -> null , txContext -> null - foundMessage = new AMQMessage(rs.getLong(3), null, messageHandleFactory, null); - if (foundType == JDBCAbstractRecord.TYPE_DEQUEUE) - { - foundRecord = new JDBCDequeueRecord(foundMessage, foundQueue); - } - else - { - foundRecord = new JDBCEnqueueRecord(foundMessage, foundQueue); - } - foundTx.addRecord(foundRecord); - } - rsr.close(); - // add this tx to the map - result.put(foundXid, foundTx); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot recover: ", e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot recover: ", e); - } - } - } - } - - - public long getNewMessageId() - { - return _messageID++; - } - - //======================================================================== - // Public methods - //======================================================================== - - public MyConnection getConnection() - throws - Exception - { - return (MyConnection) _connectionPool.acquireInstance(); - } - - public void commitConnection(MyConnection connection) - throws - InternalErrorException - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot commit connection =", e); - } - } - - public void rollbackConnection(MyConnection connection) - throws - InternalErrorException - { - try - { - connection.getConnection().rollback(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to rollback this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot rollback connection", e); - } - } - - public void appendContent(MyConnection connection, StorableMessage m, byte[] data, int offset, int size) - throws - SQLException, - MessageDoesntExistException - { - PreparedStatement pstmt = connection.getStatements()[SELECT_MESSAGE_PAYLOAD]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT Payload FROM " + _tableNameMessage + - " WHERE MessageID = ? "); - connection.getStatements()[SELECT_MESSAGE_PAYLOAD] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - ResultSet rs = pstmt.executeQuery(); - if (!rs.next()) - { - throw new MessageDoesntExistException("Cannot append content of message Id " - + m.getMessageId() + " as it has not been found"); - } - Blob myBlob = rs.getBlob(1); - byte[] oldPayload; - if (myBlob != null && myBlob.length() > 0) - { - oldPayload = myBlob.getBytes(1, (int) myBlob.length()); - } - else - { - oldPayload = new byte[0]; - } - rs.close(); - byte[] newPayload = new byte[oldPayload.length + size]; - ByteBuffer buffer = ByteBuffer.wrap(newPayload); - buffer.put(oldPayload); - buffer.put(data, offset, size); - PreparedStatement pstmtUpdate = connection.getStatements()[UPDATE_MESSAGE_PAYLOAD]; - if (pstmtUpdate == null) - { - pstmtUpdate = connection.getConnection().prepareStatement("UPDATE " + _tableNameMessage + - " SET Payload = ? WHERE MessageID = ?"); - connection.getStatements()[UPDATE_MESSAGE_PAYLOAD] = pstmtUpdate; - } - pstmtUpdate.setBytes(1, newPayload); - pstmtUpdate.setLong(2, m.getMessageId()); - pstmtUpdate.executeUpdate(); - } - - public void stage(MyConnection connection, StorableMessage m) - throws - Exception - { - PreparedStatement pstmt = connection.getStatements()[STAGE_MESSAGE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameMessage + - " (MessageID,Header,ExchangeName,RoutingKey,Mandatory,Is_Immediate) VALUES (?,?,?,?,?,?)"); - connection.getStatements()[STAGE_MESSAGE] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - pstmt.setBytes(2, m.getHeaderBody()); - pstmt.setString(3, ((AMQMessage) m).getMessagePublishInfo().getExchange().asString()); - pstmt.setString(4, ((AMQMessage) m).getMessagePublishInfo().getRoutingKey().asString()); - pstmt.setBoolean(5, ((AMQMessage) m).getMessagePublishInfo().isMandatory()); - pstmt.setBoolean(6, ((AMQMessage) m).getMessagePublishInfo().isImmediate()); - pstmt.executeUpdate(); - m.staged(); - } - - public void saveRecord(MyConnection connection, JDBCTransaction tx, JDBCAbstractRecord record) - throws - InternalErrorException - { - try - { - PreparedStatement pstmt = connection.getStatements()[SAVE_RECORD]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameRecord + - " (XID_ID,Type,MessageID,QueueID) VALUES (?,?,?,?)"); - connection.getStatements()[SAVE_RECORD] = pstmt; - } - pstmt.setLong(1, tx.getXidID()); - pstmt.setInt(2, record.getType()); - pstmt.setLong(3, record.getMessageID()); - pstmt.setLong(4, record.getQueueID()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot save record: " + record, e); - } - } - - public void saveXID(MyConnection connection, JDBCTransaction tx, Xid xid) - throws - InternalErrorException - { - try - { - PreparedStatement pstmt = connection.getStatements()[SAVE_XID]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("INSERT INTO " + _tableNameTransaction + - " (XID_ID,FormatId, BranchQualifier,GlobalTransactionId) VALUES (?,?,?,?)"); - connection.getStatements()[SAVE_XID] = pstmt; - } - pstmt.setLong(1, tx.getXidID()); - pstmt.setInt(2, xid.getFormatId()); - pstmt.setBytes(3, xid.getBranchQualifier()); - pstmt.setBytes(4, xid.getGlobalTransactionId()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot save xid: " + xid, e); - } - } - - public void deleteRecords(MyConnection connection, JDBCTransaction tx) - throws - InternalErrorException - { - try - { - PreparedStatement pstmt = connection.getStatements()[DELETE_RECORD]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameRecord + - " WHERE XID_ID = ?"); - connection.getStatements()[DELETE_RECORD] = pstmt; - } - pstmt.setLong(1, tx.getXidID()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot delete record: " + tx.getXidID(), e); - } - } - - public void deleteXID(MyConnection connection, JDBCTransaction tx) - throws - InternalErrorException - { - try - { - PreparedStatement pstmt = connection.getStatements()[DELETE_XID]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameTransaction + - " WHERE XID_ID = ?"); - connection.getStatements()[DELETE_XID] = pstmt; - } - pstmt.setLong(1, tx.getXidID()); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot delete xid: " + tx.getXidID(), e); - } - } - - public void prepareDequeu(Xid xid, StorableMessage m, StorableQueue queue) - throws - UnknownXidException, - InternalErrorException - { - JDBCTransaction tx = getTx(xid); - if (tx == null) - { - throw new UnknownXidException(xid, null); - } - updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 1); - - } - - public void rollbackDequeu(Xid xid, StorableMessage m, StorableQueue queue) - throws - UnknownXidException, - InternalErrorException - { - JDBCTransaction tx = getTx(xid); - if (tx == null) - { - throw new UnknownXidException(xid, null); - } - updateQueueMessageRelation(tx.getConnection(), queue.getQueueID(), m.getMessageId(), 0); - } - - //======================================================================== - // Private methods - //======================================================================== - - - private void updateQueueMessageRelation(MyConnection connection, - int queueID, long messageId, int prepared) - throws - InternalErrorException - { - try - { - PreparedStatement pstmt = connection.getStatements()[UPDATE_QMR]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("UPDATE " + _tableNameQueueMessageRelation + - " SET Prepared = ? WHERE MessageID = ? AND QueueID = ?"); - connection.getStatements()[UPDATE_QMR] = pstmt; - } - pstmt.setInt(1, prepared); - pstmt.setLong(2, messageId); - pstmt.setInt(3, queueID); - pstmt.executeUpdate(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot update QMR", e); - } - - } - - public MessagePublishInfo getMessagePublishInfo(StorableMessage m) - throws - InternalErrorException - { - MyConnection connection = null; - MessagePublishInfo result; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[GET_MESSAGE_INFO]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT ExchangeName, RoutingKey," + - " Mandatory, Is_Immediate from " + _tableNameMessage + - " WHERE MessageID = ?"); - connection.getStatements()[GET_MESSAGE_INFO] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - final AMQShortString exchange = new AMQShortString(rs.getString(1)); - final AMQShortString routingKey = new AMQShortString(rs.getString(2)); - final boolean mandatory = rs.getBoolean(3); - final boolean immediate = rs.getBoolean(4); - result = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return exchange; - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return mandatory; - } - - public AMQShortString getRoutingKey() - { - return routingKey; - } - }; - } - else - { - throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get MessagePublishInfo of message: " + m, e); - } - } - } - } - - public ContentHeaderBody getContentHeaderBody(StorableMessage m) - throws - InternalErrorException - { - MyConnection connection = null; - ContentHeaderBody result; - try - { - connection = (MyConnection) _connectionPool.acquireInstance(); - PreparedStatement pstmt = connection.getStatements()[GET_CONTENT_HEADER]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT Header from " + _tableNameMessage + - " WHERE MessageID = ?"); - connection.getStatements()[GET_CONTENT_HEADER] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - result = new ContentHeaderBody(ByteBuffer.wrap(rs.getBlob(1).getBytes(1, (int) rs.getBlob(1).length())), 0); - } - else - { - throw new InternalErrorException("Cannot get Content Header of message: " + m); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot get Content Header of message: " + m, e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot get Content Header of message: " + m, e); - } - } - } - } - - private List getAllMessages(MyConnection connection, StorableQueue queue) - throws - SQLException, - AMQException - { - List result = new ArrayList(); -// TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null, null); - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); - PreparedStatement pstmt = connection.getStatements()[GET_ALL_MESSAGES]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("SELECT " + _tableNameMessage + ".MessageID, Header FROM " + - _tableNameMessage + - " INNER JOIN " + - _tableNameQueueMessageRelation + - " ON " + - _tableNameMessage + ".MessageID = " + _tableNameQueueMessageRelation + ".MessageID" + - " WHERE " + - _tableNameQueueMessageRelation + ".QueueID = ?" + - " AND " + - _tableNameQueueMessageRelation + ".Prepared = 0"); - connection.getStatements()[GET_ALL_MESSAGES] = pstmt; - } - pstmt.setInt(1, queue.getQueueID()); - ResultSet rs = pstmt.executeQuery(); - AMQMessage foundMessage; - // ContentHeaderBody hb; - while (rs.next()) - { - - //DTX MessageStore - this -> null , txContext -> null - foundMessage = new AMQMessage(rs.getLong(1), null, messageHandleFactory, null); - - result.add(foundMessage); - } - rs.close(); - return result; - } - - private HashMap recover() - throws - InternalErrorException - { - MyConnection connection = null; - HashMap result = new HashMap(); - try - { - // re-create all the queues - connection = (MyConnection) _connectionPool.acquireInstance(); - Statement stmt = connection.getConnection().createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameQueue); - AMQQueue foundQueue; - List foundMessages; - StoreContext context = new StoreContext(); - while (rs.next()) - { - AMQShortString owner = null; - if (rs.getString(3) != null) - { - owner = new AMQShortString(rs.getString(3)); - } - foundQueue = new AMQQueue(new AMQShortString(rs.getString(2)), - true, owner, false, _virtualHost); - // get all the Messages of that queue - foundMessages = getAllMessages(connection, foundQueue); - // enqueue those messages - if (_log.isDebugEnabled()) - { - _log.debug("Recovering " + foundMessages.size() + " messages for queue " + foundQueue.getName()); - } - for (StorableMessage foundMessage : foundMessages) - { - foundMessage.staged(); - foundMessage.enqueue(foundQueue); - foundQueue.enqueue(foundMessage); - foundQueue.process(context, (AMQMessage) foundMessage, false); - } - // add the queue in the result map - result.put(foundQueue.getQueueID(), foundQueue); - // add it in the registry - _virtualHost.getQueueRegistry().registerQueue(foundQueue); - } - rs.close(); - return result; - } - catch (Exception e) - { - throw new InternalErrorException("Cannot recover: ", e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot recover: ", e); - } - } - } - } - - private void recoverExchanges(HashMap queueMap) - throws - InternalErrorException - { - MyConnection connection = null; - try - { - // re-create all the exchanges - connection = (MyConnection) _connectionPool.acquireInstance(); - Statement stmt = connection.getConnection().createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM " + _tableNameExchange); - Exchange foundExchange; - AMQQueue foundQueue; - while (rs.next()) - { - foundExchange = _virtualHost.getExchangeFactory().createExchange( - new AMQShortString(rs.getString(1)), new AMQShortString(rs.getString(2)), true, false, 0); - // get all the bindings - Statement stmtb = connection.getConnection().createStatement(); - ResultSet rsb = stmtb.executeQuery("SELECT * FROM " + _tableNameExchangeQueueRelation + - " WHERE Name = '" + rs.getString(1) + "'"); - while (rsb.next()) - { - foundQueue = queueMap.get(new Integer(rsb.getInt(1))); - if (foundQueue != null) - { - // the field table - FieldTable ft = null; - if (rsb.getBlob(4) != null) - { - long length = rsb.getBlob(4).length(); - ByteBuffer buffer = ByteBuffer.wrap(rsb.getBlob(4).getBytes(1, (int) length)); - ft = new FieldTable(buffer, length); - } - foundQueue.bind(new AMQShortString(rsb.getString(3)), ft, foundExchange); - } - } - rsb.close(); - // register this exchange - _virtualHost.getExchangeRegistry().registerExchange(foundExchange); - } - rs.close(); - } - catch (Exception e) - { - throw new InternalErrorException("Cannot recover: ", e); - } - finally - { - if (connection != null) - { - try - { - connection.getConnection().commit(); - _connectionPool.releaseInstance(connection); - } - catch (SQLException e) - { - // we did not manage to commit this connection - // it is better to release it - _connectionPool.releaseDeadInstance(); - throw new InternalErrorException("Cannot recover: ", e); - } - } - } - } - - private void destroy(MyConnection connection, StorableMessage m) - throws - SQLException - { - PreparedStatement pstmt = connection.getStatements()[DELETE_MESSAGE]; - if (pstmt == null) - { - pstmt = connection.getConnection().prepareStatement("DELETE FROM " + _tableNameMessage + - " WHERE MessageID = ?"); - connection.getStatements()[DELETE_MESSAGE] = pstmt; - } - pstmt.setLong(1, m.getMessageId()); - pstmt.executeUpdate(); - } - - private JDBCTransaction getTx(Xid xid) - throws - UnknownXidException - { - JDBCTransaction tx = null; - if (xid != null) - { - tx = _tm.getTransaction(xid); - } - return tx; - } - - /** - * setupConnections - Initialize the connections - * - * @return true if ok - */ - private synchronized boolean setupConnections() - { - try - { - if (_connectionPool == null) - { - // In an embedded environment, loading the driver also starts Derby. - Class.forName(_driver).newInstance(); - _connectionPool = new ConnectionPool(_maxSize); - } - } - catch (Exception e) - { - _log.warn("Setup connections trouble", e); - return false; - } - return true; - } - - /** - * Try to create the connection and table. - * If this fails, then we will exit. - */ - protected synchronized boolean setupStore(boolean dropTables) - { - if (!setupConnections()) - { - return false; - } - MyConnection myconnection = null; - try - { - myconnection = (MyConnection) _connectionPool.acquireInstance(); - Statement stmt = myconnection._connection.createStatement(); - /* - * TODO Need some management interface to delete the table! - */ - if (dropTables) - { - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameMessage); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // don't want to print error - chances are it - // just reports that the table does not exist - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameQueue); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameQueueMessageRelation); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameExchange); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameExchangeQueueRelation); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameRecord); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - try - { - stmt.executeUpdate("DROP TABLE " + _tableNameTransaction); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - } - } - // create the table for messages - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameMessage + " (MessageID FLOAT NOT NULL, Header BLOB," + - " Payload BLOB, ExchangeName VARCHAR(1024), RoutingKey VARCHAR(1024)," + - " Mandatory INTEGER, Is_Immediate INTEGER, PRIMARY KEY(MessageID))"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - // create the table for queues - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameQueue + " (QueueID INTEGER NOT NULL, " + - "Name VARCHAR(1024) NOT NULL, Owner VARCHAR(1024), PRIMARY KEY(QueueID))"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - //ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - // create the table for queue to message mapping - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameQueueMessageRelation + " (QueueID INTEGER NOT NULL, " + - "MessageID FLOAT NOT NULL, Prepared INTEGER)"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - //ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameExchange + " (Name VARCHAR(1024) NOT NULL, " + - "Type VARCHAR(1024) NOT NULL, PRIMARY KEY(Name))"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - //ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameExchangeQueueRelation + " (QueueID INTEGER NOT NULL, " + - "Name VARCHAR(1024) NOT NULL, RoutingKey VARCHAR(1024), FieldTable BLOB )"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - //ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameRecord + " (XID_ID FLOAT, Type INTEGER, MessageID FLOAT, " + - "QueueID INTEGER, PRIMARY KEY(Type, MessageID, QueueID))"); - // we could alter the table with QueueID as foreign key - myconnection._connection.commit(); - } - catch (SQLException ex) - { - //ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - try - { - stmt.executeUpdate("CREATE TABLE " + _tableNameTransaction + " (XID_ID FLOAT, FormatId INTEGER, " + - "BranchQualifier BLOB, GlobalTransactionId BLOB, PRIMARY KEY(XID_ID))"); - myconnection._connection.commit(); - } - catch (SQLException ex) - { - // ex.printStackTrace(); - // assume this is reporting that the table already exists: - } - } - catch (Throwable e) - { - _log.warn("Setup Store trouble: ", e); - return false; - } - finally - { - if (myconnection != null) - { - _connectionPool.releaseInstance(myconnection); - } - } - return true; - } - //======================================================================================== - //============== the connection pool ===================================================== - //======================================================================================== - - private class ConnectionPool extends Pool - { - - /** - * Create a pool of specified size. Negative or null pool sizes are - * disallowed. - * - * @param poolSize The size of the pool to create. Should be 1 or - * greater. - * @throws Exception If the pool size is less than 1. - */ - public ConnectionPool(int poolSize) - throws - Exception - { - super(poolSize); - } - - /** - * @return An instance of the pooled object. - * @throws Exception In case of internal error. - */ - protected MyConnection createInstance() - throws - Exception - { - try - { - // standard way to obtain a Connection object is to call the method DriverManager.getConnection, - // which takes a String containing a connection URL (uniform resource locator). - Connection conn = DriverManager.getConnection(_connectionURL); - //conn.setAutoCommit(true); - PreparedStatement[] st = new PreparedStatement[STATEMENT_SIZE]; - for (int j = 0; j < STATEMENT_SIZE; j++) - { - st[j] = null; - } - return new MyConnection(conn, st); - } - catch (SQLException e) - { - throw new Exception("sqlException when creating connection to " + _connectionURL, e); - } - } - } - - public class MyConnection - { - // the connection - private Connection _connection = null; - // its associated prepared statements - private PreparedStatement[] _preparedStatements = null; - - MyConnection(Connection con, PreparedStatement[] st) - { - _connection = con; - _preparedStatements = st; - } - - public Connection getConnection() - { - return _connection; - } - - public PreparedStatement[] getStatements() - { - return _preparedStatements; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java deleted file mode 100644 index 8954ffc4d7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MemoryMessageStore.java +++ /dev/null @@ -1,273 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.util.*; - -import javax.transaction.xa.Xid; - -import org.apache.commons.configuration.Configuration; - -import org.apache.log4j.Logger; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.txn.MemoryDequeueRecord; -import org.apache.qpid.server.txn.MemoryEnqueueRecord; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.txn.TransactionRecord; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/** - * This a simple in-memory implementation of a message store i.e. nothing is persisted - *

      - * Created by Arnaud Simon - * Date: 26-Apr-2007 - * Time: 08:23:45 - */ -public class MemoryMessageStore implements MessageStore -{ - // ======================================================================== - // Static Constants - // ======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); - - // The table of message with its corresponding stream containing the message body - private Map _stagedMessages; - // The queue/messages association - protected Map> _queueMap; - // the message ID - private long _messageID = 0; - // The transaction manager - private TransactionManager _txm; - - // ======================================================================== - // Interface MessageStore - // ======================================================================== - - public void removeExchange(Exchange exchange) throws InternalErrorException - { - // do nothing this is inmemory - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws InternalErrorException - { - // do nothing this is inmemory - } - - public void createExchange(Exchange exchange) throws InternalErrorException - { - // do nothing this is inmemory - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, StorableQueue queue, FieldTable args) - throws InternalErrorException - { - // do nothing this is inmemory - } - - public void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws InternalErrorException, IllegalArgumentException - { - _log.info("Configuring memory message store"); - // Initialise the maps - _stagedMessages = new HashMap(); - _queueMap = new HashMap>(); - _txm = tm; - _txm.configure(this, "txn", config); - } - - public void close() throws InternalErrorException - { - _log.info("Closing memory message store"); - _stagedMessages.clear(); - _queueMap.clear(); - } - - public void createQueue(StorableQueue queue) throws InternalErrorException, QueueAlreadyExistsException - { - if (_queueMap.containsKey(queue)) - { - throw new QueueAlreadyExistsException("queue " + queue + " already exists"); - } - // add this queue into the map - _queueMap.put(queue, new LinkedList()); - } - - public void destroyQueue(StorableQueue queue) throws InternalErrorException, QueueDoesntExistException - { - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " does not exist"); - } - // remove this queue from the map - _queueMap.remove(queue); - } - - public void stage(StorableMessage m) throws InternalErrorException, MessageAlreadyStagedException - { - if (_stagedMessages.containsKey(m)) - { - throw new MessageAlreadyStagedException("message " + m + " already staged"); - } - - _stagedMessages.put(m, new ByteArrayOutputStream()); - m.staged(); - } - - public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws InternalErrorException, MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - - _stagedMessages.get(m).write(data, offset, size); - } - - public byte[] loadContent(StorableMessage m, int offset, int size) - throws InternalErrorException, MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - - byte[] result = new byte[size]; - ByteBuffer buf = ByteBuffer.allocate(size); - buf.put(_stagedMessages.get(m).toByteArray(), offset, size); - buf.get(result); - - return result; - } - - public void destroy(StorableMessage m) throws InternalErrorException, MessageDoesntExistException - { - if (!_stagedMessages.containsKey(m)) - { - throw new MessageDoesntExistException("message " + m + " has not been staged"); - } - - _stagedMessages.remove(m); - } - - public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException, - MessageDoesntExistException - { - if (xid != null) - { - // this is a tx operation - TransactionRecord enqueueRecord = new MemoryEnqueueRecord(m, queue); - _txm.getTransaction(xid).addRecord(enqueueRecord); - } - else - { - if (!_stagedMessages.containsKey(m)) - { - try - { - stage(m); - } - catch (MessageAlreadyStagedException e) - { - throw new InternalErrorException(e.getMessage(), e); - } - - appendContent(m, m.getData(), 0, m.getPayloadSize()); - } - - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " dos not exist"); - } - - _queueMap.get(queue).add(m); - m.enqueue(queue); - } - } - - public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException - { - if (xid != null) - { - // this is a tx operation - TransactionRecord dequeueRecord = new MemoryDequeueRecord(m, queue); - _txm.getTransaction(xid).addRecord(dequeueRecord); - } - else - { - if (!_queueMap.containsKey(queue)) - { - throw new QueueDoesntExistException("queue " + queue + " dos not exist"); - } - - m.dequeue(queue); - _queueMap.get(queue).remove(m); - if (!m.isEnqueued()) - { - // we can delete this message - _stagedMessages.remove(m); - } - } - } - - public Collection getAllQueues() throws InternalErrorException - { - return _queueMap.keySet(); - } - - public Collection getAllMessages(StorableQueue queue) throws InternalErrorException - { - return _queueMap.get(queue); - } - - public long getNewMessageId() - { - return _messageID++; - } - - - public ContentHeaderBody getContentHeaderBody(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException - { - // do nothing this is only used during recovery - return null; - } - - public MessagePublishInfo getMessagePublishInfo(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException - { - // do nothing this is only used during recovery - return null; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java deleted file mode 100644 index f5dc160fc6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/MessageStore.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.InvalidXidException; -import org.apache.qpid.server.exception.MessageAlreadyStagedException; -import org.apache.qpid.server.exception.MessageDoesntExistException; -import org.apache.qpid.server.exception.QueueAlreadyExistsException; -import org.apache.qpid.server.exception.QueueDoesntExistException; -import org.apache.qpid.server.exception.UnknownXidException; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.transaction.xa.Xid; -import java.util.Collection; - -/** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 17:34:02 - */ -public interface MessageStore -{ - /** - * Create a new exchange - * - * @param exchange the exchange to be persisted - * @throws InternalErrorException If an error occurs - */ - public void createExchange(Exchange exchange) - throws - InternalErrorException; - - /** - * Remove an exchange - * - * @param exchange The exchange to be removed - * @throws InternalErrorException If an error occurs - */ - public void removeExchange(Exchange exchange) - throws - InternalErrorException; - - /** - * Bind a queue with an exchange given a routing key - * - * @param exchange The exchange to bind the queue with - * @param routingKey The routing key - * @param queue The queue to be bound - * @param args Args - * @throws InternalErrorException If an error occurs - */ - public void bindQueue(Exchange exchange, - AMQShortString routingKey, - StorableQueue queue, FieldTable args) - throws - InternalErrorException; - - /** - * Unbind a queue from an exchange - * - * @param exchange The exchange the queue was bound to - * @param routingKey The routing queue - * @param queue The queue to unbind - * @param args args - * @throws InternalErrorException If an error occurs - */ - public void unbindQueue(Exchange exchange, - AMQShortString routingKey, - StorableQueue queue, FieldTable args) - throws - InternalErrorException; - - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param tm The transaction manager implementation - * @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 InternalErrorException If an error occurs that means the store is unable to configure itself - * @throws IllegalArgumentException If the configuration arguments are illegal - */ - void configure(VirtualHost virtualHost, TransactionManager tm, String base, Configuration config) - throws - InternalErrorException, - IllegalArgumentException; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws InternalErrorException if close fails - */ - void close() - throws - InternalErrorException; - - /** - * Create a queue - * - * @param queue the queue to be created - * @throws InternalErrorException In case of internal message store problem - * @throws QueueAlreadyExistsException If the queue already exists in the store - */ - public void createQueue(StorableQueue queue) - throws - InternalErrorException, - QueueAlreadyExistsException; - - /** - * Destroy a queue - * - * @param queue The queue to be destroyed - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - */ - public void destroyQueue(StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException; - - /** - * Stage the message before effective enqueue - * - * @param m The message to stage - * @throws InternalErrorException In case of internal message store problem - * @throws MessageAlreadyStagedException If the message is already staged - */ - public void stage(StorableMessage m) - throws - InternalErrorException, - MessageAlreadyStagedException; - - - /** - * Append more data with a previously staged message - * - * @param m The message to which data must be appended - * @param data Data to happen to the message - * @param offset The number of bytes from the beginning of the payload - * @param size The number of bytes to be written - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message has not been staged - */ - public void appendContent(StorableMessage m, byte[] data, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Get the content of previously staged or enqueued message. - * The message headers are also set. - * - * @param m The message for which the content must be loaded - * @param offset The number of bytes from the beginning of the payload - * @param size The number of bytes to be loaded - * @return The message content - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist - */ - public byte[] loadContent(StorableMessage m, int offset, int size) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Get the content header of this message - * - * @param m The message - * @return The message content - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist - */ - public ContentHeaderBody getContentHeaderBody(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Get the MessagePublishInfo of this message - * - * @param m The message - * @return The message content - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist - */ - public MessagePublishInfo getMessagePublishInfo(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Destroy a previously staged message - * - * @param m the message to be destroyed - * @throws InternalErrorException In case of internal message store problem - * @throws MessageDoesntExistException If the message does not exist in the store - */ - public void destroy(StorableMessage m) - throws - InternalErrorException, - MessageDoesntExistException; - - /** - * Enqueue a message under the scope of the transaction branch - * identified by xid when specified. - *

      This operation is propagated to the queue and the message. - *

      A message that has been previously staged is assumed to have had - * its payload already added (see appendContent) - * - * @param xid The xid of the transaction branch under which the message must be enqueued. - *

      It he xid is null then the message is enqueued outside the scope of any transaction. - * @param m The message to be enqueued - * @param queue The queue into which the message must be enqueued - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - * @throws InvalidXidException The transaction branch is invalid - * @throws UnknownXidException The transaction branch is unknown - * @throws MessageDoesntExistException If the Message does not exist - */ - public void enqueue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException; - - /** - * Dequeue a message under the scope of the transaction branch identified by xid - * if specified. - *

      This operation is propagated to the queue and the message. - * - * @param xid The xid of the transaction branch under which the message must be dequeued. - *

      It he xid is null then the message is dequeued outside the scope of any transaction. - * @param m The message to be dequeued - * @param queue The queue from which the message must be dequeued - * @throws InternalErrorException In case of internal message store problem - * @throws QueueDoesntExistException If the queue does not exist in the store - * @throws InvalidXidException The transaction branch is invalid - * @throws UnknownXidException The transaction branch is unknown - */ - public void dequeue(Xid xid, StorableMessage m, StorableQueue queue) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException; - - //========================================================= - // Recovery specific methods - //========================================================= - - /** - * List all the persistent queues - * - * @return All the persistent queues - * @throws InternalErrorException In case of internal message store problem - */ - public Collection getAllQueues() - throws - InternalErrorException; - - /** - * All enqueued messages of a given queue - * - * @param queue The queue where the message are retrieved from - * @return The list all enqueued messages of a given queue - * @throws InternalErrorException In case of internal message store problem - */ - public Collection getAllMessages(StorableQueue queue) - throws - InternalErrorException; - - /** - * Get a new message ID - * - * @return A new message ID - */ - public long getNewMessageId(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java deleted file mode 100644 index 49af218b7a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/Pool.java +++ /dev/null @@ -1,135 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import java.util.ArrayList; - -/** - * Created by Arnaud Simon - * Date: 15-May-2007 - * Time: 10:11:49 - */ -public abstract class Pool -{ - // The maximum size of the pool. - private int _maxPoolSize = -1; - // The current size of the pool. - private int _currentPoolSize = 0; - // The pool objects. - private volatile ArrayList _poolObjects = new ArrayList(); - //The current number of created instances. - private int _instanceCount = 0; - - /** - * Create a pool of specified size. Negative or null pool sizes are - * disallowed. - * - * @param poolSize The size of the pool to create. Should be 1 or - * greater. - * @throws Exception If the pool size is less than 1. - */ - public Pool(int poolSize) throws Exception - { - if (poolSize <= 0) - { - throw new Exception("pool size is less than 1: " + poolSize); - } - _maxPoolSize = poolSize; - } - - /** - * Return the maximum size of this pool. - * - * @return The maximum size of this pool. - */ - public final int maxSize() - { - return _maxPoolSize; - } - - /** - * Return the current number of created instances. - * - * @return The current number of created instances in this pool. - */ - public final int numberOfInstances() - { - return _instanceCount; - } - - /** - * Extending classes MUST define how to create an instance of the object - * that they pool. - * - * @return An instance of the pooled object. - * @throws Exception In case of internal error. - */ - abstract protected Object createInstance() throws Exception; - - /** - * Remove the next available object from the pool or wait for one to become - * available. - * - * @return The next available instance. - * @throws Exception If the call is interrupted - */ - public final synchronized Object acquireInstance() throws Exception - { - while (_currentPoolSize == _maxPoolSize) - { - try - { - this.wait(); - } - catch (InterruptedException e) - { - throw new Exception("pool wait threw interrupted exception", e); - } - } - if (_poolObjects.size() == 0) - { - _poolObjects.add(createInstance()); - _instanceCount++; - } - _currentPoolSize++; - return _poolObjects.remove(0); - } - - /** - * Return an object back into this pool. - * - * @param object The returning object. - */ - public synchronized void releaseInstance(Object object) - { - _poolObjects.add(object); - _currentPoolSize--; - this.notify(); - } - - /** - * Return a dead object back into this pool. - * - */ - public synchronized void releaseDeadInstance() - { - _instanceCount--; - _currentPoolSize--; - this.notify(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java deleted file mode 100644 index b228bb3027..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableMessage.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -/** - * A storable message can be persisted in the message store. - * - * Created by Arnaud Simon - * Date: 03-Apr-2007 - * Time: 08:56:48 - */ -public interface StorableMessage -{ - /** - * The message ID is used by the store to identify a message. - * - * @return The message identifier - */ - public long getMessageId(); - - /** - * Get the message header body that is saved when the message is staged. - * - * @return The message header body - */ - public byte[] getHeaderBody(); - - /** - * Get the message header body size in bytes. - * - * @return The message header body size - */ - public int getHeaderSize(); - - /** - * Get the message payload. This is required when the message is - * enqueued without any prior staging. - *

      When the message is staged, the payload can be partial or even empty. - * - * @return The message payload - */ - public byte[] getData(); - - /** - * Get the message payload size in bytes. - * - * @return The message payload size in bytes - */ - public int getPayloadSize(); - - /** - * Specify whether this message has been enqueued - * - * @return true if this message is enqueued, false otherwise - */ - public boolean isEnqueued(); - - /** - * This is called by the message store when this message is enqueued in the message store. - * - * @param queue The storable queue into which the message is enqueued - */ - public void enqueue(StorableQueue queue); - - /** - * This is called by the message store when this message is dequeued. - * - * @param queue The storable queue out of which the message is dequeued - */ - public void dequeue(StorableQueue queue); - - /** - * A message can be enqueued in several queues. - * The queue position represents the index of the provided queue within the ordered - * list of queues the message has been enqueued. - *

      For example: - *

      If the message is successively enqueued in queue Q1, Q2 and Q3 then - * the position of Q1 is 0, position of Q2 is 1 and position of Q3 is 2. - *

      If the message is dequeud form Q2 then position of Q1 is stil 0 but position - * of Q3 becomes 1. - * - * @param queue The storable queue for which the position should be determined - * - * @return The position of the specified storable queue - */ - public int getQueuePosition(StorableQueue queue); - - /** - * Indicates whether this message has been staged. - * - * @return True if the message has been staged, false otherwise - */ - public boolean isStaged(); - - /** - * Call by the message store when this message is staged. - */ - public void staged(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java deleted file mode 100644 index 10a9a3b8b8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/messageStore/StorableQueue.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.messageStore; - -import org.apache.qpid.framing.AMQShortString; - -/** - * A storable queue can store storable messages and can be persisted in the store. - * Created by Arnaud Simon - * Date: 03-Apr-2007 - * Time: 08:52:18 - */ -public interface StorableQueue -{ - /** - * Get This queue unique id. - * - * @return The queue ID - */ - public int getQueueID(); - - /** - * Set the queue ID. - * - * @param id This queue ID - */ - public void setQueueID(int id); - - /** - * Get this queue owner. - * - * @return This queue owner - */ - public AMQShortString getOwner(); - - /** - * Get this queue name. - * - * @return the name of this queue - */ - public AMQShortString getName(); - - /** - * Signifies to this queue that a message is dequeued. - * This operation is called by the store. - * - * @param m The dequeued message - */ - public void dequeue(StorableMessage m); - - /** - * Signifies to this queue that a message is enqueued. - * This operation is called by the store. - * - * @param m The enqueued message - */ - public void enqueue(StorableMessage m); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java deleted file mode 100644 index e01c5aabbf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.AMQException; - -public interface ProtocolOutputConverter -{ - void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); - - interface Factory - { - ProtocolOutputConverter newInstance(AMQProtocolSession session); - } - - void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException; - - void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; - - byte getProtocolMinorVersion(); - - byte getProtocolMajorVersion(); - - void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException; - - void writeFrame(AMQDataBlock block); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java deleted file mode 100644 index 8366c426dd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; -import org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -import java.util.Map; -import java.util.HashMap; - -public class ProtocolOutputConverterRegistry -{ - - private static final Map> _registry = - new HashMap>(); - - - static - { - register((byte) 8, (byte) 0, ProtocolOutputConverterImpl.getInstanceFactory()); - } - - private static void register(byte major, byte minor, Factory converter) - { - if(!_registry.containsKey(major)) - { - _registry.put(major, new HashMap()); - } - _registry.get(major).put(minor, converter); - } - - - public static ProtocolOutputConverter getConverter(AMQProtocolSession session) - { - return _registry.get(session.getProtocolMajorVersion()).get(session.getProtocolMinorVersion()).newInstance(session); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java deleted file mode 100644 index 8462ed9557..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output.amqp0_8; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.AMQException; - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - ByteBuffer deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final Long messageId = message.getMessageId(); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext,messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); - - ByteBuffer deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - private ByteBuffer createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, getProtocolMajorVersion(), - getProtocolMinorVersion(), - consumerTag, - deliveryTag, pb.getExchange(), messageHandle.isRedelivered(), - pb.getRoutingKey()); - - - return deliverFrame.toByteBuffer(); - } - - private ByteBuffer createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, - getProtocolMajorVersion(), - getProtocolMinorVersion(), - deliveryTag, pb.getExchange(), - queueSize, - messageHandle.isRedelivered(), - pb.getRoutingKey()); - - return getOkFrame.toByteBuffer(); - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private ByteBuffer createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, - getProtocolMajorVersion(), - getProtocolMinorVersion(), - message.getMessagePublishInfo().getExchange(), - replyCode, replyText, - message.getMessagePublishInfo().getRoutingKey()); - - return returnFrame.toByteBuffer(); - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - ByteBuffer returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, headerAndFirstContent); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, - new AMQDataBlock[]{contentHeader}); - - 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()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - - writeFrame(BasicCancelOkBody.createAMQFrame(channelId, - getProtocolMajorVersion(), - getProtocolMinorVersion(), - consumerTag // consumerTag - )); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java deleted file mode 100644 index c9f5e42286..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ /dev/null @@ -1,773 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.log4j.Logger; - -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoServiceConfig; -import org.apache.mina.common.IoSession; -import org.apache.mina.transport.vmpipe.VmPipeAddress; - -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.codec.AMQDecoder; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; - -public class AMQMinaProtocolSession implements AMQProtocolSession, Managable -{ - private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - // to save boxing the channelId and looking up in a map... cache in an array the low numbered - // channels. This value must be of the form 2^x - 1. - private static final int CHANNEL_CACHE_SIZE = 0xff; - - private final IoSession _minaProtocolSession; - - private AMQShortString _contextKey; - - private AMQShortString _clientVersion = null; - - private VirtualHost _virtualHost; - - private final Map _channelMap = new HashMap(); - - private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; - - private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); - - private final AMQStateManager _stateManager; - - private AMQCodecFactory _codecFactory; - - private AMQProtocolSessionMBean _managedObject; - - private SaslServer _saslServer; - - private Object _lastReceived; - - private Object _lastSent; - - private boolean _closed; - // maximum number of channels this session should have - private long _maxNoOfChannels = 1000; - - /* AMQP Version for this session */ - private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); - - private FieldTable _clientProperties; - private final List _taskList = new CopyOnWriteArrayList(); - private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); - private List _closingChannelsList = new ArrayList(); - private ProtocolOutputConverter _protocolOutputConverter; - private Principal _authorizedID; - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) - throws AMQException - { - _stateManager = new AMQStateManager(virtualHostRegistry, this); - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - try - { - IoServiceConfig config = session.getServiceConfig(); - ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); - threadModel.getAsynchronousReadFilter().createNewJobForSession(session); - threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); - } - catch (RuntimeException e) - { - e.printStackTrace(); - // throw e; - - } - - // this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); - } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, - AMQStateManager stateManager) throws AMQException - { - _stateManager = stateManager; - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - } - - private AMQProtocolSessionMBean createMBean() throws AMQException - { - try - { - return new AMQProtocolSessionMBean(this); - } - catch (JMException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed ", ex); - throw new AMQException(null, "AMQProtocolSession MBean creation has failed ", ex); - } - } - - public IoSession getIOSession() - { - return _minaProtocolSession; - } - - public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) - { - return (AMQProtocolSession) minaProtocolSession.getAttachment(); - } - - public void dataBlockReceived(AMQDataBlock message) throws Exception - { - _lastReceived = message; - if (message instanceof ProtocolInitiation) - { - protocolInitiationReceived((ProtocolInitiation) message); - - } - else if (message instanceof AMQFrame) - { - AMQFrame frame = (AMQFrame) message; - frameReceived(frame); - - } - else - { - throw new UnknnownMessageTypeException(message, null); - } - } - - private void frameReceived(AMQFrame frame) throws AMQException - { - int channelId = frame.getChannel(); - AMQBody body = frame.getBodyFrame(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Frame Received: " + frame); - } - - if (body instanceof AMQMethodBody) - { - methodFrameReceived(channelId, (AMQMethodBody) body); - } - else if (body instanceof ContentHeaderBody) - { - contentHeaderReceived(channelId, (ContentHeaderBody) body); - } - else if (body instanceof ContentBody) - { - contentBodyReceived(channelId, (ContentBody) body); - } - else if (body instanceof HeartbeatBody) - { - // NO OP - } - else - { - _logger.warn("Unrecognised frame " + frame.getClass().getName()); - } - } - - private void protocolInitiationReceived(ProtocolInitiation pi) - { - // this ensures the codec never checks for a PI message again - ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); - try - { - pi.checkVersion(); // Fails if not correct - - // This sets the protocol version (and hence framing classes) for this session. - setProtocolVersion(pi._protocolMajor, pi._protocolMinor); - - String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); - - String locales = "en_US"; - - // Interfacing with generated code - be aware of possible changes to parameter order as versions change. - AMQFrame response = - ConnectionStartBody.createAMQFrame((short) 0, getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor) - locales.getBytes(), // locales - mechanisms.getBytes(), // mechanisms - null, // serverProperties - (short) getProtocolMajorVersion(), // versionMajor - (short) getProtocolMinorVersion()); // versionMinor - _minaProtocolSession.write(response); - } - catch (AMQException e) - { - _logger.error("Received incorrect protocol initiation", e); - - _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - // TODO: Close connection (but how to wait until message is sent?) - // ritchiem 2006-12-04 will this not do? - // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); - // future.join(); - // close connection - - } - } - - private void methodFrameReceived(int channelId, AMQMethodBody methodBody) - { - - final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); - - // Check that this channel is not closing - if (channelAwaitingClosure(channelId)) - { - if ((evt.getMethod() instanceof ChannelCloseOkBody)) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); - } - } - else - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure ignoring"); - } - - return; - } - } - - try - { - try - { - - boolean wasAnyoneInterested = _stateManager.methodReceived(evt); - - if (!_frameListeners.isEmpty()) - { - for (AMQMethodListener listener : _frameListeners) - { - wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; - } - } - - if (!wasAnyoneInterested) - { - throw new AMQNoMethodHandlerException(evt, null); - } - } - catch (AMQChannelException e) - { - if (getChannel(channelId) != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing channel due to: " + e.getMessage()); - } - - writeFrame(e.getCloseFrame(channelId)); - closeChannel(channelId); - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - closeSession(); - - AMQConnectionException ce = - evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, - AMQConstant.CHANNEL_ERROR.getName().toString()); - - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(ce.getCloseFrame(channelId)); - } - } - catch (AMQConnectionException e) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - closeSession(); - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(e.getCloseFrame(channelId)); - } - } - catch (Exception e) - { - _stateManager.error(e); - for (AMQMethodListener listener : _frameListeners) - { - listener.error(e); - } - - _minaProtocolSession.close(); - } - } - - private void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException - { - - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentHeader(body, this); - - } - - private void contentBodyReceived(int channelId, ContentBody body) throws AMQException - { - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentBody(body, this); - } - - /** - * Convenience method that writes a frame to the protocol session. Equivalent to calling - * getProtocolSession().write(). - * - * @param frame the frame to write - */ - public void writeFrame(AMQDataBlock frame) - { - _lastSent = frame; - _minaProtocolSession.write(frame); - } - - public AMQShortString getContextKey() - { - return _contextKey; - } - - public void setContextKey(AMQShortString contextKey) - { - _contextKey = contextKey; - } - - public List getChannels() - { - return new ArrayList(_channelMap.values()); - } - - public AMQChannel getAndAssertChannel(int channelId) throws AMQException - { - AMQChannel channel = getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId, null); - } - - return channel; - } - - public AMQChannel getChannel(int channelId) throws AMQException - { - final AMQChannel channel = - ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); - if ((channel == null) || channel.isClosing()) - { - return null; - } - else - { - return channel; - } - } - - public boolean channelAwaitingClosure(int channelId) - { - return _closingChannelsList.contains(channelId); - } - - public void addChannel(AMQChannel channel) throws AMQException - { - if (_closed) - { - throw new AMQException(null, "Session is closed", null); - } - - final int channelId = channel.getChannelId(); - - if (_closingChannelsList.contains(channelId)) - { - throw new AMQException(null, "Session is marked awaiting channel close", null); - } - - if (_channelMap.size() == _maxNoOfChannels) - { - String errorMessage = - toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels - + "); can't create channel"; - _logger.error(errorMessage); - throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage, null); - } - else - { - _channelMap.put(channel.getChannelId(), channel); - } - - if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) - { - _cachedChannels[channelId] = channel; - } - - checkForNotification(); - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (channelsCount >= _maxNoOfChannels) - { - _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); - } - } - - public Long getMaximumNumberOfChannels() - { - return _maxNoOfChannels; - } - - public void setMaximumNumberOfChannels(Long value) - { - _maxNoOfChannels = value; - } - - public void commitTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.commit(); - } - } - - public void rollbackTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.rollback(); - } - } - - /** - * Close a specific channel. This will remove any resources used by the channel, including:

      • 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 = getChannel(channelId); - if (channel == null) - { - throw new IllegalArgumentException("Unknown channel id"); - } - else - { - try - { - channel.close(this); - markChannelawaitingCloseOk(channelId); - } - finally - { - removeChannel(channelId); - } - } - } - - public void closeChannelOk(int channelId) - { - _closingChannelsList.remove(new Integer(channelId)); - } - - private void markChannelawaitingCloseOk(int channelId) - { - _closingChannelsList.add(channelId); - } - - /** - * In our current implementation this is used by the clustering code. - * - * @param channelId The channel to remove - */ - public void removeChannel(int channelId) - { - _channelMap.remove(channelId); - if ((channelId & CHANNEL_CACHE_SIZE) == channelId) - { - _cachedChannels[channelId] = null; - } - } - - /** - * Initialise heartbeats on the session. - * - * @param delay delay in seconds (not ms) - */ - public void initHeartbeats(int delay) - { - if (delay > 0) - { - _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); - _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); - } - } - - /** - * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. - * - * @throws AMQException if an error occurs while closing any channel - */ - private void closeAllChannels() throws AMQException - { - for (AMQChannel channel : _channelMap.values()) - { - channel.close(this); - } - - _channelMap.clear(); - for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) - { - _cachedChannels[i] = null; - } - } - - /** This must be called when the session is _closed in order to free up any resources managed by the session. */ - public void closeSession() throws AMQException - { - if (!_closed) - { - _closed = true; - closeAllChannels(); - if (_managedObject != null) - { - _managedObject.unregister(); - } - - for (Task task : _taskList) - { - task.doTask(this); - } - } - } - - 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; - } - - public FieldTable getClientProperties() - { - return _clientProperties; - } - - public void setClientProperties(FieldTable clientProperties) - { - _clientProperties = clientProperties; - if (_clientProperties != null) - { - if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) - { - setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); - } - - if (_clientProperties.getString(ClientProperties.version.toString()) != null) - { - _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); - } - } - } - - private void setProtocolVersion(byte major, byte minor) - { - _protocolVersion = new ProtocolVersion(major, minor); - - _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); - - _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); - } - - public byte getProtocolMajorVersion() - { - return _protocolVersion.getMajorVersion(); - } - - public byte getProtocolMinorVersion() - { - return _protocolVersion.getMinorVersion(); - } - - public boolean isProtocolVersion(byte major, byte minor) - { - return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); - } - - public VersionSpecificRegistry getRegistry() - { - return _registry; - } - - public Object getClientIdentifier() - { - return _minaProtocolSession.getRemoteAddress(); - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public void setVirtualHost(VirtualHost virtualHost) throws AMQException - { - _virtualHost = virtualHost; - _managedObject = createMBean(); - _managedObject.register(); - } - - public void addSessionCloseTask(Task task) - { - _taskList.add(task); - } - - public void removeSessionCloseTask(Task task) - { - _taskList.remove(task); - } - - public ProtocolOutputConverter getProtocolOutputConverter() - { - return _protocolOutputConverter; - } - - public void setAuthorizedID(Principal authorizedID) - { - _authorizedID = authorizedID; - } - - public Principal getAuthorizedID() - { - return _authorizedID; - } - - public String getClientVersion() - { - return (_clientVersion == null) ? null : _clientVersion.toString(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java deleted file mode 100644 index ee6e090e24..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to handle an AMQP method. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a - * Runtime. - */ -public class AMQNoMethodHandlerException extends AMQException -{ - public AMQNoMethodHandlerException(AMQMethodEvent evt, Throwable cause) - { - super(null, "AMQMethodEvent " + evt + " was not processed by any listener on Broker.", cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java deleted file mode 100644 index 0c80414a3e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.net.InetSocketAddress; -import 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 org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQProtocolHeaderException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.transport.ConnectorConfiguration; -import org.apache.qpid.ssl.SSLContextFactory; - -import java.io.IOException; -import java.net.InetSocketAddress; - -/** - * The protocol handler handles "protocol events" for all connections. The state - * associated with an individual connection is accessed through the protocol session. - * - * We delegate all frame (message) processing to the AMQProtocolSession which wraps - * the state for the connection. - * - */ -public class AMQPFastProtocolHandler extends IoHandlerAdapter -{ - private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); - - private final IApplicationRegistry _applicationRegistry; - - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) - { - this(ApplicationRegistry.getInstance(applicationRegistryInstance)); - } - - public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) - { - _applicationRegistry = applicationRegistry; - _logger.debug("AMQPFastProtocolHandler created"); - } - - protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) - { - this(handler._applicationRegistry); - } - - public void sessionCreated(IoSession protocolSession) throws Exception - { - SessionUtil.initialize(protocolSession); - final AMQCodecFactory codecFactory = new AMQCodecFactory(true); - - createSession(protocolSession, _applicationRegistry, codecFactory); - _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); - - final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); - - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); - if (connectorConfig.enableExecutorPool) - { - if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) - { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); - protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - - protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); - } - else - { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); - if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) - { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); - protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - - } - } - - /** - * Separated into its own, protected, method to allow easier reuse - */ - protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException - { - new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); - } - - public void sessionOpened(IoSession protocolSession) throws Exception - { - _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); - } - - public void sessionClosed(IoSession protocolSession) throws Exception - { - _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - //fixme -- this can be null - if (amqProtocolSession != null) - { - amqProtocolSession.closeSession(); - } - } - - public void sessionIdle(IoSession session, IdleStatus status) throws Exception - { - _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); - if (IdleStatus.WRITER_IDLE.equals(status)) - { - //write heartbeat frame: - session.write(HeartbeatBody.FRAME); - } - else if (IdleStatus.READER_IDLE.equals(status)) - { - //failover: - throw new IOException("Timed out while waiting for heartbeat from peer."); - } - - } - - public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception - { - AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - if (throwable instanceof AMQProtocolHeaderException) - { - - protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - protocolSession.close(); - - _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); - } - else if (throwable instanceof IOException) - { - _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); - } - else - { - _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); - - // Be aware of possible changes to parameter order as versions change. - protocolSession.write(ConnectionCloseBody.createAMQFrame(0, - session.getProtocolMajorVersion(), - session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - 200, // replyCode - new AMQShortString(throwable.getMessage()) // replyText - )); - protocolSession.close(); - } - } - - /** - * Invoked when a message is received on a particular protocol session. Note that a - * protocol session is directly tied to a particular physical connection. - * @param protocolSession the protocol session that received the message - * @param message the message itself (i.e. a decoded frame) - * @throws Exception if the message cannot be processed - */ - public void messageReceived(IoSession protocolSession, Object message) throws Exception - { - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - - if (message instanceof AMQDataBlock) - { - amqProtocolSession.dataBlockReceived((AMQDataBlock) message); - - } - else if (message instanceof ByteBuffer) - { - throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); - } - else - { - throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " - + message); - } - } - - /** - * Called after a message has been sent out on a particular protocol session - * @param protocolSession the protocol session (i.e. connection) on which this - * message was sent - * @param object the message (frame) that was encoded and sent - * @throws Exception if we want to indicate an error - */ - public void messageSent(IoSession protocolSession, Object object) throws Exception - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Message sent: " + object); - } - } - - protected boolean isSSLClient(ConnectorConfiguration connectionConfig, IoSession protocolSession) - { - InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); - - return addr.getPort() == connectionConfig.sslPort; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java deleted file mode 100644 index 07c153bfe8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; - -/** - * The protocol provide's role is to encapsulate the initialisation of the protocol handler. - * - * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events - * such as connection closing or a frame being received. It can either do this directly - * or pass off to the protocol session in the cases where state information is required to - * deal with the event. - * - */ -public class AMQPProtocolProvider -{ - /** - * Handler for protocol events - */ - private AMQPFastProtocolHandler _handler; - - public AMQPProtocolProvider() - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - _handler = new AMQPFastProtocolHandler(registry); - } - - public AMQPFastProtocolHandler getHandler() - { - return _handler; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java deleted file mode 100644 index 390117acf6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 javax.security.sasl.SaslServer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.security.Principal; - - -public interface AMQProtocolSession extends AMQVersionAwareProtocolSession -{ - - public static interface Task - { - public void doTask(AMQProtocolSession session) throws AMQException; - } - - /** - * 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; - - /** - * Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC - * 6). - * - * @return the context key - */ - AMQShortString 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(AMQShortString 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) throws AMQException; - - /** - * 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; - - /** - * Markes the specific channel as closed. This will release the lock for that channel id so a new channel can be - * created on that id. - * - * @param channelId id of the channel to close - */ - void closeChannelOk(int channelId); - - /** - * Check to see if this chanel is closing - * - * @param channelId id to check - * @return boolean with state of channel awaiting closure - */ - boolean channelAwaitingClosure(int channelId); - - /** - * 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); - - - FieldTable getClientProperties(); - - void setClientProperties(FieldTable clientProperties); - - Object getClientIdentifier(); - - VirtualHost getVirtualHost(); - - void setVirtualHost(VirtualHost virtualHost) throws AMQException; - - void addSessionCloseTask(Task task); - - void removeSessionCloseTask(Task task); - - public ProtocolOutputConverter getProtocolOutputConverter(); - - void setAuthorizedID(Principal authorizedID); - - /** @return a Principal that was used to authorized this session */ - Principal getAuthorizedID(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java deleted file mode 100644 index 66f928a70e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.security.Principal; -import java.util.Date; -import java.util.List; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; - -/** - * This MBean class implements the management interface. 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") -public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection -{ - private AMQMinaProtocolSession _session = null; - private String _name = null; - - // openmbean data types for representing the channel attributes - private static final String[] _channelAtttibuteNames = - { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; - private static final String[] _indexNames = { _channelAtttibuteNames[0] }; - private static final OpenType[] _channelAttributeTypes = - { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; - private static CompositeType _channelType = null; // represents the data type for channel data - private static TabularType _channelsType = null; // Data type for list of channels type - private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = - new AMQShortString("Broker Management Console has closed the connection."); - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException - { - super(ManagedConnection.class, ManagedConnection.TYPE); - _session = session; - String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); - init(); - } - - static - { - try - { - init(); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - /** - * initialises the openmbean data types - */ - private static void init() throws OpenDataException - { - _channelType = - new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, - _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); - } - - public String getClientId() - { - return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); - } - - public String getAuthorizedId() - { - return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; - } - - public String getVersion() - { - return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); - } - - public Date getLastIoTime() - { - return new Date(_session.getIOSession().getLastIoTime()); - } - - public String getRemoteAddress() - { - return _session.getIOSession().getRemoteAddress().toString(); - } - - public ManagedObject getParentObject() - { - return _session.getVirtualHost().getManagedObject(); - } - - public Long getWrittenBytes() - { - return _session.getIOSession().getWrittenBytes(); - } - - public Long getReadBytes() - { - return _session.getIOSession().getReadBytes(); - } - - public Long getMaximumNumberOfChannels() - { - return _session.getMaximumNumberOfChannels(); - } - - public void setMaximumNumberOfChannels(Long value) - { - _session.setMaximumNumberOfChannels(value); - } - - public String getObjectInstanceName() - { - return _name; - } - - /** - * commits transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if commit fails - */ - public void commitTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _session.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _session.commitTransactions(channel); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * rollsback the transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if rollback fails - */ - public void rollbackTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _session.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _session.rollbackTransactions(channel); - } - 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 channels() throws OpenDataException - { - TabularDataSupport channelsList = new TabularDataSupport(_channelsType); - List list = _session.getChannels(); - - for (AMQChannel channel : list) - { - Object[] itemValues = - { - channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, - channel.getUnacknowledgedMessageMap().size() - }; - - CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); - channelsList.put(channelData); - } - - return channelsList; - } - - /** - * closes the connection. The administrator can use this management operation to close connection to free up - * resources. - * @throws JMException - */ - public void closeConnection() throws JMException - { - // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) - // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. - // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = - ConnectionCloseBody.createAMQFrame(0, _session.getProtocolMajorVersion(), _session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - AMQConstant.REPLY_SUCCESS.getCode(), // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText - ); - _session.writeFrame(response); - - try - { - _session.closeSession(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Channel count has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } - - public void notifyClients(String notificationMsg) - { - Notification n = - new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, - System.currentTimeMillis(), notificationMsg); - _broadcaster.sendNotification(n); - } - -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java deleted file mode 100644 index 29d55ce763..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -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.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); - 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); - define(registry, factory, ExchangeDefaults.FANOUT_EXCHANGE_NAME, ExchangeDefaults.FANOUT_EXCHANGE_CLASS); - - registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); - } - - private void define(ExchangeRegistry r, ExchangeFactory f, - AMQShortString name, AMQShortString type) throws AMQException - { - if(r.getExchange(name)== null) - { - r.registerExchange(f.createExchange(name, type, true, false, 0)); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java deleted file mode 100644 index 310deaaf55..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class HeartbeatConfig -{ - @Configured(path = "heartbeat.delay", defaultValue = "5") - public int delay = 5;//in secs - @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0") - public double timeoutFactor = 2; - - public double getTimeoutFactor() - { - return timeoutFactor; - } - - public void setTimeoutFactor(double timeoutFactor) - { - this.timeoutFactor = timeoutFactor; - } - - public int getDelay() - { - return delay; - } - - public void setDelay(int delay) - { - this.delay = delay; - } - - int getTimeout(int writeDelay) - { - return (int) (timeoutFactor * writeDelay); - } - - public static HeartbeatConfig getInstance() - { - return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class); - } - - public String toString() - { - return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java deleted file mode 100644 index e6e713ac6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.util.Date; -import java.security.Principal; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of Connections. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedConnection -{ - static final String TYPE = "Connection"; - - @MBeanAttribute(name = "ClientId", description = "Client Id") - String getClientId(); - - @MBeanAttribute(name = "AuthorizedId", description = "User Name") - String getAuthorizedId(); - - @MBeanAttribute(name = "Version", description = "Client Version") - String getVersion(); - - /** - * Tells the remote address of this connection. - * @return remote address - */ - @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") - String getRemoteAddress(); - - /** - * Tells the last time, the IO operation was done. - * @return last IO time. - */ - @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done") - Date getLastIoTime(); - - /** - * Tells the total number of bytes written till now. - * @return number of bytes written. - * - @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") - Long getWrittenBytes(); - */ - /** - * Tells the total number of bytes read till now. - * @return number of bytes read. - * - @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") - Long getReadBytes(); - */ - - /** - * Threshold high value for no of channels. This is useful in setting notifications or - * taking required action is there are more channels being created. - * @return threshold limit for no of channels - */ - Long getMaximumNumberOfChannels(); - - /** - * Sets the threshold high value for number of channels for a connection - * @param value - */ - @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") - void setMaximumNumberOfChannels(Long value); - - //********** Operations *****************// - - /** - * channel details of all the channels opened for this connection. - * @return general channel details - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="channels", description="Channel details for this connection") - TabularData channels() throws IOException, JMException; - - /** - * Commits the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="commitTransaction", - description="Commits the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Rollsback the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="rollbackTransactions", - description="Rollsback the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Closes all the related channels and unregisters this connection from managed objects. - */ - @MBeanOperation(name="closeConnection", - description="Closes this connection and all related channels", - impact= MBeanOperationInfo.ACTION) - void closeConnection() throws Exception; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java deleted file mode 100644 index d053884e69..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; - -/** - * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to cast a frame to its expected type. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would - * be better just to leave that as a ClassCastException. However, check the framing layer catches this error - * first. - */ -public class UnknnownMessageTypeException extends AMQException -{ - public UnknnownMessageTypeException(AMQDataBlock message, Throwable cause) - { - super(null, "Unknown message type: " + message.getClass().getName() + ": " + message, cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java deleted file mode 100644 index 7fa028df29..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,1108 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionalContext; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Combines the information that make up a deliverable message into a more manageable form. - */ -public class AMQMessage implements StorableMessage -{ - /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(AMQMessage.class); - - // The ordered list of queues into which this message is enqueued. - private List _queues = new LinkedList(); - // Indicates whether this message is staged - private boolean _isStaged = false; - - /** - * Used in clustering - */ - private Set _tokens; - - /** - * Only use in clustering - //todo: should ideally be removed? - */ - private AMQProtocolSession _publisher; - - private final Long _messageId; - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - private AMQMessageHandle _messageHandle; - - /** Holds the transactional context in which this message is being processed. */ - // TODO: ideally this should be able to go into the transient message date - check this! (RG) - private TransactionalContext _txnContext; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - private boolean _deliveredToConsumer; - /** - * We need to keep track of whether the message was 'immediate' as in extreme circumstances, when the - * checkDelieveredToConsumer is called, the message may already have been received and acknowledged, and the body - * removed from the store. - */ - - /** Flag to indicate that this message requires 'immediate' delivery. */ - private boolean _immediate; - - // private Subscription _takenBySubcription; - // private AtomicBoolean _taken = new AtomicBoolean(false); - private TransientMessageData _transientMessageData = new TransientMessageData(); - - //todo: this should be part of a messageOnQueue object - private Set _rejectedBy = null; - - //todo: this should be part of a messageOnQueue object - private Map _takenMap = new HashMap(); - //todo: this should be part of a messageOnQueue object - private Map _takenBySubcriptionMap = new HashMap(); - - private final int hashcode = System.identityHashCode(this); - - //todo: this should be part of a messageOnQueue object - private long _expiration; - - public String debugIdentity() - { - return "(HC:" + hashcode + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; - } - - public void setExpiration() - { - long expiration = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); - long timestamp = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); - - if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false)) - { - _expiration = expiration; - } - else - { - // Update TTL to be in broker time. - if (expiration != 0L) - { - if (timestamp != 0L) - { - // todo perhaps use arrival time - long diff = (System.currentTimeMillis() - timestamp); - - if ((diff > 1000L) || (diff < 1000L)) - { - _expiration = expiration + diff; - } - } - } - } - - } - - /** - * 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 AMQProtocolSession _protocolSession; - - private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - _channel = channel; - _protocolSession = protocolSession; - } - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); - } - catch (AMQException e) - { - _log.error("Unable to get body count: " + e, e); - - return false; - } - } - - public AMQDataBlock next() - { - try - { - - AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - _messageId, ++_index)); - - return new AMQFrame(_channel, cb); - } - catch (AMQException e) - { - // have no choice but to throw a runtime exception - throw new RuntimeException("Error getting content body: " + e, e); - } - - } - - private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() - { - return _protocolSession.getRegistry().getProtocolVersionMethodConverter(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public StoreContext getStoreContext() - { - return _txnContext.getStoreContext(); - } - - private class BodyContentIterator implements Iterator - { - - private int _index = -1; - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); - } - catch (AMQException e) - { - _log.error("Error getting body count: " + e, e); - - return false; - } - } - - public ContentChunk next() - { - try - { - return _messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index); - } - catch (AMQException e) - { - throw new RuntimeException("Error getting content body: " + e, e); - } - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext) - { - _messageId = messageId; - _txnContext = txnContext; - _immediate = info.isImmediate(); - _transientMessageData.setMessagePublishInfo(info); - - } - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageId - * @param store - * @param factory - * - * @throws AMQException - */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws AMQException - { - _messageId = messageId; - _messageHandle = factory.createMessageHandle(store, this, true); - _txnContext = txnConext; - _transientMessageData = null; - } - - /** - * Used in testing only. This allows the passing of the content header immediately on construction. - * - * @param messageId - * @param info - * @param txnContext - * @param contentHeader - */ - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader) throws AMQException - { - this(messageId, info, txnContext); - setContentHeaderBody(contentHeader); - } - - /** - * Used in testing only. This allows the passing of the content header and some body fragments on construction. - * - * @param messageId - * @param info - * @param txnContext - * @param contentHeader - * @param destinationQueues - * @param contentBodies - * - * @throws AMQException - */ - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, - MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException - { - this(messageId, info, txnContext, contentHeader); - _transientMessageData.setDestinationQueues(destinationQueues); - routingComplete(messageStore, storeContext, messageHandleFactory); - for (ContentChunk cb : contentBodies) - { - addContentBodyFrame(storeContext, cb); - } - } - - protected AMQMessage(AMQMessage msg) throws AMQException - { - _messageId = msg._messageId; - _messageHandle = msg._messageHandle; - _txnContext = msg._txnContext; - _deliveredToConsumer = msg._deliveredToConsumer; - _transientMessageData = msg._transientMessageData; - } - - // ======================================================================== - // Interface StorableMessage - // ======================================================================== - - public long getMessageId() - { - return _messageId; - } - - public byte[] getHeaderBody() - { - byte[] result = null; - ContentHeaderBody headerBody; - ByteBuffer bufferedResult; - try - { - headerBody = _messageHandle.getContentHeaderBody(_txnContext.getStoreContext(), _messageId); - result = new byte[headerBody.getSize()]; - bufferedResult = ByteBuffer.wrap(result); - headerBody.writePayload(bufferedResult); - } - catch (AMQException e) - { - _log.error("Error when getting message header", e); - } - - return result; - } - - public int getHeaderSize() - { - int result = 0; - try - { - result = _messageHandle.getContentHeaderBody(_txnContext.getStoreContext(), _messageId).getSize(); - } - catch (AMQException e) - { - _log.error("Error when getting message header size", e); - } - - return result; - } - - public byte[] getData() - { - return _messageHandle.getMessagePayload(); - } - - public int getPayloadSize() - { - return _messageHandle.getMessagePayload().length; - } - - public boolean isEnqueued() - { - return _queues.size() > 0; - } - - public void enqueue(StorableQueue queue) - { - _queues.add(queue); - if (_log.isDebugEnabled()) - { - _log.debug("enqueued"); - } - } - - public void dequeue(StorableQueue queue) - { - _queues.remove(queue); - if (_log.isDebugEnabled()) - { - _log.debug("dequeued"); - } - } - - public int getQueuePosition(StorableQueue queue) - { - if (_log.isDebugEnabled()) - { - _log.debug("The queue position is " + _queues.indexOf(queue)); - } - - return _queues.indexOf(queue); - } - - public boolean isStaged() - { - return _isStaged; - } - - public void staged() - { - _isStaged = true; - } - - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); - } - - public Iterator getContentBodyIterator() - { - return new BodyContentIterator(); - } - - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - if (_transientMessageData != null) - { - return _transientMessageData.getContentHeaderBody(); - } - else - { - return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); - } - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException - { - _transientMessageData.setContentHeaderBody(contentHeaderBody); - } - - public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) - throws AMQException - { - final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(store, this, persistent); - if (persistent) //DTX was removed - { - _txnContext.beginTranIfNecessary(); - } - - // enqueuing the messages ensure that if required the destinations are recorded to a - // persistent store - - //DTX was removed - for (AMQQueue q : _transientMessageData.getDestinationQueues()) - { - _messageHandle.enqueue(storeContext, _messageId, q); - } - - if (_transientMessageData.getContentHeaderBody().bodySize == 0) - { - deliver(storeContext); - } - } - - public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException - { - _transientMessageData.addBodyLength(contentChunk.getSize()); - final boolean allContentReceived = isAllContentReceived(); - _messageHandle.addContentBodyFrame(storeContext, _messageId, contentChunk, allContentReceived); - if (allContentReceived) - { - deliver(storeContext); - - return true; - } - else - { - return false; - } - } - - public boolean isAllContentReceived() throws AMQException - { - return _transientMessageData.isAllContentReceived(); - } - - /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic - * operation. - */ - public AMQMessage takeReference() - { - incrementReference(); // _referenceCount.incrementAndGet(); - - return this; - } - - - /** - * Threadsafe. Increment the reference count on the message. - */ - protected void incrementReference() - { - _referenceCount.incrementAndGet(); - // if (_log.isDebugEnabled()) - // { - // _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - // } - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @param storeContext - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException - { - int count = _referenceCount.decrementAndGet(); - - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (count == 0) - { - try - { - // if (_log.isDebugEnabled()) - // { - // _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - // } - - // must check if the handle is null since there may be cases where we decide to throw away a message - // and the handle has not yet been constructed - if (_messageHandle != null) - { - _messageHandle.removeMessage(storeContext, _messageId); - } - } - catch (AMQException e) - { - // to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException("Failed to cleanup message with id " + _messageId, e); - } - } - else - { - if (count < 0) - { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() + " has gone below 0.", - null); - } - } - } - - public void setPublisher(AMQProtocolSession publisher) - { - _publisher = publisher; - } - - public AMQProtocolSession getPublisher() - { - return _publisher; - } - - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - public boolean getDeliveredToConsumer() - { - return _deliveredToConsumer; - } - - public boolean isTaken(AMQQueue queue) - { - // return _taken.get(); - - synchronized (this) - { - AtomicBoolean taken = _takenMap.get(queue); - if (taken == null) - { - taken = new AtomicBoolean(false); - _takenMap.put(queue, taken); - } - - return taken.get(); - } - } - - public boolean taken(AMQQueue queue, Subscription sub) - { - // if (_taken.getAndSet(true)) - // { - // return true; - // } - // else - // { - // _takenBySubcription = sub; - // return false; - // } - - synchronized (this) - { - AtomicBoolean taken = _takenMap.get(queue); - if (taken == null) - { - taken = new AtomicBoolean(false); - } - - if (taken.getAndSet(true)) - { - return true; - } - else - { - _takenMap.put(queue, taken); - _takenBySubcriptionMap.put(queue, sub); - - return false; - } - } - } - - public void release(AMQQueue queue) - { - if (_log.isTraceEnabled()) - { - _log.trace("Releasing Message:" + debugIdentity()); - } - - // _taken.set(false); - // _takenBySubcription = null; - - synchronized (this) - { - AtomicBoolean taken = _takenMap.get(queue); - if (taken == null) - { - taken = new AtomicBoolean(false); - } - else - { - taken.set(false); - } - - _takenMap.put(queue, taken); - _takenBySubcriptionMap.put(queue, null); - } - } - - public boolean checkToken(Object token) - { - - if (_tokens == null) - { - _tokens = new HashSet(); - } - - 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 - { - _transientMessageData.addDestinationQueue(queue); - } - - public void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException - { - _messageHandle.dequeue(storeContext, _messageId, queue); - } - - public boolean isPersistent() throws AMQException - { - if (_transientMessageData != null) - { - return _transientMessageData.isPersistent(); - } - else - { - return _messageHandle.isPersistent(getStoreContext(), _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 - { - - if (_immediate && !_deliveredToConsumer) - { - throw new NoConsumersException(this, null); - } - } - - public MessagePublishInfo getMessagePublishInfo() throws AMQException - { - MessagePublishInfo pb; - if (_transientMessageData != null) - { - pb = _transientMessageData.getMessagePublishInfo(); - } - else - { - pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); - } - - return pb; - } - - public boolean isRedelivered() - { - return _messageHandle.isRedelivered(); - } - - public void setRedelivered(boolean redelivered) - { - _messageHandle.setRedelivered(redelivered); - } - - public long getArrivalTime() - { - return _messageHandle.getArrivalTime(); - } - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @param queue The queue to check the expiration against. (Currently not used) - * - * @return true if the message has expire - * - * @throws AMQException - */ - public boolean expired(AMQQueue queue) throws AMQException - { - // note: If the storecontext isn't need then we can remove the getChannel() from Subscription. - - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } - - return false; - } - - /** Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). */ - public void setDeliveredToConsumer() - { - _deliveredToConsumer = true; - } - - private void deliver(StoreContext storeContext) throws AMQException - { - // we get a reference to the destination queues now so that we can clear the - // transient message data as quickly as possible - List destinationQueues = _transientMessageData.getDestinationQueues(); - if (_log.isDebugEnabled()) - { - _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues); - } - - try - { - // first we allow the handle to know that the message has been fully received. This is useful if it is - // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, - _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); - - // 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()); - - _transientMessageData = null; - - for (AMQQueue q : destinationQueues) - { - // Increment the references to this message for each queue delivery. - incrementReference(); - // normal deliver so add this message at the end. - _txnContext.deliver(this, q, false); - } - } - finally - { - destinationQueues.clear(); - // Remove refence for routing process . Reference count should now == delivered queue count - decrementReference(storeContext); - } - } - - /* - public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - ByteBuffer deliver = createEncodedDeliverFrame(protocolSession, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); - if (bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - protocolSession.writeFrame(compositeBlock); - } - else - { - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for (int i = 1; i < bodyCount; i++) - { - cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); - protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - public void writeGetOk(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) throws AMQException - { - ByteBuffer deliver = createEncodedGetOkFrame(protocolSession, channelId, deliveryTag, queueSize); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - final int bodyCount = _messageHandle.getBodyCount(getStoreContext(), _messageId); - if (bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - protocolSession.writeFrame(compositeBlock); - } - else - { - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for (int i = 1; i < bodyCount; i++) - { - cb = _messageHandle.getContentChunk(getStoreContext(), _messageId, i); - protocolSession.writeFrame(new AMQFrame(channelId, protocolSession.getRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - private ByteBuffer createEncodedDeliverFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - MessagePublishInfo pb = getMessagePublishInfo(); - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, protocolSession.getProtocolMajorVersion(), (byte) 0, consumerTag, - deliveryTag, pb.getExchange(), _messageHandle.isRedelivered(), - pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; - } - - private ByteBuffer createEncodedGetOkFrame(AMQProtocolSession protocolSession, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - MessagePublishInfo pb = getMessagePublishInfo(); - AMQFrame getOkFrame = BasicGetOkBody.createAMQFrame(channelId, - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - deliveryTag, pb.getExchange(), - queueSize, - _messageHandle.isRedelivered(), - pb.getRoutingKey()); - ByteBuffer buf = ByteBuffer.allocate((int) getOkFrame.getSize()); // XXX: Could cast be a problem? - getOkFrame.writePayload(buf); - buf.flip(); - return buf; - } - - private ByteBuffer createEncodedReturnFrame(AMQProtocolSession protocolSession, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - getMessagePublishInfo().getExchange(), - replyCode, replyText, - getMessagePublishInfo().getRoutingKey()); - 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, AMQShortString replyText) - throws AMQException - { - ByteBuffer returnFrame = createEncodedReturnFrame(protocolSession, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - Iterator bodyFrameIterator = getBodyFrameIterator(protocolSession, 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()); - } - } - */ - - public AMQMessageHandle getMessageHandle() - { - return _messageHandle; - } - - public long getSize() - { - try - { - long size = getContentHeaderBody().bodySize; - - return size; - } - catch (AMQException e) - { - _log.error(e.toString(), e); - - return 0; - } - - } - - public void restoreTransientMessageData() throws AMQException - { - TransientMessageData transientMessageData = new TransientMessageData(); - transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); - transientMessageData.setContentHeaderBody(getContentHeaderBody()); - transientMessageData.addBodyLength(getContentHeaderBody().getSize()); - _transientMessageData = transientMessageData; - } - - public void clearTransientMessageData() - { - _transientMessageData = null; - } - - public String toString() - { - // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - // _taken + " by :" + _takenBySubcription; - - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " - + _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); - } - - public Subscription getDeliveredSubscription(AMQQueue queue) - { - // return _takenBySubcription; - synchronized (this) - { - return _takenBySubcriptionMap.get(queue); - } - } - - public void reject(Subscription subscription) - { - - if (subscription != null) - { - if (_rejectedBy == null) - { - _rejectedBy = new HashSet(); - } - - _rejectedBy.add(subscription); - } - else - { - _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); - } - } - - public boolean isRejectedBy(Subscription subscription) - { - boolean rejected = _rejectedBy != null; - - if (rejected) // We have subscriptions that rejected this message - { - return _rejectedBy.contains(subscription); - } - else // This messasge hasn't been rejected yet. - { - return rejected; - } - } - - public String getBodyAsString() - { - StringBuilder b = new StringBuilder(); - for (Iterator it = getContentBodyIterator(); it.hasNext(); ) - { - ByteBuffer buf = it.next().getData(); - byte[] bytes = new byte[buf.remaining()]; - buf.duplicate().get(bytes); - b.append(new String(bytes)); - } - return b.toString(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java deleted file mode 100644 index 296e61bfa9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * A pluggable way of getting message data. Implementations can provide intelligent caching for example or - * even no caching at all to minimise the broker memory footprint. - * - * 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(StoreContext context, Long messageId) throws AMQException; - - /** - * @return the number of body frames associated with this message - */ - int getBodyCount(StoreContext context, Long messageId) throws AMQException; - - /** - * @return the size of the body - */ - long getBodySize(StoreContext context, 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 - */ - ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; - - void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - - MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException; - - boolean isRedelivered(); - - void setRedelivered(boolean redelivered); - - boolean isPersistent(StoreContext context, Long messageId) throws AMQException; - - void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException; - - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; - - void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; - - long getArrivalTime(); - - // added by Arnaud - byte[] getMessagePayload(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java deleted file mode 100644 index b4a92b3483..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.configuration.Configured; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import java.text.MessageFormat; -import java.util.Collection; -import java.util.Hashtable; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * 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, Comparable, StorableQueue -{ - //FROM M2 - think these have been replaced by *Exception in the broker exception package -// /** -// * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription -// * already exists. -// * -// *

      -// *
      CRC Card
      Responsibilities Collaborations -// *
      Represent failure to create a subscription, because an exclusive subscription already exists. -// *
      -// * -// * @todo Not an AMQP exception as no status code. -// * -// * @todo Move to top level, used outside this class. -// */ -// public static final class ExistingExclusiveSubscription extends AMQException -// { -// -// public ExistingExclusiveSubscription() -// { -// super(""); -// } -// } -// -// /** -// * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription -// * already exists. -// * -// *

      -// *
      CRC Card
      Responsibilities Collaborations -// *
      Represent failure to create an exclusize subscription, as a subscription already exists. -// *
      -// * -// * @todo Not an AMQP exception as no status code. -// * -// * @todo Move to top level, used outside this class. -// */ -// public static final class ExistingSubscriptionPreventsExclusive extends AMQException -// { -// public ExistingSubscriptionPreventsExclusive() -// { -// super(""); - // } - // } - public static int s_queueID = 0; - - private static final Logger _logger = Logger.getLogger(AMQQueue.class); - - private final AMQShortString _name; - - // The queueu ID - int _queueId; - // The list of enqueued messages. - Hashtable _messages = new Hashtable(); - - /** - * null means shared - */ - private final AMQShortString _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; - - private final AtomicInteger _subscriberCount = new AtomicInteger(); - - private final AtomicBoolean _isExclusive = new AtomicBoolean(); - - private final AtomicBoolean _deleted = new AtomicBoolean(false); - - private List _deleteTaskList = new CopyOnWriteArrayList(); - - /** - * Manages message delivery. - */ - private final DeliveryManager _deliveryMgr; - - /** - * 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; - - private final VirtualHost _virtualHost; - - /** - * max allowed size(KB) of a single message - */ - @Configured(path = "maximumMessageSize", defaultValue = "0") - public long _maximumMessageSize; - - /** - * max allowed number of messages on a queue. - */ - @Configured(path = "maximumMessageCount", defaultValue = "0") - public long _maximumMessageCount; - - /** - * max queue depth for the queue - */ - @Configured(path = "maximumQueueDepth", defaultValue = "0") - public long _maximumQueueDepth; - - /** - * maximum message age before alerts occur - */ - @Configured(path = "maximumMessageAge", defaultValue = "0") - public long _maximumMessageAge; - - /** - * the minimum interval between sending out consequetive alerts of the same type - */ - @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") - public long _minimumAlertRepeatGap; - - /** - * total messages received by the queue since startup. - */ - public AtomicLong _totalMessagesReceived = new AtomicLong(); - - public int compareTo(Object o) - { - return _name.compareTo(((AMQQueue) o).getName()); - } - - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException - { - this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), - new SubscriptionSet(), new SubscriptionImpl.Factory()); - } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException - { - this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, - new SubscriptionImpl.Factory()); - } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, - SubscriptionFactory subscriptionFactory) throws AMQException - { - if (name == null) - { - throw new IllegalArgumentException("Queue name must not be null"); - } - - if (virtualHost == null) - { - throw new IllegalArgumentException("Virtual Host must not be null"); - } - - _name = name; - _durable = durable; - _owner = owner; - _autoDelete = autoDelete; - _virtualHost = virtualHost; - _asyncDelivery = asyncDelivery; - - _managedObject = createMBean(); - _managedObject.register(); - - _subscribers = subscribers; - _subscriptionFactory = subscriptionFactory; - _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); - _queueId = s_queueID++; - } - - private AMQQueueMBean createMBean() throws AMQException - { - try - { - return new AMQQueueMBean(this); - } - catch (JMException ex) - { - throw new AMQException(null, "AMQQueue MBean creation has failed ", ex); - } - } - - public AMQShortString getName() - { - return _name; - } - - public boolean isShared() - { - return _owner == null; - } - - public boolean isDurable() - { - return _durable; - } - - public AMQShortString getOwner() - { - return _owner; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - /** - * @return no of messages(undelivered) on the queue. - */ - public int getMessageCount() - { - return _deliveryMgr.getQueueMessageCount(); - } - - /** - * @return List of messages(undelivered) on the queue. - */ - public List getMessagesOnTheQueue() - { - return _deliveryMgr.getMessages(); - } - - /** - * Returns messages within the given range of message Ids - * - * @param fromMessageId - * @param toMessageId - * @return List of messages - */ - public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) - { - return _deliveryMgr.getMessages(fromMessageId, toMessageId); - } - - public long getQueueDepth() - { - return _deliveryMgr.getTotalMessageSize(); - } - - /** - * @param messageId - * @return AMQMessage with give id if exists. null if AMQMessage with given id doesn't exist. - */ - public AMQMessage getMessageOnTheQueue(long messageId) - { - List list = getMessagesOnTheQueue(messageId, messageId); - if ((list == null) || (list.size() == 0)) - { - return null; - } - - return list.get(0); - } - - /** - * moves messages from this queue to another queue. to do this the approach is following- - setup the queue for - * moving messages (stop the async delivery) - get all the messages available in the given message id range - setup - * the other queue for moving messages (stop the async delivery) - send these available messages to the other queue - * (enqueue in other queue) - Once sending to other Queue is successful, remove messages from this queue - remove - * locks from both queues and start async delivery - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param queueName The queue to move the messages to. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - - MessageStore fromStore = getVirtualHost().getMessageStore(); - MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); - - if (toStore != fromStore) - { - throw new RuntimeException("Can only move messages between queues on the same message store."); - } - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - toQueue.startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity - * on the queues being moved between is suspended during the move. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param queueName The queue to move the messages to. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - - MessageStore fromStore = getVirtualHost().getMessageStore(); - MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); - - if (toStore != fromStore) - { - throw new RuntimeException("Can only move messages between queues on the same message store."); - } - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - toQueue.startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - message.takeReference(); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Removes messages from this queue, and also commits the remove on the message store. Delivery activity - * on the queues being moved between is suspended during the remove. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) - { - MessageStore fromStore = getVirtualHost().getMessageStore(); - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // remove the messages in on the message store. - for (AMQMessage message : foundMessagesList) - { - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // remove the messages on the in-memory queues. - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - stopMovingMessages(); - } - } - - public void startMovingMessages() - { - _deliveryMgr.startMovingMessages(); - } - - private void enqueueMovedMessages(StoreContext storeContext, List messageList) - { - _deliveryMgr.enqueueMovedMessages(storeContext, messageList); - _totalMessagesReceived.addAndGet(messageList.size()); - } - - public void stopMovingMessages() - { - _deliveryMgr.stopMovingMessages(); - _deliveryMgr.processAsync(_asyncDelivery); - } - - /** - * @return MBean object associated with this Queue - */ - public ManagedObject getManagedObject() - { - return _managedObject; - } - - public long getMaximumMessageSize() - { - return _maximumMessageSize; - } - - public void setMaximumMessageSize(long value) - { - _maximumMessageSize = value; - } - - public int getConsumerCount() - { - return _subscribers.size(); - } - - public int getActiveConsumerCount() - { - return _subscribers.getWeight(); - } - - public long getReceivedMessageCount() - { - return _totalMessagesReceived.get(); - } - - public long getMaximumMessageCount() - { - return _maximumMessageCount; - } - - public void setMaximumMessageCount(long value) - { - _maximumMessageCount = value; - } - - public long getMaximumQueueDepth() - { - return _maximumQueueDepth; - } - - // Sets the queue depth, the max queue size - public void setMaximumQueueDepth(long value) - { - _maximumQueueDepth = value; - } - - public long getOldestMessageArrivalTime() - { - return _deliveryMgr.getOldestMessageArrival(); - - } - - /** - * Removes the AMQMessage from the top of the queue. - */ - public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException - { - _deliveryMgr.removeAMessageFromTop(storeContext); - } - - /** - * removes all the messages from the queue. - */ - public synchronized long clearQueue(StoreContext storeContext) throws AMQException - { - return _deliveryMgr.clearAllMessages(storeContext); - } - - public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException - { - exchange.registerQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); - //DTX MessageStore -// try -// { -// _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); -// } -// catch (InternalErrorException e) -// { -// throw new AMQException(null, "Problem binding queue ", e); -// } - } - - _bindings.addBinding(routingKey, arguments, exchange); - } - - public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException - { - exchange.deregisterQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); - //DTX MessageStore -// try -// { -// _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); -// } -// catch (InternalErrorException e) -// { -// throw new AMQException(null, "problem unbinding queue", e); -// } - } - - _bindings.remove(routingKey, arguments, exchange); - } - - public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException - { - if (incrementSubscriberCount() > 1) - { - if (isExclusive()) - { - decrementSubscriberCount(); - throw new ExistingExclusiveSubscriptionException(); - } - else if (exclusive) - { - decrementSubscriberCount(); - throw new ExistingSubscriptionPreventsExclusiveException(); - } - - } - else if (exclusive) - { - setExclusive(true); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format( - "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, filters, noLocal, this); - - if (subscription.filtersMessages()) - { - if (_deliveryMgr.hasQueuedMessages()) - { - _deliveryMgr.populatePreDeliveryQueue(subscription); - } - } - - _subscribers.addSubscriber(subscription); - } - - private boolean isExclusive() - { - return _isExclusive.get(); - } - - private void setExclusive(boolean exclusive) - { - _isExclusive.set(exclusive); - } - - private int incrementSubscriberCount() - { - return _subscriberCount.incrementAndGet(); - } - - private int decrementSubscriberCount() - { - return _subscriberCount.decrementAndGet(); - } - - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format( - "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(null, "Protocol session with channel " + channel + " and consumer tag " + consumerTag - + " and protocol session key " + ps.getKey() + " not registered with queue " + this, null); - } - - removedSubscription.close(); - setExclusive(false); - decrementSubscriberCount(); - - // if we are eligible for auto deletion, unregister from the queue registry - if (_autoDelete && _subscribers.isEmpty()) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Auto-deleteing queue:" + this); - } - - 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 boolean isUnused() - { - return _subscribers.isEmpty(); - } - - public boolean isEmpty() - { - return !_deliveryMgr.hasQueuedMessages(); - } - - public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException - { - if (checkUnused && !_subscribers.isEmpty()) - { - _logger.info("Will not delete " + this + " as it is in use."); - - return 0; - } - else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) - { - _logger.info("Will not delete " + this + " as it is not empty."); - - return 0; - } - else - { - delete(); - - return _deliveryMgr.getQueueMessageCount(); - } - } - - public void delete() throws AMQException - { - if (!_deleted.getAndSet(true)) - { - _subscribers.queueDeleted(this); - _bindings.deregister(); - _virtualHost.getQueueRegistry().unregisterQueue(_name); - _managedObject.unregister(); - for (Task task : _deleteTaskList) - { - task.doTask(this); - } - - _deleteTaskList.clear(); - } - } - - protected void autodelete() throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format("autodeleting {0}", this)); - } - - delete(); - } - - /*public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException - { - // fixme not sure what this is doing. should we be passing deliverFirst through here? - // This code is not used so when it is perhaps it should - _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); - try - { - msg.checkDeliveredToConsumer(); - updateReceivedMessageCount(msg); - } - catch (NoConsumersException e) - { - // as this message will be returned, it should be removed - // from the queue: - dequeue(storeContext, msg); - } - }*/ - - // public DeliveryManager getDeliveryManager() - // { - // return _deliveryMgr; - // } - - public void process(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException - { - _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); - try - { - msg.checkDeliveredToConsumer(); - updateReceivedMessageCount(msg); - } - catch (NoConsumersException e) - { - // as this message will be returned, it should be removed - // from the queue: - dequeue(storeContext, msg); - } - } - - void dequeue(StoreContext storeContext, AMQMessage msg) throws FailedDequeueException - { - try - { - msg.dequeue(storeContext, this); - } - catch (MessageCleanupException e) - { - // Message was dequeued, but could not then be deleted - // though it is no longer referenced. This should be very - // rare and can be detected and cleaned up on recovery or - // done through some form of manual intervention. - _logger.error(e, e); - } - catch (AMQException e) - { - throw new FailedDequeueException(_name.toString(), e); - } - } - - public void deliverAsync() - { - _deliveryMgr.processAsync(_asyncDelivery); - } - - protected SubscriptionManager getSubscribers() - { - return _subscribers; - } - - protected void updateReceivedMessageCount(AMQMessage msg) throws AMQException - { - if (!msg.isRedelivered()) - { - _totalMessagesReceived.incrementAndGet(); - } - - try - { - _managedObject.checkForNotification(msg); - } - catch (JMException e) - { - throw new AMQException(null, "Unable to get notification from manage queue: " + e, e); - } - } - - 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); - } - - public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException - { - return _deliveryMgr.performGet(session, channel, acks); - } - - public QueueRegistry getQueueRegistry() - { - return _virtualHost.getQueueRegistry(); - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public static interface Task - { - public void doTask(AMQQueue queue) throws AMQException; - } - - public void addQueueDeleteTask(Task task) - { - _deleteTaskList.add(task); - } - - public long getMinimumAlertRepeatGap() - { - return _minimumAlertRepeatGap; - } - - public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) - { - _minimumAlertRepeatGap = minimumAlertRepeatGap; - } - - public long getMaximumMessageAge() - { - return _maximumMessageAge; - } - - public void setMaximumMessageAge(long maximumMessageAge) - { - _maximumMessageAge = maximumMessageAge; - } - - public void subscriberHasPendingResend(boolean hasContent, SubscriptionImpl subscription, AMQMessage msg) - { - _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, msg); - } - - // ======================================================================== - // Interface StorableQueue - // ======================================================================== - - public int getQueueID() - { - return _queueId; - } - - public void setQueueID(int id) - { - _queueId = id; - } - - public void dequeue(StorableMessage m) - { - _messages.remove(m.getMessageId()); - } - - public void enqueue(StorableMessage m) - { - _messages.put(m.getMessageId(), m); - } - - // ======================================================================== - // Used by the Store - // ======================================================================== - - /** - * Get the list of enqueud messages - * - * @return The list of enqueud messages - */ - public Collection getAllEnqueuedMessages() - { - return _messages.values(); - } - - /** - * Get the enqueued message identified by messageID - * - * @param messageId the id of the enqueued message to recover - * @return The enqueued message with the specified id - */ - public StorableMessage getEnqueuedMessage(long messageId) - { - return _messages.get(messageId); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java deleted file mode 100644 index 4331d8d870..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; - -import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.OperationsException; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -/** - * MBean class for AMQQueue. It implements all the management features exposed - * for an AMQQueue. - *

      CRC Caption
      Responsibilities Collaborations - *
      - */ -@MBeanDescription("Management Interface for AMQQueue") -public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener -{ - /** Used for debugging purposes. */ - private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); - - private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); - - /** - * Since the MBean is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - private StoreContext _storeContext = new StoreContext(); - - private AMQQueue _queue = null; - private String _queueName = null; - // OpenMBean data types for viewMessages method - private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; - private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; - private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - // OpenMBean data types for viewMessageContent method - private static CompositeType _msgContentType = null; - private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; - private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; - private Notification _lastNotification = null; - - @MBeanConstructor("Creates an MBean exposing an AMQQueue") - public AMQQueueMBean(AMQQueue queue) throws JMException - { - super(ManagedQueue.class, ManagedQueue.TYPE); - _queue = queue; - _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); - } - - public ManagedObject getParentObject() - { - return _queue.getVirtualHost().getManagedObject(); - } - - static - { - try - { - init(); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - /** - * initialises the openmbean data types - */ - private static void init() throws OpenDataException - { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = - new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, - _msgContentAttributeTypes); - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = - new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); - } - - public String getObjectInstanceName() - { - return _queueName; - } - - public String getName() - { - return _queueName; - } - - public boolean isDurable() - { - return _queue.isDurable(); - } - - public String getOwner() - { - return String.valueOf(_queue.getOwner()); - } - - public boolean isAutoDelete() - { - return _queue.isAutoDelete(); - } - - public Integer getMessageCount() - { - return _queue.getMessageCount(); - } - - public Long getMaximumMessageSize() - { - return _queue.getMaximumMessageSize(); - } - - public Long getMaximumMessageAge() - { - return _queue.getMaximumMessageAge(); - } - - public void setMaximumMessageAge(Long maximumMessageAge) - { - _queue.setMaximumMessageAge(maximumMessageAge); - } - - public void setMaximumMessageSize(Long value) - { - _queue.setMaximumMessageSize(value); - } - - public Integer getConsumerCount() - { - return _queue.getConsumerCount(); - } - - public Integer getActiveConsumerCount() - { - return _queue.getActiveConsumerCount(); - } - - public Long getReceivedMessageCount() - { - return _queue.getReceivedMessageCount(); - } - - public Long getMaximumMessageCount() - { - return _queue.getMaximumMessageCount(); - } - - public void setMaximumMessageCount(Long value) - { - _queue.setMaximumMessageCount(value); - } - - public Long getMaximumQueueDepth() - { - long queueDepthInBytes = _queue.getMaximumQueueDepth(); - - return queueDepthInBytes >> 10; - } - - public void setMaximumQueueDepth(Long value) - { - _queue.setMaximumQueueDepth(value); - } - - /** - * returns the size of messages(KB) in the queue. - */ - public Long getQueueDepth() throws JMException - { - long queueBytesSize = _queue.getQueueDepth(); - - return queueBytesSize >> 10; - } - - /** - * Checks if there is any notification to be send to the listeners - */ - public void checkForNotification(AMQMessage msg) throws AMQException, JMException - { - - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - - for (NotificationCheck check : NotificationCheck.values()) - { - if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) - { - if (check.notifyIfNecessary(msg, _queue, this)) - { - _lastNotificationTimes[check.ordinal()] = currentTime; - } - } - } - - } - - /** - * Sends the notification to the listeners - */ - public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) - { - // important : add log to the log file - monitoring tools may be looking for this - _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); - notificationMsg = notification.name() + " " + notificationMsg; - - _lastNotification = - new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, - System.currentTimeMillis(), notificationMsg); - - _broadcaster.sendNotification(_lastNotification); - } - - public Notification getLastNotification() - { - return _lastNotification; - } - - /** - * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop - */ - public void deleteMessageFromTop() throws JMException - { - try - { - _queue.deleteMessageFromTop(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * @see org.apache.qpid.server.queue.AMQQueue#clearQueue - */ - public void clearQueue() throws JMException - { - try - { - _queue.clearQueue(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * returns message content as byte array and related attributes for the given message id. - */ - public CompositeData viewMessageContent(long msgId) throws JMException - { - AMQMessage msg = _queue.getMessageOnTheQueue(msgId); - if (msg == null) - { - throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); - } - // get message content - Iterator cBodies = msg.getContentBodyIterator(); - List msgContent = new ArrayList(); - while (cBodies.hasNext()) - { - ContentChunk body = cBodies.next(); - if (body.getSize() != 0) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.getData().slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - } - - try - { - // Create header attributes list - CommonContentHeaderProperties headerProperties = - (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) - { - AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); - encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); - } - - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - catch (AMQException e) - { - JMException jme = new JMException("Error creating header attributes list: " + e); - jme.initCause(e); - throw jme; - } - } - - /** - * Returns the header contents of the messages stored in this queue in tabular form. - */ - public TabularData viewMessages(int beginIndex, int endIndex) throws JMException - { - if ((beginIndex > endIndex) || (beginIndex < 1)) - { - throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex - + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); - } - - List list = _queue.getMessagesOnTheQueue(); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - try - { - // Create the tabular list of message header contents - for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) - { - AMQMessage msg = list.get(i - 1); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); - _messageList.put(messageData); - } - } - catch (AMQException e) - { - JMException jme = new JMException("Error creating message contents: " + e); - jme.initCause(e); - throw jme; - } - - return _messageList; - } - - private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) - { - List list = new ArrayList(); - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; - list.add("reply-to = " + headerProperties.getReplyToAsString()); - list.add("propertyFlags = " + headerProperties.getPropertyFlags()); - list.add("ApplicationID = " + headerProperties.getAppIdAsString()); - list.add("ClusterID = " + headerProperties.getClusterIdAsString()); - list.add("UserId = " + headerProperties.getUserIdAsString()); - list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); - list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); - - int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); - - list.add("JMSPriority = " + headerProperties.getPriority()); - list.add("JMSType = " + headerProperties.getType()); - - long longDate = headerProperties.getExpiration(); - String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; - list.add("JMSExpiration = " + strDate); - - longDate = headerProperties.getTimestamp(); - strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; - list.add("JMSTimestamp = " + strDate); - - return list.toArray(new String[list.size()]); - } - - /** - * @see ManagedQueue#moveMessages - * @param fromMessageId - * @param toMessageId - * @param toQueueName - * @throws JMException - */ - public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException - { - if ((fromMessageId > toMessageId) || (fromMessageId < 1)) - { - throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); - } - - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); - } - - /** - * returns Notifications sent by this MBean. - */ - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Either Message count or Queue depth or Message size has reached threshold high value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } - -} // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java deleted file mode 100644 index 290fedcf7b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class AsyncDeliveryConfig -{ - private Executor _executor; - - @Configured(path = "delivery.poolsize", defaultValue = "0") - public int poolSize; - - public Executor getExecutor() - { - if (_executor == null) - { - if (poolSize > 0) - { - _executor = Executors.newFixedThreadPool(poolSize); - } - else - { - _executor = Executors.newCachedThreadPool(); - } - } - return _executor; - } - - public static Executor getAsyncDeliveryExecutor() - { - return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java deleted file mode 100644 index f3b8f0de35..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ /dev/null @@ -1,923 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.Collections; -import java.util.HashSet; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.MessageQueue; -import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; - - -/** Manages delivery of messages on behalf of a queue */ -public class ConcurrentSelectorDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class); - - @Configured(path = "advanced.compressBufferOnQueue", - defaultValue = "false") - public boolean compressBufferOnQueue; - /** Holds any queued messages */ - private final MessageQueue _messages = new ConcurrentLinkedMessageQueueAtomicSize(); - - /** Ensures that only one asynchronous task is running for this manager at any time. */ - private final AtomicBoolean _processing = new AtomicBoolean(); - /** The subscriptions on the queue to whom messages are delivered */ - private final SubscriptionManager _subscriptions; - - /** - * A reference to the queue we are delivering messages for. We need this to be able to pass the code that handles - * acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - /** - * Flag used while moving messages from this queue to another. For moving messages the async delivery should also - * stop. This flat should be set to true to stop async delivery and set to false to enable async delivery again. - */ - private AtomicBoolean _movingMessages = new AtomicBoolean(); - - /** - * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced - * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be - * delivered via the async thread.

      Lock is used to control access to hasQueuedMessages() and over the addition - * of messages to the queue. - */ - private ReentrantLock _lock = new ReentrantLock(); - private AtomicLong _totalMessageSize = new AtomicLong(); - private AtomicInteger _extraMessages = new AtomicInteger(); - private Set _hasContent = Collections.synchronizedSet(new HashSet()); - private final Object _queueHeadLock = new Object(); - private String _processingThreadName = ""; - - - /** Used by any reaping thread to purge messages */ - private StoreContext _reapingStoreContext = new StoreContext(); - - ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - - //Set values from configuration - Configurator.configure(this); - - if (compressBufferOnQueue) - { - _log.warn("Compressing Buffers on queue."); - } - - _subscriptions = subscriptions; - _queue = queue; - } - - - private boolean addMessageToQueue(AMQMessage msg, boolean deliverFirst) - { - // Shrink the ContentBodies to their actual size to save memory. - if (compressBufferOnQueue) - { - Iterator it = msg.getContentBodyIterator(); - while (it.hasNext()) - { - ContentChunk cb = it.next(); - cb.reduceToFit(); - } - } - - if (deliverFirst) - { - synchronized (_queueHeadLock) - { - _messages.pushHead(msg); - } - } - else - { - _messages.offer(msg); - } - - _totalMessageSize.addAndGet(msg.getSize()); - - return true; - } - - - public boolean hasQueuedMessages() - { - _lock.lock(); - try - { - return !(_messages.isEmpty() && _hasContent.isEmpty()); - } - finally - { - _lock.unlock(); - } - } - - public int getQueueMessageCount() - { - return getMessageCount(); - } - - /** - * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine - * size. The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. - * - * @return int the number of messages in the delivery queue. - */ - private int getMessageCount() - { - return _messages.size() + _extraMessages.get(); - } - - - public long getTotalMessageSize() - { - return _totalMessageSize.get(); - } - - public long getOldestMessageArrival() - { - AMQMessage msg = _messages.peek(); - return msg == null ? Long.MAX_VALUE : msg.getArrivalTime(); - } - - public void subscriberHasPendingResend(boolean hasContent, Subscription subscription, AMQMessage msg) - { - _lock.lock(); - try - { - if (hasContent) - { - _log.debug("Queue has adding subscriber content"); - _hasContent.add(subscription); - _totalMessageSize.addAndGet(msg.getSize()); - _extraMessages.addAndGet(1); - } - else - { - _log.debug("Queue has removing subscriber content"); - if (msg == null) - { - _hasContent.remove(subscription); - } - else - { - _totalMessageSize.addAndGet(-msg.getSize()); - _extraMessages.addAndGet(-1); - } - } - } - finally - { - _lock.unlock(); - } - } - - /** - * Returns all the messages in the Queue - * - * @return List of messages - */ - public List getMessages() - { - _lock.lock(); - List list = new ArrayList(); - - for (AMQMessage message : _messages) - { - list.add(message); - } - _lock.unlock(); - - return list; - } - - /** - * Returns messages within the range of given messageIds - * - * @param fromMessageId - * @param toMessageId - * - * @return - */ - public List getMessages(long fromMessageId, long toMessageId) - { - if (fromMessageId <= 0 || toMessageId <= 0) - { - return null; - } - - long maxMessageCount = toMessageId - fromMessageId + 1; - - _lock.lock(); - - List foundMessagesList = new ArrayList(); - - for (AMQMessage message : _messages) - { - long msgId = message.getMessageId(); - if (msgId >= fromMessageId && msgId <= toMessageId) - { - foundMessagesList.add(message); - } - // break if the no of messages are found - if (foundMessagesList.size() == maxMessageCount) - { - break; - } - } - _lock.unlock(); - - return foundMessagesList; - } - - public void populatePreDeliveryQueue(Subscription subscription) - { - if (_log.isTraceEnabled()) - { - _log.trace("Populating PreDeliveryQueue for Subscription(" + System.identityHashCode(subscription) + ")"); - } - - Iterator currentQueue = _messages.iterator(); - - while (currentQueue.hasNext()) - { - AMQMessage message = currentQueue.next(); - if (subscription.hasInterest(message)) - { - subscription.enqueueForPreDelivery(message, false); - } - } - } - - public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException - { - AMQMessage msg = getNextMessage(); - if (msg == null) - { - return false; - } - else - { - - try - { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!acks) - { - if (_log.isDebugEnabled()) - { - _log.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); - } - _queue.dequeue(channel.getStoreContext(), msg); - } - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, null, _queue); - } - - protocolSession.getProtocolOutputConverter().writeGetOk(msg, channel.getChannelId(), - deliveryTag, _queue.getMessageCount()); - _totalMessageSize.addAndGet(-msg.getSize()); - } - } - finally - { - msg.setDeliveredToConsumer(); - } - return true; - - } - } - - /** - * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, so that - * the asyn delivery is also stopped. - */ - public void startMovingMessages() - { - _movingMessages.set(true); - } - - /** - * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, so that - * the async delivery can start again. - */ - public void stopMovingMessages() - { - _movingMessages.set(false); - if (_lock.isHeldByCurrentThread()) - { - _lock.unlock(); - } - } - - /** - * Messages will be removed from this queue and all preDeliveryQueues - * - * @param messageList - */ - public void removeMovedMessages(List messageList) - { - // Remove from the - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - if (hasSubscribers) - { - for (Subscription sub : _subscriptions.getSubscriptions()) - { - if (!sub.isSuspended() && sub.filtersMessages()) - { - Queue preDeliveryQueue = sub.getPreDeliveryQueue(); - for (AMQMessage msg : messageList) - { - preDeliveryQueue.remove(msg); - } - } - } - } - - for (AMQMessage msg : messageList) - { - if (_messages.remove(msg)) - { - _totalMessageSize.getAndAdd(-msg.getSize()); - } - } - } - - /** - * Now with implementation of predelivery queues, this method will mark the message on the top as taken. - * - * @param storeContext - * - * @throws AMQException - */ - public void removeAMessageFromTop(StoreContext storeContext) throws AMQException - { - _lock.lock(); - - AMQMessage message = _messages.poll(); - if (message != null) - { - _totalMessageSize.addAndGet(-message.getSize()); - } - - _lock.unlock(); - } - - public long clearAllMessages(StoreContext storeContext) throws AMQException - { - long count = 0; - _lock.lock(); - - synchronized (_queueHeadLock) - { - AMQMessage msg = getNextMessage(); - while (msg != null) - { - //and remove it - _messages.poll(); - - _queue.dequeue(storeContext, msg); - msg = getNextMessage(); - count++; - } - _totalMessageSize.set(0L); - } - _lock.unlock(); - return count; - } - - /** - * This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. - * - * @return the next message or null - * - * @throws org.apache.qpid.AMQException - */ - private AMQMessage getNextMessage() throws AMQException - { - return getNextMessage(_messages, null); - } - - private AMQMessage getNextMessage(Queue messages, Subscription sub) throws AMQException - { - AMQMessage message = messages.peek(); - - //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) - while (purgeMessage(message, sub)) - { - // if we are purging then ensure we mark this message taken for the current subscriber - // the current subscriber may be null in the case of a get or a purge but this is ok. -// boolean alreadyTaken = message.taken(_queue, sub); - - //remove the already taken message or expired - AMQMessage removed = messages.poll(); - - assert removed == message; - - // if the message expired then the _totalMessageSize needs adjusting - if (message.expired(_queue)) - { - _totalMessageSize.addAndGet(-message.getSize()); - - // Use the reapingStoreContext as any sub(if we have one) may be in a tx. - message.dequeue(_reapingStoreContext, _queue); - - if (_log.isInfoEnabled()) - { - _log.info(debugIdentity() + " Doing clean up of the main _message queue."); - } - } - - //else the clean up is not required as the message has already been taken for this queue therefore - // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. - - if (_log.isTraceEnabled()) - { - _log.trace("Removed taken message:" + message.debugIdentity()); - } - - // try the next message - message = messages.peek(); - } - - return message; - } - - /** - * This method will return true if the message is to be purged from the queue. - * - * - * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) - * @param message - * @param sub - * @return - * @throws AMQException - */ - private boolean purgeMessage(AMQMessage message, Subscription sub) throws AMQException - { - //Original.. complicated while loop control -// (message != null -// && ( -// ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) -// || sub == null) -// && message.taken(_queue, sub)); - - boolean purge = false; - - // if the message is null then don't purge as we have no messagse. - if (message != null) - { - // Check that the message hasn't expired. - if (message.expired(_queue)) - { - return true; - } - - // if we have a subscriber perform message checks - if (sub != null) - { - // if we have a queue browser(we don't purge) so check mark the message as taken - purge = ((!sub.isBrowser() || message.isTaken(_queue))); - } - else - { - // if there is no subscription we are doing - // a get or purging so mark message as taken. - message.isTaken(_queue); - // and then ensure that it gets purged - purge = true; - } - } - - // if we are purging then ensure we mark this message taken for the current subscriber - // the current subscriber may be null in the case of a get or a purge but this is ok. - return purge && message.taken(_queue, sub); - } - - public void sendNextMessage(Subscription sub, AMQQueue queue)//Queue messageQueue) - { - - Queue messageQueue = sub.getNextQueue(_messages); - - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "Async sendNextMessage for sub (" + System.identityHashCode(sub) + - ") from queue (" + System.identityHashCode(messageQueue) + - ") AMQQueue (" + System.identityHashCode(queue) + ")"); - } - - if (messageQueue == null) - { - // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector - if (_log.isInfoEnabled()) - { - _log.info(debugIdentity() + sub + ": asked to send messages but has none on given queue:" + queue); - } - return; - } - - AMQMessage message = null; - AMQMessage removed = null; - try - { - synchronized (_queueHeadLock) - { - message = getNextMessage(messageQueue, sub); - - // message will be null if we have no messages in the messageQueue. - if (message == null) - { - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); - } - return; - } - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Async Delivery Message :" + message + "(" + System.identityHashCode(message) + - ") by :" + System.identityHashCode(this) + - ") to :" + System.identityHashCode(sub)); - } - - sub.send(message, _queue); - - //remove sent message from our queue. - removed = messageQueue.poll(); - //If we don't remove the message from _messages - // Otherwise the Async send will never end - } - - if (removed != message) - { - _log.error("Just send message:" + message.debugIdentity() + " BUT removed this from queue:" + removed); - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message + - ") by :" + System.identityHashCode(this) + - ") to :" + System.identityHashCode(sub)); - } - - - if (messageQueue == sub.getResendQueue()) - { - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "All messages sent from resendQueue for " + sub); - } - if (messageQueue.isEmpty()) - { - subscriberHasPendingResend(false, sub, null); - //better to use the above method as this keeps all the tracking in one location. - // _hasContent.remove(sub); - } - - _extraMessages.decrementAndGet(); - } - else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser()) - { - if (_log.isInfoEnabled()) - { - //fixme - we should do the clean up as the message remains on the _message queue - // this is resulting in the next consumer receiving the message and then attempting to purge it - // - _log.info(debugIdentity() + "We should do clean up of the main _message queue here"); - } - } - - if ((message != null) && (messageQueue == _messages)) - { - _totalMessageSize.addAndGet(-message.getSize()); - } - } - catch (AMQException e) - { - if (message != null) - { - message.release(_queue); - } - else - { - _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); - } - _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); - } - } - - /** - * enqueues the messages in the list on the queue and all required predelivery queues - * - * @param storeContext - * @param movedMessageList - */ - public void enqueueMovedMessages(StoreContext storeContext, List movedMessageList) - { - _lock.lock(); - for (AMQMessage msg : movedMessageList) - { - addMessageToQueue(msg, false); - } - - // enqueue on the pre delivery queues - for (Subscription sub : _subscriptions.getSubscriptions()) - { - for (AMQMessage msg : movedMessageList) - { - // Only give the message to those that want them. - if (sub.hasInterest(msg)) - { - sub.enqueueForPreDelivery(msg, true); - } - } - } - _lock.unlock(); - } - - /** - * Only one thread should ever execute this method concurrently, but it can do so while other threads invoke - * deliver(). - */ - private void processQueue() - { - //record thread name - if (_log.isDebugEnabled()) - { - _processingThreadName = Thread.currentThread().getName(); - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Running process Queue." + currentStatus()); - } - - // Continue to process delivery while we haveSubscribers and messages - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - - while (hasSubscribers && hasQueuedMessages() && !_movingMessages.get()) - { - hasSubscribers = false; - - for (Subscription sub : _subscriptions.getSubscriptions()) - { - synchronized (sub.getSendLock()) - { - if (!sub.isSuspended()) - { - sendNextMessage(sub, _queue); - - hasSubscribers = true; - } - } - } - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Done process Queue." + currentStatus()); - } - - } - - public void deliver(StoreContext context, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws AMQException - { - - final boolean debugEnabled = _log.isDebugEnabled(); - if (debugEnabled) - { - _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + msg); - } - - //Check if we have someone to deliver the message to. - _lock.lock(); - try - { - Subscription s = _subscriptions.nextSubscriber(msg); - - if (s == null || hasQueuedMessages()) //no-one can take the message right now or we're queueing - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Testing Message(" + msg + ") for Queued Delivery:" + currentStatus()); - } - if (!msg.getMessagePublishInfo().isImmediate()) - { - addMessageToQueue(msg, deliverFirst); - - //release lock now message is on queue. - _lock.unlock(); - - //Pre Deliver to all subscriptions - if (debugEnabled) - { - _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() + - " subscribers to give the message to:" + currentStatus()); - } - for (Subscription sub : _subscriptions.getSubscriptions()) - { - - // stop if the message gets delivered whilst PreDelivering if we have a shared queue. - if (_queue.isShared() && msg.getDeliveredToConsumer()) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Stopping PreDelivery as message(" + System.identityHashCode(msg) + - ") is already delivered."); - } - continue; - } - - // Only give the message to those that want them. - if (sub.hasInterest(msg)) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(msg) + - ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); - } - sub.enqueueForPreDelivery(msg, deliverFirst); - } - } - } - } - else - { - - if (_messages.size() > 0) - { - _log.error("Direct delivery with queued msgs:" + _messages.size()); - } - - //release lock now - _lock.unlock(); - synchronized (s.getSendLock()) - { - if (!s.isSuspended()) - { - if (_log.isTraceEnabled()) - { - _log.trace(debugIdentity() + "Delivering Message:" + msg.debugIdentity() + " to(" + - System.identityHashCode(s) + ") :" + s); - } - msg.taken(_queue, s); - //Deliver the message - s.send(msg, _queue); - } - else - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + - "suspended between nextSubscriber and send for message:" + msg.debugIdentity()); - } - } - } - - if (!msg.isTaken(_queue)) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Message(" + msg.debugIdentity() + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); - } - - deliver(context, name, msg, deliverFirst); - } - else - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Message(" + msg.toString() + - ") has been taken so disregarding deliver request to Subscriber:" + - System.identityHashCode(s)); - } - } - } - - } - finally - { - //ensure lock is released - if (_lock.isHeldByCurrentThread()) - { - _lock.unlock(); - } - } - } - - private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")"; - - private String debugIdentity() - { - return id; - } - - Runner asyncDelivery = new Runner(); - - private class Runner implements Runnable - { - public void run() - { - boolean running = true; - while (running && !_movingMessages.get()) - { - processQueue(); - - //Check that messages have not been added since we did our last peek(); - // Synchronize with the thread that adds to the queue. - // If the queue is still empty then we can exit - - if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) - { - running = false; - _processing.set(false); - } - } - } - } - - public void processAsync(Executor executor) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Processing Async." + currentStatus()); - } - - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Executing Async process."); - } - executor.execute(asyncDelivery); - } - } - } - - private String currentStatus() - { - return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains(M:H)") + - "(" + _messages.size() + ":" + ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize() + ") " + - " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") + - "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + (_processing.get() ? " true : Processing Thread: " + _processingThreadName : " false"); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java deleted file mode 100644 index cbe9246f09..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class DefaultQueueRegistry implements QueueRegistry -{ - private ConcurrentMap _queueMap = new ConcurrentHashMap(); - - private final VirtualHost _virtualHost; - - public DefaultQueueRegistry(VirtualHost virtualHost) - { - _virtualHost = virtualHost; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public void registerQueue(AMQQueue queue) throws AMQException - { - _queueMap.put(queue.getName(), queue); - } - - public void unregisterQueue(AMQShortString name) throws AMQException - { - _queueMap.remove(name); - } - - public AMQQueue getQueue(AMQShortString name) - { - return _queueMap.get(name); - } - - public Collection getQueueNames() - { - return _queueMap.keySet(); - } - - public Collection getQueues() - { - return _queueMap.values(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java deleted file mode 100644 index 10ba48552c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; -import java.util.concurrent.Executor; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; - -interface DeliveryManager -{ - /** - * Determines whether there are queued messages. Sets _queueing to false if there are no queued messages. This needs - * to be atomic. - * - * @return true if there are queued messages - */ - boolean hasQueuedMessages(); - - /** - * This method should not be used to determin if there are messages in the queue. - * - * @return int The number of messages in the queue - * - * @use hasQueuedMessages() for all controls relating to having messages on the queue. - */ - int getQueueMessageCount(); - - /** - * Requests that the delivery manager start processing the queue asynchronously if there is work that can be done - * (i.e. there are messages queued up and subscribers that can receive them.

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

      - * - * @param executor the executor on which the delivery should take place - */ - void processAsync(Executor executor); - - /** - * Handles message delivery. The delivery manager is always in one of two modes; it is either queueing messages for - * asynchronous delivery or delivering directly. - * - * @param storeContext - * @param name the name of the entity on whose behalf we are delivering the message - * @param msg the message to deliver - * @param deliverFirst - * - * @throws org.apache.qpid.server.queue.FailedDequeueException - * if the message could not be dequeued - */ - void deliver(StoreContext storeContext, AMQShortString name, AMQMessage msg, boolean deliverFirst) throws FailedDequeueException, AMQException; - - void removeAMessageFromTop(StoreContext storeContext) throws AMQException; - - long clearAllMessages(StoreContext storeContext) throws AMQException; - - void startMovingMessages(); - - void enqueueMovedMessages(StoreContext context, List messageList); - - void stopMovingMessages(); - - void removeMovedMessages(List messageListToRemove); - - List getMessages(); - - List getMessages(long fromMessageId, long toMessageId); - - void populatePreDeliveryQueue(Subscription subscription); - - boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; - - long getTotalMessageSize(); - - long getOldestMessageArrival(); - - void subscriberHasPendingResend(boolean hasContent, Subscription subscription, AMQMessage msg); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java deleted file mode 100644 index a950678487..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; - -/** - * 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 -{ - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); - - static class ExchangeBinding - { - private final Exchange _exchange; - private final AMQShortString _routingKey; - private final FieldTable _arguments; - - ExchangeBinding(AMQShortString routingKey, Exchange exchange) - { - this(routingKey, exchange,EMPTY_ARGUMENTS); - } - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) - { - _routingKey = routingKey; - _exchange = exchange; - _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; - } - - void unbind(AMQQueue queue) throws AMQException - { - _exchange.deregisterQueue(_routingKey, queue, _arguments); - } - - public Exchange getExchange() - { - return _exchange; - } - - public AMQShortString getRoutingKey() - { - return _routingKey; - } - - public int hashCode() - { - return (_exchange == null ? 0 : _exchange.hashCode()) - + (_routingKey == null ? 0 : _routingKey.hashCode()) - + (_arguments == null ? 0 : _arguments.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) - && _arguments.equals(eb._arguments); - } - } - - 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(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); - } - - - public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); - } - - - /** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java deleted file mode 100644 index a5ff9e6326..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingExclusiveSubscriptionException.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * ExistingExclusiveSubscriptionException signals a failure to create a subscription, because an exclusive subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create a subscription, because an exclusive subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - */ -public final class ExistingExclusiveSubscriptionException extends AMQException -{ - public ExistingExclusiveSubscriptionException() - { - super(null, "", null); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java deleted file mode 100644 index a13686eb56..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExistingSubscriptionPreventsExclusiveException.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * ExistingSubscriptionPreventsExclusiveException signals a failure to create an exclusize subscription, as a subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create an exclusize subscription, as a subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - */ -public final class ExistingSubscriptionPreventsExclusiveException extends AMQException -{ - public ExistingSubscriptionPreventsExclusiveException() - { - super(null, "", null); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java deleted file mode 100644 index d5c34152a8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * Signals that the dequeue of a message from a queue failed. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Indicates the a message could not be dequeued from a queue. - *
      - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Happens as a consequence of a message store failure, or reference counting error. Both of which migh become - * runtime exceptions, as unrecoverable conditions? In which case this one might be dropped too. - */ -public class FailedDequeueException extends AMQException -{ - public FailedDequeueException(String queue, Throwable cause) - { - super(null, "Failed to dequeue message from " + queue, cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java deleted file mode 100644 index c81360e7d4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.nio.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.StoreContext; - -/** - */ -public class InMemoryMessageHandle implements AMQMessageHandle -{ - - private ContentHeaderBody _contentHeaderBody; - - private MessagePublishInfo _messagePublishInfo; - - private List _contentBodies = new LinkedList(); - - private boolean _redelivered; - - private long _arrivalTime; - - // the message payload - private byte[] _payload; - // a buffer to write the payload - ByteBuffer _buffer; - - public InMemoryMessageHandle() - { - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException - { - return _contentHeaderBody; - } - - public int getBodyCount(StoreContext context, Long messageId) - { - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context, Long messageId) throws AMQException - { - return getContentHeaderBody(context, messageId).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, 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(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) - throws AMQException - { - _contentBodies.add(contentBody); - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException - { - return _messagePublishInfo; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent(StoreContext context, Long messageId) throws AMQException - { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(context, messageId); - return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; - } - - /** - * This is called when all the content has been received. - * @param messagePublishInfo - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _messagePublishInfo = messagePublishInfo; - _contentHeaderBody = contentHeaderBody; - _arrivalTime = System.currentTimeMillis(); - } - - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - // NO OP - } - - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - // NO OP - } - - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - // NO OP - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - - // added by Arnaud - public byte[] getMessagePayload() - { - if (_payload == null) - { - int bodySize = (int) _contentHeaderBody.bodySize; - _buffer = ByteBuffer.allocate(bodySize); - _payload = new byte[bodySize]; - for (ContentChunk contentBody : _contentBodies) - { - int chunkSize = contentBody.getSize(); - byte[] chunk = new byte[chunkSize]; - contentBody.getData().get(chunk); - _buffer.put(chunk); - } - _buffer.get(_payload); - } - return _payload; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java deleted file mode 100644 index 061ab56024..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of a queue. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedQueue -{ - static final String TYPE = "Queue"; - - /** - * Returns the Name of the ManagedQueue. - * @return the name of the managedQueue. - * @throws IOException - */ - @MBeanAttribute(name="Name", description = TYPE + " Name") - String getName() throws IOException; - - /** - * Total number of messages on the queue, which are yet to be delivered to the consumer(s). - * @return number of undelivered message in the Queue. - * @throws IOException - */ - @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") - Integer getMessageCount() throws IOException; - - /** - * Tells the total number of messages receieved by the queue since startup. - * @return total number of messages received. - * @throws IOException - */ - @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") - Long getReceivedMessageCount() throws IOException; - - /** - * Size of messages in the queue - * @return - * @throws IOException - */ - @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue") - Long getQueueDepth() throws IOException, JMException; - - /** - * Returns the total number of active subscribers to the queue. - * @return the number of active subscribers - * @throws IOException - */ - @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") - Integer getActiveConsumerCount() throws IOException; - - /** - * Returns the total number of subscribers to the queue. - * @return the number of subscribers. - * @throws IOException - */ - @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") - Integer getConsumerCount() throws IOException; - - /** - * Tells the Owner of the ManagedQueue. - * @return the owner's name. - * @throws IOException - */ - @MBeanAttribute(name="Owner", description = "Owner") - String getOwner() throws IOException; - - /** - * Tells whether this ManagedQueue is durable or not. - * @return true if this ManagedQueue is a durable queue. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the ManagedQueue is set to AutoDelete. - * @return true if the ManagedQueue is set to AutoDelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") - boolean isAutoDelete() throws IOException; - - /** - * Returns the maximum age of a message (expiration time) - * @return the maximum age - * @throws IOException - */ - Long getMaximumMessageAge() throws IOException; - - /** - * Sets the maximum age of a message - * @param age maximum age of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on thr broker") - void setMaximumMessageAge(Long age) throws IOException; - - /** - * Returns the maximum size of a message (in kbytes) allowed to be accepted by the - * ManagedQueue. This is useful in setting notifications or taking - * appropriate action, if the size of the message received is more than - * the allowed size. - * @return the maximum size of a message allowed to be aceepted by the - * ManagedQueue. - * @throws IOException - */ - Long getMaximumMessageSize() throws IOException; - - /** - * Sets the maximum size of the message (in kbytes) that is allowed to be - * accepted by the Queue. - * @param size maximum size of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(KB) for a message size") - void setMaximumMessageSize(Long size) throws IOException; - - /** - * Tells the maximum number of messages that can be stored in the queue. - * This is useful in setting the notifications or taking required - * action is the number of message increase this limit. - * @return maximum muber of message allowed to be stored in the queue. - * @throws IOException - */ - Long getMaximumMessageCount() throws IOException; - - /** - * Sets the maximum number of messages allowed to be stored in the queue. - * @param value the maximum number of messages allowed to be stored in the queue. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") - void setMaximumMessageCount(Long value) throws IOException; - - /** - * This is useful for setting notifications or taking required action if the size of messages - * stored in the queue increases over this limit. - * @return threshold high value for Queue Depth - * @throws IOException - */ - Long getMaximumQueueDepth() throws IOException; - - /** - * Sets the maximum size of all the messages together, that can be stored - * in the queue. - * @param value - * @throws IOException - */ - @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth") - void setMaximumQueueDepth(Long value) throws IOException; - - - - //********** Operations *****************// - - - /** - * Returns a subset of all the messages stored in the queue. The messages - * are returned based on the given index numbers. - * @param fromIndex - * @param toIndex - * @return - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="viewMessages", - description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") - TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, - @MBeanOperationParameter(name="to index", description="to index")int toIndex) - throws IOException, JMException, AMQException; - - @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") - CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) - throws IOException, JMException; - - /** - * Deletes the first message from top. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", - impact= MBeanOperationInfo.ACTION) - void deleteMessageFromTop() throws IOException, JMException; - - /** - * Clears the queue by deleting all the undelivered messages from the queue. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="clearQueue", - description="Clears the queue by deleting all the undelivered messages from the queue", - impact= MBeanOperationInfo.ACTION) - void clearQueue() throws IOException, JMException; - - /** - * Moves the messages in given range of message Ids to given Queue. QPID-170 - * @param fromMessageId first in the range of message ids - * @param toMessageId last in the range of message ids - * @param toQueue where the messages are to be moved - * @throws IOException - * @throws JMException - * @throws AMQException - */ - @MBeanOperation(name="moveMessages", - description="You can move messages to another queue from this queue ", - impact= MBeanOperationInfo.ACTION) - void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, - @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, - @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) - throws IOException, JMException, AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java deleted file mode 100644 index 2fdd2791b1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * MessageCleanupException represents the failure to perform reference counting on messages correctly. This should not - * happen, but there may be programming errors giving race conditions that cause the reference counting to go wrong. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Signals that the reference count of a message has gone below zero. - *
      Indicates that a message store has lost a message which is still referenced. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo The race conditions leading to this error should be cleaned up, and a runtime exception used instead. If the - * message store loses messages, then something is seriously wrong and it would be sensible to terminate the - * broker. This may be disguising out of memory errors. - */ -public class MessageCleanupException extends AMQException -{ - public MessageCleanupException(String message, Throwable cause) - { - super(null, message, cause); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java deleted file mode 100644 index 35e43aa412..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.messageStore.StorableMessage; - -/** - * Constructs a message handle based on the publish body, the content header and the queue to which the message - * has been routed. - * - */ -public class MessageHandleFactory -{ - - public AMQMessageHandle createMessageHandle(MessageStore store, StorableMessage m, boolean persistent) - { - // just hardcoded for now - if (persistent) - { - return new WeakReferenceMessageHandle(store); - //DTX MessageStore -// return new StorableMessageHandle(store, m); - } - else - { - return new InMemoryMessageHandle(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java deleted file mode 100644 index 6118a4c11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * Encapsulates a publish body and a content header. In the context of the message store these are treated as a - * single unit. - */ -public class MessageMetaData -{ - private MessagePublishInfo _messagePublishInfo; - - private ContentHeaderBody _contentHeaderBody; - - private int _contentChunkCount; - - private long _arrivalTime; - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) - { - this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); - } - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) - { - _contentHeaderBody = contentHeaderBody; - _messagePublishInfo = publishBody; - _contentChunkCount = contentChunkCount; - _arrivalTime = arrivalTime; - } - - public int getContentChunkCount() - { - return _contentChunkCount; - } - - public void setContentChunkCount(int contentChunkCount) - { - _contentChunkCount = contentChunkCount; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public void setArrivalTime(long arrivalTime) - { - _arrivalTime = arrivalTime; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java deleted file mode 100644 index afcdf062de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate - * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is - * always used to report this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoConsumersException extends RequiredDeliveryException -{ - public NoConsumersException(AMQMessage message, Throwable cause) - { - super("Immediate delivery is not possible.", message, cause); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_CONSUMERS; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java deleted file mode 100644 index 6b3d65661f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -public enum NotificationCheck -{ - - MESSAGE_COUNT_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - int msgCount = queue.getMessageCount(); - final long maximumMessageCount = queue.getMaximumMessageCount(); - if (maximumMessageCount!= 0 && msgCount >= maximumMessageCount) - { - listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); - return true; - } - return false; - } - }, - MESSAGE_SIZE_ALERT(true) - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - final long maximumMessageSize = queue.getMaximumMessageSize(); - if(maximumMessageSize != 0) - { - // Check for threshold message size - long messageSize; - try - { - messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - messageSize = 0; - } - - - if (messageSize >= maximumMessageSize) - { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); - return true; - } - } - return false; - } - - }, - QUEUE_DEPTH_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - // Check for threshold queue depth in bytes - final long maximumQueueDepth = queue.getMaximumQueueDepth(); - - if(maximumQueueDepth != 0) - { - final long queueDepth = queue.getQueueDepth(); - - if (queueDepth >= maximumQueueDepth) - { - listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); - return true; - } - } - return false; - } - - }, - MESSAGE_AGE_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - - final long maxMessageAge = queue.getMaximumMessageAge(); - if(maxMessageAge != 0) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - maxMessageAge; - final long firstArrivalTime = queue.getOldestMessageArrivalTime(); - - if(firstArrivalTime < thresholdTime) - { - long oldestAge = currentTime - firstArrivalTime; - listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); - - return true; - } - } - return false; - - } - - } - ; - - private final boolean _messageSpecific; - - NotificationCheck() - { - this(false); - } - - NotificationCheck(boolean messageSpecific) - { - _messageSpecific = messageSpecific; - } - - public boolean isMessageSpecific() - { - return _messageSpecific; - } - - abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java deleted file mode 100644 index d2680ffcc8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public interface QueueNotificationListener -{ - void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java deleted file mode 100644 index 1210f0e97c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Collection; - -public interface QueueRegistry -{ - VirtualHost getVirtualHost(); - - void registerQueue(AMQQueue queue) throws AMQException; - - void unregisterQueue(AMQShortString name) throws AMQException; - - AMQQueue getQueue(AMQShortString name); - - Collection getQueueNames(); - - Collection getQueues(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java deleted file mode 100644 index 8c20050027..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/StorableMessageHandle.java +++ /dev/null @@ -1,304 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.store.StoreContext; - -import javax.transaction.xa.Xid; -import java.nio.ByteBuffer; -import java.util.LinkedList; -import java.util.List; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 14:26:34 - */ -public class StorableMessageHandle implements AMQMessageHandle -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(StorableMessageHandle.class); - - //======================================================================== - // Instance Fields - //======================================================================== - // the message store - final private MessageStore _messageStore; - // A reference on the message itself - final private StorableMessage _message; - // the message payload - private byte[] _payload; - // a buffer to write the payload - ByteBuffer _buffer; - // the ContentHeaderBody - private ContentHeaderBody _contentHeaderBody; - // the arrival time - private long _arrivalTime; - // Specify if this messag is redelivered - private boolean _redelivered; - // MessagePublishInfo - private MessagePublishInfo _messagePublishInfo; - // list of chunks - private List _chunks; - - //======================================================================== - // Constructors - //======================================================================== - - public StorableMessageHandle(MessageStore messageStore, StorableMessage message) - { - _messageStore = messageStore; - _message = message; - } - - //======================================================================== - // Interface AMQMessageHandle - //======================================================================== - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) - throws - AMQException - { - if (_contentHeaderBody == null) - { - // load it from the store - try - { - _contentHeaderBody = _messageStore.getContentHeaderBody(_message); - } - catch (Exception e) - { - throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); - } - } - return _contentHeaderBody; - } - - public int getBodyCount(StoreContext context, Long messageId) - throws - AMQException - { - if (_chunks == null) - { - if (_message.isStaged()) - { - loadChunks(); - } - else - { - return 0; - } - } - return _chunks.size(); - } - - public long getBodySize(StoreContext context, Long messageId) - throws - AMQException - { - return _payload.length; - } - - public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) - throws - IllegalArgumentException, - AMQException - { - if (_chunks == null) - { - loadChunks(); - } - return _chunks.get(index); - } - - private void loadChunks() - throws - AMQException - { - try - { - _chunks = new LinkedList(); - byte[] underlying = _messageStore.loadContent(_message, 1, 0); - final int size = underlying.length; - final org.apache.mina.common.ByteBuffer data = - org.apache.mina.common.ByteBuffer.wrap(underlying); - ContentChunk cb = new ContentChunk() - { - - public int getSize() - { - return size; - } - - public org.apache.mina.common.ByteBuffer getData() - { - return data; - } - - public void reduceToFit() - { - - } - }; - _chunks.add(cb); - } - catch (Exception e) - { - throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); - } - } - - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) - throws - AMQException - { - if (_chunks == null) - { - _chunks = new LinkedList(); - } - _chunks.add(contentBody); - // if rquired this message can be added to the store - //_messageStore.appendContent(_message, _payload, 0, 10); - - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) - throws - AMQException - { - if (_messagePublishInfo == null) - { - // read it from the store - try - { - - _messagePublishInfo = _messageStore.getMessagePublishInfo(_message); - } - catch (Exception e) - { - throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e); - } - } - return _messagePublishInfo; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent(StoreContext context, Long messageId) - throws - AMQException - { - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; - } - - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, - MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws - AMQException - { - _contentHeaderBody = contentHeaderBody; - _arrivalTime = System.currentTimeMillis(); - _messagePublishInfo = messagePublishInfo; - } - - public void removeMessage(StoreContext storeContext, Long messageId) - throws - AMQException - { - // This is already handled by the store but we can possibly do: - // _messageStore.destroy(_message); - } - - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) - throws - AMQException - { - try - { - if (queue.isDurable()) - { - _messageStore.enqueue((Xid) storeContext.getPayload(), _message, queue); - } - } - catch (Exception e) - { - throw new AMQException(null, "PRoblem during message enqueue", e); - } - } - - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) - throws - AMQException - { - try - { - if (queue.isDurable()) - { - _messageStore.dequeue((Xid) storeContext.getPayload(), _message, queue); - } - } - catch (Exception e) - { - throw new AMQException(null, "PRoblem during message dequeue", e); - } - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public byte[] getMessagePayload() - { - if (_payload == null) - { - int bodySize = (int) _contentHeaderBody.bodySize; - _payload = new byte[bodySize]; - _buffer = ByteBuffer.wrap(_payload); - for (ContentChunk contentBody : _chunks) - { - int chunkSize = contentBody.getSize(); - byte[] chunk = new byte[chunkSize]; - contentBody.getData().get(chunk); - _buffer.put(chunk); - } - } - return _payload; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java deleted file mode 100644 index 77688f19be..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.Queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; - -public interface Subscription -{ - void send(AMQMessage msg, AMQQueue queue) throws AMQException; - - boolean isSuspended(); - - void queueDeleted(AMQQueue queue) throws AMQException; - - boolean filtersMessages(); - - boolean hasInterest(AMQMessage msg); - - Queue getPreDeliveryQueue(); - - Queue getResendQueue(); - - Queue getNextQueue(Queue messages); - - void enqueueForPreDelivery(AMQMessage msg, boolean deliverFirst); - - boolean isAutoClose(); - - void close(); - - boolean isClosed(); - - boolean isBrowser(); - - boolean wouldSuspend(AMQMessage msg); - - void addToResendQueue(AMQMessage msg); - - Object getSendLock(); - - AMQChannel getChannel(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java deleted file mode 100644 index 917f7c4e97..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -/** - * 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, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, AMQQueue queue) throws AMQException; - - - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) - throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java deleted file mode 100644 index 1cebf08fa6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.Queue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.filter.FilterManager; -import org.apache.qpid.server.filter.FilterManagerFactory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import org.apache.qpid.util.MessageQueue; -import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; - -/** - * 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 _suspensionlogger = Logger.getLogger("Suspension"); - private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); - - public final AMQChannel channel; - - public final AMQProtocolSession protocolSession; - - public final AMQShortString consumerTag; - - private final Object _sessionKey; - - private MessageQueue _messages; - - private Queue _resendQueue; - - private final boolean _noLocal; - - /** True if messages need to be acknowledged */ - private final boolean _acks; - private FilterManager _filters; - private final boolean _isBrowser; - private final Boolean _autoClose; - private boolean _sentClose = false; - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - private AMQQueue _queue; - private final AtomicBoolean _sendLock = new AtomicBoolean(false); - - - public static class Factory implements SubscriptionFactory - { - public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, - boolean noLocal, AMQQueue queue) throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal, queue); - } - - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) - throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false, null); - } - } - - public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks) - throws AMQException - { - this(channelId, protocolSession, consumerTag, acks, null, false, null); - } - - public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, - boolean noLocal, AMQQueue queue) - throws AMQException - { - AMQChannel channel = protocolSession.getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session", null); - } - - this.channel = channel; - this.protocolSession = protocolSession; - this.consumerTag = consumerTag; - _sessionKey = protocolSession.getKey(); - _acks = acks; - _noLocal = noLocal; - _queue = queue; - - _filters = FilterManagerFactory.createManager(filters); - - - if (_filters != null) - { - Object isBrowser = filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); - if (isBrowser != null) - { - _isBrowser = (Boolean) isBrowser; - } - else - { - _isBrowser = false; - } - } - else - { - _isBrowser = false; - } - - - if (_filters != null) - { - Object autoClose = filters.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); - if (autoClose != null) - { - _autoClose = (Boolean) autoClose; - } - else - { - _autoClose = false; - } - } - else - { - _autoClose = false; - } - - - if (filtersMessages()) - { - _messages = new ConcurrentLinkedMessageQueueAtomicSize(); - } - else - { - // Reference the DeliveryManager - _messages = null; - } - } - - - public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, - AMQShortString 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. - * - * @param psc The subscriptionImpl to compare - * - * @return equality - */ - 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() - { - String subscriber = "[channel=" + channel + - ", consumerTag=" + consumerTag + - ", session=" + protocolSession.getKey() + - ", resendQueue=" + (_resendQueue != null); - - if (_resendQueue != null) - { - subscriber += ", resendSize=" + _resendQueue.size(); - } - - - return subscriber + "]"; - } - - /** - * 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 The message to send - * @param queue the Queue it has been sent from - * - * @throws AMQException - */ - public void send(AMQMessage msg, AMQQueue queue) throws AMQException - { - if (msg != null) - { - if (_isBrowser) - { - sendToBrowser(msg, queue); - } - else - { - sendToConsumer(channel.getStoreContext(), msg, queue); - } - } - else - { - _logger.error("Attempt to send Null message", new NullPointerException()); - } - } - - private void sendToBrowser(AMQMessage msg, AMQQueue queue) throws AMQException - { - // We don't decrement the reference here as we don't want to consume the message - // but we do want to send it to the client. - - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - // We don't need to add the message to the unacknowledgedMap as we don't need to know if the client - // received the message. If it is lost in transit that is not important. -// if (_acks) -// { -// channel.addUnacknowledgedBrowsedMessage(msg, deliveryTag, consumerTag, queue); -// } - - if (_sendLock.get()) - { - _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); - } - - protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); - } - } - - private void sendToConsumer(StoreContext storeContext, AMQMessage msg, AMQQueue queue) - throws AMQException - { - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!_acks) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("No ack mode so dequeuing message immediately: " + msg.getMessageId()); - } - queue.dequeue(storeContext, msg); - } - - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (_sendLock.get()) - { - _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); - } - - if (_acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - } - - protocolSession.getProtocolOutputConverter().writeDeliver(msg, channel.getChannelId(), deliveryTag, consumerTag); - - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - msg.setDeliveredToConsumer(); - } - } - - public boolean isSuspended() - { -// if (_suspensionlogger.isInfoEnabled()) -// { -// if (channel.isSuspended()) -// { -// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") channel's is susupended"); -// } -// if (_sendLock.get()) -// { -// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") has sendLock set so closing."); -// } -// } - return channel.isSuspended() || _sendLock.get(); - } - - /** - * Callback indicating that a queue has been deleted. - * - * @param queue The queue to delete - */ - public void queueDeleted(AMQQueue queue) throws AMQException - { - channel.queueDeleted(queue); - } - - public boolean filtersMessages() - { - return _filters != null || _noLocal; - } - - public boolean hasInterest(AMQMessage msg) - { - //check that the message hasn't been rejected - if (msg.isRejectedBy(this)) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + msg.debugIdentity()); - } -// return false; - } - - final AMQProtocolSession publisher = msg.getPublisher(); - - //todo - client id should be recoreded and this test removed but handled below - if (_noLocal && publisher != null) - { - // We don't want local messages so check to see if message is one we sent - Object localInstance; - Object msgInstance; - - if ((protocolSession.getClientProperties() != null) && - (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) - { - - if ((publisher.getClientProperties() != null) && - (msgInstance = publisher.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) - { - if (localInstance == msgInstance || localInstance.equals(msgInstance)) - { -// if (_logger.isTraceEnabled()) -// { -// _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + -// msg.debugIdentity() + ")"); -// } - return false; - } - } - } - else - { - - localInstance = protocolSession.getClientIdentifier(); - //todo - client id should be recoreded and this test removed but handled here - - msgInstance = publisher.getClientIdentifier(); - if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) - { -// if (_logger.isTraceEnabled()) -// { -// _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + -// msg.debugIdentity() + ")"); -// } - return false; - } - } - - - } - - - if (_logger.isTraceEnabled()) - { - _logger.trace("(" + debugIdentity() + ") checking filters for message (" + msg.debugIdentity()); - } - return checkFilters(msg); - - } - - private String id = String.valueOf(System.identityHashCode(this)); - - private String debugIdentity() - { - return id; - } - - private boolean checkFilters(AMQMessage msg) - { - if (_filters != null) - { -// if (_logger.isTraceEnabled()) -// { -// _logger.trace("(" + debugIdentity() + ") has filters."); -// } - return _filters.allAllow(msg); - } - else - { -// if (_logger.isTraceEnabled()) -// { -// _logger.trace("(" + debugIdentity() + ") has no filters"); -// } - - return true; - } - } - - public Queue getPreDeliveryQueue() - { - return _messages; - } - - public void enqueueForPreDelivery(AMQMessage msg, boolean deliverFirst) - { - if (_messages != null) - { - if (deliverFirst) - { - _messages.pushHead(msg); - } - else - { - _messages.offer(msg); - } - } - } - - public boolean isAutoClose() - { - return _autoClose; - } - - public void close() - { - boolean closed = false; - synchronized (_sendLock) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Setting SendLock true:" + debugIdentity()); - } - - closed = _sendLock.getAndSet(true); - } - - if (closed) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Called close() on a closed subscription"); - } - - return; - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing subscription (" + debugIdentity() + "):" + this); - } - - if (_resendQueue != null && !_resendQueue.isEmpty()) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Requeuing closing subscription (" + debugIdentity() + "):" + this); - } - requeue(); - } - - //remove references in PDQ - if (_messages != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Clearing PDQ (" + debugIdentity() + "):" + this); - } - - _messages.clear(); - } - } - - private void autoclose() - { - close(); - - if (_autoClose && !_sentClose) - { - _logger.info("Closing autoclose subscription (" + debugIdentity() + "):" + this); - - ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag); - _sentClose = true; - - //fixme JIRA do this better - try - { - channel.unsubscribeConsumer(protocolSession, consumerTag); - } - catch (AMQException e) - { - // Occurs if we cannot find the subscriber in the channel with protocolSession and consumerTag. - } - } - } - - private void requeue() - { - if (_queue != null) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Requeuing :" + _resendQueue.size() + " messages"); - } - - while (!_resendQueue.isEmpty()) - { - AMQMessage resent = _resendQueue.poll(); - - if (_logger.isTraceEnabled()) - { - _logger.trace("Removed for resending:" + resent.debugIdentity()); - } - - resent.release(_queue); - _queue.subscriberHasPendingResend(false, this, resent); - - try - { - channel.getTransactionalContext().deliver(resent, _queue, true); - } - catch (AMQException e) - { - _logger.error("MESSAGE LOSS : Unable to re-deliver messages", e); - } - } - - if (!_resendQueue.isEmpty()) - { - _logger.error("[MESSAGES LOST]Unable to re-deliver messages as queue is null."); - } - - _queue.subscriberHasPendingResend(false, this, null); - } - else - { - if (!_resendQueue.isEmpty()) - { - _logger.error("Unable to re-deliver messages as queue is null."); - } - } - - // Clear the messages - _resendQueue = null; - } - - - public boolean isClosed() - { - return _sendLock.get(); // This rather than _close is used to signify the subscriber is now closed. - } - - public boolean isBrowser() - { - return _isBrowser; - } - - public boolean wouldSuspend(AMQMessage msg) - { - return channel.wouldSuspend(msg); - } - - public Queue getResendQueue() - { - if (_resendQueue == null) - { - _resendQueue = new ConcurrentLinkedQueueAtomicSize(); - } - return _resendQueue; - } - - - public Queue getNextQueue(Queue messages) - { - if (_resendQueue != null && !_resendQueue.isEmpty()) - { - return _resendQueue; - } - - if (filtersMessages()) - { - if (isAutoClose()) - { - if (_messages.isEmpty()) - { - autoclose(); - return null; - } - } - return _messages; - } - else // we want the DM queue - { - return messages; - } - } - - public void addToResendQueue(AMQMessage msg) - { - // add to our resend queue - getResendQueue().add(msg); - - // Mark Queue has having content. - if (_queue == null) - { - _logger.error("Queue is null won't be able to resend messages"); - } - else - { - _queue.subscriberHasPendingResend(true, this, msg); - } - } - - public Object getSendLock() - { - return _sendLock; - } - - public AMQChannel getChannel() - { - return channel; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java deleted file mode 100644 index 4df88baebc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; - -/** - * Abstraction of actor that will determine the subscriber to whom - * a message will be sent. - */ -public interface SubscriptionManager -{ - public List getSubscriptions(); - public boolean hasActiveSubscribers(); - public Subscription nextSubscriber(AMQMessage msg); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java deleted file mode 100644 index b500247fa4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; -import java.util.ListIterator; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; - -/** 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; - private final Object _subscriptionsChange = new Object(); - - - /** Accessor for unit tests. */ - int getCurrentSubscriber() - { - return _currentSubscriber; - } - - public void addSubscriber(Subscription subscription) - { - synchronized (_subscriptionsChange) - { - _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) - { - // TODO: possibly need O(1) operation here. - - Subscription sub = null; - synchronized (_subscriptionsChange) - { - int subIndex = _subscriptions.indexOf(subscription); - - if (subIndex != -1) - { - //we can't just return the passed in subscription as it is a new object - // and doesn't contain the stored state we need. - //NOTE while this may be removed now anyone with an iterator will still have it in the list!! - sub = _subscriptions.remove(subIndex); - } - else - { - _log.error("Unable to remove from index(" + subIndex + ")subscription:" + subscription); - } - } - if (sub != null) - { - return sub; - } - 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 = nextSubscriberImpl(msg); - if (result == null) - { - _currentSubscriber = 0; - return nextSubscriberImpl(msg); - } - else - { - return result; - } - } - catch (IndexOutOfBoundsException e) - { - _currentSubscriber = 0; - return nextSubscriber(msg); - } - } - - private Subscription nextSubscriberImpl(AMQMessage msg) - { - final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); - while (iterator.hasNext()) - { - Subscription subscription = iterator.next(); - ++_currentSubscriber; - subscriberScanned(); - - if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) - { - if (subscription.hasInterest(msg)) - { - // if the queue is not empty then this client is ready to receive a message. - //FIXME the queue could be full of sent messages. - // Either need to clean all PDQs after sending a message - // OR have a clean up thread that runs the PDQs expunging the messages. - if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) - { - return subscription; - } - } - } - } - - return null; - } - - /** Overridden in test classes. */ - protected void subscriberScanned() - { - } - - public boolean isEmpty() - { - return _subscriptions.isEmpty(); - } - - public List getSubscriptions() - { - return _subscriptions; - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java deleted file mode 100644 index 79ee6b93a3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * Contains data that is only used in AMQMessage transiently, e.g. while the content - * body fragments are arriving. - * - * Having this data stored in a separate class means that the AMQMessage class avoids - * the small overhead of numerous guaranteed-null references. - * - * @author Apache Software Foundation - */ -public class TransientMessageData -{ - /** - * Stored temporarily until the header has been received at which point it is used when - * constructing the handle - */ - private MessagePublishInfo _messagePublishInfo; - - /** - * Also stored temporarily. - */ - private ContentHeaderBody _contentHeaderBody; - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done - * by the message handle. - */ - private List _destinationQueues = new LinkedList(); - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public List getDestinationQueues() - { - return _destinationQueues; - } - - public void setDestinationQueues(List destinationQueues) - { - _destinationQueues = destinationQueues; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public long getBodyLengthReceived() - { - return _bodyLengthReceived; - } - - public void addBodyLength(int value) - { - _bodyLengthReceived += value; - } - - public boolean isAllContentReceived() throws AMQException - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public void addDestinationQueue(AMQQueue queue) - { - _destinationQueues.add(queue); - } - - public boolean isPersistent() - { - //todo remove literal values to a constant file such as AMQConstants in common - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java deleted file mode 100644 index 88eb891a20..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - */ -public class WeakReferenceMessageHandle implements AMQMessageHandle -{ - private WeakReference _contentHeaderBody; - - private WeakReference _messagePublishInfo; - - private List> _contentBodies; - - private boolean _redelivered; - - private final MessageStore _messageStore; - - private long _arrivalTime; - - - public WeakReferenceMessageHandle(MessageStore messageStore) - { - _messageStore = messageStore; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException - { - ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); - if (chb == null) - { - MessageMetaData mmd = loadMessageMetaData(context, messageId); - chb = mmd.getContentHeaderBody(); - } - return chb; - } - - private MessageMetaData loadMessageMetaData(StoreContext context, Long messageId) - throws AMQException - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); - populateFromMessageMetaData(mmd); - return mmd; - } - - private void populateFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); - _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); - } - - public int getBodyCount(StoreContext context, Long messageId) throws AMQException - { - if (_contentBodies == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); - int chunkCount = mmd.getContentChunkCount(); - _contentBodies = new ArrayList>(chunkCount); - for (int i = 0; i < chunkCount; i++) - { - _contentBodies.add(new WeakReference(null)); - } - } - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context, Long messageId) throws AMQException - { - return getContentHeaderBody(context, messageId).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, 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); - ContentChunk cb = wr.get(); - if (cb == null) - { - cb = _messageStore.getContentBodyChunk(context, messageId, index); - _contentBodies.set(index, new WeakReference(cb)); - } - return cb; - } - - /** - * Content bodies are set before the publish and header frames - * - * @param storeContext - * @param messageId - * @param contentChunk - * @param isLastContentBody - * @throws AMQException - */ - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - if (_contentBodies == null && isLastContentBody) - { - _contentBodies = new ArrayList>(1); - } - else - { - if (_contentBodies == null) - { - _contentBodies = new LinkedList>(); - } - } - _contentBodies.add(new WeakReference(contentChunk)); - _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, - contentChunk, isLastContentBody); - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException - { - MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); - if (bpb == null) - { - MessageMetaData mmd = loadMessageMetaData(context, messageId); - - bpb = mmd.getMessagePublishInfo(); - } - return bpb; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent(StoreContext context, Long messageId) throws AMQException - { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(context, 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(StoreContext storeContext, Long messageId, MessagePublishInfo publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - // if there are no content bodies the list will be null so we must - // create en empty list here - if (contentHeaderBody.bodySize == 0) - { - _contentBodies = new LinkedList>(); - } - - final long arrivalTime = System.currentTimeMillis(); - - - MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); - - _messageStore.storeMessageMetaData(storeContext, messageId, mmd); - - populateFromMessageMetaData(mmd); - } - - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - _messageStore.removeMessage(storeContext, messageId); - } - - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); - } - - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - - // added by Arnaud - public byte[] getMessagePayload() - { - return new byte[0]; //To change body of implemented methods use File | Settings | File Templates. - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java deleted file mode 100644 index 6c71571807..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public interface WeightedSubscriptionManager extends SubscriptionManager -{ - public int getWeight(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java deleted file mode 100644 index a70505ff6c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/** - * 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 (_instanceMap) - { - Iterator keyIterator = _instanceMap.values().iterator(); - - while (keyIterator.hasNext()) - { - IApplicationRegistry instance = keyIterator.next(); - - instance.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 - { - synchronized (_instanceMap) - { - 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) - { - synchronized (_instanceMap) - { - try - { - _instanceMap.get(instanceID).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) - { - synchronized (_instanceMap) - { - IApplicationRegistry instance = _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", e); - } - } - else - { - return instance; - } - } - } - - public void close() throws Exception - { - for(VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) - { - virtualHost.close(); - } - - // close the rmi registry(if any) started for management - if (getInstance().getManagedObjectRegistry() != null) - { - getInstance().getManagedObjectRegistry().close(); - } - } - - 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", e); - } - Configurator.configure(instance); - _configuredObjects.put(instanceType, instance); - } - return instance; - } - - - - public static void setDefaultApplicationRegistry(String clazz) - { - _APPLICATION_REGISTRY = clazz; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java deleted file mode 100644 index 1cca259a8d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.io.File; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.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.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.AMQException; - -public class ConfigurationFileApplicationRegistry extends ApplicationRegistry -{ - - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - private PrincipalDatabaseManager _databaseManager; - - private VirtualHostRegistry _virtualHostRegistry; - - - private final Map _virtualHosts = new ConcurrentHashMap(); - - - 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(); - - _virtualHostRegistry = new VirtualHostRegistry(); - - _accessManager = new AccessManagerImpl("default", _configuration); - - _databaseManager = new ConfigurationFilePrincipalDatabaseManager(); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _databaseManager.initialiseManagement(_configuration); - - _managedObjectRegistry.start(); - - initialiseVirtualHosts(); - - } - - private void initialiseVirtualHosts() throws Exception - { - for (String name : getVirtualHostNames()) - { - - _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name))); - } - } - - private void initialiseManagedObjectRegistry() throws AMQException - { - ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); - if (config.enabled) - { - _managedObjectRegistry = new JMXManagedObjectRegistry(); - } - else - { - _managedObjectRegistry = new NoopManagedObjectRegistry(); - } - } - - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public PrincipalDatabaseManager getDatabaseManager() - { - return _databaseManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public Collection getVirtualHostNames() - { - return getConfiguration().getList("virtualhosts.virtualhost.name"); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java deleted file mode 100644 index 5a48431288..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.util.Collection; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -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; - - void close() throws Exception; - - /** - * This gets access to a "configured object". A configured object has fields populated from a the configuration - * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields. - * Application registry implementations can choose the refresh strategy or caching approach. - * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only - * have a single object of this type in the system. - * @return the configured object - */ - T 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(); - - ManagedObjectRegistry getManagedObjectRegistry(); - - PrincipalDatabaseManager getDatabaseManager(); - - AuthenticationManager getAuthenticationManager(); - - Collection getVirtualHostNames(); - - VirtualHostRegistry getVirtualHostRegistry(); - - AccessManager getAccessManager(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java deleted file mode 100644 index f9e093dba7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security; - -import org.apache.commons.codec.binary.Base64; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; - -public class Passwd -{ - public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException - { - if (args.length != 2) - { - System.out.println("Passwd "); - System.exit(0); - } - - byte[] data = args[1].getBytes("utf-8"); - - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - Base64 b64 = new Base64(); - - byte[] encoded = b64.encode(digest); - - output(args[0], encoded); - } - - private static void output(String user, byte[] encoded) throws IOException - { - -// File passwdFile = new File("qpid.passwd"); - - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java deleted file mode 100644 index 2dc7fcbc1e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; - -import javax.management.JMException; -import javax.management.remote.JMXPrincipal; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.auth.Subject; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.FileOutputStream; -import java.util.Properties; -import java.util.List; -import java.util.Enumeration; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.AccessControlContext; -import java.security.AccessController; - -/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ -@MBeanDescription("User Management Interface") -public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement -{ - - private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); - - private PrincipalDatabase _principalDatabase; - private String _accessFileName; - private Properties _accessRights; - // private File _accessFile; - private ReentrantLock _accessRightsUpdate = new ReentrantLock(); - - // Setup for the TabularType - static TabularType _userlistDataType; // Datatype for representing User Lists - - static CompositeType _userDataType; // Composite type for representing User - static String[] _userItemNames = {"Username", "read", "write", "admin"}; - - static - { - String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", - "Management Console Write Permission", "Management Console Admin Permission"}; - - OpenType[] userItemTypes = new OpenType[4]; // User item types. - userItemTypes[0] = SimpleType.STRING; // For Username - userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read - userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write - userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin - String[] userDataIndex = {_userItemNames[0]}; - - try - { - _userDataType = - new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); - - _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); - } - catch (OpenDataException e) - { - _logger.error("Tabular data setup for viewing users incorrect."); - _userlistDataType = null; - } - } - - - public AMQUserManagementMBean() throws JMException - { - super(UserManagement.class, UserManagement.TYPE); - } - - public String getObjectInstanceName() - { - return UserManagement.TYPE; - } - - public boolean setPassword(String username, char[] password) - { - try - { - //delegate password changes to the Principal Database - return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to set password of non-existant user'" + username + "'"); - return false; - } - } - - public boolean setRights(String username, boolean read, boolean write, boolean admin) - { - - if (_accessRights.get(username) == null) - { - // If the user doesn't exist in the user rights file check that they at least have an account. - if (_principalDatabase.getUser(username) == null) - { - return false; - } - } - - try - { - - _accessRightsUpdate.lock(); - - // Update the access rights - if (admin) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); - } - else - { - if (read | write) - { - if (read) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); - } - if (write) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); - } - } - else - { - _accessRights.remove(username); - } - } - - saveAccessFile(); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - - return true; - } - - public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) - { - if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) - { - _accessRights.put(username, ""); - - return setRights(username, read, write, admin); - } - - return false; - } - - public boolean deleteUser(String username) - { - - try - { - if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) - { - try - { - _accessRightsUpdate.lock(); - - _accessRights.remove(username); - saveAccessFile(); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - return true; - } - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); - } - - return false; - } - - public boolean reloadData() - { - try - { - try - { - loadAccessFile(); - } - catch (ConfigurationException e) - { - _logger.info("Reload failed due to:" + e); - return false; - } - - // Reload successful - return true; - } - catch (IOException e) - { - _logger.info("Reload failed due to:" + e); - // Reload unsuccessful - return false; - } - } - - - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") - public TabularData viewUsers() - { - // Table of users - // Username(string), Access rights Read,Write,Admin(bool,bool,bool) - - if (_userlistDataType == null) - { - _logger.warn("TabluarData not setup correctly"); - return null; - } - - List users = _principalDatabase.getUsers(); - - TabularDataSupport userList = new TabularDataSupport(_userlistDataType); - - try - { - // Create the tabular list of message header contents - for (Principal user : users) - { - // Create header attributes list - - String rights = (String) _accessRights.get(user.getName()); - - Boolean read = false; - Boolean write = false; - Boolean admin = false; - - if (rights != null) - { - read = rights.equals(MBeanInvocationHandlerImpl.READONLY) - || rights.equals(MBeanInvocationHandlerImpl.READWRITE); - write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); - admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); - } - - Object[] itemData = {user.getName(), read, write, admin}; - CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); - userList.put(messageData); - } - } - catch (OpenDataException e) - { - _logger.warn("Unable to create user list due to :" + e); - return null; - } - - return userList; - } - - /*** Broker Methods **/ - - /** - * setPrincipalDatabase - * - * @param database set The Database to use for user lookup - */ - public void setPrincipalDatabase(PrincipalDatabase database) - { - _principalDatabase = database; - } - - /** - * setAccessFile - * - * @param accessFile the file to use for updating. - * - * @throws java.io.IOException If the file cannot be accessed - * @throws org.apache.commons.configuration.ConfigurationException - * if checks on the file fail. - */ - public void setAccessFile(String accessFile) throws IOException, ConfigurationException - { - _accessFileName = accessFile; - - if (_accessFileName != null) - { - loadAccessFile(); - } - else - { - _logger.warn("Access rights file specified is null. Access rights not changed."); - } - } - - private void loadAccessFile() throws IOException, ConfigurationException - { - try - { - _accessRightsUpdate.lock(); - - Properties accessRights = new Properties(); - - File accessFile = new File(_accessFileName); - - if (!accessFile.exists()) - { - throw new ConfigurationException("'" + _accessFileName + "' does not exist"); - } - - if (!accessFile.canRead()) - { - throw new ConfigurationException("Cannot read '" + _accessFileName + "'."); - } - - if (!accessFile.canWrite()) - { - _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved."); - } - - accessRights.load(new FileInputStream(accessFile)); - checkAccessRights(accessRights); - setAccessRights(accessRights); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - - private void checkAccessRights(Properties accessRights) - { - Enumeration values = accessRights.propertyNames(); - - while (values.hasMoreElements()) - { - String user = (String) values.nextElement(); - - if (_principalDatabase.getUser(user) == null) - { - _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); - } - } - } - - private void saveAccessFile() - { - try - { - _accessRightsUpdate.lock(); - try - { - // remove old temporary file - File tmp = new File(_accessFileName + ".tmp"); - if (tmp.exists()) - { - tmp.delete(); - } - - //remove old backup - File old = new File(_accessFileName + ".old"); - if (old.exists()) - { - old.delete(); - } - - // Rename current file - File rights = new File(_accessFileName); - rights.renameTo(old); - - FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); - output.close(); - - // Rename new file to main file - tmp.renameTo(rights); - - // delete tmp - tmp.delete(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e); - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - - private String getCurrentJMXUser() - { - AccessControlContext acc = AccessController.getContext(); - Subject subject = Subject.getSubject(acc); - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - return "Unknown user principals were null"; - } - - Principal principal = principals.iterator().next(); - return principal.getName(); - } - - /** - * user=read user=write user=readwrite user=admin - * - * @param accessRights The properties list of access rights to process - */ - private void setAccessRights(Properties accessRights) - { - _logger.debug("Setting Access Rights:" + accessRights); - _accessRights = accessRights; - MBeanInvocationHandlerImpl.setAccessRights(_accessRights); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java deleted file mode 100644 index d70a6dc8f4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import java.security.Principal; - -public interface AccessManager -{ - AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights); - - @Deprecated - AccessResult isAuthorized(Accessable accessObject, String username); - - String getName(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java deleted file mode 100644 index 35d036d20f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.log4j.Logger; - -import java.util.List; -import java.lang.reflect.Method; -import java.security.Principal; - -public class AccessManagerImpl implements AccessManager -{ - private static final Logger _logger = Logger.getLogger(AccessManagerImpl.class); - - AccessManager _accessManager; - - public AccessManagerImpl(String name, Configuration hostConfig) throws ConfigurationException - { - if (hostConfig == null) - { - _logger.warn("No Configuration specified. Using default access controls for VirtualHost:'" + name + "'"); - return; - } - - String accessClass = hostConfig.getString("security.access.class"); - if (accessClass == null) - { - _logger.warn("No access control specified. Using default access controls for VirtualHost:'" + name + "'"); - return; - } - - Object o; - try - { - o = Class.forName(accessClass).newInstance(); - } - catch (Exception e) - { - throw new ConfigurationException("Error initialising access control: " + e, e); - } - - if (!(o instanceof AccessManager)) - { - throw new ConfigurationException("Access control must implement the VirtualHostAccess interface"); - } - - initialiseAccessControl((AccessManager) o, hostConfig); - - _accessManager = (AccessManager) o; - - _logger.info("Initialised access control for virtualhost '" + name + "' successfully"); - - } - - - private void initialiseAccessControl(AccessManager accessManager, Configuration config) - throws ConfigurationException - { - String baseName = "security.access.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 ConfigurationException("Access Control 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 = null; - try - { - method = accessManager.getClass().getMethod(methodName, String.class); - } - catch (NoSuchMethodException e) - { - //do nothing as method will be null - } - - if (method == null) - { - throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() + - " hence unable to configure access control. The method must be public and " + - "have a single String argument with a void return type"); - } - try - { - method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i))); - } - catch (Exception e) - { - ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause()); - ce.initCause(e); - throw ce; - } - } - } - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); - } - - public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) - { - if (_accessManager == null) - { - if (ApplicationRegistry.getInstance().getAccessManager() == this) - { - _logger.warn("No Default access manager specified DENYING ALL ACCESS"); - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - else - { - return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, user, rights); - } - } - else - { - return _accessManager.isAuthorized(accessObject, user, rights); - } - } - - public String getName() - { - return "AccessManagerImpl"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java deleted file mode 100644 index b8d8fc605a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessResult -{ - public enum AccessStatus - { - GRANTED, REFUSED - } - - StringBuilder _authorizer; - AccessStatus _status; - - public AccessResult(AccessManager authorizer, AccessStatus status) - { - _status = status; - _authorizer = new StringBuilder(authorizer.getName()); - } - - public void setAuthorizer(AccessManager authorizer) - { - _authorizer.append(authorizer.getName()); - } - - public String getAuthorizer() - { - return _authorizer.toString(); - } - - public void setStatus(AccessStatus status) - { - _status = status; - } - - public AccessStatus getStatus() - { - return _status; - } - - public void addAuthorizer(AccessManager accessManager) - { - _authorizer.insert(0, "->"); - _authorizer.insert(0, accessManager.getName()); - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java deleted file mode 100644 index 1b79a5a0e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessRights -{ - public enum Rights - { - ANY, - READ, - WRITE, - READWRITE - } - - Rights _right; - - public AccessRights(Rights right) - { - _right = right; - } - - public boolean allows(Rights rights) - { - switch (_right) - { - case ANY: - return (rights.equals(Rights.WRITE) - || rights.equals(Rights.READ) - || rights.equals(Rights.READWRITE) - || rights.equals(Rights.ANY)); - case READ: - return rights.equals(Rights.READ) || rights.equals(Rights.ANY); - case WRITE: - return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); - case READWRITE: - return true; - } - return false; - } - - public Rights getRights() - { - return _right; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java deleted file mode 100644 index f51cf24caa..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public interface Accessable -{ - void setAccessableName(String name); - String getAccessableName(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java deleted file mode 100644 index 1ddca3a64e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import java.security.Principal; - -public class AllowAll implements AccessManager -{ - - public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) - { - return new AccessResult(this, AccessResult.AccessStatus.GRANTED); - } - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return new AccessResult(this, AccessResult.AccessStatus.GRANTED); - } - - public String getName() - { - return "AllowAll"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java deleted file mode 100644 index bf40eeba4e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import java.security.Principal; - -public class DenyAll implements AccessManager -{ - public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) - { - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - - public String getName() - { - return "DenyAll"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java deleted file mode 100644 index 291bc714ed..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.log4j.Logger; - -import java.io.IOException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.io.File; -import java.util.regex.Pattern; -import java.security.Principal; - -/** - * 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 FileAccessManager implements AccessManager -{ - private static final Logger _logger = Logger.getLogger(FileAccessManager.class); - - protected File _accessFile; - - protected Pattern _regexp = Pattern.compile(":"); - - private static final short USER_INDEX = 0; - private static final short VIRTUALHOST_INDEX = 1; - - public void setAccessFile(String accessFile) throws FileNotFoundException - { - File f = new File(accessFile); - _logger.info("FileAccessManager using file " + f.getAbsolutePath()); - _accessFile = f; - if (!f.exists()) - { - throw new FileNotFoundException("Cannot find access file " + f); - } - if (!f.canRead()) - { - throw new FileNotFoundException("Cannot read access file " + f + - ". Check permissions."); - } - } - - /** - * Looks up the virtual hosts for a specified user in the access file. - * - * @param user The user to lookup - * - * @return a list of virtualhosts - */ - private VirtualHostAccess[] lookupVirtualHost(String user) - { - String[] results = lookup(user, VIRTUALHOST_INDEX); - VirtualHostAccess vhosts[] = new VirtualHostAccess[results.length]; - - for (int index = 0; index < results.length; index++) - { - vhosts[index] = new VirtualHostAccess(results[index]); - } - - return vhosts; - } - - - private String[] lookup(String user, int index) - { - try - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_accessFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < (index + 1)) - { - continue; - } - - if (user.equals(result[USER_INDEX])) - { - return result[index].split(","); - } - } - return null; - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - catch (IOException ioe) - { - //ignore - } - return null; - } - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); - } - - public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) - { - if (accessObject instanceof VirtualHost) - { - VirtualHostAccess[] hosts = lookupVirtualHost(user.getName()); - - if (hosts != null) - { - for (VirtualHostAccess host : hosts) - { - if (accessObject.getAccessableName().equals(host.getVirtualHost())) - { - if (host.getAccessRights().allows(rights)) - { - return new AccessResult(this, AccessResult.AccessStatus.GRANTED); - } - else - { - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - } - } - } - } -// else if (accessObject instanceof AMQQueue) -// { -// String[] queues = lookupQueue(username, ((AMQQueue) accessObject).getVirtualHost()); -// -// if (queues != null) -// { -// for (String queue : queues) -// { -// if (accessObject.getAccessableName().equals(queue)) -// { -// return new AccessResult(this, AccessResult.AccessStatus.GRANTED); -// } -// } -// } -// } - - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - - public String getName() - { - return "FileAccessManager"; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java deleted file mode 100644 index 6ccadb2e7d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.log4j.Logger; - -import java.security.Principal; - -public class PrincipalDatabaseAccessManager implements AccessManager -{ - private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAccessManager.class); - - PrincipalDatabase _database; - AccessManager _default; - - public PrincipalDatabaseAccessManager() - { - _default = null; - } - - public void setDefaultAccessManager(String defaultAM) - { - if (defaultAM.equals("AllowAll")) - { - _default = new AllowAll(); - } - - if (defaultAM.equals("DenyAll")) - { - _default = new DenyAll(); - } - } - - public void setPrincipalDatabase(String database) - { - _database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(database); - if (!(_database instanceof AccessManager)) - { - _logger.warn("Database '" + database + "' cannot perform access management"); - } - } - - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); - } - - public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) - { - AccessResult result; - - if (_database == null) - { - if (_default != null) - { - result = _default.isAuthorized(accessObject, username, rights); - } - else - { - throw new RuntimeException("Principal Database and default Access Manager are both null unable to perform Access Control"); - } - } - else - { - if (!(_database instanceof AccessManager)) - { - _logger.warn("Specified PrincipalDatabase is not an AccessManager so using default AccessManager"); - result = _default.isAuthorized(accessObject, username, rights); - } - else - { - result = ((AccessManager) _database).isAuthorized(accessObject, username, rights); - } - } - - result.addAuthorizer(this); - - return result; - } - - public String getName() - { - return "PrincipalDatabaseFileAccessManager"; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java deleted file mode 100644 index b8762aa43b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.AMQException; - -import javax.management.openmbean.TabularData; -import javax.management.openmbean.CompositeData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.io.IOException; - -public interface UserManagement -{ - String TYPE = "UserManagement"; - - //********** Operations *****************// - /** - * set password for user - * - * @param username The username to create - * @param password The password for the user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setPassword", description = "Set password for user.", - impact = MBeanOperationInfo.ACTION) - boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password); - - /** - * set rights for users with given details - * - * @param username The username to create - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setRights", description = "Set access rights for user.", - impact = MBeanOperationInfo.ACTION) - boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * Create users with given details - * - * @param username The username to create - * @param password The password for the user - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "createUser", description = "Create new user from system.", - impact = MBeanOperationInfo.ACTION) - boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * View users returns all the users that are currently available to the system. - * - * @param username The user to delete - * - * @return The result of the operation - */ - @MBeanOperation(name = "deleteUser", description = "Delete user from system.", - impact = MBeanOperationInfo.ACTION) - boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); - - - /** - * Reload the date from disk - * - * @return The result of the operation - */ - @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", - impact = MBeanOperationInfo.ACTION) - boolean reloadData(); - - /** - * View users returns all the users that are currently available to the system. - * - * @return a table of users data (Username, read, write, admin) - */ - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", - impact = MBeanOperationInfo.INFO) - TabularData viewUsers(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java deleted file mode 100644 index 13151a66b8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class VirtualHostAccess -{ - private String _vhost; - private AccessRights _rights; - - public VirtualHostAccess(String vhostaccess) - { - //format () - int hostend = vhostaccess.indexOf('('); - - if (hostend == -1) - { - throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); - } - - _vhost = vhostaccess.substring(0, hostend); - - String rights = vhostaccess.substring(hostend); - - if (rights.indexOf('r') != -1) - { - if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.READWRITE); - } - else - { - _rights = new AccessRights(AccessRights.Rights.READ); - } - } - else if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.WRITE); - } - } - - public AccessRights getAccessRights() - { - return _rights; - } - - public String getVirtualHost() - { - return _vhost; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java deleted file mode 100644 index 0e3aea4de0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -public class AuthenticationResult -{ - public enum AuthenticationStatus - { - SUCCESS, CONTINUE, ERROR - } - - public AuthenticationStatus status; - public byte[] challenge; - - public AuthenticationResult(byte[] challenge, AuthenticationStatus status) - { - this.status = status; - this.challenge = challenge; - } - - public AuthenticationResult(AuthenticationStatus status) - { - this.status = status; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java deleted file mode 100644 index 10adfdd9fc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; -import org.apache.qpid.server.security.access.AMQUserManagementMBean; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.EncoderException; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.UnsupportedEncodingException; -import java.io.PrintStream; -import java.util.regex.Pattern; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.NoSuchAlgorithmException; -import java.security.MessageDigest; - -/** - * 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 Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map _saslServers; - - AMQUserManagementMBean _mbean; - private static final String DEFAULT_ENCODING = "utf-8"; - private Map _users = new HashMap(); - private ReentrantLock _userUpdate = new ReentrantLock(); - - public Base64MD5PasswordFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for MD5 Password file. - */ - - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); - cram.initialise(this); - _saslServers.put(cram.getMechanismName(), cram); - - //fixme The PDs should setup a PD Mangement MBean -// try -// { -// _mbean = new AMQUserManagementMBean(); -// _mbean.setPrincipalDatabase(this); -// } -// catch (JMException e) -// { -// _logger.warn("User management disabled as unable to create MBean:" + e); -// } - } - - public void setPasswordFile(String passwordFile) throws IOException - { - 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."); - } - - loadPasswordFile(); - } - - /** - * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile - * - * @param principal The Principal to set the password for - * @param callback The PasswordCallback to call setPassword on - * - * @throws AccountNotFoundException If the Principal cannont be found in this Database - */ - public void setPassword(Principal principal, PasswordCallback callback) throws 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); - } - } - - /** - * Used to verify that the presented Password is correct. Currently only used by Management Console - * - * @param principal The principal to authenticate - * @param password The password to check - * - * @return true if password is correct - * - * @throws AccountNotFoundException if the principal cannot be found - */ - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - char[] pwd = lookupPassword(principal); - - int index = 0; - boolean verified = true; - - while (verified & index < password.length) - { - verified = (pwd[index] == password[index]); - index++; - } - return verified; - } - - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - User user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - try - { - _userUpdate.lock(); - char[] orig = user.getPassword(); - user.setPassword(password); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to save password file, password change for user'" - + principal + "' will revert at restart"); - //revert the password change - user.setPassword(orig); - return false; - } - return true; - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - catch (Exception e) - { - return false; - } - } - - public boolean createPrincipal(Principal principal, char[] password) - { - if (_users.get(principal.getName()) != null) - { - return false; - } - - User user = new User(principal.getName(), password); - - try - { - _userUpdate.lock(); - _users.put(user.getName(), user); - - try - { - savePasswordFile(); - return true; - } - catch (IOException e) - { - //remove the use on failure. - _users.remove(user.getName()); - return false; - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - User user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - _userUpdate.lock(); - user.delete(); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); - return false; - } - - _users.remove(user.getName()); - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - - return true; - } - - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(_users.values()); - } - - public Principal getUser(String username) - { - if (_users.containsKey(username)) - { - return new UsernamePrincipal(username); - } - return null; - } - - /** - * 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 The principal name to lookup - * - * @return a char[] for use in SASL. - */ - private char[] lookupPassword(String name) - { - User user = _users.get(name); - if (user == null) - { - return null; - } - else - { - return user.getPassword(); - } - } - - - private void loadPasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - _users.clear(); - - 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 || result[0].startsWith("#")) - { - continue; - } - - User user = new User(result); - _logger.info("Created user:" + user); - _users.put(user.getName(), user); - } - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - private void savePasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp"); - if (tmp.exists()) - { - tmp.delete(); - } - try - { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - continue; - } - - User user = _users.get(result[0]); - - if (user == null) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else if (!user.isDeleted()) - { - if (!user.isModified()) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else - { - try - { - byte[] encodedPassword = user.getEncodePassword(); - - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to encode new password reverting to old password."); - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - } - } - } - - for (User user : _users.values()) - { - if (user.isModified()) - { - byte[] encodedPassword; - try - { - encodedPassword = user.getEncodePassword(); - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); - } - } - } - } - finally - { - if (reader != null) - { - reader.close(); - } - - if (writer != null) - { - writer.close(); - } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - _passwordFile.renameTo(old); - tmp.renameTo(_passwordFile); - tmp.delete(); - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - private class User implements Principal - { - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - User(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be lenght 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public User(String name, char[] password) - { - _name = name; - setPassword(password); - } - - public String getName() - { - return _name; - } - - public String toString() - { - if (_logger.isDebugEnabled()) - { - return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); - } - else - { - return _name; - } - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - _encodedPassword = null; - } - - - byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - _encodedPassword = (new Base64()).encode(byteArray); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java deleted file mode 100644 index 06eb9329a6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.PropertyException; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.AMQUserManagementMBean; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; - -public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager -{ - private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); - - private static final String _base = "security.principal-databases.principal-database"; - - Map _databases; - - public ConfigurationFilePrincipalDatabaseManager() throws Exception - { - _logger.info("Initialising PrincipleDatabase authentication manager"); - _databases = initialisePrincipalDatabases(); - } - - private Map initialisePrincipalDatabases() throws Exception - { - Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - List databaseNames = config.getList(_base + ".name"); - List databaseClasses = config.getList(_base + ".class"); - Map databases = new HashMap(); - - if (databaseNames.size() == 0) - { - _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); - } - - 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 not provided"); - } - - _logger.info("Initialised principal database '" + name + "' successfully"); - databases.put(name, (PrincipalDatabase) o); - } - - return databases; - } - - private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) - throws FileNotFoundException, ConfigurationException - { - String baseName = _base + "(" + 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 ConfigurationException("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 = null; - try - { - method = principalDatabase.getClass().getMethod(methodName, String.class); - } - catch (Exception e) - { - // do nothing.. as on error method will be null - } - - if (method == null) - { - throw new ConfigurationException("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"); - } - - try - { - method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); - } - catch (Exception ite) - { - if (ite instanceof ConfigurationException) - { - throw(ConfigurationException) ite; - } - else - { - throw new ConfigurationException(ite.getMessage(), ite); - } - } - } - } - - public Map getDatabases() - { - return _databases; - } - - public void initialiseManagement(Configuration config) throws ConfigurationException - { - try - { - AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); - - String baseSecurity = "security.jmx"; - List principalDBs = config.getList(baseSecurity + ".principal-database"); - - if (principalDBs.size() == 0) - { - throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity - + ".principal-database)"); - } - - String databaseName = principalDBs.get(0); - - PrincipalDatabase database = getDatabases().get(databaseName); - - if (database == null) - { - throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); - } - - _mbean.setPrincipalDatabase(database); - - List jmxaccesslist = config.getList(baseSecurity + ".access"); - - if (jmxaccesslist.size() == 0) - { - throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity - + ".access)"); - } - - String jmxaccesssFile = null; - - try - { - jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); - } - catch (PropertyException e) - { - throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'", e); - } - - try - { - _mbean.setAccessFile(jmxaccesssFile); - } - catch (IOException e) - { - _logger.warn("Unable to load access file:" + jmxaccesssFile); - } - - try - { - _mbean.register(); - } - catch (AMQException e) - { - _logger.warn("Unable to register user management MBean"); - } - } - catch (JMException e) - { - _logger.warn("User management disabled as unable to create MBean:" + e); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java deleted file mode 100644 index 352d41a0ba..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -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 PlainPasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); - - protected File _passwordFile; - - protected Pattern _regexp = Pattern.compile(":"); - - protected Map _saslServers; - - public PlainPasswordFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for Plain Password file. - */ - - // Accept AMQPlain incomming and compare it to the file. - AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); - amqplain.initialise(this); - - // Accept Plain incomming and compare it to the file. - PlainInitialiser plain = new PlainInitialiser(); - plain.initialise(this); - - // Accept MD5 incomming and Hash file value for comparison - CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); - cram.initialise(this); - - _saslServers.put(amqplain.getMechanismName(), amqplain); - _saslServers.put(plain.getMechanismName(), plain); - _saslServers.put(cram.getMechanismName(), cram); - } - - public void setPasswordFile(String passwordFile) throws FileNotFoundException - { - File f = new File(passwordFile); - _logger.info("PlainPasswordFile 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); - } - } - - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - try - { - char[] pwd = lookupPassword(principal); - - return compareCharArray(pwd, password); - } - catch (IOException e) - { - return false; - } - } - - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - return false; // updates denied - } - - public boolean createPrincipal(Principal principal, char[] password) - { - return false; // updates denied - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - return false; // updates denied - } - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(); //todo - } - - public Principal getUser(String username) - { - try - { - if (lookupPassword(username) != null) - { - return new UsernamePrincipal(username); - } - } - catch (IOException e) - { - //fall through to null return - } - return null; - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - - /** - * 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 the name of the principal to lookup - * - * @return char[] of the password - * - * @throws java.io.IOException whilst accessing the file - */ - private char[] lookupPassword(String name) throws IOException - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - if (!line.startsWith("#")) - { - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java deleted file mode 100644 index 5c372f6c2c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.AccessRights; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.security.Principal; - -/** - * 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 PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePrincipalDatabase implements AccessManager -{ - private static final Logger _logger = Logger.getLogger(PlainPasswordVhostFilePrincipalDatabase.class); - - /** - * Looks up the virtual hosts for a specified user in the password file. - * - * @param user The user to lookup - * - * @return a list of virtualhosts - */ - private String[] lookupVirtualHost(String user) - { - try - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - if (!line.startsWith("#")) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 3) - { - continue; - } - - if (user.equals(result[0])) - { - return result[2].split(","); - } - } - } - return null; - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - catch (IOException ioe) - { - //ignore - } - return null; - } - - - public AccessResult isAuthorized(Accessable accessObject, String username) - { - return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); - } - - public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) - { - - if (accessObject instanceof VirtualHost) - { - String[] hosts = lookupVirtualHost(user.getName()); - - if (hosts != null) - { - for (String host : hosts) - { - if (accessObject.getAccessableName().equals(host)) - { - return new AccessResult(this, AccessResult.AccessStatus.GRANTED); - } - } - } - } - - return new AccessResult(this, AccessResult.AccessStatus.REFUSED); - } - - public String getName() - { - return "PlainPasswordVhostFile"; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java deleted file mode 100644 index a82f9ed40b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.util.Map; -import java.util.List; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -/** 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; - - /** - * Used to verify that the presented Password is correct. Currently only used by Management Console - * @param principal The principal to authenticate - * @param password The password to check - * @return true if password is correct - * @throws AccountNotFoundException if the principal cannot be found - */ - boolean verifyPassword(String principal, char[] password) - throws AccountNotFoundException; - - /** - * Update(Change) the password for the given principal - * @param principal Who's password is to be changed - * @param password The new password to use - * @return True if change was successful - * @throws AccountNotFoundException If the given principal doesn't exist in the Database - */ - boolean updatePassword(Principal principal, char[] password) - throws AccountNotFoundException; - - /** - * Create a new principal in the database - * @param principal The principal to create - * @param password The password to set for the principal - * @return True on a successful creation - */ - boolean createPrincipal(Principal principal, char[] password); - - /** - * Delete a principal - * @param principal The principal to delete - * @return True on a successful creation - * @throws AccountNotFoundException If the given principal doesn't exist in the Database - */ - boolean deletePrincipal(Principal principal) - throws AccountNotFoundException; - - /** - * Get the principal from the database with the given username - * @param username of the principal to lookup - * @return The Principal object for the given username or null if not found. - */ - Principal getUser(String username); - - - public Map getMechanisms(); - - - List getUsers(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java deleted file mode 100644 index 2c553ae76a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -import java.util.Map; - -public interface PrincipalDatabaseManager -{ - public Map getDatabases(); - - public void initialiseManagement(Configuration config) throws ConfigurationException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java deleted file mode 100644 index 73d58ca489..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.util.Properties; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.security.Principal; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -public class PropertiesPrincipalDatabase implements PrincipalDatabase -{ - private Properties _users; - - private Map _saslServers; - - public PropertiesPrincipalDatabase(Properties users) - { - _users = users; - - _saslServers = new HashMap(); - - /** - * Create Authenticators for Properties Principal Database. - */ - - // Accept MD5 incomming and use plain comparison with the file - PlainInitialiser cram = new PlainInitialiser(); - cram.initialise(this); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); - plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); - - _saslServers.put(plain.getMechanismName(), cram); - _saslServers.put(cram.getMechanismName(), plain); - } - - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException - { - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - char[] pwd = _users.getProperty(principal.getName()).toCharArray(); - if (pwd != null) - { - callback.setPassword(pwd); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } - - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - //fixme this is not correct as toCharArray is not safe based on the type of string. - char[] pwd = _users.getProperty(principal).toCharArray(); - - return compareCharArray(pwd, password); - } - - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - return false; // updates denied - } - - public boolean createPrincipal(Principal principal, char[] password) - { - return false; // updates denied - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - return false; // updates denied - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - private char[] convertPassword(String password) throws UnsupportedEncodingException - { - byte[] passwdBytes = password.getBytes("utf-8"); - - char[] passwd = new char[passwdBytes.length]; - - int index = 0; - - for (byte b : passwdBytes) - { - passwd[index++] = (char) b; - } - - return passwd; - } - - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(); //todo - } - - public Principal getUser(String username) - { - if (_users.getProperty(username) != null) - { - return new UsernamePrincipal(username); - } - else - { - return null; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java deleted file mode 100644 index 6b86a46bd2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.configuration.Configuration; - -import java.util.Map; -import java.util.Properties; -import java.util.HashMap; - -public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager -{ - - Map _databases = new HashMap(); - - public PropertiesPrincipalDatabaseManager(String name, Properties users) - { - _databases.put(name, new PropertiesPrincipalDatabase(users)); - } - - public Map getDatabases() - { - return _databases; - } - - public void initialiseManagement(Configuration config) - { - //todo - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java deleted file mode 100644 index bb94e0b7bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.manager; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.AuthenticationResult; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java deleted file mode 100644 index ce5e0cd748..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.manager; - -import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.SubsetConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.JCAProvider; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.AuthenticationResult; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.Sasl; -import java.util.Map; -import java.util.HashMap; -import java.util.TreeMap; -import java.security.Security; - -public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager -{ - private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.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>(); - - private AuthenticationManager _default = null; - - public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception - { - _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") - + " PrincipleDatabase authentication manager."); - - // Fixme This should be done per Vhost but allowing global hack isn't right but ... - // required as authentication is done before Vhost selection - - Map> providerMap = new TreeMap>(); - - - if (name == null || hostConfig == null) - { - initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); - } - else - { - String databaseName = hostConfig.getString("security.authentication.name"); - - if (databaseName == null) - { - - if (hostConfig instanceof SubsetConfiguration) - { - _logger.warn("No authentication specified for '" + ((SubsetConfiguration) hostConfig).getPrefix() + "'. Using Default authentication manager"); - } - else - { - _logger.warn("No authentication specified. Using Default authentication manager"); - } - _default = ApplicationRegistry.getInstance().getAuthenticationManager(); - return; - } - else - { - PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); - - if (database == null) - { - throw new ConfigurationException("Requested database:" + databaseName + " was not found"); - } - - initialiseAuthenticationMechanisms(providerMap, database); - } - } - - if (providerMap.size() > 0) - { - // Ensure we are used before the defaults - if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1) - { - _logger.warn("Unable to set order of providers."); - } - } - else - { - _logger.warn("No additional SASL providers registered."); - } - - } - - - private void initialiseAuthenticationMechanisms(Map> providerMap, 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. - - - if (databases.size() > 1) - { - _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); - } - - for (Map.Entry entry : databases.entrySet()) - { - - // fixme As the database now provide the mechanisms they support, they will ... - // overwrite each other in the map. There should only be one database per vhost. - // But currently we must have authentication before vhost definition. - initialiseAuthenticationMechanisms(providerMap, entry.getValue()); - } - - } - - private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception - { - if (database == null || database.getMechanisms().size() == 0) - { - _logger.warn("No Database or no mechanisms to initialise authentication"); - return; - } - - for (Map.Entry mechanism : database.getMechanisms().entrySet()) - { - initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); - } - } - - private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, - Map> providerMap) - throws Exception - { - 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); - } - _logger.info("Initialised " + mechanism + " SASL provider successfully"); - } - - public String getMechanisms() - { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.getMechanisms(); - } - else - { - return _mechanisms; - } - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.createSaslServer(mechanism, localFQDN); - } - else - { - return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), - _callbackHandlerMap.get(mechanism)); - } - - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - // Use the default AuthenticationManager if present - if (_default != null) - { - return _default.authenticate(server, 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); - } - } - - public AuthenticationResult isAuthorize(VirtualHost vhost, String username) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java deleted file mode 100644 index 89e545d6f5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -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 - * @throws Exception needs refined Exception is too broad. - */ - void initialise(String baseConfigPath, Configuration configuration, - Map principalDatabases) throws Exception; - - /** - * Initialise the authentication provider. - * @param db The principal database to initialise with - */ - void initialise(PrincipalDatabase db); - - - /** - * @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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java deleted file mode 100644 index fd4ad86055..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.security.Provider; -import java.security.Security; -import java.util.Map; - -import javax.security.sasl.SaslServerFactory; - -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()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java deleted file mode 100644 index dd0bd096c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.io.IOException; -import java.security.Principal; -import java.util.Map; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; - -import org.apache.commons.configuration.Configuration; - -import org.apache.log4j.Logger; - -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; - -public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser -{ - protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); - - 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 - IOException ioe = new IOException("Error looking up user " + e); - ioe.initCause(e); - throw ioe; - } - } - 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); - - initialise(db); - } - - public void initialise(PrincipalDatabase db) - { - if (db == null) - { - throw new NullPointerException("Cannot initialise with a null Principal database."); - } - - _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java deleted file mode 100644 index d7c8383690..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -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; - } - - public String toString() - { - return _name; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java deleted file mode 100644 index 7acc6322d1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; - -public class AmqPlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "AMQPLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return AmqPlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java deleted file mode 100644 index 7842f376fb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; - -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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.getString("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.getString("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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java deleted file mode 100644 index 67d20136bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java deleted file mode 100644 index 97f9a4e91a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -import javax.security.sasl.SaslServerFactory; -import java.util.Map; - -public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return CRAMMD5HashedSaslServer.MECHANISM; - } - - public Class getServerFactoryClassForJCARegistration() - { - return CRAMMD5HashedServerFactory.class; - } - - public void initialise(PrincipalDatabase passwordFile) - { - super.initialise(passwordFile); - } - - public Map getProperties() - { - return null; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java deleted file mode 100644 index f6cab084ea..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslServerFactory; -import javax.security.auth.callback.CallbackHandler; -import java.util.Enumeration; -import java.util.Map; - -public class CRAMMD5HashedSaslServer implements SaslServer -{ - public static final String MECHANISM = "CRAM-MD5-HASHED"; - - private SaslServer _realServer; - - public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - Enumeration factories = Sasl.getSaslServerFactories(); - - while (factories.hasMoreElements()) - { - SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); - - if (factory instanceof CRAMMD5HashedServerFactory) - { - continue; - } - - String[] mechs = factory.getMechanismNames(props); - - for (String mech : mechs) - { - if (mech.equals("CRAM-MD5")) - { - _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); - return; - } - } - } - - throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - return _realServer.evaluateResponse(response); - } - - public boolean isComplete() - { - return _realServer.isComplete(); - } - - public String getAuthorizationID() - { - return _realServer.getAuthorizationID(); - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - return _realServer.unwrap(incoming, offset, len); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - return _realServer.wrap(outgoing, offset, len); - } - - public Object getNegotiatedProperty(String propName) - { - return _realServer.getNegotiatedProperty(propName); - } - - public void dispose() throws SaslException - { - _realServer.dispose(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java deleted file mode 100644 index 5298b5cc63..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5HashedServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) - { - return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); - } - else - { - return null; - } - } - - public String[] getMechanismNames(Map props) - { - if (props != null) - { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) - { - // returned array must be non null according to interface documentation - return new String[0]; - } - } - - return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java deleted file mode 100644 index 264832888d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5Initialiser extends UsernamePasswordInitialiser -{ - private HashDirection _hashDirection; - - public enum HashDirection - { - INCOMMING, PASSWORD_FILE - } - - - 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. - if (_hashDirection == HashDirection.PASSWORD_FILE) - { - return null; - } - else - { - //fixme we need a server that will correctly has the incomming plain text for comparison to file. - _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); - return null; - } - } - - public void initialise(PrincipalDatabase passwordFile) - { - initialise(passwordFile, HashDirection.PASSWORD_FILE); - } - - public void initialise(PrincipalDatabase passwordFile, HashDirection direction) - { - super.initialise(passwordFile); - - _hashDirection = direction; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java deleted file mode 100644 index 1d16cd8755..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; - -public class PlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "PLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return PlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java deleted file mode 100644 index 36aeb77fe1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java deleted file mode 100644 index f0dd9eeb6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java deleted file mode 100644 index f427cc7206..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -/** - * States used in the AMQ protocol. Used by the finite state machine to determine - * valid responses. - */ -public enum AMQState -{ - CONNECTION_NOT_STARTED, - CONNECTION_NOT_AUTH, - CONNECTION_NOT_TUNED, - CONNECTION_NOT_OPENED, - CONNECTION_OPEN, - CONNECTION_CLOSING, - CONNECTION_CLOSED -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java deleted file mode 100644 index f96900d0a9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.BasicAckBody; -import org.apache.qpid.framing.BasicCancelBody; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicGetBody; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.BasicQosBody; -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.BasicRejectBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.framing.ChannelFlowBody; -import org.apache.qpid.framing.ChannelOpenBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.framing.ConnectionOpenBody; -import org.apache.qpid.framing.ConnectionSecureOkBody; -import org.apache.qpid.framing.ConnectionStartOkBody; -import org.apache.qpid.framing.ConnectionTuneOkBody; -import org.apache.qpid.framing.ExchangeBoundBody; -import org.apache.qpid.framing.ExchangeDeclareBody; -import org.apache.qpid.framing.ExchangeDeleteBody; -import org.apache.qpid.framing.QueueBindBody; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.QueueDeleteBody; -import org.apache.qpid.framing.QueuePurgeBody; -import org.apache.qpid.framing.TxCommitBody; -import org.apache.qpid.framing.TxRollbackBody; -import org.apache.qpid.framing.TxSelectBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.server.handler.BasicAckMethodHandler; -import org.apache.qpid.server.handler.BasicCancelMethodHandler; -import org.apache.qpid.server.handler.BasicConsumeMethodHandler; -import org.apache.qpid.server.handler.BasicGetMethodHandler; -import org.apache.qpid.server.handler.BasicPublishMethodHandler; -import org.apache.qpid.server.handler.BasicQosHandler; -import org.apache.qpid.server.handler.BasicRecoverMethodHandler; -import org.apache.qpid.server.handler.BasicRejectMethodHandler; -import org.apache.qpid.server.handler.ChannelCloseHandler; -import org.apache.qpid.server.handler.ChannelCloseOkHandler; -import org.apache.qpid.server.handler.ChannelFlowHandler; -import org.apache.qpid.server.handler.ChannelOpenHandler; -import org.apache.qpid.server.handler.ConnectionCloseMethodHandler; -import org.apache.qpid.server.handler.ConnectionCloseOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionOpenMethodHandler; -import org.apache.qpid.server.handler.ConnectionSecureOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionStartOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionTuneOkMethodHandler; -import org.apache.qpid.server.handler.ExchangeBoundHandler; -import org.apache.qpid.server.handler.ExchangeDeclareHandler; -import org.apache.qpid.server.handler.ExchangeDeleteHandler; -import org.apache.qpid.server.handler.QueueBindHandler; -import org.apache.qpid.server.handler.QueueDeclareHandler; -import org.apache.qpid.server.handler.QueueDeleteHandler; -import org.apache.qpid.server.handler.QueuePurgeHandler; -import org.apache.qpid.server.handler.TxCommitHandler; -import org.apache.qpid.server.handler.TxRollbackHandler; -import org.apache.qpid.server.handler.TxSelectHandler; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -/** - * 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); - - private final VirtualHostRegistry _virtualHostRegistry; - private final AMQProtocolSession _protocolSession; - /** The current state */ - private AMQState _currentState; - - /** - * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of - * AMQFrame. - */ - private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = - new EnumMap, StateAwareMethodListener>>( - AMQState.class); - - private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - - public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) - { - this(AMQState.CONNECTION_NOT_STARTED, true, virtualHostRegistry, protocolSession); - } - - protected AMQStateManager(AMQState initial, boolean register, VirtualHostRegistry virtualHostRegistry, - AMQProtocolSession protocolSession) - { - _virtualHostRegistry = virtualHostRegistry; - _protocolSession = protocolSession; - _currentState = initial; - if (register) - { - registerListeners(); - } - } - - protected void registerListeners() - { - Map, StateAwareMethodListener> 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(ExchangeBoundBody.class, ExchangeBoundHandler.getInstance()); - frame2handlerMap.put(BasicAckBody.class, BasicAckMethodHandler.getInstance()); - frame2handlerMap.put(BasicRecoverBody.class, BasicRecoverMethodHandler.getInstance()); - frame2handlerMap.put(BasicConsumeBody.class, BasicConsumeMethodHandler.getInstance()); - frame2handlerMap.put(BasicGetBody.class, BasicGetMethodHandler.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(QueuePurgeBody.class, QueuePurgeHandler.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()); - frame2handlerMap.put(BasicRejectBody.class, BasicRejectMethodHandler.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(Exception e) - { - _logger.error("State manager received error notification[Current State:" + _currentState + "]: " + e, e); - for (StateListener l : _stateListeners) - { - l.error(e); - } - } - - public boolean methodReceived(AMQMethodEvent evt) throws AMQException - { - StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod()); - if (handler != null) - { - - checkChannel(evt, _protocolSession); - - handler.methodReceived(this, evt); - - return true; - } - - return false; - } - - private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) - throws AMQException - { - if ((evt.getChannelId() != 0) && !(evt.getMethod() instanceof ChannelOpenBody) - && (protocolSession.getChannel(evt.getChannelId()) == null) - && !protocolSession.channelAwaitingClosure(evt.getChannelId())) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - } - - protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, - B frame) - // throws IllegalStateTransitionException - { - final Map, StateAwareMethodListener> classToHandlerMap = - _state2HandlersMap.get(currentState); - - final StateAwareMethodListener handler = - (classToHandlerMap == null) ? null : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); - - if (handler == null) - { - _logger.debug("No state transition handler defined for receiving frame " + frame); - - return null; - } - else - { - return handler; - } - } - - public void addStateListener(StateListener listener) - { - _logger.debug("Adding state listener"); - _stateListeners.add(listener); - } - - public void removeStateListener(StateListener listener) - { - _stateListeners.remove(listener); - } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java deleted file mode 100644 index e3af0bc486..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * 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, AMQMethodEvent evt) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java deleted file mode 100644 index 00fc09867b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -public interface StateListener -{ - void stateChanged(AMQState oldState, AMQState newState) throws AMQException; - - void error(Throwable t); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java deleted file mode 100644 index 8ccb0be0a8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.Exchange; - -/** - * 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(VirtualHost virtualHost, 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(StoreContext context, Long messageId) - { - if (_log.isDebugEnabled()) - { - _log.debug("Removing message with id " + messageId); - } - _metaDataMap.remove(messageId); - _contentBodyMap.remove(messageId); - } - - public void createExchange(Exchange exchange) throws AMQException - { - - } - - public void removeExchange(Exchange exchange) throws AMQException - { - - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - - } - - public void createQueue(AMQQueue queue) throws AMQException - { - // Not required to do anything - } - - public void removeQueue(AMQShortString name) throws AMQException - { - // Not required to do anything - } - - public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException - { - // Not required to do anything - } - - public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException - { - // Not required to do anything - } - - public void beginTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void commitTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void abortTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public boolean inTran(StoreContext context) - { - return false; - } - - public List createQueues() throws AMQException - { - return null; - } - - public Long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) - throws AMQException - { - List bodyList = _contentBodyMap.get(messageId); - - if(bodyList == null && lastContentBody) - { - _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); - } - else - { - if (bodyList == null) - { - bodyList = new ArrayList(); - _contentBodyMap.put(messageId, bodyList); - } - - bodyList.add(index, contentBody); - } - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) - throws AMQException - { - _metaDataMap.put(messageId, messageMetaData); - } - - public MessageMetaData getMessageMetaData(StoreContext context,Long messageId) throws AMQException - { - return _metaDataMap.get(messageId); - } - - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - List bodyList = _contentBodyMap.get(messageId); - return bodyList.get(index); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java deleted file mode 100644 index 2a83d9b649..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/** - * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues - * and exchanges in a transactional manner. - * - *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which - * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single - * transaction. - * - *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. - * - *

      - *
      CRC Card
      Responsibilities - *
      Accept transaction boundary demarcations: Begin, Commit, Abort. - *
      Store and remove queues. - *
      Store and remove exchanges. - *
      Store and remove messages. - *
      Bind and unbind queues to exchanges. - *
      Enqueue and dequeue messages to queues. - *
      Generate message identifiers. - *
      - */ -public interface MessageStore -{ - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object. - * - * @throws Exception If any error occurs that means the store is unable to configure itself. - */ - void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws Exception If the close fails. - */ - void close() throws Exception; - - /** - * Removes the specified message from the store in the given transactional store context. - * - * @param storeContext The transactional context to remove the message in. - * @param messageId Identifies the message to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - /** - * Makes the specified exchange persistent. - * - * @param exchange The exchange to persist. - * - * @throws AMQException If the operation fails for any reason. - */ - void createExchange(Exchange exchange) throws AMQException; - - /** - * Removes the specified persistent exchange. - * - * @param exchange The exchange to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeExchange(Exchange exchange) throws AMQException; - - /** - * Binds the specified queue to an exchange with a routing key. - * - * @param exchange The exchange to bind to. - * @param routingKey The routing key to bind by. - * @param queue The queue to bind. - * @param args Additional parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Unbinds the specified from an exchange under a particular routing key. - * - * @param exchange The exchange to unbind from. - * @param routingKey The routing key to unbind. - * @param queue The queue to unbind. - * @param args Additonal parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue) throws AMQException; - - /** - * Removes the specified queue from the persistent store. - * - * @param name The queue to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeQueue(AMQShortString name) throws AMQException; - - /** - * Places a message onto a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param name The name of the queue to place the message on. - * @param messageId The message to enqueue. - * - * @throws AMQException If the operation fails for any reason. - */ - void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param name The name of the queue to take the message from. - * @param messageId The message to dequeue. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; - - /** - * Begins a transactional context. - * - * @param context The transactional context to begin. - * - * @throws AMQException If the operation fails for any reason. - */ - void beginTran(StoreContext context) throws AMQException; - - /** - * Commits all operations performed within a given transactional context. - * - * @param context The transactional context to commit all operations for. - * - * @throws AMQException If the operation fails for any reason. - */ - void commitTran(StoreContext context) throws AMQException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @param context The transactional context to abandon. - * - * @throws AMQException If the operation fails for any reason. - */ - void abortTran(StoreContext context) throws AMQException; - - /** - * Tests a transactional context to see if it has been begun but not yet committed or aborted. - * - * @param context The transactional context to test. - * - * @return true if the transactional context is live, false otherwise. - */ - boolean inTran(StoreContext context); - - /** - * Return a valid, currently unused message id. - * - * @return A fresh message id. - */ - Long getNewMessageId(); - - /** - * Stores a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param index The index of the data chunk. - * @param contentBody The content of the data chunk. - * @param lastContentBody Flag to indicate that this is the last such chunk for the message. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, - boolean lastContentBody) throws AMQException; - - /** - * Stores message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param messageMetaData The message meta data to store. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - - /** - * Retrieves message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the meta-data for. - * - * @return The message meta data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - - /** - * Retrieves a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the data chunk for. - * @param index The offset index of the data chunk within the message. - * - * @return A chunk of message data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java deleted file mode 100644 index 3ee49d58cf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.log4j.Logger; - -/** - * A context that the store can use to associate with a transactional context. For example, it could store - * some kind of txn id. - * - * @author Apache Software Foundation - */ -public class StoreContext -{ - private static final Logger _logger = Logger.getLogger(StoreContext.class); - - private String _name; - private Object _payload; - - public StoreContext() - { - _name = super.toString(); - } - - public StoreContext(String name) - { - _name = name; - } - - public Object getPayload() - { - return _payload; - } - - public void setPayload(Object payload) - { - _logger.debug("public void setPayload(Object payload = " + payload + "): called"); - _payload = payload; - } - - /** - * Prints out the transactional context as a string, mainly for debugging purposes. - * - * @return The transactional context as a string. - */ - public String toString() - { - return "<_name = " + _name + ", _payload = " + _payload + ">"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java deleted file mode 100644 index a4ed859fa7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transport; - -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.util.NewThreadExecutor; -import org.apache.qpid.configuration.Configured; - -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.socketReceiveBuffer", - defaultValue = "32767") - public int socketReceiveBufferSize; - - @Configured(path = "connector.socketWriteBuffer", - defaultValue = "32767") - public int socketWriteBuferSize; - - @Configured(path = "connector.tcpNoDelay", - defaultValue = "true") - public boolean tcpNoDelay; - - @Configured(path = "advanced.filterchain[@enableExecutorPool]", - defaultValue = "false") - public boolean enableExecutorPool; - - @Configured(path = "advanced.enablePooledAllocator", - defaultValue = "false") - public boolean enablePooledAllocator; - - @Configured(path = "advanced.enableDirectBuffers", - defaultValue = "false") - public boolean enableDirectBuffers; - - @Configured(path = "connector.ssl.enabled", - defaultValue = "false") - public boolean enableSSL; - - @Configured(path = "connector.ssl.sslOnly", - defaultValue = "true") - public boolean sslOnly; - - @Configured(path = "connector.ssl.port", - defaultValue = SSL_PORT) - public int sslPort; - - @Configured(path = "connector.ssl.keystorePath", - defaultValue = "none") - public String keystorePath; - - @Configured(path = "connector.ssl.keystorePassword", - defaultValue = "none") - public String keystorePassword; - - @Configured(path = "connector.ssl.certType", - defaultValue = "SunX509") - public String certType; - - public IoAcceptor createAcceptor() - { - return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java deleted file mode 100644 index e6ee8891f6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ /dev/null @@ -1,712 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoFilterAdapter; -import org.apache.mina.common.IoHandler; -import org.apache.mina.common.IoSession; -//import org.apache.mina.util.BlockingQueue; -//import org.apache.mina.util.ByteBufferUtil; -//import org.apache.mina.util.IdentityHashSet; -//import org.apache.mina.util.Queue; -//import org.apache.mina.util.Stack; -//import org.apache.mina.util.IdentityHashSet; - -/** - * 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 null; // threadNamePrefix; - } - - public int getPoolSize() - { - /* synchronized (poolSizeLock) - { - return poolSize; - }*/ - return 0; - } - - 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); - } - - */ - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java deleted file mode 100644 index 988f589339..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.StoreContext; - -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(StoreContext context) 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(StoreContext context) - { - // No-op can't be done here has this is before the message has been attempted to be delivered. - /*try - { - _msg.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - _returns.add(e); - }*/ - } - - public void rollback(StoreContext context) - { - // NO OP - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java deleted file mode 100644 index d899bb972c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DequeueRecord.java +++ /dev/null @@ -1,59 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.exception.*; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 17:13:07 - */ -public class DequeueRecord implements TransactionRecord -{ - - - public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - // nothing - } - - public void rollback(MessageStore store) - throws - InternalErrorException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void prepare(MessageStore store) - throws - InternalErrorException - { - //To change body of implemented methods use File | Settings | File Templates. - } -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java deleted file mode 100644 index 13f66fac5b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/DistributedTransactionalContext.java +++ /dev/null @@ -1,267 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.log4j.Logger; - -import javax.transaction.xa.Xid; -import java.util.List; -import java.util.LinkedList; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 15:58:07 - */ -public class DistributedTransactionalContext implements TransactionalContext -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(DistributedTransactionalContext.class); - private static final Object _lockXID = new Object(); - private static int _count = 0; - //======================================================================== - // Instance Fields - //======================================================================== - // the message store - final private MessageStore _messageStore; - // The transaction manager - final private TransactionManager _transactionManager; - // the store context - final private StoreContext _storeContext; - // the returned messages - final private List _returnMessages; - // for generating xids - private byte[] _txId = ("txid").getBytes(); - - public DistributedTransactionalContext(TransactionManager transactionManager, MessageStore messageStore, StoreContext storeContext, - List returnMessages) - { - _messageStore = messageStore; - _storeContext = storeContext; - _returnMessages = returnMessages; - _transactionManager = transactionManager; - } - - public void beginTranIfNecessary() - throws - AMQException - { - if (_storeContext.getPayload() == null) - { - synchronized (_lockXID) - { - // begin the transaction and pass the XID through the context - Xid xid = new XidImpl(("branch" + _count++).getBytes(), 1, _txId); - try - { - _transactionManager.begin(xid); - _storeContext.setPayload(xid); - } catch (Exception e) - { - throw new AMQException(null, "Problem during transaction begin", e); - } - } - } - } - - public void commit() - throws - AMQException - { - try - { - if (_storeContext.getPayload() != null) - { - _transactionManager.commit_one_phase((Xid) _storeContext.getPayload()); - } - } catch (Exception e) - { - throw new AMQException(null, "Problem during transaction commit", e); - } - finally - { - _storeContext.setPayload(null); - } - } - - public void rollback() - throws - AMQException - { - try - { - if (_storeContext.getPayload() != null) - { - _transactionManager.rollback((Xid) _storeContext.getPayload()); - } - } catch (Exception e) - { - throw new AMQException(null, "Problem during transaction rollback", e); - } - finally - { - _storeContext.setPayload(null); - } - } - - public void messageFullyReceived(boolean persistent) - throws - AMQException - { - // The message is now fully received, we can stage it before enqueued if necessary - } - - public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) - throws - AMQException - { - try - { - //The message has been delivered to the queues - message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); - // add a record in the transaction - _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new EnqueueRecord(_storeContext, message, queue, deliverFirst)); - } catch (Exception e) - { - throw new AMQException(null, "Problem during transaction rollback", e); - } - } - - public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, - boolean multiple, - final UnacknowledgedMessageMap unacknowledgedMessageMap) - throws - AMQException - { - beginTranIfNecessary(); - 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 - { - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + message.message.getMessageId()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - dequeue(message); - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException(null, "Multiple ack on delivery tag " + deliveryTag + " not known for channel", null); - } - - LinkedList acked = new LinkedList(); - unacknowledgedMessageMap.drainTo(acked, deliveryTag); - for (UnacknowledgedMessage msg : acked) - { - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + msg.message.getMessageId()); - } - //Message has been ack so discard it. This will dequeue and decrement the reference. - dequeue(msg); - } - } - } else - { - UnacknowledgedMessage msg; - msg = unacknowledgedMessageMap.remove(deliveryTag); - - if (msg == null) - { - _log.info("Single ack on delivery tag " + deliveryTag); - throw new AMQException(null, "Single ack on delivery tag " + deliveryTag, null); - } - - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + msg.message.getMessageId()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - dequeue(msg); - - if (_log.isDebugEnabled()) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - msg.message.getMessageId()); - } - } - } - - private void dequeue(UnacknowledgedMessage message) - throws - AMQException - { - // Dequeue the message from the strore - message.discard(_storeContext); - // Add a record - try - { - _transactionManager.getTransaction((Xid) _storeContext.getPayload()).addRecord(new DequeueRecord()); - } catch (Exception e) - { - throw new AMQException(null, "Problem during message dequeue", e); - } - } - - - public void messageProcessed(AMQProtocolSession protocolSession) - throws - AMQException - { - // The message has been sent - } - - public StoreContext getStoreContext() - { - return _storeContext; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java deleted file mode 100644 index 6770d8a8dd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/EnqueueRecord.java +++ /dev/null @@ -1,72 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 javax.transaction.xa.Xid; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 17:01:06 - */ -public class EnqueueRecord implements TransactionRecord -{ - private final StoreContext _storeContext; - private final AMQMessage _msg; - private final AMQQueue _queue; - private final boolean _first; - - EnqueueRecord(StoreContext storeContext, AMQMessage msg, AMQQueue q, boolean firsr) - { - _storeContext = storeContext; - _msg = msg; - _queue = q; - _first = firsr; - } - - public void commit(MessageStore store, Xid xid) - throws InternalErrorException, QueueDoesntExistException, InvalidXidException, UnknownXidException, - MessageDoesntExistException - { - try - { - _queue.process(_storeContext, _msg, _first); - } - catch (AMQException e) - { - throw new InternalErrorException(e.getMessage(), e); - } - } - - public void rollback(MessageStore store) throws InternalErrorException - { - // To change body of implemented methods use File | Settings | File Templates. - } - - public void prepare(MessageStore store) throws InternalErrorException - { - // To change body of implemented methods use File | Settings | File Templates. - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java deleted file mode 100644 index cc0cc7140b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCAbstractRecord.java +++ /dev/null @@ -1,93 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.exception.InternalErrorException; -import org.apache.qpid.server.exception.UnknownXidException; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 16-May-2007 - * Time: 15:15:18 - */ -public abstract class JDBCAbstractRecord implements TransactionRecord -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCEnqueueRecord.class); - // The record types - static public final int TYPE_DEQUEUE = 1; - static public final int TYPE_ENQUEUE = 2; - - // the queue - StorableQueue _queue; - // the message - StorableMessage _message; - - //======================================================================== - // Constructor - //======================================================================== - public JDBCAbstractRecord(StorableMessage m, StorableQueue queue) - { - _queue = queue; - _message = m; - } - - public abstract int getType(); - public long getMessageID() - { - return _message.getMessageId(); - } - - public int getQueueID() - { - return _queue.getQueueID(); - } - - public void rollback(MessageStore store) - throws - InternalErrorException - { - - } - - public void prepare(MessageStore store) - throws - InternalErrorException - { - } - - - public abstract void rollback(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException; - - public abstract void prepare(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java deleted file mode 100644 index c18a6a7fcf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCDequeueRecord.java +++ /dev/null @@ -1,85 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.JDBCStore; -import org.apache.qpid.server.exception.*; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 16-May-2007 - * Time: 14:50:34 - */ -public class JDBCDequeueRecord extends JDBCAbstractRecord -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCDequeueRecord.class); - - //======================================================================== - // Constructor - //======================================================================== - public JDBCDequeueRecord( StorableMessage m, StorableQueue queue) - { - super(m, queue); - } - - //======================================================================== - // Interface TransactionRecord - //======================================================================== - - public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - store.dequeue(xid, _message, _queue); - } - - public void rollback(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException - { - ((JDBCStore) store).rollbackDequeu(xid, _message, _queue); - } - - public void prepare(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException - { - ((JDBCStore) store).prepareDequeu(xid, _message, _queue); - } - - public int getType() - { - return TYPE_DEQUEUE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java deleted file mode 100644 index 4a4a23153e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCEnqueueRecord.java +++ /dev/null @@ -1,106 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.JDBCStore; -import org.apache.qpid.server.exception.*; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 16-May-2007 - * Time: 14:50:20 - */ -public class JDBCEnqueueRecord extends JDBCAbstractRecord -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCEnqueueRecord.class); - - //======================================================================== - // Constructor - //======================================================================== - public JDBCEnqueueRecord(StorableMessage m, StorableQueue queue) - { - super(m, queue); - } - - //======================================================================== - // Interface TransactionRecord - //======================================================================== - - public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - store.enqueue(xid, _message, _queue); - } - - public void rollback(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException - { - if (!_message.isEnqueued()) - { - // try to delete the message - try - { - store.destroy(_message); - } catch (Exception e) - { - throw new InternalErrorException("Problem when destoying message ", e); - } - } - } - - public void prepare(MessageStore store, Xid xid) - throws - InternalErrorException, - UnknownXidException - { - try - { - if (!_message.isEnqueued() && !_message.isStaged()) - { - store.stage(_message); - store.appendContent(_message, _message.getData(), 0, _message.getData().length); - } - } - catch (Exception e) - { - throw new InternalErrorException("Problem when persisting message ", e); - } - } - - public int getType() - { - return TYPE_ENQUEUE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java deleted file mode 100644 index cc35b50cc8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransaction.java +++ /dev/null @@ -1,196 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.server.messageStore.JDBCStore; - -import java.util.List; -import java.util.LinkedList; - -/** - * Created by Arnaud Simon - * Date: 16-May-2007 - * Time: 14:09:35 - */ -public class JDBCTransaction implements Transaction -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCTransaction.class); - public static long _xidId = 0; - //======================================================================== - // Instance Fields - //======================================================================== - // the associated connection - private JDBCStore.MyConnection _connection; - // Indicates whether this transaction is prepared - private boolean _prepared = false; - // Indicates that this transaction has heuristically rolled back - private boolean _heurRollBack = false; - // The list of records associated with this tx - private List _records = new LinkedList(); - // The date when this tx has been created. - private long _dateCreated; - // The timeout in seconds - private long _timeout; - // this instance xid id used as primary key - private long _thisxidId; - - //========================================================= - // Constructors - //========================================================= - - /** - * Create a transaction - * - */ - public JDBCTransaction() - { - _dateCreated = System.currentTimeMillis(); - _thisxidId = _xidId++; - } - - //========================================================= - // Getter and Setter methods - //========================================================= - - /** - * Notify that this tx has been prepared - */ - public void prepare() - { - _prepared = true; - } - - /** - * Specify whether this transaction is prepared - * - * @return true if this transaction is prepared, false otherwise - */ - public boolean isPrepared() - { - return _prepared; - } - - /** - * Notify that this tx has been heuristically rolled back - */ - public void heurRollback() - { - _heurRollBack = true; - } - - /** - * Specify whether this transaction has been heuristically rolled back - * - * @return true if this transaction has been heuristically rolled back , false otherwise - */ - public boolean isHeurRollback() - { - return _heurRollBack; - } - - /** - * Add an abstract record to this tx. - * - * @param record The record to be added - */ - public void addRecord(TransactionRecord record) - { - _records.add(record); - } - - /** - * Get the list of records associated with this tx. - * - * @return The list of records associated with this tx. - */ - public List getrecords() - { - return _records; - } - - /** - * Set this tx timeout - * - * @param timeout This tx timeout in seconds - */ - public void setTimeout(long timeout) - { - _timeout = timeout; - } - - /** - * Get this tx timeout - * - * @return This tx timeout in seconds - */ - public long getTimeout() - { - return _timeout; - } - - /** - * Specify whether this tx has expired - * - * @return true if this tx has expired, false otherwise - */ - public boolean hasExpired() - { - long currentDate = System.currentTimeMillis(); - boolean result = currentDate - _dateCreated > _timeout * 1000; - if (_log.isDebugEnabled() && result) - { - _log.debug("transaction has expired"); - } - return result; - } - - /** - * Get the JDBC connection - * @return The JDBC connection - */ - public JDBCStore.MyConnection getConnection() - { - return _connection; - } - - /** - * Set the JDBC connection - * - * @param connection The new JDBC connection - */ - public void setConnection(JDBCStore.MyConnection connection) - { - _connection = connection; - } - - /** - * This tx xid id used as primary key - * - * @return this tx xid id - */ - public long getXidID() - { - return _thisxidId; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java deleted file mode 100644 index 26ddbc881d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/JDBCTransactionManager.java +++ /dev/null @@ -1,554 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.JDBCStore; -import org.apache.qpid.server.exception.*; -import org.apache.commons.configuration.Configuration; - -import javax.transaction.xa.Xid; -import java.util.HashMap; -import java.util.Set; - - -/** - * Created by Arnaud Simon - * Date: 16-May-2007 - * Time: 14:05:45 - */ -public class JDBCTransactionManager implements TransactionManager -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(JDBCTransactionManager.class); - - private static final String ENVIRONMENT_TX_TIMEOUT = "environment-tx-timeout"; - - //======================================================================== - // Instance Fields - //======================================================================== - // The underlying jdbc message store - private JDBCStore _messagStore; - - // A map of XID/x - private HashMap _xidMap; - - // A map of in-doubt txs - private HashMap _indoubtXidMap; - - // A default tx timeout in sec - private int _defaultTimeout; // set to 10s if not specified in the config - - //=================================== - //=== Configuartion - //=================================== - - /** - * Configure this TM with the Message store implementation - * - * @param base The base element identifier from which all configuration items are relative. For example, if the base - * element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object - * @param messageStroe the message store associated with the TM - */ - public void configure(MessageStore messageStroe, String base, Configuration config) - { - _messagStore = (JDBCStore) messageStroe; - if (config != null) - { - _defaultTimeout = config.getInt(base + "." + ENVIRONMENT_TX_TIMEOUT, 120); - } else - { - _defaultTimeout = 120; - } - _log.info("Using transaction timeout of " + _defaultTimeout + " s"); - // get the list of in-doubt transactions - try - { - _indoubtXidMap = _messagStore.getAllInddoubt(); - _xidMap = _indoubtXidMap; - } catch (Exception e) - { - _log.fatal("Cannot recover in-doubt transactions", e); - } - } - - //=================================== - //=== TransactionManager interface - //=================================== - - /** - * Begin a transaction branch identified by Xid - * - * @param xid The xid of the branch to begin - * @return

        - *
      • XAFlag.ok: Normal execution. - *
      - * @throws InternalErrorException In case of internal problem - * @throws InvalidXidException The Xid is invalid - */ - public synchronized XAFlag begin(Xid xid) - throws - InternalErrorException, - InvalidXidException - { - if (xid == null) - { - throw new InvalidXidException(xid, "null xid"); - } - if (_xidMap.containsKey(xid)) - { - throw new InvalidXidException(xid, "Xid already exist"); - } - Transaction tx = new JDBCTransaction(); - tx.setTimeout(_defaultTimeout); - _xidMap.put(xid, tx); - return XAFlag.ok; - } - - /** - * Prepare the transaction branch identified by Xid - * - * @param xid The xid of the branch to prepare - * @return
        - *
      • XAFlag.ok: Normal execution. - *
      • XAFlag.rdonly: The transaction branch was read-only and has been committed. - *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspecied reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Prepare has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public synchronized XAFlag prepare(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException - { - // get the transaction - JDBCTransaction tx = getTransaction(xid); - XAFlag result = XAFlag.ok; - if (tx.isHeurRollback()) - { - result = XAFlag.rdonly; - } else if (tx.hasExpired()) - { - result = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } else - { - if (tx.isPrepared()) - { - throw new CommandInvalidException("TransactionImpl is already prepared"); - } - if (tx.getrecords().size() == 0) - { - // the tx was read only (no work has been done) - _xidMap.remove(xid); - result = XAFlag.rdonly; - } else - { - try - { - JDBCStore.MyConnection con = _messagStore.getConnection(); - tx.setConnection(con); - // save the xid - _messagStore.saveXID(con, tx, xid); - for (TransactionRecord record : tx.getrecords()) - { - if (record instanceof JDBCAbstractRecord) - { - ((JDBCAbstractRecord) record).prepare(_messagStore, xid); - _messagStore.saveRecord(con, tx, (JDBCAbstractRecord) record); - } else - { - record.prepare(_messagStore); - } - } - _messagStore.commitConnection(con); - tx.setConnection(null); - } catch (Exception e) - { - _log.error("Cannot prepare tx: " + xid); - throw new InternalErrorException("Cannot prepare tx: " + xid, e); - } - tx.prepare(); - } - } - return result; - } - - /** - * Rollback the transaction branch identified by Xid - * - * @param xid The xid of the branch to rollback - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • NOT SUPPORTED XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      • NOT SUPPORTED XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Rollback has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public synchronized XAFlag rollback(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException - { - // get the transaction - JDBCTransaction tx = getTransaction(xid); - XAFlag flag = XAFlag.ok; - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } else - { - try - { - JDBCStore.MyConnection con = _messagStore.getConnection(); - tx.setConnection(con); - for (TransactionRecord record : tx.getrecords()) - { - if (record instanceof JDBCAbstractRecord) - { - ((JDBCAbstractRecord) record).rollback(_messagStore, xid); - } else - { - record.rollback(_messagStore); - } - } - if (tx.isPrepared()) - { - _messagStore.deleteRecords(con, tx); - _messagStore.deleteXID(con, tx); - _messagStore.commitConnection(con); - } - _messagStore.commitConnection(con); - tx.setConnection(null); - } - catch (Exception e) - { - // this should not happen - _log.error("Error when rolling back distributed transaction: " + xid); - throw new InternalErrorException("Error when rolling back distributed transaction: " + xid, e); - } - removeTransaction(xid); - } - if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - } - return flag; - } - - /** - * Commit the transaction branch identified by Xid - * - * @param xid The xid of the branch to commit - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the specied transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Commit has been call in an improper context - * @throws UnknownXidException The Xid is unknown - * @throws org.apache.qpid.server.exception.NotPreparedException - * The branch was not prepared prior to commit - */ - public synchronized XAFlag commit(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException, - NotPreparedException - { - // get the transaction - JDBCTransaction tx = getTransaction(xid); - XAFlag flag = XAFlag.ok; - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } else if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } else - { - if (!tx.isPrepared()) - { - throw new NotPreparedException("TransactionImpl is not prepared"); - } - try - { - JDBCStore.MyConnection con = _messagStore.getConnection(); - tx.setConnection(con); - for (TransactionRecord record : tx.getrecords()) - { - try - { - record.commit(_messagStore, xid); - } catch (InvalidXidException e) - { - throw new UnknownXidException(xid, e); - } catch (Exception e) - { - // this should not happen as the queue and the message must exist - _log.error("Error when committing distributed transaction heurmix mode returned: " + xid); - flag = XAFlag.heurmix; - } - } - _messagStore.deleteRecords(con, tx); - _messagStore.deleteXID(con, tx); - _messagStore.commitConnection(con); - tx.setConnection(null); - } catch (Exception e) - { - // this should not happen - _log.error("Error when committing distributed transaction heurrb mode returned: " + xid); - throw new InternalErrorException("Error when committing distributed transaction: " + xid, e); - } - removeTransaction(xid); - } - return flag; - } - - /** - * One phase commit the transaction branch identified by Xid - * - * @param xid The xid of the branch to one phase commit - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • NOT SUPPORTED XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • NOT SUPPORTED XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • NOT SUPPORTED XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      • NOT SUPPORTED XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Commit has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public synchronized XAFlag commit_one_phase(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException - { - XAFlag flag = XAFlag.ok; - JDBCTransaction tx = getTransaction(xid); - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } else if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } else - { - try - { - // we do not need to prepare the tx - tx.prepare(); - JDBCStore.MyConnection con = _messagStore.getConnection(); - tx.setConnection(con); - for (TransactionRecord record : tx.getrecords()) - { - try - { - record.commit(_messagStore, xid); - } catch (InvalidXidException e) - { - throw new UnknownXidException(xid, e); - } catch (Exception e) - { - // this should not happen as the queue and the message must exist - _log.error("Error when committing transaction heurmix mode returned: " + xid); - flag = XAFlag.heurmix; - } - } - _messagStore.commitConnection(con); - tx.setConnection(null); - } catch (Exception e) - { - e.printStackTrace(); - throw new InternalErrorException("cannot commit transaxtion with xid " + xid + " " + e, e); - } - finally - { - removeTransaction(xid); - } - } - return flag; - } - - /** - * Forget about the transaction branch identified by Xid - * - * @param xid The xid of the branch to forget - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Forget has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public void forget(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException - { - synchronized (xid) - { - getTransaction(xid); - removeTransaction(xid); - } - } - - /** - * Set the transaction branch timeout value in seconds - * - * @param xid The xid of the branch to set timeout - * @param timeout Timeout value in seconds - * @throws InternalErrorException In case of internal problem - * @throws UnknownXidException The Xid is unknown - */ - public void setTimeout(Xid xid, long timeout) - throws - InternalErrorException, - UnknownXidException - { - JDBCTransaction tx = getTransaction(xid); - tx.setTimeout(timeout); - } - - /** - * Get the transaction branch timeout - * - * @param xid The xid of the branch to get the timeout from - * @return The timeout associated with the branch identified with xid - * @throws InternalErrorException In case of internal problem - * @throws UnknownXidException The Xid is unknown - */ - public long getTimeout(Xid xid) - throws - InternalErrorException, - UnknownXidException - { - JDBCTransaction tx = getTransaction(xid); - return tx.getTimeout(); - } - - /** - * Get a set of Xids the RM has prepared or heuristically completed - * - * @param startscan Indicates that recovery scan should start - * @param endscan Indicates that the recovery scan should end after returning the Xids - * @return Set of Xids the RM has prepared or heuristically completed - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Recover has been call in an improper context - */ - public Set recover(boolean startscan, boolean endscan) - throws - InternalErrorException, - CommandInvalidException - { - return _indoubtXidMap.keySet(); - } - - /** - * An error happened (for example the channel has been abruptly closed) - * with this Xid, TM must make a heuristical decision. - * - * @param xid The Xid of the transaction branch to be heuristically completed - * @throws UnknownXidException The Xid is unknown - * @throws InternalErrorException In case of internal problem - */ - public void HeuristicOutcome(Xid xid) - throws - UnknownXidException, - InternalErrorException - { - synchronized (xid) - { - JDBCTransaction tx = getTransaction(xid); - if (!tx.isPrepared()) - { - // heuristically rollback this tx - for (TransactionRecord record : tx.getrecords()) - { - record.rollback(_messagStore); - } - tx.heurRollback(); - } - // add this branch in the list of indoubt tx - _indoubtXidMap.put(xid, tx); - } - } - - - public JDBCTransaction getTransaction(Xid xid) - throws - UnknownXidException - { - Transaction tx = _xidMap.get(xid); - if (tx == null) - { - throw new UnknownXidException(xid, null); - } - return (JDBCTransaction) tx; - } - - //========================================================================== - //== Methods for Message Store - //========================================================================== - - /** - * Get the default tx timeout in seconds - * - * @return the default tx timeout in seconds - */ - public int getDefaultTimeout() - { - return _defaultTimeout; - } - //========================================================================== - //== Private Methods - //========================================================================== - - private void removeTransaction(Xid xid) - { - _xidMap.remove(xid); - _indoubtXidMap.remove(xid); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java deleted file mode 100644 index 4e684098d0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -import java.util.LinkedList; -import java.util.List; - -/** A transactional context that only supports local transactions. */ -public class LocalTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); - - private final TxnBuffer _txnBuffer = new TxnBuffer(); - - private final List _postCommitDeliveryList = new LinkedList(); - - /** - * 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 final StoreContext _storeContext; - - private boolean _inTran = false; - - /** Are there messages to deliver. NOT Has the message been delivered */ - private boolean _messageDelivered = false; - - private static class DeliveryDetails - { - public AMQMessage message; - public AMQQueue queue; - private boolean deliverFirst; - - public DeliveryDetails(AMQMessage message, AMQQueue queue, boolean deliverFirst) - { - this.message = message; - this.queue = queue; - this.deliverFirst = deliverFirst; - } - } - - public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, - List returnMessages) - { - _messageStore = messageStore; - _storeContext = storeContext; - _returnMessages = returnMessages; - // _txnBuffer.enlist(new StoreMessageOperation(messageStore)); - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void rollback() throws AMQException - { - _txnBuffer.rollback(_storeContext); - // Hack to deal with uncommitted non-transactional writes - if (_messageStore.inTran(_storeContext)) - { - _messageStore.abortTran(_storeContext); - _inTran = false; - } - - _postCommitDeliveryList.clear(); - } - - public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException - { - // A publication will result in the enlisting of several - // TxnOps. The first is an op that will store the message. - // Following that (and ordering is important), an op will - // be added for every queue onto which the message is - // enqueued. Finally a cleanup op will be added to decrement - // the reference associated with the routing. - // message.incrementReference(); - _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); - _messageDelivered = true; - _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); - /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); - if (_log.isDebugEnabled()) - { - _log.debug("Incrementing ref count on message and enlisting cleanup operation - id " + - message.getMessageId()); - } - message.incrementReference(); - _messageDelivered = true; - - */ - } - - private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException(null, "Ack with delivery tag " + deliveryTag + " not known for channel", null); - } - } - - 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) - { - beginTranIfNecessary(); - _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 messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - // Not required in this transactional context - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - if (_log.isDebugEnabled()) - { - _log.debug("Starting transaction on message store: " + this); - } - - _messageStore.beginTran(_storeContext); - _inTran = true; - } - } - - public void commit() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing transactional context: " + this); - } - - if (_ackOp != null) - { - - _messageDelivered = true; - _ackOp.consolidate(); - // already enlisted, after commit will reset regardless of outcome - _ackOp = null; - } - - if (_messageDelivered && _inTran) - { - _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); - } - // fixme fail commit here ... QPID-440 - try - { - _txnBuffer.commit(_storeContext); - } - finally - { - _messageDelivered = false; - _inTran = _messageStore.inTran(_storeContext); - } - - try - { - postCommitDelivery(_returnMessages); - } - catch (AMQException e) - { - // OK so what do we do now...? - _log.error("Failed to deliver messages following txn commit: " + e, e); - } - } - - private void postCommitDelivery(List returnMessages) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Performing post commit delivery"); - } - - try - { - for (DeliveryDetails dd : _postCommitDeliveryList) - { - dd.queue.process(_storeContext, dd.message, dd.deliverFirst); - - try - { - dd.message.checkDeliveredToConsumer(); - } - catch (NoConsumersException nce) - { - returnMessages.add(nce); - } - } - } - finally - { - _postCommitDeliveryList.clear(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java deleted file mode 100644 index abbd2ad923..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryDequeueRecord.java +++ /dev/null @@ -1,82 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.exception.*; -import org.apache.log4j.Logger; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 03-May-2007 - * Time: 13:59:47 - */ -public class MemoryDequeueRecord implements TransactionRecord -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryDequeueRecord.class); - // the queue - StorableQueue _queue; - // the message - StorableMessage _message; - - //======================================================================== - // Constructor - //======================================================================== - public MemoryDequeueRecord( StorableMessage m, StorableQueue queue) - { - _queue = queue; - _message = m; - } - - //======================================================================== - // Interface TransactionRecord - //======================================================================== - - public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - store.dequeue(null, _message, _queue); - } - - public void rollback(MessageStore store) - throws - InternalErrorException - { - // do nothing - } - - public void prepare(MessageStore store) - throws - InternalErrorException - { - // do nothing - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java deleted file mode 100644 index 159a5a471c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryEnqueueRecord.java +++ /dev/null @@ -1,82 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.qpid.server.messageStore.StorableMessage; -import org.apache.qpid.server.messageStore.StorableQueue; -import org.apache.qpid.server.exception.*; -import org.apache.log4j.Logger; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 03-May-2007 - * Time: 14:00:04 - */ -public class MemoryEnqueueRecord implements TransactionRecord -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryDequeueRecord.class); - - // the queue - StorableQueue _queue; - // the message - StorableMessage _message; - - //======================================================================== - // Constructor - //======================================================================== - public MemoryEnqueueRecord(StorableMessage m, StorableQueue queue) - { - _queue = queue; - _message = m; - } - //======================================================================== - // Interface TransactionRecord - //======================================================================== - - public void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException - { - store.enqueue(null, _message, _queue); - } - - public void rollback(MessageStore store) - throws - InternalErrorException - { - // do nothing - } - - public void prepare(MessageStore store) - throws - InternalErrorException - { - // do nothing - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java deleted file mode 100644 index 4cd52b1a72..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransaction.java +++ /dev/null @@ -1,158 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import java.util.List; -import java.util.LinkedList; - -/** - * Created by Arnaud Simon - * Date: 03-May-2007 - * Time: 14:30:41 - */ -public class MemoryTransaction implements Transaction -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryTransaction.class); - - //======================================================================== - // Instance Fields - //======================================================================== - // Indicates whether this transaction is prepared - private boolean _prepared = false; - // Indicates that this transaction has heuristically rolled back - private boolean _heurRollBack = false; - // The list of Abstract records associated with this tx - private List _records = new LinkedList(); - // The date when this tx has been created. - private long _dateCreated; - // The timeout in seconds - private long _timeout; - - //========================================================= - // Constructors - //========================================================= - /** - * Create a transaction that wraps a BDB tx and set the creation date. - * - */ - public MemoryTransaction() - { - _dateCreated = System.currentTimeMillis(); - } - - //========================================================= - // Getter and Setter methods - //========================================================= - /** - * Notify that this tx has been prepared - */ - public void prepare() - { - _prepared = true; - } - - /** - * Specify whether this transaction is prepared - * - * @return true if this transaction is prepared, false otherwise - */ - public boolean isPrepared() - { - return _prepared; - } - - /** - * Notify that this tx has been heuristically rolled back - */ - public void heurRollback() - { - _heurRollBack = true; - } - - /** - * Specify whether this transaction has been heuristically rolled back - * - * @return true if this transaction has been heuristically rolled back , false otherwise - */ - public boolean isHeurRollback() - { - return _heurRollBack; - } - - /** - * Add an abstract record to this tx. - * - * @param record The record to be added - */ - public void addRecord(TransactionRecord record) - { - _records.add(record); - } - - /** - * Get the list of records associated with this tx. - * - * @return The list of records associated with this tx. - */ - public List getrecords() - { - return _records; - } - - /** - * Set this tx timeout - * - * @param timeout This tx timeout in seconds - */ - public void setTimeout(long timeout) - { - _timeout = timeout; - } - - /** - * Get this tx timeout - * - * @return This tx timeout in seconds - */ - public long getTimeout() - { - return _timeout; - } - - /** - * Specify whether this tx has expired - * - * @return true if this tx has expired, false otherwise - */ - public boolean hasExpired() - { - long currentDate = System.currentTimeMillis(); - boolean result = currentDate - _dateCreated > _timeout * 1000; - if (_log.isDebugEnabled()) - { - _log.debug("transaction has expired"); - } - return result; - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java deleted file mode 100644 index 8b0d986d4b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/MemoryTransactionManager.java +++ /dev/null @@ -1,321 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import java.util.HashMap; -import java.util.Set; -import javax.transaction.xa.Xid; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.messageStore.MessageStore; - -/** - * Created by Arnaud Simon - * Date: 02-May-2007 - * Time: 08:41:33 - */ -public class MemoryTransactionManager implements TransactionManager -{ - // ======================================================================== - // Static Constants - // ======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(MemoryTransactionManager.class); - - private static final String ENVIRONMENT_TX_TIMEOUT = "environment-tx-timeout"; - - // ======================================================================== - // Instance Fields - // ======================================================================== - // The underlying BDB message store - private MessageStore _messagStore; - // A map of XID/BDBtx - private HashMap _xidMap; - // A map of in-doubt txs - private HashMap _indoubtXidMap; - - // A default tx timeout in sec - private int _defaultTimeout; // set to 10s if not specified in the config - - // ======================================================================== - // Interface TransactionManager - // ======================================================================== - public void configure(MessageStore messageStroe, String base, Configuration config) - { - _messagStore = messageStroe; - if (config != null) - { - _defaultTimeout = config.getInt(base + "." + ENVIRONMENT_TX_TIMEOUT, 10); - } - else - { - _defaultTimeout = 10; - } - - _log.info("Using transaction timeout of " + _defaultTimeout + " s"); - _xidMap = new HashMap(); - _indoubtXidMap = new HashMap(); - } - - public XAFlag begin(Xid xid) throws InternalErrorException, InvalidXidException - { - synchronized (xid) - { - if (xid == null) - { - throw new InvalidXidException(xid, "null xid"); - } - - if (_xidMap.containsKey(xid)) - { - throw new InvalidXidException(xid, "Xid already exist"); - } - - MemoryTransaction tx = new MemoryTransaction(); - tx.setTimeout(_defaultTimeout); - _xidMap.put(xid, tx); - - return XAFlag.ok; - } - } - - public XAFlag prepare(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException - { - synchronized (xid) - { - // get the transaction - MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); - XAFlag result = XAFlag.ok; - if (tx.hasExpired()) - { - result = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } - else - { - if (tx.isPrepared()) - { - throw new CommandInvalidException("TransactionImpl is already prepared", null); - } - - if (tx.getrecords().size() == 0) - { - // the tx was read only (no work has been done) - _xidMap.remove(xid); - result = XAFlag.rdonly; - } - else - { - // we need to persist the tx records - tx.prepare(); - } - } - - return result; - } - } - - public XAFlag rollback(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException - { - synchronized (xid) - { - // get the transaction - MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); - XAFlag flag = XAFlag.ok; - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } - else - { - for (TransactionRecord record : tx.getrecords()) - { - record.rollback(_messagStore); - } - - _xidMap.remove(xid); - } - - if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - } - - return flag; - } - } - - public XAFlag commit(Xid xid) - throws InternalErrorException, CommandInvalidException, UnknownXidException, NotPreparedException - { - synchronized (xid) - { - // get the transaction - MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); - XAFlag flag = XAFlag.ok; - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } - else if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } - else - { - if (!tx.isPrepared()) - { - throw new NotPreparedException("TransactionImpl is not prepared"); - } - - for (TransactionRecord record : tx.getrecords()) - { - try - { - record.commit(_messagStore, xid); - } - catch (InvalidXidException e) - { - throw new UnknownXidException(xid, e); - } - catch (Exception e) - { - // this should not happen as the queue and the message must exist - _log.error("Error when committing distributed transaction heurmix mode returned: " + xid); - flag = XAFlag.heurmix; - } - } - - _xidMap.remove(xid); - } - - return flag; - } - } - - public XAFlag commit_one_phase(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException - { - synchronized (xid) - { - XAFlag flag = XAFlag.ok; - MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); - if (tx.isHeurRollback()) - { - flag = XAFlag.heurrb; - } - else if (tx.hasExpired()) - { - flag = XAFlag.rbtimeout; - // rollback this tx branch - rollback(xid); - } - else - { - // we need to prepare the tx - tx.prepare(); - try - { - for (TransactionRecord record : tx.getrecords()) - { - try - { - record.commit(_messagStore, xid); - } - catch (InvalidXidException e) - { - throw new UnknownXidException(xid, e); - } - catch (Exception e) - { - // this should not happen as the queue and the message must exist - _log.error("Error when committing transaction heurmix mode returned: " + xid); - flag = XAFlag.heurmix; - } - } - } - finally - { - _xidMap.remove(xid); - } - } - - return flag; - } - } - - public void forget(Xid xid) throws InternalErrorException, CommandInvalidException, UnknownXidException - { - synchronized (xid) - { - _xidMap.remove(xid); - } - } - - public void setTimeout(Xid xid, long timeout) throws InternalErrorException, UnknownXidException - { - Transaction tx = getTransaction(xid); - tx.setTimeout(timeout); - } - - public long getTimeout(Xid xid) throws InternalErrorException, UnknownXidException - { - Transaction tx = getTransaction(xid); - - return tx.getTimeout(); - } - - public Set recover(boolean startscan, boolean endscan) throws InternalErrorException, CommandInvalidException - { - return _indoubtXidMap.keySet(); - } - - public void HeuristicOutcome(Xid xid) throws UnknownXidException, InternalErrorException - { - synchronized (xid) - { - MemoryTransaction tx = (MemoryTransaction) getTransaction(xid); - if (!tx.isPrepared()) - { - // heuristically rollback this tx - for (TransactionRecord record : tx.getrecords()) - { - record.rollback(_messagStore); - } - - tx.heurRollback(); - } - // add this branch in the list of indoubt tx - _indoubtXidMap.put(xid, tx); - } - } - - public Transaction getTransaction(Xid xid) throws UnknownXidException - { - Transaction tx = _xidMap.get(xid); - if (tx == null) - { - throw new UnknownXidException(xid, null); - } - - return tx; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java deleted file mode 100644 index 47c94114a3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -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.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** @author Apache Software Foundation */ -public class NonTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - - /** Channel is useful for logging */ - private final AMQChannel _channel; - - /** Where to put undeliverable messages */ - private final List _returnMessages; - - private Set _browsedAcks; - - private final MessageStore _messageStore; - - private StoreContext _storeContext; - - /** Whether we are in a transaction */ - private boolean _inTran; - - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, - List returnMessages, Set browsedAcks) - { - _channel = channel; - _storeContext = storeContext; - _returnMessages = returnMessages; - _messageStore = messageStore; - _browsedAcks = browsedAcks; - } - - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _messageStore.beginTran(_storeContext); - _inTran = true; - } - } - - public void commit() throws AMQException - { - // Does not apply to this context - } - - public void rollback() throws AMQException - { - // Does not apply to this context - } - - public void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException - { - try - { - //DTX removed - deliverFirst is to do with the position on the Queue not enqueuing!! - // This should be done in routingComplete -// if( ! deliverFirst ) -// { -// message.getMessageHandle().enqueue(_storeContext, message.getMessageId(), queue); -// } - queue.process(_storeContext, message, deliverFirst); - //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 - { - if (!_browsedAcks.contains(deliveryTag)) - { - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + message.message.getMessageId()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - message.discard(_storeContext); - } - else - { - _browsedAcks.remove(deliveryTag); - } - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } - else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException(null, "Multiple ack on delivery tag " + deliveryTag + " not known for channel", null); - } - - LinkedList acked = new LinkedList(); - unacknowledgedMessageMap.drainTo(acked, deliveryTag); - for (UnacknowledgedMessage msg : acked) - { - if (!_browsedAcks.contains(deliveryTag)) - { - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + msg.message.getMessageId()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); - } - else - { - _browsedAcks.remove(deliveryTag); - } - } - } - } - 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(null, "Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId(), null); - } - - if (!_browsedAcks.contains(deliveryTag)) - { - if (_log.isDebugEnabled()) - { - _log.debug("Discarding message: " + msg.message.getMessageId()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); - } - else - { - _browsedAcks.remove(deliveryTag); - } - - if (_log.isDebugEnabled()) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - msg.message.getMessageId()); - } - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - if (persistent) - { - //DTX removed this option. - _messageStore.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - _channel.processReturns(protocolSession); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java deleted file mode 100644 index 0e4d6c2030..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * A transactional operation to store messages in an underlying persistent store. When this operation - * commits it will do everything to ensure that all messages are safely committed to persistent - * storage. - */ -public class StoreMessageOperation implements TxnOp -{ - private final MessageStore _messsageStore; - - public StoreMessageOperation(MessageStore messageStore) - { - _messsageStore = messageStore; - } - - public void prepare(StoreContext context) throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit(StoreContext context) throws AMQException - { - _messsageStore.commitTran(context); - } - - public void rollback(StoreContext context) throws AMQException - { - _messsageStore.abortTran(context); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java deleted file mode 100644 index 2dc6ec2b77..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/Transaction.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 14:08:39 - */ -public interface Transaction -{ - - /** - * Add an abstract record to this tx. - * - * @param record The record to be added - */ - public void addRecord(TransactionRecord record); - - /** - * Set this tx timeout - * - * @param timeout This tx timeout in seconds - */ - public void setTimeout(long timeout); - - /** - * Get this tx timeout - * - * @return This tx timeout in seconds - */ - public long getTimeout(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java deleted file mode 100644 index bcbf2c9de4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionManager.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.messageStore.MessageStore; -import org.apache.commons.configuration.Configuration; - -import javax.transaction.xa.Xid; -import java.util.Set; - -/** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 13:29:31 - */ -public interface TransactionManager -{ - - /** - * Configure this TM with the Message store implementation - * - * @param base The base element identifier from which all configuration items are relative. For example, if the base - * element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object - * @param messageStroe the message store associated with the TM - */ - public void configure(MessageStore messageStroe, String base, Configuration config); - - /** - * Begin a transaction branch identified by Xid - * - * @param xid The xid of the branch to begin - * @return
        - *
      • XAFlag.ok: Normal execution. - *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspecified reason. - *
      - * @throws InternalErrorException In case of internal problem - * @throws InvalidXidException The Xid is invalid - */ - public XAFlag begin(Xid xid) - throws - InternalErrorException, - InvalidXidException; - - /** - * Prepare the transaction branch identified by Xid - * - * @param xid The xid of the branch to prepare - * @return
        - *
      • XAFlag.ok: Normal execution. - *
      • XAFlag.rdonly: The transaction branch was read-only and has been committed. - *
      • XAFlag.rbrollback: The transaction branch was marked rollback-only for an unspeci?ed reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Prepare has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public XAFlag prepare(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException; - - /** - * Rollback the transaction branch identified by Xid - * - * @param xid The xid of the branch to rollback - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      • XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Rollback has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public XAFlag rollback(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException; - - /** - * Commit the transaction branch identified by Xid - * - * @param xid The xid of the branch to commit - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Commit has been call in an improper context - * @throws UnknownXidException The Xid is unknown - * @throws NotPreparedException The branch was not prepared prior to commit - */ - public XAFlag commit(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException, - NotPreparedException; - - /** - * One phase commit the transaction branch identified by Xid - * - * @param xid The xid of the branch to one phase commit - * @return
        - *
      • XAFlag.ok: Normal execution, - *
      • XAFlag.heurhaz: Due to some failure, the work done on behalf of the specified transaction branch may have been heuristically completed. - *
      • XAFlag.heurcom: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was committed. - *
      • XAFlag.heurrb: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was rolled back. - *
      • XAFlag.heurmix: Due to a heuristic decision, the work done on behalf of the speci?ed transaction branch was partially committed and partially rolled back. - *
      • XAFlag.rbrollback: The broker marked the transaction branch rollback-only for an unspeci?ed reason. - *
      • XAFlag.rbtimeout: The work represented by this transaction branch took too long. - *
      - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Commit has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public XAFlag commit_one_phase(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException; - - /** - * Forget about the transaction branch identified by Xid - * - * @param xid The xid of the branch to forget - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Forget has been call in an improper context - * @throws UnknownXidException The Xid is unknown - */ - public void forget(Xid xid) - throws - InternalErrorException, - CommandInvalidException, - UnknownXidException; - - /** - * Set the transaction branch timeout value in seconds - * - * @param xid The xid of the branch to set timeout - * @param timeout Timeout value in seconds - * @throws InternalErrorException In case of internal problem - * @throws UnknownXidException The Xid is unknown - */ - public void setTimeout(Xid xid, long timeout) - throws - InternalErrorException, - UnknownXidException; - - /** - * Get the transaction branch timeout - * - * @param xid The xid of the branch to get the timeout from - * @return The timeout associated with the branch identified with xid - * @throws InternalErrorException In case of internal problem - * @throws UnknownXidException The Xid is unknown - */ - public long getTimeout(Xid xid) - throws - InternalErrorException, - UnknownXidException; - - /** - * Get a set of Xids the RM has prepared or heuristically completed - * - * @param startscan Indicates that recovery scan should start - * @param endscan Indicates that the recovery scan should end after returning the Xids - * @return Set of Xids the RM has prepared or heuristically completed - * @throws InternalErrorException In case of internal problem - * @throws CommandInvalidException Recover has been call in an improper context - */ - public Set recover(boolean startscan, boolean endscan) - throws - InternalErrorException, - CommandInvalidException; - - - /** - * An error happened (for example the channel has been abruptly closed) - * with this Xid, TM must make a heuristical decision. - * - * @param xid The Xid of the transaction branch to be heuristically completed - * @throws UnknownXidException The Xid is unknown - * @throws InternalErrorException In case of internal problem - */ - public void HeuristicOutcome(Xid xid) - throws - UnknownXidException, - InternalErrorException; - - /** - * Get the Transaction corresponding to the provided Xid - * @param xid The Xid of the transaction to ger - * @return The transaction with the provided Xid - * @throws UnknownXidException The Xid is unknown - */ - public Transaction getTransaction(Xid xid) - throws - UnknownXidException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java deleted file mode 100644 index 3f6f1d6b8e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionRecord.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.server.exception.*; -import org.apache.qpid.server.messageStore.MessageStore; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 25-Apr-2007 - * Time: 14:12:17 - */ -public interface TransactionRecord -{ - /** - * Commit this record. - * - * @param store the store to be used during commit - * @param xid the xid of the tx branch - * @throws org.apache.qpid.server.exception.InternalErrorException in case of internal problem - * @throws org.apache.qpid.server.exception.QueueDoesntExistException the queue does not exist - * @throws org.apache.qpid.server.exception.InvalidXidException the xid is invalid - * @throws org.apache.qpid.server.exception.UnknownXidException the xid is unknonw - * @throws org.apache.qpid.server.exception.MessageDoesntExistException the message does not exist - */ - public abstract void commit(MessageStore store, Xid xid) - throws - InternalErrorException, - QueueDoesntExistException, - InvalidXidException, - UnknownXidException, - MessageDoesntExistException; - - /** - * rollback this record - * - * @param store the store to be used - * @throws InternalErrorException In case of internal error - */ - public abstract void rollback(MessageStore store) - throws - InternalErrorException; - - /** - * Prepare this record - * - * @param store the store to be used - * @throws InternalErrorException In case of internal error - */ - public abstract void prepare(MessageStore store) - throws - InternalErrorException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java deleted file mode 100644 index fee25c07df..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -/** - * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. - * Different levels of transactional support for the delivery of messages may be provided by different implementations - * of this interface. - * - *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. - * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} - * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. - * - *

      - *
      CRC Card
      Responsibilities - *
      Explicitly accept a transaction start notification. - *
      Commit all pending operations in a transaction. - *
      Rollback all pending operations in a transaction. - *
      Deliver a message to a queue as part of a transaction. - *
      Redeliver a message to a queue as part of a transaction. - *
      Mark a message as acknowledged as part of a transaction. - *
      Accept notification that a message has been completely received as part of a transaction. - *
      Accept notification that a message has been fully processed as part of a transaction. - *
      Associate a message store context with this transaction context. - *
      - * - * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional - * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them - * somewhere else, a seperate interface for example. - * - * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides - * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any - * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean - * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be - * conceptually neater. - * - * For example: - *

      - * public interface Transactional
      - * {
      - *    public void commit();
      - *    public void rollback();
      - * }
      - *
      - * public interface TransactionalQueue extends Transactional, SizeableQueue
      - * {}
      - *
      - * public class Queues
      - * {
      - *    ...
      - *    // For transactional messaging, take a transactional view onto the queue.
      - *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      - *
      - *    // For non-transactional messaging, take a non-transactional view onto the queue.
      - *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      - * }
      - * 
      - */ -public interface TransactionalContext -{ - /** - * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} - * should automatically begin the next transaction in the chain. - * - * @throws AMQException If the transaction cannot be started for any reason. - */ - void beginTranIfNecessary() throws AMQException; - - /** - * Makes all pending operations on the transaction permanent and visible. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void commit() throws AMQException; - - /** - * Erases all pending operations on the transaction. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void rollback() throws AMQException; - - /** - * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a - * redelivery, and should be placed on the front of the queue. - * - *

      This is an 'enqueue' operation. - * - * @param message The message to deliver. - * @param queue The queue to deliver the message to. - * @param deliverFirst true to place the message on the front of the queue for redelivery, false - * for normal FIFO message ordering. - * - * @throws AMQException If the message cannot be delivered for any reason. - */ - void deliver(AMQMessage message, AMQQueue queue, boolean deliverFirst) throws AMQException; - - /** - * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by - * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' - * flag is set, in which case an acknowledgement up to the latest delivered message should be done. - * - *

      This is a 'dequeue' operation. - * - * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement - * up to the latest message. - * @param lastDeliveryTag The latest message delivered. - * @param multiple true if all message ids up the acknowledged one or latest delivered, are - * to be acknowledged, false otherwise. - * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message - * from. - * - * @throws AMQException If the message cannot be acknowledged for any reason. - */ - void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - - /** - * Notifies the transactional context that a message has been fully received. The actual message that was received - * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, - * flushing its data to disk. - * - * @param persistent true if the received message is persistent, false otherwise. - * - * @throws AMQException If the fully received event cannot be processed for any reason. - */ - void messageFullyReceived(boolean persistent) throws AMQException; - - /** - * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual - * message that was delivered is not specified. This event may be used to trigger a process related to the - * outcome of the delivery of the message, for example, cleaning up failed deliveries. - * - * @param protocolSession The protocol session of the deliverable message. - * - * @throws AMQException If the message processed event cannot be handled for any reason. - */ - void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; - - /** - * Gets the message store context associated with this transactional context. - * - * @return The message store context associated with this transactional context. - */ - StoreContext getStoreContext(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java deleted file mode 100644 index 405c233552..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** Holds a list of TxnOp instance representing transactional operations. */ -public class TxnBuffer -{ - private final List _ops = new ArrayList(); - private static final Logger _log = Logger.getLogger(TxnBuffer.class); - - public TxnBuffer() - { - } - - public void commit(StoreContext context) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); - } - - if (prepare(context)) - { - for (TxnOp op : _ops) - { - op.commit(context); - } - } - _ops.clear(); - } - - private boolean prepare(StoreContext context) - { - for (int i = 0; i < _ops.size(); i++) - { - TxnOp op = _ops.get(i); - try - { - op.prepare(context); - } - 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(StoreContext context) throws AMQException - { - for (TxnOp op : _ops) - { - op.rollback(context); - } - _ops.clear(); - } - - public void enlist(TxnOp op) - { - _ops.add(op); - } - - public void cancel(TxnOp op) - { - _ops.remove(op); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java deleted file mode 100644 index 919c078cf0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** - * This provides the abstraction of an individual operation within a - * transaction. It is used by the TxnBuffer class. - */ -public interface TxnOp -{ - /** - * Do the part of the operation that updates persistent state - */ - public void prepare(StoreContext context) throws AMQException; - /** - * Complete the operation started by prepare. Can now update in - * memory state or make netork transfers. - */ - public void commit(StoreContext context) throws AMQException; - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback(StoreContext context) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java deleted file mode 100644 index 8214ab7dac..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XAFlag.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.apache.qpid.server.txn; - -/** - * Created by Arnaud Simon - * Date: 29-Mar-2007 - * Time: 14:57:01 - */ -public enum XAFlag -{ - rbrollback(1, "XA-RBROLLBACK", "The rollback was caused by an unspecified reason"), - rbtimeout(2, "XA-RBTIMEOUT", "The transaction branch took too long"), - heurhaz(3, "XA-HEURHAZ", "The transaction branch may have been heuristically completed"), - heurcom(4, "XA-HEURCOM", "The transaction branch has been heuristically committed"), - heurrb(5, "XA-HEURRB", "The transaction branch has been heuristically rolled back"), - heurmix(6, "XA-HEURMIX", "The transaction branch has been heuristically committed and rolled back"), - rdonly(7, "XA-RDONLY", "The transaction branch was read-only and has been committed"), - ok(8, "XA-OK", "Normal execution"); - - private final int _code; - - private final String _name; - - private final String _description; - - XAFlag(int code, String name, String description) - { - _code = code; - _name = name; - _description = description; - } - - //============================================== - // Getter methods - //============================================== - - public int getCode() - { - return _code; - } - - public String getName() - { - return _name; - } - - public String getDescription() - { - return _description; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java deleted file mode 100644 index 91db1d97c0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/XidImpl.java +++ /dev/null @@ -1,210 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.txn; - - -import org.apache.log4j.Logger; - -import javax.transaction.xa.Xid; - -/** - * Created by Arnaud Simon - * Date: 03-Apr-2007 - * Time: 20:32:55 - */ -public class XidImpl implements Xid -{ - //======================================================================== - // Static Constants - //======================================================================== - // The logger for this class - private static final Logger _log = Logger.getLogger(XidImpl.class); - - //======================================================================== - // Instance Fields - //======================================================================== - - //the transaction branch identifier part of XID as an array of bytes - private byte[] m_branchQualifier; - - // the format identifier part of the XID. - private int m_formatID; - - // the global transaction identifier part of XID as an array of bytes. - private byte[] m_globalTransactionID; - - //======================================================================== - // Constructor(s) - //======================================================================== - - /** - * Create new Xid. - */ - public XidImpl() - { - - } - - /** - * Create new XidImpl from an existing Xid. - *

      - * This is usually called when an application server provides some implementation - * of the Xid interface and we need to cast this into our own XidImpl. - * - * @param xid the xid to cloning - */ - public XidImpl(Xid xid) - { - if (_log.isDebugEnabled()) - { - _log.debug("Cloning Xid"); - } - m_branchQualifier = xid.getBranchQualifier(); - m_formatID = xid.getFormatId(); - m_globalTransactionID = xid.getGlobalTransactionId(); - } - - /** - * Create a new Xid. - * - * @param branchQualifier The transaction branch identifier part of XID as an array of bytes. - * @param format The format identifier part of the XID. - * @param globalTransactionID The global transaction identifier part of XID as an array of bytes. - */ - public XidImpl(byte[] branchQualifier, int format, byte[] globalTransactionID) - { - if (_log.isDebugEnabled()) - { - _log.debug("creating Xid"); - } - m_branchQualifier = branchQualifier; - m_formatID = format; - m_globalTransactionID = globalTransactionID; - } - -//======================================================================== - - // Xid interface implementation - //======================================================================== - /** - * Format identifier. O means the OSI CCR format. - * - * @return Global transaction identifier. - */ - public byte[] getGlobalTransactionId() - { - return m_globalTransactionID; - } - - /** - * Obtain the transaction branch identifier part of XID as an array of bytes. - * - * @return Branch identifier part of XID. - */ - public byte[] getBranchQualifier() - { - return m_branchQualifier; - } - - /** - * Obtain the format identifier part of the XID. - * - * @return Format identifier. O means the OSI CCR format. - */ - public int getFormatId() - { - return m_formatID; - } - -//======================================================================== -// Object operations -//======================================================================== - - /** - * Indicates whether some other Xid is "equal to" this one. - *

      - * Two Xids are equal if and only if their three elementary parts are equal - * - * @param o the object to compare this XidImpl against. - * @return code>true if the XidImpl are equal; false otherwise. - */ - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o instanceof XidImpl) - { - XidImpl other = (XidImpl) o; - if (m_formatID == other.getFormatId()) - { - if (m_branchQualifier.length == other.getBranchQualifier().length) - { - for (int i = 0; i < m_branchQualifier.length; i++) - { - if (m_branchQualifier[i] != other.getBranchQualifier()[i]) - { - return false; - } - } - - if (m_globalTransactionID.length == other.getGlobalTransactionId().length) - { - for (int i = 0; i < m_globalTransactionID.length; i++) - { - if (m_globalTransactionID[i] != other.getGlobalTransactionId()[i]) - { - return false; - } - } - // everithing is equal - return true; - } - } - } - } - return false; - } - - /** - * Returns a hash code for this Xid. - *

      - * As this object is used as a key entry in a hashMap it is necessary to provide an implementation - * of hashcode in order to fulfill the following aspect of the general contract of - * {@link Object#hashCode()} that is: - *

        - *
      • If two objects are equal according to the equals(Object) - * method, then calling the hashCode method on each of - * the two objects must produce the same integer result. - *
      - *

      - * The hash code for a - * XidImpl object is computed as - *

      -     *  hashcode( globalTransactionID ) + hashcode( branchQualifier ) + formatID
      -     * 
      - * - * @return a hash code value for this object. - */ - public int hashCode() - { - return (new String(m_globalTransactionID)).hashCode() + (new String(m_branchQualifier)).hashCode() + m_formatID; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java deleted file mode 100644 index e730e2f3c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Iterator; - -import org.apache.log4j.Logger; - -public class CircularBuffer implements Iterable -{ - - private static final Logger _logger = Logger.getLogger(CircularBuffer.class); - - 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) - { - _logger.info(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); - _logger.info(buffer); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java deleted file mode 100644 index cf5e71a6e2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue -{ - public int size() - { - if (isEmpty()) - { - return 0; - } - else - { - return 1; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java deleted file mode 100644 index eda97e0ed2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; - -/** - * Dynamic proxy that records invocations in a fixed size circular buffer, - * dumping details on hitting an exception. - *

      - * Useful in debugging. - *

      - */ -public class LoggingProxy implements InvocationHandler -{ - private final Object _target; - private final CircularBuffer _log; - - public LoggingProxy(Object target, int size) - { - _target = target; - _log = new CircularBuffer(size); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - try - { - entered(method, args); - Object result = method.invoke(_target, args); - returned(method, result); - return result; - } - catch(InvocationTargetException e) - { - dump(); - throw e.getTargetException(); - } - } - - void dump() - { - _log.dump(); - } - - CircularBuffer getBuffer() - { - return _log; - } - - private synchronized void entered(Method method, Object[] args) - { - if (args == null) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); - } - } - - private synchronized void returned(Method method, Object result) - { - if (method.getReturnType() == Void.TYPE) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); - } - } - - public Object getProxy(Class... c) - { - return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); - } - - public int getBufferSize() { - return _log.size(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java deleted file mode 100644 index 4985c12dbb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Properties; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.MapConfiguration; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AllowAll; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -public class NullApplicationRegistry extends ApplicationRegistry -{ - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private VirtualHostRegistry _virtualHostRegistry; - - private AccessManager _accessManager; - - private PrincipalDatabaseManager _databaseManager; - - - public NullApplicationRegistry() - { - super(new MapConfiguration(new HashMap())); - } - - public void initialise() throws Exception - { - //DTX MessageStore -// _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.MemoryMessageStore"); - _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); - _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.MemoryTransactionManager"); - // _configuration.addProperty("store.class", "org.apache.qpid.server.messageStore.JDBCStore"); - // _configuration.addProperty("txn.class", "org.apache.qpid.server.txn.JDBCTransactionManager"); - - Properties users = new Properties(); - - users.put("guest", "guest"); - - _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); - - _accessManager = new AllowAll(); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _managedObjectRegistry = new NoopManagedObjectRegistry(); - _virtualHostRegistry = new VirtualHostRegistry(); - VirtualHost dummyHost = new VirtualHost("test", getConfiguration()); - _virtualHostRegistry.registerVirtualHost(dummyHost); - _virtualHostRegistry.setDefaultVirtualHostName("test"); - - _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes - - } - - public Configuration getConfiguration() - { - return _configuration; - } - - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public PrincipalDatabaseManager getDatabaseManager() - { - return _databaseManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public Collection getVirtualHostNames() - { - String[] hosts = {"test"}; - return Arrays.asList(hosts); - } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } -} - - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java deleted file mode 100644 index 85d804457e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; - -/** - * The management interface exposed to allow management of an Exchange. - * @version 0.1 - */ -public interface ManagedVirtualHost -{ - static final String TYPE = "VirtualHost"; - - /** - * Returns the name of the managed virtualHost. - * @return the name of the exchange. - * @throws java.io.IOException - */ - @MBeanAttribute(name="Name", description= TYPE + " Name") - String getName() throws IOException; - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java deleted file mode 100644 index 53844ccc4b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.txn.TransactionManager; -import org.apache.qpid.server.security.access.AccessManager; -import org.apache.qpid.server.security.access.AccessManagerImpl; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - - private final String _name; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - private TransactionManager _transactionManager; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private AccessManager _accessManager; - - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, "VirtualHost"); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - - } // End of MBean class - - /** - * Used for testing only - * @param name - * @param store - * - * @throws Exception - */ - public VirtualHost(String name, MessageStore store) throws Exception - { - this(name, null, store); - } - - /** - * Normal Constructor - * - * @param name - * @param hostConfig - * - * @throws Exception - */ - public VirtualHost(String name, Configuration hostConfig) throws Exception - { - this(name, hostConfig, null); - } - - private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception - { - _name = name; - - _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); - - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - _exchangeRegistry = new DefaultExchangeRegistry(this); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseTransactionManager(hostConfig); - initialiseMessageStore(hostConfig); - } - - _exchangeRegistry.initialise(); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - - _accessManager = new AccessManagerImpl(name, hostConfig); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - } - - private void initialiseMessageStore(Configuration config) throws Exception - { - String messageStoreClass = config.getString("store.class"); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - //DTX MessageStore -// _messageStore.configure(this, _transactionManager, "store", config); - _messageStore.configure(this, "store", config); - } - - private void initialiseTransactionManager(Configuration config) throws Exception - { - String transactionManagerClass = config.getString("txn.class"); - Class clazz = Class.forName(transactionManagerClass); - Object o = clazz.newInstance(); - - if (!(o instanceof TransactionManager)) - { - throw new ClassCastException("Transaction Manager class must implement " + TransactionManager.class + ". Class " + clazz + - " does not."); - } - _transactionManager = (TransactionManager) o; - } - - - public T getConfiguredObject(Class instanceType, Configuration config) - { - T instance; - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); - } - Configurator.configure(instance); - - return instance; - } - - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public TransactionManager getTransactionManager() - { - return _transactionManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public AccessManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - if (_messageStore != null) - { - _messageStore.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java deleted file mode 100644 index 27917fac8a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -public class VirtualHostRegistry -{ - private final Map _registry = new ConcurrentHashMap(); - - - private String _defaultVirtualHostName; - - public synchronized void registerVirtualHost(VirtualHost host) throws Exception - { - if(_registry.containsKey(host.getName())) - { - throw new Exception("Virtual Host with name " + host.getName() + " already registered."); - } - _registry.put(host.getName(),host); - } - - public VirtualHost getVirtualHost(String name) - { - if(name == null || name.trim().length() == 0 ) - { - name = getDefaultVirtualHostName(); - } - - return _registry.get(name); - } - - private String getDefaultVirtualHostName() - { - return _defaultVirtualHostName; - } - - public void setDefaultVirtualHostName(String defaultVirtualHostName) - { - _defaultVirtualHostName = defaultVirtualHostName; - } - - - public Collection getVirtualHosts() - { - return new ArrayList(_registry.values()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java deleted file mode 100644 index edc900f401..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore; - -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.commands.Clear; -import org.apache.qpid.tools.messagestore.commands.Command; -import org.apache.qpid.tools.messagestore.commands.Copy; -import org.apache.qpid.tools.messagestore.commands.Dump; -import org.apache.qpid.tools.messagestore.commands.Help; -import org.apache.qpid.tools.messagestore.commands.List; -import org.apache.qpid.tools.messagestore.commands.Load; -import org.apache.qpid.tools.messagestore.commands.Quit; -import org.apache.qpid.tools.messagestore.commands.Select; -import org.apache.qpid.tools.messagestore.commands.Show; -import org.apache.qpid.tools.messagestore.commands.Move; -import org.apache.qpid.tools.messagestore.commands.Purge; -import org.apache.qpid.tools.utils.CommandParser; -import org.apache.qpid.tools.utils.Console; -import org.apache.qpid.tools.utils.SimpleCommandParser; -import org.apache.qpid.tools.utils.SimpleConsole; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * MessageStoreTool. - */ -public class MessageStoreTool -{ - /** Text outputted at the start of each console.*/ - private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; - - /** I/O Wrapper. */ - protected Console _console; - - /** Batch mode flag. */ - protected boolean _batchMode; - - /** Internal State object. */ - private State _state = new State(); - - private HashMap _commands = new HashMap(); - - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); - - /** Loaded configuration file. */ - private Configuration _config; - - /** Control used for main run loop. */ - private boolean _running = true; - private boolean _initialised = false; - - //---------------------------------------------------------------------------------------------------/ - - public static void main(String[] args) throws Configuration.InitException - { - - MessageStoreTool tool = new MessageStoreTool(args); - - tool.start(); - } - - - public MessageStoreTool(String[] args) throws Configuration.InitException - { - this(args, System.in, System.out); - } - - public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException - { - BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); - BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); - - Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); - _batchMode = false; - - _console = new SimpleConsole(consoleWriter, consoleReader); - - _config = new Configuration(); - - setOptions(); - _config.processCommandline(args); - } - - - private void setOptions() - { - 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 By " - + "default looks for a file named " - + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) - .withLongOpt("config") - .create("c"); - - _config.setOption(help); - _config.setOption(version); - _config.setOption(configFile); - } - - public State getState() - { - return _state; - } - - public Map getCommands() - { - return _commands; - } - - public void setConfigurationFile(String configfile) throws Configuration.InitException - { - _config.loadConfig(new File(configfile)); - setup(); - } - - public Console getConsole() - { - return _console; - } - - public void setConsole(Console console) - { - _console = console; - } - - /** - * Simple ShutdownHook to cleanly shutdown the databases - */ - class ShutdownHook implements Runnable - { - MessageStoreTool _tool; - - ShutdownHook(MessageStoreTool messageStoreTool) - { - _tool = messageStoreTool; - } - - public void run() - { - _tool.quit(); - } - } - - public void quit() - { - _running = false; - - if (_initialised) - { - ApplicationRegistry.remove(1); - } - - _console.println("...exiting"); - - _console.close(); - } - - public void setBatchMode(boolean batchmode) - { - _batchMode = batchmode; - } - - /** - * Main loop - */ - protected void start() - { - setup(); - - if (!_initialised) - { - System.exit(1); - } - - _console.println(""); - - _console.println(BOILER_PLATE); - - runCLI(); - } - - private void setup() - { - loadDefaultVirtualHosts(); - - loadCommands(); - - _state.clearAll(); - } - - private void loadCommands() - { - _commands.clear(); - //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands - _commands.put("close", new Clear(this)); - _commands.put("copy", new Copy(this)); - _commands.put("dump", new Dump(this)); - _commands.put("help", new Help(this)); - _commands.put("list", new List(this)); - _commands.put("load", new Load(this)); - _commands.put("move", new Move(this)); - _commands.put("purge", new Purge(this)); - _commands.put("quit", new Quit(this)); - _commands.put("select", new Select(this)); - _commands.put("show", new Show(this)); - } - - private void loadDefaultVirtualHosts() - { - final File configFile = _config.getConfigFile(); - - loadVirtualHosts(configFile); - } - - private void loadVirtualHosts(File configFile) - { - - if (!configFile.exists()) - { - _devlog.error("Config file not found:" + configFile.getAbsolutePath()); - return; - } - else - { - _devlog.debug("using config file :" + configFile.getAbsolutePath()); - } - - try - { - ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); - - ApplicationRegistry.remove(1); - - ApplicationRegistry.initialise(registry); - - checkMessageStores(); - _initialised = true; - } - catch (ConfigurationException e) - { - _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); - e.printStackTrace(); - } - catch (Exception e) - { - _console.println("Unable to load configuration due to: " + e.getMessage()); - e.printStackTrace(); - } - - - } - - private void checkMessageStores() - { - Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); - - boolean warning = false; - for (VirtualHost vhost : vhosts) - { - if (vhost.getMessageStore() instanceof MemoryMessageStore) - { - _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " - + "Changes will not persist."); - warning = true; - } - } - - if (warning) - { - _console.println(""); - _console.println("Please ensure you are using the correct config file currently using '" - + _config.getConfigFile().getAbsolutePath() + "'"); - _console.println("New config file can be specifed by 'load ' or -c on the commandline."); - _console.println(""); - } - } - - private void runCLI() - { - while (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - String[] args = _console.readCommand(); - - while (args != null) - { - exec(args); - - if (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - args = _console.readCommand(); - } - } - } - } - - private void printPrompt() - { - _console.print(prompt()); - } - - - /** - * Execute a script (batch mode). - * - * @param script The file script - */ - protected void runScripts(String script) - { - //Store Current State - boolean oldBatch = _batchMode; - CommandParser oldParser = _console.getCommandParser(); - setBatchMode(true); - - try - { - _devlog.debug("Running script '" + script + "'"); - - _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); - - start(); - } - catch (java.io.FileNotFoundException e) - { - _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); - } - - //Restore previous state - _console.setCommandParser(oldParser); - setBatchMode(oldBatch); - } - - public String prompt() - { - String state = _state.toString(); - if (state != null && state.length() != 0) - { - return state + ":bdb$ "; - } - else - { - return "bdb$ "; - } - } - - /** - * Execute the command. - * - * @param args [command, arg0, arg1...]. - */ - protected void exec(String[] args) - { - // Comment lines start with a # - if (args.length == 0 || args[0].startsWith("#")) - { - return; - } - - final String command = args[0]; - - Command cmd = _commands.get(command); - - if (cmd == null) - { - _console.println("Command not understood: " + command); - } - else - { - cmd.execute(args); - } - } - - - /** - * Displays usage info. - */ - protected static void help() - { - System.out.println(BOILER_PLATE); - System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); - System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); - } - - - /** - * This class is used to store the current state of the tool. - * - * This is then interrogated by the various commands to augment their behaviour. - * - * - */ - public class State - { - private VirtualHost _vhost = null; - private AMQQueue _queue = null; - private Exchange _exchange = null; - private java.util.List _msgids = null; - - public State() - { - } - - public void setQueue(AMQQueue queue) - { - _queue = queue; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public void setVhost(VirtualHost vhost) - { - _vhost = vhost; - } - - public VirtualHost getVhost() - { - return _vhost; - } - - public Exchange getExchange() - { - return _exchange; - } - - public void setExchange(Exchange exchange) - { - _exchange = exchange; - } - - public String toString() - { - StringBuilder status = new StringBuilder(); - - if (_vhost != null) - { - status.append(_vhost.getName()); - - if (_exchange != null) - { - status.append("["); - status.append(_exchange.getName()); - status.append("]"); - - if (_queue != null) - { - status.append("->'"); - status.append(_queue.getName()); - status.append("'"); - - if (_msgids != null) - { - status.append(printMessages()); - } - } - } - } - - return status.toString(); - } - - - public String printMessages() - { - StringBuilder sb = new StringBuilder(); - - Long previous = null; - - Long start = null; - for (Long id : _msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(id); - start = null; - } - else - { - sb.append(","); - sb.append(previous); - } - } - } - - previous = id; - } - - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(_msgids.get(_msgids.size() - 1)); - } - else - { - sb.append(","); - sb.append(previous); - } - - // surround list in () - sb.replace(0, 1, "("); - sb.append(")"); - return sb.toString(); - } - - public void clearAll() - { - _vhost = null; - clearExchange(); - } - - public void clearExchange() - { - _exchange = null; - clearQueue(); - } - - public void clearQueue() - { - _queue = null; - clearMessages(); - } - - public void clearMessages() - { - _msgids = null; - } - - /** - * A common location to provide parsing of the message id string - * utilised by a number of the commands. - * The String is comma separated list of ids that can be individual ids - * or a range (4-10) - * - * @param msgString string of msg ids to parse 1,2,4-10 - */ - public void setMessages(String msgString) - { - StringTokenizer tok = new StringTokenizer(msgString, ","); - - if (tok.hasMoreTokens()) - { - _msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - _msgids.add(l); - } - } - } - else - { - _msgids.add(Long.parseLong(next)); - } - } - - } - - public void setMessages(java.util.List msgids) - { - _msgids = msgids; - } - - public java.util.List getMessages() - { - return _msgids; - } - }//Class State - -}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java deleted file mode 100644 index 5444197cb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -public abstract class AbstractCommand implements Command -{ - protected Console _console; - protected MessageStoreTool _tool; - - public AbstractCommand(MessageStoreTool tool) - { - _console = tool.getConsole(); - _tool = tool; - } - - public void setOutput(Console out) - { - _console = out; - } - - protected void commandError(String message, String[] args) - { - _console.print(getCommand() + " : " + message); - - if (args != null) - { - for (int i = 1; i < args.length; i++) - { - _console.print(args[i]); - } - } - _console.println(""); - _console.println(help()); - } - - - public abstract String help(); - - public abstract String usage(); - - public abstract String getCommand(); - - - public abstract void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java deleted file mode 100644 index b0006b3fe6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Clear extends AbstractCommand -{ - public Clear(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Clears any selection."; - } - - public String usage() - { - return "clear [ all | virtualhost | exchange | queue | msgs ]"; - } - - public String getCommand() - { - return "clear"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 1) - { - doClose("all"); - } - else - { - doClose(args[1]); - } - } - - private void doClose(String type) - { - if (type.equals("virtualhost") - || type.equals("all")) - { - _tool.getState().clearAll(); - } - - if (type.equals("exchange")) - { - _tool.getState().clearExchange(); - } - - if (type.equals("queue")) - { - _tool.getState().clearQueue(); - } - - if (type.equals("msgs")) - { - _tool.getState().clearMessages(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java deleted file mode 100644 index bfa775a34a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.utils.Console; - -public interface Command -{ - public void setOutput(Console out); - - public String help(); - - public abstract String usage(); - - String getCommand(); - - public void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java deleted file mode 100644 index a5b3a87616..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Copy extends Move -{ - public Copy(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Copy messages between queues.";/*\n" + - "The currently selected message set will be copied to the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; */ - } - - public String usage() - { - return "copy to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "copy"; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) - { - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java deleted file mode 100644 index a0fe54994b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.commons.codec.binary.Hex; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.io.UnsupportedEncodingException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -public class Dump extends Show -{ - private static final int LINE_SIZE = 8; - private static final String DEFAULT_ENCODING = "utf-8"; - private static final boolean SPACE_BYTES = true; - private static final String BYTE_SPACER = " "; - private static final String NON_PRINTING_ASCII_CHAR = "?"; - - protected boolean _content = true; - - public Dump(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Dump selected message content. Default: show=content"; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; - } - - public String getCommand() - { - return "dump"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _content = arg.contains("content") || arg.contains("all"); - } - } - - parseArgs(args); - } - - performShow(); - } - - - protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - List display = new LinkedList(); - - List hex = new LinkedList(); - List ascii = new LinkedList(); - display.add(hex); - display.add(ascii); - - for (AMQMessage msg : messages) - { - if (!includeMsg(msg, msgids)) - { - continue; - } - - //Add divider between messages - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - // Show general message information - hex.add(Show.Columns.ID.name()); - ascii.add("" +msg.getMessageId()); - - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - if (showRouting) - { - addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); - } - if (showHeaders) - { - addShowInformation(hex, ascii, msg, "Headers", false, true, false); - } - if (showMessageHeaders) - { - addShowInformation(hex, ascii, msg, null, false, false, true); - } - - // Add Content Body seciont - hex.add("Content Body"); - ascii.add(""); - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - Iterator bodies = msg.getContentBodyIterator(); - if (bodies.hasNext()) - { - - hex.add("Hex"); - hex.add(Console.ROW_DIVIDER); - - - ascii.add("ASCII"); - ascii.add(Console.ROW_DIVIDER); - - while (bodies.hasNext()) - { - ContentChunk chunk = (ContentChunk) bodies.next(); - - //Duplicate so we don't destroy original data :) - ByteBuffer hexBuffer = chunk.getData().duplicate(); - - ByteBuffer charBuffer = hexBuffer.duplicate(); - - Hex hexencoder = new Hex(); - - while (hexBuffer.hasRemaining()) - { - byte[] line = new byte[LINE_SIZE]; - - int bufsize = hexBuffer.remaining(); - if (bufsize < LINE_SIZE) - { - hexBuffer.get(line, 0, bufsize); - } - else - { - bufsize = line.length; - hexBuffer.get(line); - } - - byte[] encoded = hexencoder.encode(line); - - try - { - String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); - String hexLine = ""; - - int strKength = encStr.length(); - for (int c = 0; c < strKength; c++) - { - hexLine += encStr.charAt(c); - - if (c % 2 == 1 && SPACE_BYTES) - { - hexLine += BYTE_SPACER; - } - } - - hex.add(hexLine); - } - catch (UnsupportedEncodingException e) - { - _console.println(e.getMessage()); - return null; - } - } - - while (charBuffer.hasRemaining()) - { - String asciiLine = ""; - - for (int pos = 0; pos < LINE_SIZE; pos++) - { - if (charBuffer.hasRemaining()) - { - byte ch = charBuffer.get(); - - if (isPrintable(ch)) - { - asciiLine += (char) ch; - } - else - { - asciiLine += NON_PRINTING_ASCII_CHAR; - } - - if (SPACE_BYTES) - { - asciiLine += BYTE_SPACER; - } - } - else - { - break; - } - } - - ascii.add(asciiLine); - } - } - } - else - { - List result = new LinkedList(); - - display.add(result); - result.add("No ContentBodies"); - } - } - - // if hex is empty then we have no data to display - if (hex.size() == 0) - { - return null; - } - - return display; - } - - private void addShowInformation(List column1, List column2, AMQMessage msg, - String title, boolean routing, boolean headers, boolean messageHeaders) - { - List single = new LinkedList(); - single.add(msg); - - List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); - - //Reformat data - if (title != null) - { - column1.add(title); - column2.add(""); - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - // look at all columns in the routing Data - for (List item : routingData) - { - // the item should be: - // Title - // *divider - // value - // otherwise we can't reason about the correct value - if (item.size() == 3) - { - //Filter out the columns we are not interested in. - - String columnName = item.get(0).toString(); - - if (!(columnName.equals(Show.Columns.ID.name()) - || columnName.equals(Show.Columns.Size.name()))) - { - column1.add(columnName); - column2.add(item.get(2).toString()); - } - } - } - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - private boolean isPrintable(byte c) - { - return c > 31 && c < 127; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java deleted file mode 100644 index 0f9546541b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.Map; - -public class Help extends AbstractCommand -{ - public Help(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Provides detailed help on commands."; - } - - public String getCommand() - { - return "help"; - } - - public String usage() - { - return "help []"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - Command command = _tool.getCommands().get(args[1]); - if (command != null) - { - _console.println(command.help()); - _console.println("Usage:" + command.usage()); - } - else - { - commandError("Command not found: ", args); - } - } - else - { - java.util.List data = new LinkedList(); - - java.util.List commandName = new LinkedList(); - java.util.List commandDescription = new LinkedList(); - - data.add(commandName); - data.add(commandDescription); - - //Set up Headers - commandName.add("Command"); - commandDescription.add("Description"); - - commandName.add(Console.ROW_DIVIDER); - commandDescription.add(Console.ROW_DIVIDER); - - //Add current Commands with descriptions - Map commands = _tool.getCommands(); - - for (Command command : commands.values()) - { - commandName.add(command.getCommand()); - commandDescription.add(command.help()); - } - - _console.printMap("Available Commands", data); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java deleted file mode 100644 index df8b59ec19..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.Collection; -import java.util.LinkedList; - -public class List extends AbstractCommand -{ - - public List(MessageStoreTool tool) - { - super(tool); - } - - public void setOutput(Console out) - { - _console = out; - } - - public String help() - { - return "list available items."; - } - - public String usage() - { - return "list queues [] | exchanges | bindings [] | all"; - } - - public String getCommand() - { - return "list"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - if ((args[1].equals("exchanges")) - || (args[1].equals("queues")) - || (args[1].equals("bindings")) - || (args[1].equals("all"))) - { - if (args.length == 2) - { - doList(args[1]); - } - else if (args.length == 3) - { - doList(args[1], args[2]); - } - } - else - { - commandError("Unknown options. ", args); - } - } - else if (args.length < 2) - { - doList("all"); - } - else - { - doList(args[1]); - } - } - - private void doList(String... listItem) - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - listVirtualHosts(); - return; - } - - VirtualHost vhost = _tool.getState().getVhost(); - - java.util.List data = null; - - if (listItem[0].equals("queues")) - { - if (listItem.length > 1) - { - data = listQueues(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - data = listQueues(vhost, exchange); - } - } - - if (listItem[0].equals("exchanges")) - { - data = listExchanges(vhost); - } - - if (listItem[0].equals("bindings")) - { - - if (listItem.length > 1) - { - data = listBindings(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - - data = listBindings(vhost, exchange); - } - } - - if (data != null) - { - if (data.size() == 1) - { - _console.println("No '" + listItem[0] + "' to display,"); - } - else - { - _console.displayList(true, data.toArray(new String[0])); - } - } - - - if (listItem[0].equals("all")) - { - - boolean displayed = false; - Exchange exchange = _tool.getState().getExchange(); - - //Do the display here for each one so that they are pretty printed - data = listQueues(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (exchange == null) - { - data = listExchanges(vhost); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - } - - data = listBindings(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (!displayed) - { - _console.println("Nothing to list"); - } - } - } - - private void listVirtualHosts() - { - Collection vhosts = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHosts(); - - String[] data = new String[vhosts.size() + 1]; - - data[0] = "Available VirtualHosts"; - - int index = 1; - for (VirtualHost vhost : vhosts) - { - data[index] = vhost.getName(); - index++; - } - - _console.displayList(true, data); - } - - private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) - { - return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listBindings(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueueNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Current Bindings"); - - for (AMQShortString queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.toString()); - } - } - else - { - data.add(queue.toString()); - } - } - - return data; - } - - private java.util.List listExchanges(VirtualHost vhost) - { - Collection queues = vhost.getExchangeRegistry().getExchangeNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Exchanges"); - - for (AMQShortString queue : queues) - { - data.add(queue.toString()); - } - - return data; - } - - private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) - { - return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listQueues(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueues(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Queues"); - - for (AMQQueue queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.getName().toString()); - } - } - else - { - data.add(queue.getName().toString()); - } - } - - if (exchange != null) - { - if (queues.size() == 1) - { - return null; - } - } - - return data; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java deleted file mode 100644 index 244a311c30..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Load extends AbstractCommand -{ - public Load(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Loads specified broker configuration file."; - } - - public String usage() - { - return "load "; - } - - public String getCommand() - { - return "load"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 2) - { - _console.print("load " + args[1] + ": additional options not understood:"); - for (int i = 2; i < args.length; i++) - { - _console.print(args[i] + " "); - } - _console.println(""); - } - else if (args.length < 2) - { - _console.println("Enter Configuration file."); - String input = _console.readln(); - if (input != null) - { - doLoad(input); - } - else - { - _console.println("Did not recognise config file."); - } - } - else - { - doLoad(args[1]); - } - } - - private void doLoad(String configfile) - { - _console.println("Loading Configuration:" + configfile); - - try - { - _tool.setConfigurationFile(configfile); - } - catch (Configuration.InitException e) - { - _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java deleted file mode 100644 index 25cff27445..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.LinkedList; -import java.util.List; - -public class Move extends AbstractCommand -{ - - /** - * Since the Coopy command is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - protected StoreContext _storeContext = new StoreContext(); - - public Move(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Move messages between queues.";/*\n" + - "The currently selected message set will be moved to the specifed queue.\n" + - "Alternatively the values can be provided on the command line.";*/ - } - - public String usage() - { - return "move to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "move"; - } - - public void execute(String... args) - { - AMQQueue toQueue = null; - AMQQueue fromQueue = _tool.getState().getQueue(); - java.util.List msgids = _tool.getState().getMessages(); - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("to=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("from=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("msgids=")) - { - String msgidStr = arg.substring(arg.indexOf("=") + 1); - - // Record the current message selection - java.util.List currentIDs = _tool.getState().getMessages(); - - // Use the ToolState class to perform the messasge parsing - _tool.getState().setMessages(msgidStr); - msgids = _tool.getState().getMessages(); - - // Reset the original selection of messages - _tool.getState().setMessages(currentIDs); - } - } - } - - if (!checkRequirements(fromQueue, toQueue, msgids)) - { - return; - } - - processIDs(fromQueue, toQueue, msgids); - } - - private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - Long previous = null; - Long start = null; - - if (msgids == null) - { - msgids = allMessageIDs(fromQueue); - } - - if (msgids == null || msgids.size() == 0) - { - _console.println("No Messages to move."); - return; - } - - for (long id : msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - //move a range of ids - doCommand(fromQueue, start, id, toQueue); - start = null; - } - else - { - //move a single id - doCommand(fromQueue, id, id, toQueue); - } - } - } - - previous = id; - } - - if (start != null) - { - //move a range of ids - doCommand(fromQueue, start, previous, toQueue); - } - } - - private List allMessageIDs(AMQQueue fromQueue) - { - List ids = new LinkedList(); - - if (fromQueue != null) - { - List messages = fromQueue.getMessagesOnTheQueue(); - if (messages != null) - { - for (AMQMessage msg : messages) - { - ids.add(msg.getMessageId()); - } - } - } - - return ids; - } - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) - { - if (toQueue == null) - { - _console.println("Destination queue not specifed."); - _console.println(usage()); - return false; - } - - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) - { - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java deleted file mode 100644 index f187e26593..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Purge extends Move -{ - public Purge(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Purge messages from a queue.\n" + - "The currently selected message set will be purged from the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; - } - - public String usage() - { - return "purge from= [msgids=]"; - } - - public String getCommand() - { - return "purge"; - } - - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) - { - fromQueue.removeMessagesFromQueue(start, end, _storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java deleted file mode 100644 index a81bc07c38..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Quit extends AbstractCommand -{ - public Quit(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Quit the tool."; - } - - public String usage() - { - return "quit"; - } - - public String getCommand() - { - return "quit"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals("quit"); - - _tool.quit(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java deleted file mode 100644 index fd7d4c3f13..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.LinkedList; -import java.util.StringTokenizer; - -public class Select extends AbstractCommand -{ - - public Select(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Perform a selection."; - } - - public String usage() - { - return "select virtualhost |exchange |queue | msg id="; - } - - public String getCommand() - { - return "select"; - } - - public void execute(String... args) - { - assert args.length > 2; - assert args[0].equals("select"); - - if (args.length < 3) - { - if (args[1].equals("show")) - { - doSelect(args[1], null); - } - else - { - _console.print("select : unknown command:"); - _console.println(help()); - } - } - else - { - if (args[1].equals("virtualhost") - || args[1].equals("vhost") - || args[1].equals("exchange") - || args[1].equals("queue") - || args[1].equals("msg") - ) - { - doSelect(args[1], args[2]); - } - else - { - _console.println(help()); - } - } - } - - private void doSelect(String type, String item) - { - if (type.equals("virtualhost")) - { - - VirtualHost vhost = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHost(item); - - if (vhost == null) - { - _console.println("Virtualhost '" + item + "' not found."); - } - else - { - _tool.getState().setVhost(vhost); - } - } - - if (type.equals("exchange")) - { - - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - - Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); - - if (exchange == null) - { - _console.println("Exchange '" + item + "' not found."); - } - else - { - _tool.getState().setExchange(exchange); - } - - if (_tool.getState().getQueue() != null) - { - if (!exchange.isBound(_tool.getState().getQueue())) - { - _tool.getState().setQueue(null); - } - } - } - - if (type.equals("queue")) - { - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); - - if (queue == null) - { - _console.println("Queue '" + item + "' not found."); - } - else - { - _tool.getState().setQueue(queue); - - if (_tool.getState().getExchange() == null) - { - for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) - { - Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); - if (exchange.isBound(queue)) - { - _tool.getState().setExchange(exchange); - break; - } - } - } - - //remove the message selection - _tool.getState().setMessages((java.util.List) null); - } - } - - if (type.equals("msg")) - { - if (item.startsWith("id=")) - { - StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); - - java.util.List msgids = null; - - if (tok.hasMoreTokens()) - { - msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - msgids.add(l); - } - } - } - else - { - msgids.add(Long.parseLong(next)); - } - } - - _tool.getState().setMessages(msgids); - } - - } - - if (type.equals("show")) - { - _console.println(_tool.getState().toString()); - if (_tool.getState().getMessages() != null) - { - _console.print("Msgs:"); - for (Long l : _tool.getState().getMessages()) - { - _console.print(" " + l); - } - _console.println(""); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java deleted file mode 100644 index 8487afba76..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.List; - -public class Show extends AbstractCommand -{ - protected boolean _amqHeaders = false; - protected boolean _routing = false; - protected boolean _msgHeaders = false; - - public Show(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Shows the messages headers."; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; - } - - public String getCommand() - { - return "show"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 2) - { - parseArgs("all"); - } - else - { - parseArgs(args); - } - - performShow(); - } - - protected void parseArgs(String... args) - { - List msgids = null; - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); - _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); - _routing = arg.contains("routing") || arg.contains("all"); - } - - if (arg.startsWith("id=")) - { - _tool.getState().setMessages(msgids); - } - }//for args - }// if args > 2 - } - - protected void performShow() - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); - return; - } - - AMQQueue _queue = _tool.getState().getQueue(); - - List msgids = _tool.getState().getMessages(); - - if (_queue != null) - { - List messages = _queue.getMessagesOnTheQueue(); - if (messages == null || messages.size() == 0) - { - _console.println("No messages on queue"); - return; - } - - List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); - if (data != null) - { - _console.printMap(null, data); - } - else - { - String message = "No data to display."; - if (msgids != null) - { - message += " Is message selection correct? " + _tool.getState().printMessages(); - } - _console.println(message); - } - - } - else - { - _console.println("No Queue specified to show."); - } - } - - /** - * Create the list data for display from the messages. - * - * @param msgids The list of message ids to display - * @param messages A list of messages to format and display. - * @param showHeaders should the header info be shown - * @param showRouting show the routing info be shown - * @param showMessageHeaders show the msg headers be shown - * @return the formated data lists for printing - */ - protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - // Currenly exposed message properties -// //Printing the content Body -// msg.getContentBodyIterator(); -// //Print the Headers -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); -// -// //Print out all the property names -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); -// -// msg.getMessageId(); -// msg.getSize(); -// msg.getArrivalTime(); - -// msg.getDeliveredSubscription(); -// msg.getDeliveredToConsumer(); -// msg.getMessageHandle(); -// msg.getMessageId(); -// msg.getMessagePublishInfo(); -// msg.getPublisher(); - -// msg.getStoreContext(); -// msg.isAllContentReceived(); -// msg.isPersistent(); -// msg.isRedelivered(); -// msg.isRejectedBy(); -// msg.isTaken(); - - //Header setup - - List data = new LinkedList(); - - List id = new LinkedList(); - data.add(id); - id.add(Columns.ID.name()); - id.add(Console.ROW_DIVIDER); - - List exchange = new LinkedList(); - List routingkey = new LinkedList(); - List immediate = new LinkedList(); - List mandatory = new LinkedList(); - if (showRouting) - { - data.add(exchange); - exchange.add(Columns.Exchange.name()); - exchange.add(Console.ROW_DIVIDER); - - data.add(routingkey); - routingkey.add(Columns.RoutingKey.name()); - routingkey.add(Console.ROW_DIVIDER); - - data.add(immediate); - immediate.add(Columns.isImmediate.name()); - immediate.add(Console.ROW_DIVIDER); - - data.add(mandatory); - mandatory.add(Columns.isMandatory.name()); - mandatory.add(Console.ROW_DIVIDER); - } - - List size = new LinkedList(); - List appid = new LinkedList(); - List clusterid = new LinkedList(); - List contenttype = new LinkedList(); - List correlationid = new LinkedList(); - List deliverymode = new LinkedList(); - List encoding = new LinkedList(); - List arrival = new LinkedList(); - List expiration = new LinkedList(); - List priority = new LinkedList(); - List propertyflag = new LinkedList(); - List replyto = new LinkedList(); - List timestamp = new LinkedList(); - List type = new LinkedList(); - List userid = new LinkedList(); - List ispersitent = new LinkedList(); - List isredelivered = new LinkedList(); - List isdelivered = new LinkedList(); - - data.add(size); - size.add(Columns.Size.name()); - size.add(Console.ROW_DIVIDER); - - if (showHeaders) - { - data.add(ispersitent); - ispersitent.add(Columns.isPersistent.name()); - ispersitent.add(Console.ROW_DIVIDER); - - data.add(isredelivered); - isredelivered.add(Columns.isRedelivered.name()); - isredelivered.add(Console.ROW_DIVIDER); - - data.add(isdelivered); - isdelivered.add(Columns.isDelivered.name()); - isdelivered.add(Console.ROW_DIVIDER); - - data.add(appid); - appid.add(Columns.App_ID.name()); - appid.add(Console.ROW_DIVIDER); - - data.add(clusterid); - clusterid.add(Columns.Cluster_ID.name()); - clusterid.add(Console.ROW_DIVIDER); - - data.add(contenttype); - contenttype.add(Columns.Content_Type.name()); - contenttype.add(Console.ROW_DIVIDER); - - data.add(correlationid); - correlationid.add(Columns.Correlation_ID.name()); - correlationid.add(Console.ROW_DIVIDER); - - data.add(deliverymode); - deliverymode.add(Columns.Delivery_Mode.name()); - deliverymode.add(Console.ROW_DIVIDER); - - data.add(encoding); - encoding.add(Columns.Encoding.name()); - encoding.add(Console.ROW_DIVIDER); - - data.add(arrival); - expiration.add(Columns.Arrival.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(expiration); - expiration.add(Columns.Expiration.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(priority); - priority.add(Columns.Priority.name()); - priority.add(Console.ROW_DIVIDER); - - data.add(propertyflag); - propertyflag.add(Columns.Property_Flag.name()); - propertyflag.add(Console.ROW_DIVIDER); - - data.add(replyto); - replyto.add(Columns.ReplyTo.name()); - replyto.add(Console.ROW_DIVIDER); - - data.add(timestamp); - timestamp.add(Columns.Timestamp.name()); - timestamp.add(Console.ROW_DIVIDER); - - data.add(type); - type.add(Columns.Type.name()); - type.add(Console.ROW_DIVIDER); - - data.add(userid); - userid.add(Columns.UserID.name()); - userid.add(Console.ROW_DIVIDER); - } - - List msgHeaders = new LinkedList(); - if (showMessageHeaders) - { - data.add(msgHeaders); - msgHeaders.add(Columns.MsgHeaders.name()); - msgHeaders.add(Console.ROW_DIVIDER); - } - - //Add create the table of data - for (AMQMessage msg : messages) - { - if (!includeMsg(msg, msgids)) - { - continue; - } - - id.add("" + msg.getMessageId()); - - size.add("" + msg.getSize()); - - arrival.add("" + msg.getArrivalTime()); - - try - { - ispersitent.add(msg.isPersistent() ? "true" : "false"); - } - catch (AMQException e) - { - ispersitent.add("n/a"); - } - - isredelivered.add(msg.isRedelivered() ? "true" : "false"); - - isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); - -// msg.getMessageHandle(); - - BasicContentHeaderProperties headers = null; - - try - { - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); - } - catch (AMQException e) - { - //ignore -// commandError("Unable to read properties for message: " + e.getMessage(), null); - } - - if (headers != null) - { - String appidS = headers.getAppIdAsString(); - appid.add(appidS == null ? "null" : appidS); - - String clusterS = headers.getClusterIdAsString(); - clusterid.add(clusterS == null ? "null" : clusterS); - - String contentS = headers.getContentTypeAsString(); - contenttype.add(contentS == null ? "null" : contentS); - - String correlationS = headers.getCorrelationIdAsString(); - correlationid.add(correlationS == null ? "null" : correlationS); - - deliverymode.add("" + headers.getDeliveryMode()); - - AMQShortString encodeSS = headers.getEncoding(); - encoding.add(encodeSS == null ? "null" : encodeSS.toString()); - - expiration.add("" + headers.getExpiration()); - - FieldTable headerFT = headers.getHeaders(); - msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); - - priority.add("" + headers.getPriority()); - propertyflag.add("" + headers.getPropertyFlags()); - - AMQShortString replytoSS = headers.getReplyTo(); - replyto.add(replytoSS == null ? "null" : replytoSS.toString()); - - timestamp.add("" + headers.getTimestamp()); - - AMQShortString typeSS = headers.getType(); - type.add(typeSS == null ? "null" : typeSS.toString()); - - AMQShortString useridSS = headers.getUserId(); - userid.add(useridSS == null ? "null" : useridSS.toString()); - - MessagePublishInfo info = null; - try - { - info = msg.getMessagePublishInfo(); - } - catch (AMQException e) - { - //ignore - } - - if (info != null) - { - AMQShortString exchangeSS = info.getExchange(); - exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); - - AMQShortString routingkeySS = info.getRoutingKey(); - routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); - - immediate.add(info.isImmediate() ? "true" : "false"); - mandatory.add(info.isMandatory() ? "true" : "false"); - } - -// msg.getPublisher(); -- only used in clustering -// msg.getStoreContext(); -// msg.isAllContentReceived(); - - }// if headers!=null - -// need to access internal map and do lookups. -// msg.isTaken(); -// msg.getDeliveredSubscription(); -// msg.isRejectedBy(); - - } - - // if id only had the header and the divider in it then we have no data to display - if (id.size() == 2) - { - return null; - } - return data; - } - - protected boolean includeMsg(AMQMessage msg, List msgids) - { - if (msgids == null) - { - return true; - } - - Long msgid = msg.getMessageId(); - - boolean found = false; - - if (msgids != null) - { - //check msgid is in msgids - for (Long l : msgids) - { - if (l.equals(msgid)) - { - found = true; - break; - } - } - } - return found; - } - - public enum Columns - { - ID, - Size, - Exchange, - RoutingKey, - isImmediate, - isMandatory, - isPersistent, - isRedelivered, - isDelivered, - App_ID, - Cluster_ID, - Content_Type, - Correlation_ID, - Delivery_Mode, - Encoding, - Arrival, - Expiration, - Priority, - Property_Flag, - ReplyTo, - Timestamp, - Type, - UserID, - MsgHeaders - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java deleted file mode 100644 index c27c52eb8e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.security; - -import org.apache.commons.codec.binary.Base64; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; - -public class Passwd -{ - public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException - { - if (args.length != 2) - { - System.out.println("Passwd "); - System.exit(0); - } - - byte[] data = args[1].getBytes("utf-8"); - - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - Base64 b64 = new Base64(); - - byte[] encoded = b64.encode(digest); - - output(args[0], encoded); - } - - private static void output(String user, byte[] encoded) throws IOException - { - -// File passwdFile = new File("qpid.passwd"); - - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java deleted file mode 100644 index 986fea32cc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -public interface CommandParser -{ - /** - * If there is more than one command received on the last parse request. - * - * Subsequent calls to parse will utilise this input rather than reading new data from the input source - * @return boolean - */ - boolean more(); - - /** - * True if the currently parsed command has been requested as a background operation - * - * @return boolean - */ - boolean isBackground(); - - /** - * Parses user commands, and groups tokens in the - * String[] format that all Java main's love. - * - * If more than one command is provided in one input line then the more() method will return true. - * A subsequent call to parse() will continue to parse that input line before reading new input. - * - * @return input split in args[] format; null if eof. - * @throws java.io.IOException if there is a problem reading from the input stream - */ - String[] parse() throws java.io.IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java deleted file mode 100644 index cf457d1ea5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.util.List; - -public interface Console -{ - public enum CellFormat - { - CENTRED, LEFT, RIGHT - } - - public static String ROW_DIVIDER = "*divider"; - - public void print(String... message); - - public void println(String... message); - - public String readln(); - - /** - * Reads and parses the command line. - * - * - * @return The next command or null - */ - public String[] readCommand(); - - public CommandParser getCommandParser(); - - public void setCommandParser(CommandParser parser); - - /** - * - * Prints the list of String nicely. - * - * +-------------+ - * | Heading | - * +-------------+ - * | Item 1 | - * | Item 2 | - * | Item 3 | - * +-------------+ - * - * @param hasTitle should list[0] be used as a heading - * @param list The list of Strings to display - */ - public void displayList(boolean hasTitle, String... list); - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * +----------------------------+ (*divider) - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - void printMap(String title, List entries); - - - public void close(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java deleted file mode 100644 index 09444ccdd7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.StringTokenizer; - -public class SimpleCommandParser implements CommandParser -{ - private static final String COMMAND_SEPERATOR = ";"; - - /** Input source of commands */ - protected BufferedReader _reader; - - /** The next list of commands from the command line */ - private StringBuilder _nextCommand = null; - - public SimpleCommandParser(BufferedReader reader) - { - _reader = reader; - } - - public boolean more() - { - return _nextCommand != null; - } - - public boolean isBackground() - { - return false; - } - - public String[] parse() throws IOException - { - String[] commands = null; - - String input = null; - - if (_nextCommand == null) - { - input = _reader.readLine(); - } - else - { - input = _nextCommand.toString(); - _nextCommand = null; - } - - if (input == null) - { - return null; - } - - StringTokenizer tok = new StringTokenizer(input, " "); - - int tokenCount = tok.countTokens(); - int index = 0; - - if (tokenCount > 0) - { - commands = new String[tokenCount]; - boolean commandComplete = false; - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - - if (next.equals(COMMAND_SEPERATOR)) - { - commandComplete = true; - _nextCommand = new StringBuilder(); - continue; - } - - if (commandComplete) - { - _nextCommand.append(next); - _nextCommand.append(" "); - } - else - { - commands[index] = next; - index++; - } - } - - } - - //Reduce the String[] if not all the tokens were used in this command. - // i.e. there is more than one command on the line. - if (index != tokenCount) - { - String[] shortCommands = new String[index]; - System.arraycopy(commands, 0, shortCommands, 0, index); - return shortCommands; - } - else - { - return commands; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java deleted file mode 100644 index ec080a4611..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -public class SimpleConsole implements Console -{ - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); - - /** Console Writer. */ - protected static BufferedWriter _consoleWriter; - - /** Console Reader. */ - protected static BufferedReader _consoleReader; - - /** Parser for command-line input. */ - protected CommandParser _parser; - - public SimpleConsole(BufferedWriter writer, BufferedReader reader) - { - _consoleWriter = writer; - _consoleReader = reader; - _parser = new SimpleCommandParser(_consoleReader); - } - - public void print(String... message) - { - try - { - for (String s : message) - { - _consoleWriter.write(s); - } - _consoleWriter.flush(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); - } - - } - - public void println(String... message) - { - print(message); - print(System.getProperty("line.separator")); - } - - - public String readln() - { - try - { - return _consoleReader.readLine(); - } - catch (IOException e) - { - _devlog.debug("Unable to read input due to:" + e.getMessage()); - return null; - } - } - - public String[] readCommand() - { - try - { - return _parser.parse(); - } - catch (IOException e) - { - _devlog.error("Error reading command:" + e.getMessage()); - return new String[0]; - } - } - - public CommandParser getCommandParser() - { - return _parser; - } - - public void setCommandParser(CommandParser parser) - { - _parser = parser; - } - - public void displayList(boolean hasTitle, String... list) - { - java.util.List data = new LinkedList(); - - java.util.List values = new LinkedList(); - - data.add(values); - - for (String value : list) - { - values.add(value); - } - - if (hasTitle) - { - values.add(1, "*divider"); - } - - printMap(null, data); - } - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - public void printMap(String title, java.util.List entries) - { - try - { - int columns = entries.size(); - - int[] columnWidth = new int[columns]; - - // calculate row count - int rowMax = 0; - - //the longest item - int itemMax = 0; - - for (int i = 0; i < columns; i++) - { - int columnIRowMax = entries.get(i).size(); - - if (columnIRowMax > rowMax) - { - rowMax = columnIRowMax; - } - for (Object values : entries.get(i)) - { - if (values.toString().equals(Console.ROW_DIVIDER)) - { - continue; - } - - int itemLength = values.toString().length(); - - //note for single width - if (itemLength > itemMax) - { - itemMax = itemLength; - } - - //note for mulit width - if (itemLength > columnWidth[i]) - { - columnWidth[i] = itemLength; - } - - } - } - - int tableWidth = 0; - - - for (int i = 0; i < columns; i++) - { - // plus 2 for the space padding - columnWidth[i] += 2; - } - for (int size : columnWidth) - { - tableWidth += size; - } - tableWidth += (columns - 1); - - if (title != null) - { - if (title.length() > tableWidth) - { - tableWidth = title.length(); - } - - printCellRow("+", "-", tableWidth); - - printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); - _consoleWriter.newLine(); - - } - - //put top line | or bottom of title - printCellRow("+", "-", tableWidth); - - //print the table data - int row = 0; - - for (; row < rowMax; row++) - { - for (int i = 0; i < columns; i++) - { - java.util.List columnData = entries.get(i); - - String value; - // does this column have a value for this row - if (columnData.size() > row) - { - value = " " + columnData.get(row).toString() + " "; - } - else - { - value = " "; - } - - if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) - { - printCellRow("+", "-", tableWidth); - //move on to the next row - break; - } - else - { - printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); - } - - // if it is the last row then do a new line. - if (i == columns - 1) - { - _consoleWriter.newLine(); - } - } - } - - printCellRow("+", "-", tableWidth); - - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write."); - } - } - - public void close() - { - - try - { - _consoleReader.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); - } - - try - { - - _consoleWriter.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); - } - - } - - private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException - { - int pad = cellWidth - cell.length(); - - if (column == 0) - { - _consoleWriter.write(edge); - } - - switch (format) - { - case CENTRED: - printPad(" ", pad / 2); - break; - case RIGHT: - printPad(" ", pad); - break; - } - - _consoleWriter.write(cell); - - - switch (format) - { - case CENTRED: - // if pad isn't even put the extra one on the right - if (pad % 2 == 0) - { - printPad(" ", pad / 2); - } - else - { - printPad(" ", (pad / 2) + 1); - } - break; - case LEFT: - printPad(" ", pad); - break; - } - - - _consoleWriter.write(edge); - - } - - private void printCellRow(String edge, String mid, int cellWidth) throws IOException - { - _consoleWriter.write(edge); - - printPad(mid, cellWidth); - - _consoleWriter.write(edge); - _consoleWriter.newLine(); - } - - private void printPad(String padChar, int count) throws IOException - { - for (int i = 0; i < count; i++) - { - _consoleWriter.write(padChar); - } - } - - -} -- cgit v1.2.1 From 65971bf662ccc0df167b23ecb831f1ccb3d5e475 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 23 Apr 2008 23:53:55 +0000 Subject: QPID-832 copy the M2.x broker git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651112 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 1007 ++++++++++++++ .../apache/qpid/configuration/Configuration.java | 188 +++ .../apache/qpid/server/AMQBrokerManagerMBean.java | 244 ++++ .../java/org/apache/qpid/server/AMQChannel.java | 1040 ++++++++++++++ .../qpid/server/ConsumerTagNotUniqueException.java | 25 + .../src/main/java/org/apache/qpid/server/Main.java | 522 +++++++ .../org/apache/qpid/server/ManagedChannel.java | 68 + .../qpid/server/RequiredDeliveryException.java | 68 + .../java/org/apache/qpid/server/ack/TxAck.java | 153 +++ .../qpid/server/ack/UnacknowledgedMessage.java | 91 ++ .../qpid/server/ack/UnacknowledgedMessageMap.java | 80 ++ .../server/ack/UnacknowledgedMessageMapImpl.java | 226 +++ .../qpid/server/configuration/Configurator.java | 118 ++ .../configuration/VirtualHostConfiguration.java | 269 ++++ .../qpid/server/exchange/AbstractExchange.java | 217 +++ .../server/exchange/DefaultExchangeFactory.java | 113 ++ .../server/exchange/DefaultExchangeRegistry.java | 138 ++ .../qpid/server/exchange/DestNameExchange.java | 260 ++++ .../qpid/server/exchange/DestWildExchange.java | 579 ++++++++ .../org/apache/qpid/server/exchange/Exchange.java | 97 ++ .../qpid/server/exchange/ExchangeFactory.java | 40 + .../server/exchange/ExchangeInUseException.java | 45 + .../qpid/server/exchange/ExchangeRegistry.java | 51 + .../apache/qpid/server/exchange/ExchangeType.java | 35 + .../qpid/server/exchange/FanoutExchange.java | 240 ++++ .../qpid/server/exchange/HeadersBinding.java | 219 +++ .../qpid/server/exchange/HeadersExchange.java | 360 +++++ .../org/apache/qpid/server/exchange/Index.java | 90 ++ .../qpid/server/exchange/ManagedExchange.java | 98 ++ .../apache/qpid/server/exchange/MessageRouter.java | 40 + .../qpid/server/exchange/NoRouteException.java | 48 + .../qpid/server/filter/ArithmeticExpression.java | 275 ++++ .../qpid/server/filter/BinaryExpression.java | 106 ++ .../qpid/server/filter/BooleanExpression.java | 40 + .../qpid/server/filter/ComparisonExpression.java | 634 +++++++++ .../qpid/server/filter/ConstantExpression.java | 217 +++ .../org/apache/qpid/server/filter/Expression.java | 37 + .../apache/qpid/server/filter/FilterManager.java | 37 + .../qpid/server/filter/FilterManagerFactory.java | 77 ++ .../qpid/server/filter/JMSSelectorFilter.java | 71 + .../apache/qpid/server/filter/LogicExpression.java | 110 ++ .../apache/qpid/server/filter/MessageFilter.java | 29 + .../qpid/server/filter/NoConsumerFilter.java | 42 + .../qpid/server/filter/PropertyExpression.java | 322 +++++ .../qpid/server/filter/SimpleFilterManager.java | 76 + .../apache/qpid/server/filter/UnaryExpression.java | 337 +++++ .../apache/qpid/server/filter/XPathExpression.java | 126 ++ .../qpid/server/filter/XQueryExpression.java | 57 + .../qpid/server/filter/XalanXPathEvaluator.java | 102 ++ .../qpid/server/handler/AccessRequestHandler.java | 65 + .../qpid/server/handler/BasicAckMethodHandler.java | 67 + .../server/handler/BasicCancelMethodHandler.java | 76 + .../server/handler/BasicConsumeMethodHandler.java | 169 +++ .../qpid/server/handler/BasicGetMethodHandler.java | 101 ++ .../server/handler/BasicPublishMethodHandler.java | 101 ++ .../qpid/server/handler/BasicQosHandler.java | 60 + .../server/handler/BasicRecoverMethodHandler.java | 73 + .../handler/BasicRecoverSyncMethodHandler.java | 75 + .../server/handler/BasicRejectMethodHandler.java | 130 ++ .../qpid/server/handler/ChannelCloseHandler.java | 77 ++ .../qpid/server/handler/ChannelCloseOkHandler.java | 53 + .../qpid/server/handler/ChannelFlowHandler.java | 66 + .../qpid/server/handler/ChannelOpenHandler.java | 103 ++ .../handler/ConnectionCloseMethodHandler.java | 72 + .../handler/ConnectionCloseOkMethodHandler.java | 63 + .../handler/ConnectionOpenMethodHandler.java | 99 ++ .../handler/ConnectionSecureOkMethodHandler.java | 126 ++ .../handler/ConnectionStartOkMethodHandler.java | 161 +++ .../handler/ConnectionTuneOkMethodHandler.java | 54 + .../qpid/server/handler/ExchangeBoundHandler.java | 180 +++ .../server/handler/ExchangeDeclareHandler.java | 116 ++ .../qpid/server/handler/ExchangeDeleteHandler.java | 71 + .../server/handler/OnCurrentThreadExecutor.java | 34 + .../qpid/server/handler/QueueBindHandler.java | 139 ++ .../qpid/server/handler/QueueDeclareHandler.java | 212 +++ .../qpid/server/handler/QueueDeleteHandler.java | 124 ++ .../qpid/server/handler/QueuePurgeHandler.java | 121 ++ .../qpid/server/handler/QueueUnbindHandler.java | 134 ++ .../server/handler/ServerMethodDispatcherImpl.java | 566 ++++++++ .../handler/ServerMethodDispatcherImpl_0_9.java | 164 +++ .../handler/ServerMethodDispatcherImpl_8_0.java | 86 ++ .../qpid/server/handler/TxCommitHandler.java | 80 ++ .../qpid/server/handler/TxRollbackHandler.java | 77 ++ .../qpid/server/handler/TxSelectHandler.java | 63 + .../server/handler/UnexpectedMethodException.java | 33 + .../org/apache/qpid/server/jms/JmsConsumer.java | 110 ++ .../qpid/server/management/AMQManagedObject.java | 97 ++ .../server/management/DefaultManagedObject.java | 191 +++ .../management/JMXManagedObjectRegistry.java | 283 ++++ .../qpid/server/management/MBeanAttribute.java | 41 + .../qpid/server/management/MBeanConstructor.java | 39 + .../qpid/server/management/MBeanDescription.java | 38 + .../qpid/server/management/MBeanIntrospector.java | 388 ++++++ .../management/MBeanInvocationHandlerImpl.java | 239 ++++ .../qpid/server/management/MBeanOperation.java | 43 + .../server/management/MBeanOperationParameter.java | 37 + .../apache/qpid/server/management/Managable.java | 34 + .../qpid/server/management/ManagedBroker.java | 98 ++ .../qpid/server/management/ManagedObject.java | 58 + .../server/management/ManagedObjectRegistry.java | 48 + .../server/management/ManagementConfiguration.java | 30 + .../management/NoopManagedObjectRegistry.java | 60 + .../server/output/ProtocolOutputConverter.java | 57 + .../output/ProtocolOutputConverterRegistry.java | 61 + .../amqp0_8/ProtocolOutputConverterImpl.java | 285 ++++ .../amqp0_9/ProtocolOutputConverterImpl.java | 397 ++++++ .../org/apache/qpid/server/plugins/Activator.java | 44 + .../apache/qpid/server/plugins/PluginManager.java | 145 ++ .../server/protocol/AMQMinaProtocolSession.java | 796 +++++++++++ .../protocol/AMQNoMethodHandlerException.java | 46 + .../server/protocol/AMQPFastProtocolHandler.java | 276 ++++ .../qpid/server/protocol/AMQPProtocolProvider.java | 52 + .../qpid/server/protocol/AMQProtocolSession.java | 179 +++ .../server/protocol/AMQProtocolSessionMBean.java | 306 +++++ .../qpid/server/protocol/ExchangeInitialiser.java | 51 + .../qpid/server/protocol/HeartbeatConfig.java | 67 + .../qpid/server/protocol/ManagedConnection.java | 135 ++ .../protocol/UnknnownMessageTypeException.java | 46 + .../org/apache/qpid/server/queue/AMQMessage.java | 717 ++++++++++ .../apache/qpid/server/queue/AMQMessageHandle.java | 79 ++ .../org/apache/qpid/server/queue/AMQQueue.java | 1024 ++++++++++++++ .../apache/qpid/server/queue/AMQQueueMBean.java | 479 +++++++ .../qpid/server/queue/AsyncDeliveryConfig.java | 56 + .../queue/ConcurrentSelectorDeliveryManager.java | 1061 ++++++++++++++ .../qpid/server/queue/DefaultQueueRegistry.java | 71 + .../apache/qpid/server/queue/DeliveryManager.java | 102 ++ .../apache/qpid/server/queue/ExchangeBindings.java | 135 ++ .../qpid/server/queue/FailedDequeueException.java | 50 + .../qpid/server/queue/InMemoryMessageHandle.java | 144 ++ .../org/apache/qpid/server/queue/ManagedQueue.java | 245 ++++ .../qpid/server/queue/MessageCleanupException.java | 52 + .../qpid/server/queue/MessageHandleFactory.java | 46 + .../apache/qpid/server/queue/MessageMetaData.java | 92 ++ .../qpid/server/queue/NoConsumersException.java | 47 + .../qpid/server/queue/NotificationCheck.java | 138 ++ .../org/apache/qpid/server/queue/QueueEntry.java | 173 +++ .../server/queue/QueueNotificationListener.java | 27 + .../apache/qpid/server/queue/QueueRegistry.java | 43 + .../org/apache/qpid/server/queue/Subscription.java | 63 + .../qpid/server/queue/SubscriptionFactory.java | 43 + .../apache/qpid/server/queue/SubscriptionImpl.java | 680 +++++++++ .../qpid/server/queue/SubscriptionManager.java | 34 + .../apache/qpid/server/queue/SubscriptionSet.java | 274 ++++ .../qpid/server/queue/TransientMessageData.java | 127 ++ .../server/queue/WeakReferenceMessageHandle.java | 227 +++ .../server/queue/WeightedSubscriptionManager.java | 26 + .../qpid/server/registry/ApplicationRegistry.java | 203 +++ .../ConfigurationFileApplicationRegistry.java | 188 +++ .../qpid/server/registry/IApplicationRegistry.java | 75 + .../qpid/server/security/access/ACLManager.java | 161 +++ .../qpid/server/security/access/ACLPlugin.java | 58 + .../qpid/server/security/access/AccessResult.java | 66 + .../qpid/server/security/access/AccessRights.java | 63 + .../qpid/server/security/access/Accessable.java | 27 + .../qpid/server/security/access/Permission.java | 37 + .../security/access/PrincipalPermissions.java | 579 ++++++++ .../server/security/access/VirtualHostAccess.java | 68 + .../access/management/AMQUserManagementMBean.java | 468 +++++++ .../security/access/management/UserManagement.java | 118 ++ .../server/security/access/plugins/AllowAll.java | 72 + .../server/security/access/plugins/DenyAll.java | 57 + .../server/security/access/plugins/SimpleXML.java | 342 +++++ .../server/security/auth/AuthenticationResult.java | 43 + .../Base64MD5PasswordFilePrincipalDatabase.java | 598 ++++++++ .../ConfigurationFilePrincipalDatabaseManager.java | 235 ++++ .../PlainPasswordFilePrincipalDatabase.java | 240 ++++ .../security/auth/database/PrincipalDatabase.java | 100 ++ .../auth/database/PrincipalDatabaseManager.java | 34 + .../auth/database/PropertiesPrincipalDatabase.java | 164 +++ .../PropertiesPrincipalDatabaseManager.java | 48 + .../auth/manager/AuthenticationManager.java | 37 + .../PrincipalDatabaseAuthenticationManager.java | 241 ++++ .../sasl/AuthenticationProviderInitialiser.java | 76 + .../server/security/auth/sasl/JCAProvider.java | 47 + .../auth/sasl/UsernamePasswordInitialiser.java | 123 ++ .../security/auth/sasl/UsernamePrincipal.java | 44 + .../auth/sasl/amqplain/AmqPlainInitialiser.java | 38 + .../auth/sasl/amqplain/AmqPlainSaslServer.java | 129 ++ .../sasl/amqplain/AmqPlainSaslServerFactory.java | 60 + .../sasl/crammd5/CRAMMD5HashedInitialiser.java | 50 + .../auth/sasl/crammd5/CRAMMD5HashedSaslServer.java | 105 ++ .../sasl/crammd5/CRAMMD5HashedServerFactory.java | 61 + .../auth/sasl/crammd5/CRAMMD5Initialiser.java | 71 + .../security/auth/sasl/plain/PlainInitialiser.java | 38 + .../security/auth/sasl/plain/PlainSaslServer.java | 149 ++ .../auth/sasl/plain/PlainSaslServerFactory.java | 60 + .../org/apache/qpid/server/state/AMQState.java | 36 + .../apache/qpid/server/state/AMQStateManager.java | 263 ++++ .../state/IllegalStateTransitionException.java | 52 + .../server/state/StateAwareMethodListener.java | 35 + .../apache/qpid/server/state/StateListener.java | 30 + .../qpid/server/store/DerbyMessageStore.java | 1445 ++++++++++++++++++++ .../qpid/server/store/MemoryMessageStore.java | 223 +++ .../org/apache/qpid/server/store/MessageStore.java | 261 ++++ .../server/store/MessageStoreClosedException.java | 36 + .../org/apache/qpid/server/store/StoreContext.java | 68 + .../server/transport/ConnectorConfiguration.java | 114 ++ .../qpid/server/transport/ThreadPoolFilter.java | 705 ++++++++++ .../qpid/server/txn/CleanupMessageOperation.java | 77 ++ .../qpid/server/txn/LocalTransactionalContext.java | 267 ++++ .../qpid/server/txn/NonTransactionalContext.java | 233 ++++ .../qpid/server/txn/StoreMessageOperation.java | 58 + .../qpid/server/txn/TransactionalContext.java | 170 +++ .../java/org/apache/qpid/server/txn/TxnBuffer.java | 109 ++ .../java/org/apache/qpid/server/txn/TxnOp.java | 55 + .../apache/qpid/server/util/CircularBuffer.java | 131 ++ .../server/util/ConcurrentLinkedQueueNoSize.java | 38 + .../org/apache/qpid/server/util/LoggingProxy.java | 105 ++ .../qpid/server/util/NullApplicationRegistry.java | 131 ++ .../server/virtualhost/ManagedVirtualHost.java | 44 + .../qpid/server/virtualhost/VirtualHost.java | 308 +++++ .../server/virtualhost/VirtualHostRegistry.java | 70 + .../qpid/tools/messagestore/MessageStoreTool.java | 652 +++++++++ .../messagestore/commands/AbstractCommand.java | 66 + .../qpid/tools/messagestore/commands/Clear.java | 85 ++ .../qpid/tools/messagestore/commands/Command.java | 36 + .../qpid/tools/messagestore/commands/Copy.java | 55 + .../qpid/tools/messagestore/commands/Dump.java | 301 ++++ .../qpid/tools/messagestore/commands/Help.java | 98 ++ .../qpid/tools/messagestore/commands/List.java | 314 +++++ .../qpid/tools/messagestore/commands/Load.java | 94 ++ .../qpid/tools/messagestore/commands/Move.java | 206 +++ .../qpid/tools/messagestore/commands/Purge.java | 68 + .../qpid/tools/messagestore/commands/Quit.java | 54 + .../qpid/tools/messagestore/commands/Select.java | 233 ++++ .../qpid/tools/messagestore/commands/Show.java | 515 +++++++ .../org/apache/qpid/tools/security/Passwd.java | 81 ++ .../org/apache/qpid/tools/utils/CommandParser.java | 51 + .../java/org/apache/qpid/tools/utils/Console.java | 90 ++ .../qpid/tools/utils/SimpleCommandParser.java | 121 ++ .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 +++++ 231 files changed, 38407 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java new file mode 100644 index 0000000000..7e0c4defe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -0,0 +1,1007 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.log4j; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.GZIPOutputStream; + +import org.apache.log4j.helpers.CountingQuietWriter; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.spi.LoggingEvent; + +/** + *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either + * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is + * crossed at which time it rolls all of those files as per the DailyRollingFileAppender) based on the setting for + * rollingStyle.

      To use CompositeRollingAppender to roll log files as they reach a certain size + * (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      To use CompositeRollingAppender to roll log + * files at certain time intervals (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      To + * have CompositeRollingAppender roll log files at a certain size AND rename those according to time intervals, set + * rollingStyle=3 (@see config.composite)
      + * + *

      A of few additional optional features have been added:
      -- Attach date pattern for current log file (@see + * staticLogFileName)
      -- Backup number increments for newer files (@see countDirection)
      -- Infinite number of + * backups by file size (@see maxSizeRollBackups)

      A few notes and warnings: For large or infinite number of + * backups countDirection > 0 is highly recommended, with staticLogFileName = false if time based rolling is also used + * -- this will reduce the number of file renamings to few or none. Changing staticLogFileName or countDirection + * without clearing the directory could have nasty side effects. If Date/Time based rolling is enabled, + * CompositeRollingAppender will attempt to roll existing files in the directory without a date/time tag based on the + * last modified date of the base log files last modification.

      A maximum number of backups based on + * date/time boundries would be nice but is not yet implemented.
      + * + * @author Kevin Steppe + * @author Heinz Richter + * @author Eirik Lygre + * @author Ceki Gülcü + * @author Martin Ritchie + */ +public class QpidCompositeRollingAppender extends FileAppender +{ + // The code assumes that the following 'time' constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE = -1; + static final int TOP_OF_MINUTE = 0; + static final int TOP_OF_HOUR = 1; + static final int HALF_DAY = 2; + static final int TOP_OF_DAY = 3; + static final int TOP_OF_WEEK = 4; + static final int TOP_OF_MONTH = 5; + + /** Style of rolling to use */ + static final int BY_SIZE = 1; + static final int BY_DATE = 2; + static final int BY_COMPOSITE = 3; + + // Not currently used + static final String S_BY_SIZE = "Size"; + static final String S_BY_DATE = "Date"; + static final String S_BY_COMPOSITE = "Composite"; + + /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ + private String datePattern = "'.'yyyy-MM-dd"; + + /** + * The actual formatted filename that is currently being written to or will be the file transferred to on roll over + * (based on staticLogFileName). + */ + private String scheduledFilename = null; + + /** The timestamp when we shall next recompute the filename. */ + private long nextCheck = System.currentTimeMillis() - 1; + + /** Holds date of last roll over */ + Date now = new Date(); + + SimpleDateFormat sdf; + + /** Helper class to determine next rollover time */ + RollingCalendar rc = new RollingCalendar(); + + /** Current period for roll overs */ + int checkPeriod = TOP_OF_TROUBLE; + + /** The default maximum file size is 10MB. */ + protected long maxFileSize = 10 * 1024 * 1024; + + /** There is zero backup files by default. */ + protected int maxSizeRollBackups = 0; + /** How many sized based backups have been made so far */ + protected int curSizeRollBackups = 0; + + /** not yet implemented */ + protected int maxTimeRollBackups = -1; + protected int curTimeRollBackups = 0; + + /** + * By default newer files have lower numbers. (countDirection < 0) ie. log.1 is most recent, log.5 is the 5th + * backup, etc... countDirection > 0 does the opposite ie. log.1 is the first backup made, log.5 is the 5th backup + * made, etc. For infinite backups use countDirection > 0 to reduce rollOver costs. + */ + protected int countDirection = -1; + + /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ + protected int rollingStyle = BY_COMPOSITE; + protected boolean rollDate = true; + protected boolean rollSize = true; + + /** + * By default file.log is always the current file. Optionally file.log.yyyy-mm-dd for current formated datePattern + * can by the currently logging file (or file.log.curSizeRollBackup or even file.log.yyyy-mm-dd.curSizeRollBackup) + * This will make time based roll overs with a large number of backups much faster -- it won't have to rename all + * the backups! + */ + protected boolean staticLogFileName = true; + + /** FileName provided in configuration. Used for rolling properly */ + protected String baseFileName; + + /** Do we want to .gz our backup files. */ + protected boolean compress = false; + + /** Do we want to use a second thread when compressing our backup files. */ + protected boolean compressAsync = false; + + /** Do we want to start numbering files at zero. */ + protected boolean zeroBased = false; + + /** Path provided in configuration. Used for moving backup files to */ + protected String backupFilesToPath = null; + private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); + private AtomicBoolean _compressing = new AtomicBoolean(false); + + /** The default constructor does nothing. */ + public QpidCompositeRollingAppender() + { } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The + * opened filename will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern) throws IOException + { + this(layout, filename, datePattern, true); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + * + *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by + * filename will be truncated before being opened. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) throws IOException + { + super(layout, filename, append); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern, boolean append) + throws IOException + { + super(layout, filename, append); + this.datePattern = datePattern; + activateOptions(); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the output destination for this appender. + * + *

      The file will be appended to. DatePattern is default. + */ + public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException + { + super(layout, filename); + } + + /** + * The DatePattern takes a string in the same format as expected by {@link java.text.SimpleDateFormat}. This + * options determines the rollover schedule. + */ + public void setDatePattern(String pattern) + { + datePattern = pattern; + } + + /** Returns the value of the DatePattern option. */ + public String getDatePattern() + { + return datePattern; + } + + /** Returns the value of the maxSizeRollBackups option. */ + public int getMaxSizeRollBackups() + { + return maxSizeRollBackups; + } + + /** + * Get the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + * @since 1.1 + */ + public long getMaximumFileSize() + { + return maxFileSize; + } + + /** + *

      Set the maximum number of backup files to keep around based on file size. + * + *

      The MaxSizeRollBackups option determines how many backup files are kept before the oldest is erased. + * This option takes an integer value. If set to zero, then there will be no backup files and the log file will be + * truncated when it reaches MaxFileSize. If a negative number is supplied then no deletions will be + * made. Note that this could result in very slow performance as a large number of files are rolled over unless + * {@link #setCountDirection} up is used. + * + *

      The maximum applys to -each- time based group of files and -not- the total. Using a daily roll the maximum + * total files would be (#days run) * (maxSizeRollBackups) + */ + public void setMaxSizeRollBackups(int maxBackups) + { + maxSizeRollBackups = maxBackups; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaxFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaximumFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      In configuration files, the MaxFileSize option takes an long integer in the range 0 - 2^63. You can + * specify the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed + * respectively in kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240. + */ + public void setMaxFileSize(String value) + { + maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); + } + + protected void setQWForFiles(Writer writer) + { + qw = new CountingQuietWriter(writer, errorHandler); + } + + // Taken verbatum from DailyRollingFileAppender + int computeCheckPeriod() + { + RollingCalendar c = new RollingCalendar(); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date(0); + if (datePattern != null) + { + for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) + { + String r0 = sdf.format(epoch); + c.setType(i); + Date next = new Date(c.getNextCheckMillis(epoch)); + String r1 = sdf.format(next); + // LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if ((r0 != null) && (r1 != null) && !r0.equals(r1)) + { + return i; + } + } + } + + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + // Now for the new stuff + /** + * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked + * first) or time (checked second) is need and then appends to the file last. + */ + protected void subAppend(LoggingEvent event) + { + + if (rollDate) + { + long n = System.currentTimeMillis(); + if (n >= nextCheck) + { + now.setTime(n); + nextCheck = rc.getNextCheckMillis(now); + + rollOverTime(); + } + } + + if (rollSize) + { + if ((fileName != null) && (((CountingQuietWriter) qw).getCount() >= maxFileSize)) + { + rollOverSize(); + } + } + + super.subAppend(event); + } + + public void setFile(String file) + { + baseFileName = file.trim(); + fileName = file.trim(); + } + + /** + * Creates and opens the file for logging. If staticLogFileName is false then the fully qualified name + * is determined and used. + */ + public synchronized void setFile(String fileName, boolean append) throws IOException + { + if (!staticLogFileName) + { + scheduledFilename = fileName = fileName.trim() + sdf.format(now); + if (countDirection > 0) + { + scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); + } + } + + super.setFile(fileName, append, bufferedIO, bufferSize); + + if (append) + { + File f = new File(fileName); + ((CountingQuietWriter) qw).setCount(f.length()); + } + } + + public int getCountDirection() + { + return countDirection; + } + + public void setCountDirection(int direction) + { + countDirection = direction; + } + + public int getRollingStyle() + { + return rollingStyle; + } + + public void setRollingStyle(int style) + { + rollingStyle = style; + switch (rollingStyle) + { + + case BY_SIZE: + rollDate = false; + rollSize = true; + break; + + case BY_DATE: + rollDate = true; + rollSize = false; + break; + + case BY_COMPOSITE: + rollDate = true; + rollSize = true; + break; + + default: + errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); + } + } + + /* + public void setRollingStyle(String style) { + if (style == S_BY_SIZE) { + rollingStyle = BY_SIZE; + } + else if (style == S_BY_DATE) { + rollingStyle = BY_DATE; + } + else if (style == S_BY_COMPOSITE) { + rollingStyle = BY_COMPOSITE; + } + } + */ + public boolean getStaticLogFileName() + { + return staticLogFileName; + } + + public void setStaticLogFileName(boolean s) + { + staticLogFileName = s; + } + + public void setStaticLogFileName(String value) + { + setStaticLogFileName(OptionConverter.toBoolean(value, true)); + } + + public boolean getCompressBackupFiles() + { + return compress; + } + + public void setCompressBackupFiles(boolean c) + { + compress = c; + } + + public boolean getCompressAsync() + { + return compressAsync; + } + + public void setCompressAsync(boolean c) + { + compressAsync = c; + if (compressAsync) + { + executor = Executors.newFixedThreadPool(1); + + compressor = new Compressor(); + } + } + + public boolean getZeroBased() + { + return zeroBased; + } + + public void setZeroBased(boolean z) + { + zeroBased = z; + } + + public String getBackupFilesToPath() + { + return backupFilesToPath; + } + + public void setbackupFilesToPath(String path) + { + File td = new File(path); + if (!td.exists()) + { + td.mkdirs(); + } + + backupFilesToPath = path; + } + + /** + * Initializes based on exisiting conditions at time of activateOptions. The following is done:
      + *
      A) determine curSizeRollBackups
      B) determine curTimeRollBackups (not implemented)
      C) initiates a + * roll over if needed for crossing a date boundary since the last run. + */ + protected void existingInit() + { + + if (zeroBased) + { + curSizeRollBackups = -1; + } + + curTimeRollBackups = 0; + + // part A starts here + String filter; + if (staticLogFileName || !rollDate) + { + filter = baseFileName + ".*"; + } + else + { + filter = scheduledFilename + ".*"; + } + + File f = new File(baseFileName); + f = f.getParentFile(); + if (f == null) + { + f = new File("."); + } + + LogLog.debug("Searching for existing files in: " + f); + String[] files = f.list(); + + if (files != null) + { + for (int i = 0; i < files.length; i++) + { + if (!files[i].startsWith(baseFileName)) + { + continue; + } + + int index = files[i].lastIndexOf("."); + + if (staticLogFileName) + { + int endLength = files[i].length() - index; + if ((baseFileName.length() + endLength) != files[i].length()) + { + // file is probably scheduledFilename + .x so I don't care + continue; + } + } + + try + { + int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); + LogLog.debug("From file: " + files[i] + " -> " + backup); + if (backup > curSizeRollBackups) + { + curSizeRollBackups = backup; + } + } + catch (Exception e) + { + // this happens when file.log -> file.log.yyyy-mm-dd which is normal + // when staticLogFileName == false + LogLog.debug("Encountered a backup file not ending in .x " + files[i]); + } + } + } + + LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); + // part A ends here + + // part B not yet implemented + + // part C + if (staticLogFileName && rollDate) + { + File old = new File(baseFileName); + if (old.exists()) + { + Date last = new Date(old.lastModified()); + if (!(sdf.format(last).equals(sdf.format(now)))) + { + scheduledFilename = baseFileName + sdf.format(last); + LogLog.debug("Initial roll over to: " + scheduledFilename); + rollOverTime(); + } + } + } + + LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); + // part C ends here + + } + + /** + * Sets initial conditions including date/time roll over information, first check, scheduledFilename, and calls + * existingInit to initialize the current # of backups. + */ + public void activateOptions() + { + + // REMOVE removed rollDate from boolean to enable Alex's change + if (datePattern != null) + { + now.setTime(System.currentTimeMillis()); + sdf = new SimpleDateFormat(datePattern); + int type = computeCheckPeriod(); + // printPeriodicity(type); + rc.setType(type); + // next line added as this removes the name check in rollOver + nextCheck = rc.getNextCheckMillis(now); + } + else + { + if (rollDate) + { + LogLog.error("Either DatePattern or rollingStyle options are not set for [" + name + "]."); + } + } + + existingInit(); + + if (rollDate && (fileName != null) && (scheduledFilename == null)) + { + scheduledFilename = fileName + sdf.format(now); + } + + try + { + this.setFile(fileName, true); + } + catch (IOException e) + { + errorHandler.error("Cannot set file name:" + fileName); + } + + super.activateOptions(); + } + + /** + * Rollover the file(s) to date/time tagged file(s). Opens the new file (through setFile) and resets + * curSizeRollBackups. + */ + protected void rollOverTime() + { + + curTimeRollBackups++; + + this.closeFile(); // keep windows happy. + + // delete the old stuff here + + if (staticLogFileName) + { + /* Compute filename, but only if datePattern is specified */ + if (datePattern == null) + { + errorHandler.error("Missing DatePattern option in rollOver()."); + + return; + } + + // is the new file name equivalent to the 'current' one + // something has gone wrong if we hit this -- we should only + // roll over if the new file will be different from the old + String dateFormat = sdf.format(now); + if (scheduledFilename.equals(fileName + dateFormat)) + { + errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); + + return; + } + + // close current file, and rename it to datedFilename + this.closeFile(); + + // we may have to roll over a large number of backups here + String from, to; + for (int i = 1; i <= curSizeRollBackups; i++) + { + from = fileName + '.' + i; + to = scheduledFilename + '.' + i; + rollFile(from, to, false); + } + + rollFile(fileName, scheduledFilename, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new + + // new scheduled name + scheduledFilename = fileName + sdf.format(now); + this.setFile(baseFileName, false); + } + catch (IOException e) + { + errorHandler.error("setFile(" + fileName + ", false) call failed."); + } + + } + + /** + * Renames file from to file to. It also checks for existence of target file and deletes + * if it does. + */ + protected void rollFile(String from, String to, boolean compress) + { + if (from.equals(to)) + { + if (compress) + { + LogLog.debug("Attempting to compress file with same output name."); + } + + return; + } + + File target = new File(to); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + File file = new File(from); + if (compress) + { + compress(file, target); + } + else + { + if (!file.getPath().equals(target.getPath())) + { + file.renameTo(target); + } + } + + LogLog.debug(from + " -> " + to); + } + + protected void compress(String file) + { + File f = new File(file); + compress(f, f); + } + + private void compress(File from, File target) + { + if (compressAsync) + { + synchronized (_compress) + { + _compress.offer(new CompressJob(from, target)); + } + + startCompression(); + } + else + { + doCompress(from, target); + } + } + + private void startCompression() + { + if (_compressing.compareAndSet(false, true)) + { + executor.execute(compressor); + } + } + + /** Delete's the specified file if it exists */ + protected static void deleteFile(String fileName) + { + File file = new File(fileName); + if (file.exists()) + { + file.delete(); + } + } + + /** + * Implements roll overs base on file size. + * + *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If + * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} + * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is + * renamed File.1 and closed.
      + * + * A new file is created to receive further log output. + * + *

      If maxSizeRollBackups is equal to zero, then the File is truncated with no backup + * files created. + * + *

      If maxSizeRollBackups < 0, then File is renamed if needed and no files are deleted. + */ + + // synchronization not necessary since doAppend is alreasy synched + protected void rollOverSize() + { + File file; + + this.closeFile(); // keep windows happy. + + LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); + LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); + LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); + LogLog.debug("countDirection = " + countDirection); + + // If maxBackups <= 0, then there is no file renaming to be done. + if (maxSizeRollBackups != 0) + { + + if (countDirection < 0) + { + // Delete the oldest file, to keep Windows happy. + if (curSizeRollBackups == maxSizeRollBackups) + { + deleteFile(fileName + '.' + maxSizeRollBackups); + curSizeRollBackups--; + } + + // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} + for (int i = curSizeRollBackups; i >= 1; i--) + { + rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); + } + + curSizeRollBackups++; + // Rename fileName to fileName.1 + rollFile(fileName, fileName + ".1", compress); + + } // REMOVE This code branching for Alexander Cerna's request + else if (countDirection == 0) + { + // rollFile based on date pattern + curSizeRollBackups++; + now.setTime(System.currentTimeMillis()); + scheduledFilename = fileName + sdf.format(now); + rollFile(fileName, scheduledFilename, compress); + } + else + { // countDirection > 0 + if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) + { + // delete the first and keep counting up. + int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + deleteFile(fileName + '.' + oldestFileIndex); + } + + if (staticLogFileName) + { + curSizeRollBackups++; + rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(baseFileName, false); + } + catch (IOException e) + { + LogLog.error("setFile(" + fileName + ", false) call failed.", e); + } + } + + protected synchronized void doCompress(File from, File to) + { + String toFile; + if (backupFilesToPath == null) + { + toFile = to.getPath() + ".gz"; + } + else + { + toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; + } + + File target = new File(toFile); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + try + { + // Create the GZIP output stream + GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); + + // Open the input file + FileInputStream in = new FileInputStream(from); + + // Transfer bytes from the input file to the GZIP output stream + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + + in.close(); + + // Complete the GZIP file + out.finish(); + out.close(); + // Remove old file. + from.delete(); + } + catch (IOException e) + { + if (target.exists()) + { + target.delete(); + } + + rollFile(from.getPath(), to.getPath(), false); + } + } + + private class CompressJob + { + File _from, _to; + + CompressJob(File from, File to) + { + _from = from; + _to = to; + } + + File getFrom() + { + return _from; + } + + File getTo() + { + return _to; + } + } + + Compressor compressor = null; + + Executor executor; + + private class Compressor implements Runnable + { + public void run() + { + boolean running = true; + while (running) + { + CompressJob job = _compress.poll(); + + doCompress(job.getFrom(), job.getTo()); + + synchronized (_compress) + { + if (_compress.isEmpty()) + { + running = false; + _compressing.set(false); + } + } + } + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java new file mode 100644 index 0000000000..40ff590a0a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.configuration; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class Configuration +{ + public static final String QPID_HOME = "QPID_HOME"; + + final String QPIDHOME = System.getProperty(QPID_HOME); + + private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); + + public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + protected final Options _options = new Options(); + protected CommandLine _commandLine; + protected File _configFile; + + + public Configuration() + { + + } + + public void processCommandline(String[] args) throws InitException + { + try + { + _commandLine = new PosixParser().parse(_options, args); + } + catch (ParseException e) + { + throw new InitException("Unable to parse commmandline", e); + } + + final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); + setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); + } + + public void setConfig(File file) + { + _configFile = file; + } + + /** + * @param option The option to set. + */ + public void setOption(Option option) + { + _options.addOption(option); + } + + /** + * getOptionValue from the configuration + * @param option variable argument, first string is option to get, second if present is the default value. + * @return the String for the given option or null if not present (if default value not specified) + */ + public String getOptionValue(String... option) + { + if (option.length == 1) + { + return _commandLine.getOptionValue(option[0]); + } + else if (option.length == 2) + { + return _commandLine.getOptionValue(option[0], option[1]); + } + return null; + } + + public void loadConfig(File file) throws InitException + { + setConfig(file); + loadConfig(); + } + + private void loadConfig() throws InitException + { + 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, null); + } + else + { + _devlog.debug("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); +// } + } + + +// private void configureLogging(File logConfigFile, String logWatchConfig) +// { +// int logWatchTime = 0; +// try +// { +// logWatchTime = Integer.parseInt(logWatchConfig); +// } +// catch (NumberFormatException e) +// { +// _devlog.error("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()) +// { +// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); +// if (logWatchTime > 0) +// { +// _devlog.info("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(); +// } +// } + + public File getConfigFile() + { + return _configFile; + } + + + public class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java new file mode 100644 index 0000000000..9335723bc5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -0,0 +1,244 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedBroker; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * This MBean 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") +public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBroker +{ + private final QueueRegistry _queueRegistry; + private final ExchangeRegistry _exchangeRegistry; + private final ExchangeFactory _exchangeFactory; + private final MessageStore _messageStore; + + private final VirtualHost.VirtualHostMBean _virtualHostMBean; + + @MBeanConstructor("Creates the Broker Manager MBean") + public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException + { + super(ManagedBroker.class, ManagedBroker.TYPE); + + _virtualHostMBean = virtualHostMBean; + VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); + + _queueRegistry = virtualHost.getQueueRegistry(); + _exchangeRegistry = virtualHost.getExchangeRegistry(); + _messageStore = virtualHost.getMessageStore(); + _exchangeFactory = virtualHost.getExchangeFactory(); + } + + public String getObjectInstanceName() + { + return _virtualHostMBean.getVirtualHost().getName(); + } + + /** + * Creates new exchange and registers it with the registry. + * + * @param exchangeName + * @param type + * @param durable + * @throws JMException + */ + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException + { + try + { + synchronized (_exchangeRegistry) + { + Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); + if (exchange == null) + { + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), + durable, false, 0); + _exchangeRegistry.registerExchange(exchange); + } + else + { + throw new JMException("The exchange \"" + exchangeName + "\" already exists."); + } + } + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in creating exchange " + exchangeName); + } + } + + /** + * Unregisters the exchange from registry. + * + * @param exchangeName + * @throws JMException + */ + public void unregisterExchange(String exchangeName) throws JMException + { + // TODO + // Check if the exchange is in use. + // boolean inUse = false; + // Check if there are queue-bindings with the exchange and unregister + // when there are no bindings. + try + { + _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); + } + } + + /** + * 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 + * @throws JMException + */ + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue != null) + { + throw new JMException("The queue \"" + queueName + "\" already exists."); + } + + try + { + AMQShortString ownerShortString = null; + if (owner != null) + { + ownerShortString = new AMQShortString(owner); + } + + queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); + if (queue.isDurable() && !queue.isAutoDelete()) + { + _messageStore.createQueue(queue); + } + + Configuration virtualHostDefaultQueueConfiguration = + VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + if (virtualHostDefaultQueueConfiguration != null) + { + Configurator.configure(queue, virtualHostDefaultQueueConfiguration); + } + + _queueRegistry.registerQueue(queue); + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in creating queue " + queueName); + } + } + + private VirtualHost getVirtualHost() + { + return _virtualHostMBean.getVirtualHost(); + } + + /** + * Deletes the queue from queue registry and persistant storage. + * + * @param queueName + * @throws JMException + */ + public void deleteQueue(String queueName) throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("The Queue " + queueName + " is not a registerd queue."); + } + + try + { + queue.delete(); + _messageStore.removeQueue(new AMQShortString(queueName)); + + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in deleting queue " + queueName); + } + } + + public ManagedObject getParentObject() + { + return _virtualHostMBean; + } + + // This will have a single instance for a virtual host, so not having the name property in the ObjectName + public ObjectName getObjectName() throws MalformedObjectNameException + { + return getObjectNameForSingleInstanceMBean(); + } +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java new file mode 100644 index 0000000000..74169a19bb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -0,0 +1,1040 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.configuration.Configured; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +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.configuration.Configurator; +import org.apache.qpid.server.exchange.NoRouteException; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.LocalTransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.txn.TransactionalContext; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +public class AMQChannel +{ + public static final int DEFAULT_PREFETCH = 5000; + + private static final Logger _log = Logger.getLogger(AMQChannel.class); + + private final int _channelId; + + // private boolean _transactional; + + private long _prefetch_HighWaterMark; + + private long _prefetch_LowWaterMark; + + private long _prefetchSize; + + /** + * 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 long _deliveryTag = 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 ConcurrentHashMap(); + + private final MessageStore _messageStore; + + private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); + + private final AtomicBoolean _suspended = new AtomicBoolean(false); + + private TransactionalContext _txnContext, _nonTransactedContext; + + /** + * A context used by the message store enabling it to track context for a given channel even across thread + * boundaries + */ + private final StoreContext _storeContext; + + private final List _returnMessages = new LinkedList(); + + private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + + private Set _browsedAcks = new HashSet(); + + // Why do we need this reference ? - ritchiem + private final AMQProtocolSession _session; + private boolean _closing; + + @Configured(path = "advanced.enableJMSXUserID", + defaultValue = "false") + public boolean ENABLE_JMSXUserID; + + + public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) + throws AMQException + { + //Set values from configuration + Configurator.configure(this); + + _session = session; + _channelId = channelId; + _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); + _prefetch_HighWaterMark = DEFAULT_PREFETCH; + _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; + _messageStore = messageStore; + + // by default the session is non-transactional + _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + + /** Sets this channel to be part of a local transaction */ + public void setLocalTransactional() + { + _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); + } + + public boolean isTransactional() + { + // this does not look great but there should only be one "non-transactional" + // transactional context, while there could be several transactional ones in + // theory + return !(_txnContext instanceof NonTransactionalContext); + } + + public int getChannelId() + { + return _channelId; + } + + public long getPrefetchCount() + { + return _prefetch_HighWaterMark; + } + + public void setPrefetchCount(long prefetchCount) + { + _prefetch_HighWaterMark = prefetchCount; + } + + public long getPrefetchSize() + { + return _prefetchSize; + } + + public void setPrefetchSize(long prefetchSize) + { + _prefetchSize = prefetchSize; + } + + public long getPrefetchLowMarkCount() + { + return _prefetch_LowWaterMark; + } + + public void setPrefetchLowMarkCount(long prefetchCount) + { + _prefetch_LowWaterMark = prefetchCount; + } + + public long getPrefetchHighMarkCount() + { + return _prefetch_HighWaterMark; + } + + public void setPrefetchHighMarkCount(long prefetchCount) + { + _prefetch_HighWaterMark = prefetchCount; + } + + public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher, final Exchange e) throws AMQException + { + + _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); + _currentMessage.setPublisher(publisher); + _currentMessage.setExchange(e); + } + + public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content header without previously receiving a BasicPublish frame"); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Content header received on channel " + _channelId); + } + + if (ENABLE_JMSXUserID) + { + //Set JMSXUserID + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeaderBody.properties; + //fixme: fudge for QPID-677 + properties.getHeaders().keySet(); + + properties.setUserId(protocolSession.getAuthorizedID().getName()); + } + + _currentMessage.setContentHeaderBody(contentHeaderBody); + _currentMessage.setExpiration(); + + routeCurrentMessage(); + _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); + + // check and deliver if header says body length is zero + if (contentHeaderBody.bodySize == 0) + { + _txnContext.messageProcessed(protocolSession); + _currentMessage = null; + } + } + } + + public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content body without previously receiving a JmsPublishBody"); + } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Content body received on channel " + _channelId); + } + + try + { + + // returns true iff the message was delivered (i.e. if all data was + // received + if (_currentMessage.addContentBodyFrame(_storeContext, + protocolSession.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( + contentBody))) + { + // callback to allow the context to do any post message processing + // primary use is to allow message return processing in the non-tx case + _txnContext.messageProcessed(protocolSession); + _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 + { + try + { + _currentMessage.route(); + } + catch (NoRouteException e) + { + _returnMessages.add(e); + } + } + + public long getNextDeliveryTag() + { + return ++_deliveryTag; + } + + 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 + * @param noLocal Flag stopping own messages being receivied. + * @param exclusive Flag requesting exclusive access to the queue + * @param acks Are acks enabled for this subscriber + * @param filters Filters to apply to this 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 AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + { + if (tag == null) + { + tag = new AMQShortString("sgen_" + getNextConsumerTag()); + } + + if (_consumerTag2QueueMap.containsKey(tag)) + { + throw new ConsumerTagNotUniqueException(); + } + + // We add before we register as the Async Delivery process may AutoClose the subscriber + // so calling _cT2QM.remove before we have done put which was after the register succeeded. + // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. + _consumerTag2QueueMap.put(tag, queue); + + try + { + queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive); + } + catch (AMQException e) + { + _consumerTag2QueueMap.remove(tag); + throw e; + } + + return tag; + } + + /** + * Unsubscribe a consumer from a queue. + * @param session + * @param consumerTag + * @return true if the consumerTag had a mapped queue that could be unregistered. + * @throws AMQException + */ + public boolean unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Unacked Map Dump size:" + _unacknowledgedMessageMap.size()); + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug(message); + + return true; + } + + public void visitComplete() + { + } + }); + } + + AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); + if (q != null) + { + q.unregisterProtocolSession(session, _channelId, consumerTag); + return true; + } + return false; + } + + /** + * Called from the protocol session to close this channel and clean up. T + * + * @param session The session to close + * + * @throws AMQException if there is an error during closure + */ + public void close(AMQProtocolSession session) throws AMQException + { + _txnContext.rollback(); + unsubscribeAllConsumers(session); + try + { + requeue(); + } + catch (AMQException e) + { + _log.error("Caught AMQException whilst attempting to reque:" + e); + } + + setClosing(true); + } + + private void setClosing(boolean closing) + { + _closing = closing; + } + + private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException + { + if (_log.isInfoEnabled()) + { + if (!_consumerTag2QueueMap.isEmpty()) + { + _log.info("Unsubscribing all consumers on channel " + toString()); + } + else + { + _log.info("No consumers to unsubscribe on channel " + toString()); + } + } + + for (Map.Entry me : _consumerTag2QueueMap.entrySet()) + { + if (_log.isInfoEnabled()) + { + _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); + } + + me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); + } + + _consumerTag2QueueMap.clear(); + } + + /** + * Add a message to the channel-based list of unacknowledged messages + * + * @param entry the record of the message on the queue that was delivered + * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the + * delivery tag) + * @param consumerTag The tag for the consumer that is to acknowledge this message. + */ + public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, AMQShortString consumerTag) + { + if (_log.isDebugEnabled()) + { + if (entry.getQueue() == null) + { + _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity()); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + + ") with a queue(" + entry.getQueue() + ") for " + consumerTag); + } + } + } + + synchronized (_unacknowledgedMessageMap.getLock()) + { + _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(entry, consumerTag, deliveryTag)); + checkSuspension(); + } + } + + private final String id = "(" + System.identityHashCode(this) + ")"; + + public String debugIdentity() + { + return _channelId + id; + } + + /** + * Called to attempt re-delivery 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(); + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext = null; + + if (!messagesToBeDelivered.isEmpty()) + { + if (_log.isInfoEnabled()) + { + _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + } + + if (!(_txnContext instanceof NonTransactionalContext)) + { + // if (_nonTransactedContext == null) + { + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; + } + } + + for (UnacknowledgedMessage unacked : messagesToBeDelivered) + { + if (!unacked.isQueueDeleted()) + { + // Ensure message is released for redelivery + unacked.entry.release(); + + // Mark message redelivered + unacked.getMessage().setRedelivered(true); + + // Deliver Message + deliveryContext.deliver(unacked.entry, false); + + // Should we allow access To the DM to directy deliver the message? + // As we don't need to check for Consumers or worry about incrementing the message count? + // unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); + } + } + + } + + /** + * Requeue a single message + * + * @param deliveryTag The message to requeue + * + * @throws AMQException If something goes wrong. + */ + public void requeue(long deliveryTag) throws AMQException + { + UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); + + if (unacked != null) + { + + // Ensure message is released for redelivery + if (!unacked.isQueueDeleted()) + { + unacked.entry.release(); + } + + // Mark message redelivered + unacked.getMessage().setRedelivered(true); + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; + if (!(_txnContext instanceof NonTransactionalContext)) + { + // if (_nonTransactedContext == null) + { + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; + } + + if (!unacked.isQueueDeleted()) + { + // Redeliver the messages to the front of the queue + deliveryContext.deliver(unacked.entry, true); + // Deliver increments the message count but we have already deliverted this once so don't increment it again + // this was because deliver did an increment changed this. + } + else + { + _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); + // _log.error("Requested requeue of message:" + deliveryTag + + // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); + // + // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); + // + } + } + else + { + _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + + _unacknowledgedMessageMap.size()); + + if (_log.isDebugEnabled()) + { + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + int count = 0; + + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + _log.debug( + (count++) + ": (" + message.getMessage().debugIdentity() + ")" + "[" + message.deliveryTag + "]"); + + return false; // Continue + } + + public void visitComplete() + { + } + }); + } + } + + } + + /** + * Called to resend all outstanding unacknowledged messages to this same channel. + * + * @param requeue Are the messages to be requeued or dropped. + * + * @throws AMQException When something goes wrong. + */ + public void resend(final boolean requeue) throws AMQException + { + final List msgToRequeue = new LinkedList(); + final List msgToResend = new LinkedList(); + + if (_log.isDebugEnabled()) + { + _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); + } + + // Process the Unacked-Map. + // Marking messages who still have a consumer for to be resent + // and those that don't to be requeued. + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + AMQShortString consumerTag = message.consumerTag; + AMQMessage msg = message.getMessage(); + msg.setRedelivered(true); + if (consumerTag != null) + { + // Consumer exists + if (_consumerTag2QueueMap.containsKey(consumerTag)) + { + msgToResend.add(message); + } + else // consumer has gone + { + msgToRequeue.add(message); + } + } + else + { + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (!message.isQueueDeleted()) + { + if (requeue) + { + msgToRequeue.add(message); + } + else + { + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + } + } + else + { + _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + } + } + + // false means continue processing + return false; + } + + public void visitComplete() + { + } + }); + + // Process Messages to Resend + if (_log.isDebugEnabled()) + { + if (!msgToResend.isEmpty()) + { + _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); + } + else + { + _log.debug("No message to resend."); + } + } + + for (UnacknowledgedMessage message : msgToResend) + { + AMQMessage msg = message.getMessage(); + + // Our Java Client will always suspend the channel when resending! + // If the client has requested the messages be resent then it is + // their responsibility to ensure that thay are capable of receiving them + // i.e. The channel hasn't been server side suspended. + // if (isSuspended()) + // { + // _log.info("Channel is suspended so requeuing"); + // //move this message to requeue + // msgToRequeue.add(message); + // } + // else + // { + // release to allow it to be delivered + message.entry.release(); + + // Without any details from the client about what has been processed we have to mark + // all messages in the unacked map as redelivered. + msg.setRedelivered(true); + + Subscription sub = message.entry.getDeliveredSubscription(); + + if (sub != null) + { + // Get the lock so we can tell if the sub scription has closed. + // will stop delivery to this subscription until the lock is released. + // note: this approach would allow the use of a single queue if the + // PreDeliveryQueue would allow head additions. + // In the Java Qpid client we are suspended whilst doing this so it is all rather Mute.. + // needs guidance from AMQP WG Model SIG + synchronized (sub.getSendLock()) + { + if (sub.isClosed()) + { + if (_log.isDebugEnabled()) + { + _log.debug("Subscription(" + System.identityHashCode(sub) + + ") closed during resend so requeuing message"); + } + // move this message to requeue + msgToRequeue.add(message); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" + + System.identityHashCode(sub)); + } + + sub.addToResendQueue(message.entry); + _unacknowledgedMessageMap.remove(message.deliveryTag); + } + } // sync(sub.getSendLock) + } + else + { + + if (_log.isInfoEnabled()) + { + _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + + ")to prevent loss"); + } + // move this message to requeue + msgToRequeue.add(message); + } + } // for all messages + // } else !isSuspend + + if (_log.isInfoEnabled()) + { + if (!msgToRequeue.isEmpty()) + { + _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); + } + } + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; + if (!(_txnContext instanceof NonTransactionalContext)) + { + if (_nonTransactedContext == null) + { + _nonTransactedContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + + deliveryContext = _nonTransactedContext; + } + else + { + deliveryContext = _txnContext; + } + + // Process Messages to Requeue at the front of the queue + for (UnacknowledgedMessage message : msgToRequeue) + { + message.entry.release(); + message.entry.setRedelivered(true); + + deliveryContext.deliver(message.entry, true); + + _unacknowledgedMessageMap.remove(message.deliveryTag); + } + } + + /** + * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to + * remove the queue reference and also decrement any message reference counts, without actually removing the item + * since we may get an ack for a delivery tag that was generated from the deleted queue. + * + * @param queue the queue that has been deleted + * + * @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.getQueue() == queue) + { + try + { + message.discard(_storeContext); + message.setQueueDeleted(true); + + } + catch (AMQException e) + { + _log.error( + "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); + } + } + + 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 + { + synchronized (_unacknowledgedMessageMap.getLock()) + { + if (_log.isDebugEnabled()) + { + _log.debug("Unacked (PreAck) Size:" + _unacknowledgedMessageMap.size()); + } + + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); + + if (_log.isDebugEnabled()) + { + _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size()); + } + + } + + checkSuspension(); + } + + /** + * Used only for testing purposes. + * + * @return the map of unacknowledged messages + */ + public UnacknowledgedMessageMap getUnacknowledgedMessageMap() + { + return _unacknowledgedMessageMap; + } + + private void checkSuspension() + { + boolean suspend; + + suspend = + ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) + || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); + + setSuspended(suspend); + } + + public void setSuspended(boolean suspended) + { + boolean isSuspended = _suspended.get(); + + if (isSuspended && !suspended) + { + // Continue being suspended if we are above the _prefetch_LowWaterMark + suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; + } + + boolean wasSuspended = _suspended.getAndSet(suspended); + if (wasSuspended != suspended) + { + if (wasSuspended) + { + _log.debug("Unsuspending channel " + this); + // may need to deliver queued messages + for (AMQQueue q : _consumerTag2QueueMap.values()) + { + q.deliverAsync(); + } + } + else + { + _log.debug("Suspending channel " + this); + } + } + } + + public boolean isSuspended() + { + return _suspended.get(); + } + + public void commit() throws AMQException + { + if (!isTransactional()) + { + throw new AMQException("Fatal error: commit called on non-transactional channel"); + } + + _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 mode: ").append(isTransactional()); + sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); + sb.append("/").append(_prefetch_HighWaterMark); + + return sb.toString(); + } + + public void setDefaultQueue(AMQQueue queue) + { + _defaultQueue = queue; + } + + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public StoreContext getStoreContext() + { + return _storeContext; + } + + public void processReturns(AMQProtocolSession session) throws AMQException + { + if (!_returnMessages.isEmpty()) + { + for (RequiredDeliveryException bouncedMessage : _returnMessages) + { + AMQMessage message = bouncedMessage.getAMQMessage(); + session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), + new AMQShortString(bouncedMessage.getMessage())); + + message.decrementReference(_storeContext); + } + + _returnMessages.clear(); + } + } + + public boolean wouldSuspend(AMQMessage msg) + { + if (isSuspended()) + { + return true; + } + else + { + boolean willSuspend = + ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); + if (!willSuspend) + { + final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); + + willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < (msg.getSize() + unackedSize)); + } + + if (willSuspend) + { + setSuspended(true); + } + + return willSuspend; + } + + } + + public TransactionalContext getTransactionalContext() + { + return _txnContext; + } + + public boolean isClosing() + { + return _closing; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java new file mode 100644 index 0000000000..9a98af5689 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -0,0 +1,25 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +public class ConsumerTagNotUniqueException extends Exception +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java new file mode 100644 index 0000000000..d8a8cfb6d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -0,0 +1,522 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.common.SimpleByteBufferAllocator; +import org.apache.mina.common.FixedSizeByteBufferAllocator; +import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; +import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; +import org.apache.qpid.server.protocol.AMQPProtocolProvider; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.url.URLSyntaxException; + +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; + +/** + * Main entry point for AMQPD. + * + */ +@SuppressWarnings({"AccessStaticViaInstance"}) +public class Main +{ + private static final Logger _logger = Logger.getLogger(Main.class); + public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); + + private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String QPID_HOME = "QPID_HOME"; + private static final int IPV4_ADDRESS_LENGTH = 4; + + private static final char IPV4_LITERAL_SEPARATOR = '.'; + + protected static class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } + + 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 mport = + OptionBuilder.withArgName("mport").hasArg() + .withDescription("listen on the specified management port. Overrides any value in the config file") + .withLongOpt("mport").create("m"); + + + 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(mport); + 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 = QpidProperties.getVersionString(); + + StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: "); + + boolean first = true; + for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) + { + if (first) + { + first = false; + } + else + { + protocol.append(", "); + } + + protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); + + } + + System.out.println(ver + " (" + protocol + ")"); + } + else + { + try + { + startup(); + } + catch (InitException e) + { + System.out.println(e.getMessage()); + _brokerLogger.error("Initialisation Error : " + e.getMessage()); + + } + catch (ConfigurationException e) + { + System.out.println("Error configuring message broker: " + e); + _brokerLogger.error("Error configuring message broker: " + e); + e.printStackTrace(); + } + catch (Exception e) + { + System.out.println("Error intialising message broker: " + e); + _brokerLogger.error("Error intialising message broker: " + e); + 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, null); + } + 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); + } + + ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); + + + updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); + + + + ApplicationRegistry.initialise(config); + + + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + // that are causing the broker build to pick up the wrong properties file and hence say + // Starting Qpid Client + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); + + ConnectorConfiguration connectorConfig = + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); + + ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); + + // the MINA default is currently to use the pooled allocator although this may change in future + // once more testing of the performance of the simple allocator has been done + if (!connectorConfig.enablePooledAllocator) + { + ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); + } + + 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, e); + } + } + + 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); + + } + + /** + * Update the configuration data with the management port. + * @param configuration + * @param managementPort The string from the command line + */ + private void updateManagementPort(Configuration configuration, String managementPort) + { + if (managementPort != null) + { + int mport; + int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); + try + { + mport = Integer.parseInt(managementPort); + configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); + } + catch (NumberFormatException e) + { + _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); + } + } + } + + 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) throws BindException + { + 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(ReadWriteThreadModel.getInstance()); + } + + if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) + { + 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); + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); + } + + if (connectorConfig.enableSSL) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + try + { + + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); + + } + catch (IOException e) + { + _brokerLogger.error("Unable to listen on SSL port: " + e, e); + } + } + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); + } + catch (Exception e) + { + _logger.error("Unable to bind service to registry: " + e, e); + //fixme this need tidying up + throw new BindException(e.getMessage()); + } + } + + public static void main(String[] args) + { + + new Main(args); + } + + private byte[] parseIP(String address) throws Exception + { + char[] literalBuffer = address.toCharArray(); + int byteCount = 0; + int currByte = 0; + byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; + for (int i = 0; i < literalBuffer.length; i++) + { + char currChar = literalBuffer[i]; + if ((currChar >= '0') && (currChar <= '9')) + { + currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); + } + + if (currChar == IPV4_LITERAL_SEPARATOR || (i + 1 == literalBuffer.length)) + { + ip[byteCount++] = (byte) currByte; + currByte = 0; + } + } + + if (byteCount != 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(); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java new file mode 100644 index 0000000000..e76f9c3f6c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server; + +import java.io.IOException; + +import javax.management.JMException; + +/** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java new file mode 100644 index 0000000000..d61bb8916a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the + * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. + * + *

      The failed message is associated with this error condition, by taking a reference to it. This enables the + * correct compensating action to be taken against the message, for example, bouncing it back to the sender. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      Associate the failed message with the error condition. {@link AMQMessage} + *
      + */ +public abstract class RequiredDeliveryException extends AMQException +{ + private final AMQMessage _amqMessage; + + public RequiredDeliveryException(String message, AMQMessage payload) + { + super(message); + + // Increment the reference as this message is in the routing phase + // and so will have the ref decremented as routing fails. + // we need to keep this message around so we can return it in the + // handler. So increment here. + _amqMessage = payload.takeReference(); + + // payload.incrementReference(); + } + + public AMQMessage getAMQMessage() + { + return _amqMessage; + } + + public AMQConstant getErrorCode() + { + return getReplyCode(); + } + + public abstract AMQConstant getReplyCode(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java new file mode 100644 index 0000000000..6ad704a5d8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -0,0 +1,153 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TxnOp; + +/** + * A TxnOp implementation for handling accumulated acks + */ +public class TxAck implements TxnOp +{ + private final UnacknowledgedMessageMap _map; + private final List _unacked = new ArrayList(); + private List _individual; + private long _deliveryTag; + private boolean _multiple; + + public TxAck(UnacknowledgedMessageMap map) + { + _map = map; + } + + public void update(long deliveryTag, boolean multiple) + { + if (!multiple) + { + if(_individual == null) + { + _individual = new ArrayList(); + } + //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; + } + _unacked.clear(); + } + + public void consolidate() + { + if(_unacked.isEmpty()) + { + consolidate(_unacked); + } + + } + + private void consolidate(List unacked) + { + //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 + if(_individual != null) + { + for (Long tag : _individual) + { + if(_deliveryTag < tag) + { + _map.collect(tag, false, unacked); + } + } + } + } + + public boolean checkPersistent() throws AMQException + { + + + consolidate(); + //if any of the messages in unacked are persistent the txn + //buffer must be marked as persistent: + for (UnacknowledgedMessage msg : _unacked) + { + if (msg.getMessage().isPersistent()) + { + return true; + } + } + return false; + } + + public void prepare(StoreContext storeContext) throws AMQException + { + //make persistent changes, i.e. dequeue and decrementReference + for (UnacknowledgedMessage msg : _unacked) + { + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(storeContext); + + } + } + + public void undoPrepare() + { + //decrementReference is annoyingly untransactional (due to + //in memory counter) so if we failed in prepare for full + //txn, this op will have to compensate by fixing the count + //in memory (persistent changes will be rolled back by store) + for (UnacknowledgedMessage msg : _unacked) + { + msg.getMessage().takeReference(); + } + } + + public void commit(StoreContext storeContext) + { + //remove the unacked messages from the channels map + _map.remove(_unacked); + } + + public void rollback(StoreContext storeContext) + { + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java new file mode 100644 index 0000000000..df7cecc940 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -0,0 +1,91 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; + +public class UnacknowledgedMessage +{ + public final QueueEntry entry; + public final AMQShortString consumerTag; + public final long deliveryTag; + + private boolean _queueDeleted; + + + public UnacknowledgedMessage(QueueEntry entry, AMQShortString consumerTag, long deliveryTag) + { + this.entry = entry; + this.consumerTag = consumerTag; + this.deliveryTag = deliveryTag; + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("Q:"); + sb.append(entry.getQueue()); + sb.append(" M:"); + sb.append(entry.getMessage()); + sb.append(" CT:"); + sb.append(consumerTag); + sb.append(" DT:"); + sb.append(deliveryTag); + + return sb.toString(); + } + + public void discard(StoreContext storeContext) throws AMQException + { + if (entry.getQueue() != null) + { + entry.getQueue().dequeue(storeContext, entry); + } + //if the queue is null then the message is waiting to be acked, but has been removed. + entry.getMessage().decrementReference(storeContext); + } + + public AMQMessage getMessage() + { + return entry.getMessage(); + } + + public AMQQueue getQueue() + { + return entry.getQueue(); + } + + public void setQueueDeleted(boolean queueDeleted) + { + _queueDeleted = queueDeleted; + } + + public boolean isQueueDeleted() + { + return _queueDeleted; + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java new file mode 100644 index 0000000000..5b0f3cf5eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TransactionalContext; + +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; + + Object getLock(); + + 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(); + + UnacknowledgedMessage get(long deliveryTag); + + /** + * Get the set of delivery tags that are outstanding. + * + * @return a set of delivery tags + */ + Set getDeliveryTags(); + + public long getUnacknowledgeBytes(); +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java new file mode 100644 index 0000000000..5204f13e81 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -0,0 +1,226 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TransactionalContext; + +public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap +{ + private final Object _lock = new Object(); + + private long _unackedSize; + + private Map _map; + + private long _lastDeliveryTag; + + private final int _prefetchLimit; + + public UnacknowledgedMessageMapImpl(int prefetchLimit) + { + _prefetchLimit = prefetchLimit; + _map = new LinkedHashMap(prefetchLimit); + } + + 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) + { + remove(msg.deliveryTag); + } + } + } + + public UnacknowledgedMessage remove(long deliveryTag) + { + synchronized (_lock) + { + + UnacknowledgedMessage message = _map.remove(deliveryTag); + if(message != null) + { + _unackedSize -= message.getMessage().getSize(); + } + + return message; + } + } + + public void visit(Visitor visitor) throws AMQException + { + synchronized (_lock) + { + Collection currentEntries = _map.values(); + for (UnacknowledgedMessage msg : currentEntries) + { + visitor.callback(msg); + } + visitor.visitComplete(); + } + } + + public Object getLock() + { + return _lock; + } + + public void add(long deliveryTag, UnacknowledgedMessage message) + { + synchronized (_lock) + { + _map.put(deliveryTag, message); + _unackedSize += message.getMessage().getSize(); + _lastDeliveryTag = deliveryTag; + } + } + + public Collection cancelAllMessages() + { + synchronized (_lock) + { + Collection currentEntries = _map.values(); + _map = new LinkedHashMap(_prefetchLimit); + _unackedSize = 0l; + 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(); + _unackedSize = 0l; + } + } + + 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(); + _unackedSize -= unacked.getValue().getMessage().getSize(); + + destination.add(unacked.getValue()); + if (unacked.getKey() == deliveryTag) + { + break; + } + } + } + } + + public UnacknowledgedMessage get(long key) + { + synchronized (_lock) + { + return _map.get(key); + } + } + + public Set getDeliveryTags() + { + synchronized (_lock) + { + return _map.keySet(); + } + } + + private void collect(Long key, List msgs) + { + synchronized (_lock) + { + for (Map.Entry entry : _map.entrySet()) + { + msgs.add(entry.getValue()); + if (entry.getKey().equals(key)) + { + break; + } + } + } + } + + public long getUnacknowledgeBytes() + { + return _unackedSize; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java new file mode 100644 index 0000000000..31c1b61a21 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java @@ -0,0 +1,118 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import java.lang.reflect.Field; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.server.registry.ApplicationRegistry; + +/** + * This class contains utilities for populating classes automatically from values pulled from configuration + * files. + */ +public class Configurator +{ + private static final Logger _logger = Logger.getLogger(Configurator.class); + + + /** + * Configure a given instance using the supplied configuration. Note that superclasses are not + * currently configured but this could easily be added if required. + * @param instance the instance to configure + * @param config the configuration to use to configure the object + */ + public static void configure(Object instance, Configuration config) + { + + for (Field f : instance.getClass().getDeclaredFields()) + { + Configured annotation = f.getAnnotation(Configured.class); + if (annotation != null) + { + setValueInField(f, instance, config, annotation); + } + } + } + + + + /** + * Configure a given instance using the application configuration. Note that superclasses are not + * currently configured but this could easily be added if required. + * @param instance the instance to configure + */ + public static void configure(Object instance) + { + configure(instance, ApplicationRegistry.getInstance().getConfiguration()); + } + + private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) + { + Class fieldClass = f.getType(); + String configPath = annotation.path(); + try + { + if (fieldClass == String.class) + { + String val = config.getString(configPath, annotation.defaultValue()); + val = PropertyUtils.replaceProperties(val); + f.set(instance, val); + } + else if (fieldClass == int.class) + { + int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue())); + f.setInt(instance, val); + } + else if (fieldClass == long.class) + { + long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue())); + f.setLong(instance, val); + } + else if (fieldClass == double.class) + { + double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue())); + f.setDouble(instance, val); + } + else if (fieldClass == boolean.class) + { + boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue())); + f.setBoolean(instance, val); + } + else + { + _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value"); + } + } + catch (PropertyException e) + { + _logger.error("Unable to expand property: " + e + " INGORING field " + f, e); + } + catch (IllegalAccessException e) + { + _logger.error("Unable to access field " + f + " IGNORING configured value"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java new file mode 100644 index 0000000000..8573902af4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -0,0 +1,269 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import java.util.Collections; +import java.util.List; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class VirtualHostConfiguration +{ + private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); + + private static XMLConfiguration _config; + + private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; + + + public VirtualHostConfiguration(String configFile) throws ConfigurationException + { + _logger.info("Loading Config file:" + configFile); + + _config = new XMLConfiguration(configFile); + + } + + + + private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException + { + _logger.debug("Loding configuration for virtaulhost: "+virtualHostName); + + + VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); + + + + if(virtualHost == null) + { + throw new ConfigurationException("Unknown virtual host: " + virtualHostName); + } + + List exchangeNames = configuration.getList("exchanges.exchange.name"); + + for(Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(virtualHost, exchangeName, configuration); + } + + + List queueNames = configuration.getList("queues.queue.name"); + + for(Object queueNameObj : queueNames) + { + String queueName = String.valueOf(queueNameObj); + configureQueue(virtualHost, queueName, configuration); + } + + } + + private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) throws AMQException + { + + CompositeConfiguration exchangeConfiguration = new CompositeConfiguration(); + + exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString)); + exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); + + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore messageStore = virtualHost.getMessageStore(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + AMQShortString exchangeName = new AMQShortString(exchangeNameString); + + + Exchange exchange; + + + + synchronized (exchangeRegistry) + { + exchange = exchangeRegistry.getExchange(exchangeName); + if(exchange == null) + { + + AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type","direct")); + boolean durable = exchangeConfiguration.getBoolean("durable",false); + boolean autodelete = exchangeConfiguration.getBoolean("autodelete",false); + + Exchange newExchange = exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); + exchangeRegistry.registerExchange(newExchange); + } + + } + } + + public static CompositeConfiguration getDefaultQueueConfiguration(AMQQueue queue) + { + CompositeConfiguration queueConfiguration = null; + if (_config == null) + return null; + + Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + queue.getVirtualHost().getName()); + + if (vHostConfiguration == null) + return null; + + Configuration defaultQueueConfiguration = vHostConfiguration.subset("queues"); + if (defaultQueueConfiguration != null) + { + queueConfiguration = new CompositeConfiguration(); + queueConfiguration.addConfiguration(defaultQueueConfiguration); + } + + return queueConfiguration; + } + + private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException + { + CompositeConfiguration queueConfiguration = new CompositeConfiguration(); + + queueConfiguration.addConfiguration(configuration.subset("queues.queue."+ queueNameString)); + queueConfiguration.addConfiguration(configuration.subset("queues")); + + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore messageStore = virtualHost.getMessageStore(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + + AMQShortString queueName = new AMQShortString(queueNameString); + + AMQQueue queue; + + synchronized (queueRegistry) + { + queue = queueRegistry.getQueue(queueName); + + if (queue == null) + { + _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName()); + + boolean durable = queueConfiguration.getBoolean("durable" ,false); + boolean autodelete = queueConfiguration.getBoolean("autodelete", false); + String owner = queueConfiguration.getString("owner", null); + + queue = new AMQQueue(queueName, + durable, + owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, + autodelete /* Therefore autodelete makes no sence */, virtualHost); + + if (queue.isDurable()) + { + messageStore.createQueue(queue); + } + + queueRegistry.registerQueue(queue); + } + else + { + _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating."); + } + + String exchangeName = queueConfiguration.getString("exchange", null); + + Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if(exchange == null) + { + exchange = virtualHost.getExchangeRegistry().getDefaultExchange(); + } + + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } + + synchronized (exchange) + { + List routingKeys = queueConfiguration.getList("routingKey"); + if(routingKeys == null || routingKeys.isEmpty()) + { + routingKeys = Collections.singletonList(queue.getName()); + } + + for(Object routingKeyNameObj : routingKeys) + { + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + + + queue.bind(routingKey, null, exchange); + + + _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); + } + + if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) + { + queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); + } + } + + } + + + + Configurator.configure(queue, queueConfiguration); + } + + + public void performBindings() throws AMQException, ConfigurationException + { + List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); + String defaultVirtualHostName = _config.getString("default"); + if(defaultVirtualHostName != null) + { + ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); + } + _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); + + for(Object nameObject : virtualHostNames) + { + String name = String.valueOf(nameObject); + configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name)); + } + + if (virtualHostNames == null || virtualHostNames.isEmpty()) + { + throw new ConfigurationException( + "Virtualhost Configuration document does not contain a valid virtualhost."); + } + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java new file mode 100644 index 0000000000..9ebb893362 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -0,0 +1,217 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.ArrayType; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.List; +import java.util.Map; + +public abstract class AbstractExchange implements Exchange, Managable +{ + private AMQShortString _name; + + + + protected boolean _durable; + protected String _exchangeType; + protected int _ticket; + + private VirtualHost _virtualHost; + + 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 + { + // open mbean data types for representing exchange bindings + protected String[] _bindingItemNames; + protected String[] _bindingItemIndexNames; + protected OpenType[] _bindingItemTypes; + protected CompositeType _bindingDataType; + protected TabularType _bindinglistDataType; + protected TabularDataSupport _bindingList; + + public ExchangeMBean() throws NotCompliantMBeanException + { + super(ManagedExchange.class, ManagedExchange.TYPE); + } + + protected void init() throws OpenDataException + { + _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[2]; + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + + public ManagedObject getParentObject() + { + return _virtualHost.getManagedObject(); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public String getExchangeType() + { + return _exchangeType; + } + + public Integer getTicketNo() + { + return _ticket; + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + // Added exchangetype in the object name lets maangement apps to do any customization required + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + _exchangeType; + return new ObjectName(objNameString); + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + } // End of MBean class + + public AMQShortString 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(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + { + _virtualHost = host; + _name = name; + _durable = durable; + _autoDelete = autoDelete; + _ticket = ticket; + _exchangeMbean = createMBean(); + _exchangeMbean.register(); + } + + 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(); + } + } + + abstract public Map> getBindings(); + + public String toString() + { + return getClass().getName() + "[" + getName() +"]"; + } + + public ManagedObject getManagedObject() + { + return _exchangeMbean; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public QueueRegistry getQueueRegistry() + { + return getVirtualHost().getQueueRegistry(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java new file mode 100644 index 0000000000..1a9dc6673a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -0,0 +1,113 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class DefaultExchangeFactory implements ExchangeFactory +{ + private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); + + private Map> _exchangeClassMap = new HashMap>(); + private final VirtualHost _host; + + public DefaultExchangeFactory(VirtualHost host) + { + _host = host; + registerExchangeType(DestNameExchange.TYPE); + registerExchangeType(DestWildExchange.TYPE); + registerExchangeType(HeadersExchange.TYPE); + registerExchangeType(FanoutExchange.TYPE); + } + + public void registerExchangeType(ExchangeType type) + { + _exchangeClassMap.put(type.getName(), type); + } + + public Collection> getRegisteredTypes() + { + return _exchangeClassMap.values(); + } + + public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException + { + ExchangeType exchType = _exchangeClassMap.get(type); + if (exchType == null) + { + + throw new AMQUnknownExchangeType("Unknown exchange type: " + type); + } + Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); + return e; + } + + public void initialise(Configuration hostConfig) + { + + if (hostConfig == null) + { + return; + } + + for(Object className : hostConfig.getList("custom-exchanges.class-name")) + { + try + { + ExchangeType exchangeType = ApplicationRegistry.getInstance().getPluginManager().getExchanges().get(String.valueOf(className)); + if (exchangeType == null) + { + _logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\""); + return; + } + Class exchangeTypeClass = exchangeType.getClass(); + ExchangeType type = exchangeTypeClass.newInstance(); + registerExchangeType(type); + } + catch (ClassCastException classCastEx) + { + _logger.error("No custom exchange class: \""+String.valueOf(className)+"\" cannot be registered as it does not extend class \""+ExchangeType.class+"\""); + } + catch (IllegalAccessException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } + catch (InstantiationException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java new file mode 100644 index 0000000000..98abf7977a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.protocol.ExchangeInitialiser; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; +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(); + + private Exchange _defaultExchange; + private VirtualHost _host; + + public DefaultExchangeRegistry(VirtualHost host) + { + //create 'standard' exchanges: + _host = host; + + } + + public void initialise() throws AMQException + { + new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); + } + + public MessageStore getMessageStore() + { + return _host.getMessageStore(); + } + + public void registerExchange(Exchange exchange) throws AMQException + { + _exchangeMap.put(exchange.getName(), exchange); + if (exchange.isDurable()) + { + getMessageStore().createExchange(exchange); + } + } + + public void setDefaultExchange(Exchange exchange) + { + _defaultExchange = exchange; + } + + public Exchange getDefaultExchange() + { + return _defaultExchange; + } + + public Collection getExchangeNames() + { + return _exchangeMap.keySet(); + } + + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException + { + // TODO: check inUse argument + Exchange e = _exchangeMap.remove(name); + if (e != null) + { + if (e.isDurable()) + { + getMessageStore().removeExchange(e); + } + e.close(); + } + else + { + throw new AMQException("Unknown exchange " + name); + } + } + + public Exchange getExchange(AMQShortString name) + { + if ((name == null) || name.length() == 0) + { + return getDefaultExchange(); + } + else + { + 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 AMQShortString exchange = payload.getMessagePublishInfo().getExchange(); + final Exchange exch = getExchange(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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java new file mode 100644 index 0000000000..12347c0278 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -0,0 +1,260 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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(); + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DestNameExchange.class; + } + + public DestNameExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + DestNameExchange exch = new DestNameExchange(); + exch.initialise(host,name,durable,ticket,autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_NAME; + } + }; + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Direct Exchange") + private final class DestNameExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DestNameExchangeMBean() throws JMException + { + super(); + _exchangeType = "direct"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + Map> bindings = _index.getBindingsMap(); + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (Map.Entry> entry : bindings.entrySet()) + { + AMQShortString key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = entry.getValue(); + for (AMQQueue q : queues) + { + queueList.add(q.getName().toString()); + } + + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(new AMQShortString(binding), null, DestNameExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + }// End of MBean class + + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DestNameExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public AMQShortString getType() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + + if (!_index.remove(routingKey, queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "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 MessagePublishInfo info = payload.getMessagePublishInfo(); + final AMQShortString routingKey = info.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : info.getRoutingKey(); + final List queues = (routingKey == null) ? null : _index.get(routingKey); + if (queues == null || queues.isEmpty()) + { + String msg = "Routing key " + routingKey + " is not known to " + this; + if (info.isMandatory() || info.isImmediate()) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); + _logger.warn(msg); + } + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + queues); + } + + payload.enqueue(queues); + + + } + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey,queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + final List queues = _index.get(routingKey); + return queues != null && queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + final List queues = _index.get(routingKey); + return queues != null && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + Map> bindings = _index.getBindingsMap(); + for (List queues : bindings.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() + { + return !_index.getBindingsMap().isEmpty(); + } + + public Map> getBindings() + { + return _index.getBindingsMap(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java new file mode 100644 index 0000000000..6fa3686152 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java @@ -0,0 +1,579 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortStringTokenizer; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class DestWildExchange extends AbstractExchange +{ + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DestWildExchange.class; + } + + public DestWildExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + DestWildExchange exch = new DestWildExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_NAME; + } + }; + + + private static final Logger _logger = Logger.getLogger(DestWildExchange.class); + + private final ConcurrentHashMap> _bindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _simpleBindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _wildCardBindingKey2queues = + new ConcurrentHashMap>(); + + private static final byte TOPIC_SEPARATOR = (byte)'.'; + private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); + private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); + private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); + private ConcurrentHashMap _bindingKey2Tokenized = + new ConcurrentHashMap(); + private static final byte HASH_BYTE = (byte)'#'; + private static final byte STAR_BYTE = (byte)'*'; + + /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */ + @MBeanDescription("Management Bean for Topic Exchange") + private final class DestWildExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public DestWildExchangeMBean() throws JMException + { + super(); + _exchangeType = "topic"; + init(); + } + + /** returns exchange bindings in tabular form */ + public TabularData bindings() throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + for (Map.Entry> entry : _bindingKey2queues.entrySet()) + { + AMQShortString key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = getMatchedQueues(key); + for (AMQQueue q : queues) + { + queueList.add(q.getName().toString()); + } + + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(new AMQShortString(binding), null, DestWildExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + public AMQShortString getType() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); + + // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition + List queueList = _bindingKey2queues.putIfAbsent(rKey, 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 = _bindingKey2queues.get(rKey); + } + + + + if (!queueList.contains(queue)) + { + queueList.add(queue); + + + if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) + { + AMQShortString routingKey = normalize(rKey); + List queueList2 = _wildCardBindingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList()); + + if(queueList2 == null) + { + queueList2 = _wildCardBindingKey2queues.get(routingKey); + AMQShortStringTokenizer keyTok = routingKey.tokenize(TOPIC_SEPARATOR); + + ArrayList keyTokList = new ArrayList(keyTok.countTokens()); + + while (keyTok.hasMoreTokens()) + { + keyTokList.add(keyTok.nextToken()); + } + + _bindingKey2Tokenized.put(routingKey, keyTokList.toArray(new AMQShortString[keyTokList.size()])); + } + queueList2.add(queue); + + } + else + { + List queueList2 = _simpleBindingKey2queues.putIfAbsent(rKey, new CopyOnWriteArrayList()); + if(queueList2 == null) + { + queueList2 = _simpleBindingKey2queues.get(rKey); + } + queueList2.add(queue); + + } + + + + + } + else if (_logger.isDebugEnabled()) + { + _logger.debug("Queue " + queue + " is already registered with routing key " + rKey); + } + + + + } + + private AMQShortString normalize(AMQShortString routingKey) + { + if(routingKey == null) + { + routingKey = AMQShortString.EMPTY_STRING; + } + + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + List subscriptionList = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + subscriptionList.add(routingTokens.nextToken()); + } + + int size = subscriptionList.size(); + + for (int index = 0; index < size; index++) + { + // if there are more levels + if ((index + 1) < size) + { + if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) + { + if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) + { + // we don't need #.# delete this one + subscriptionList.remove(index); + size--; + // redo this normalisation + index--; + } + + if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + subscriptionList.add(index + 1, subscriptionList.remove(index)); + } + } + } // if we have more levels + } + + + + AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); + + return normalizedString; + } + + public void route(AMQMessage payload) throws AMQException + { + MessagePublishInfo info = payload.getMessagePublishInfo(); + + final AMQShortString routingKey = info.getRoutingKey(); + + List queues = getMatchedQueues(routingKey); + // if we have no registered queues we have nothing to do + // TODO: add support for the immediate flag + if ((queues == null) || queues.isEmpty()) + { + if (info.isMandatory() || info.isImmediate()) + { + String msg = "Topic " + routingKey + " is not known to " + this; + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn("No queues found for routing key " + routingKey); + _logger.warn("Routing map contains: " + _bindingKey2queues); + + return; + } + } + + payload.enqueue(queues); + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + List queues = _bindingKey2queues.get(normalize(routingKey)); + + return (queues != null) && queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + List queues = _bindingKey2queues.get(normalize(routingKey)); + + return (queues != null) && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + for (List queues : _bindingKey2queues.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + + return false; + } + + public boolean hasBindings() + { + return !_bindingKey2queues.isEmpty(); + } + + public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + List queues = _bindingKey2queues.get(rKey); + if (queues == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + rKey + ". No queue was registered with that _routing key"); + + } + + boolean removedQ = queues.remove(queue); + if (!removedQ) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + rKey); + } + + + if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) + { + AMQShortString bindingKey = normalize(rKey); + List queues2 = _wildCardBindingKey2queues.get(bindingKey); + queues2.remove(queue); + if(queues2.isEmpty()) + { + _wildCardBindingKey2queues.remove(bindingKey); + _bindingKey2Tokenized.remove(bindingKey); + } + + } + else + { + List queues2 = _simpleBindingKey2queues.get(rKey); + queues2.remove(queue); + if(queues2.isEmpty()) + { + _simpleBindingKey2queues.remove(rKey); + } + + } + + + + + if (queues.isEmpty()) + { + _bindingKey2queues.remove(rKey); + } + } + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DestWildExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the topic exchenge mbean", ex); + throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); + } + } + + public Map> getBindings() + { + return _bindingKey2queues; + } + + private List getMatchedQueues(AMQShortString routingKey) + { + + List list = null; + + if(!_wildCardBindingKey2queues.isEmpty()) + { + + + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + final int routingTokensCount = routingTokens.countTokens(); + + + AMQShortString[] routingkeyTokens = new AMQShortString[routingTokensCount]; + + if(routingTokensCount == 1) + { + routingkeyTokens[0] =routingKey; + } + else + { + + + int token = 0; + while (routingTokens.hasMoreTokens()) + { + + AMQShortString next = routingTokens.nextToken(); + + routingkeyTokens[token++] = next; + } + } + for (AMQShortString bindingKey : _wildCardBindingKey2queues.keySet()) + { + + AMQShortString[] bindingKeyTokens = _bindingKey2Tokenized.get(bindingKey); + + + boolean matching = true; + boolean done = false; + + int depthPlusRoutingSkip = 0; + int depthPlusQueueSkip = 0; + + final int bindingKeyTokensCount = bindingKeyTokens.length; + + while (matching && !done) + { + + if ((bindingKeyTokensCount == depthPlusQueueSkip) || (routingTokensCount == depthPlusRoutingSkip)) + { + done = true; + + // if it was the routing key that ran out of digits + if (routingTokensCount == depthPlusRoutingSkip) + { + if (bindingKeyTokensCount > depthPlusQueueSkip) + { // a hash and it is the last entry + matching = + bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN) + && (bindingKeyTokensCount == (depthPlusQueueSkip + 1)); + } + } + else if (routingTokensCount > depthPlusRoutingSkip) + { + // There is still more routing key to check + matching = false; + } + + continue; + } + + // if the values on the two topics don't match + if (!bindingKeyTokens[depthPlusQueueSkip].equals(routingkeyTokens[depthPlusRoutingSkip])) + { + if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_STAR_TOKEN)) + { + depthPlusQueueSkip++; + depthPlusRoutingSkip++; + + continue; + } + else if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN)) + { + // Is this a # at the end + if (bindingKeyTokensCount == (depthPlusQueueSkip + 1)) + { + done = true; + + continue; + } + + // otherwise # in the middle + while (routingTokensCount > depthPlusRoutingSkip) + { + if (routingkeyTokens[depthPlusRoutingSkip].equals(bindingKeyTokens[depthPlusQueueSkip + 1])) + { + depthPlusQueueSkip += 2; + depthPlusRoutingSkip++; + + break; + } + + depthPlusRoutingSkip++; + } + + continue; + } + + matching = false; + } + + depthPlusQueueSkip++; + depthPlusRoutingSkip++; + } + + if (matching) + { + if(list == null) + { + list = new ArrayList(_wildCardBindingKey2queues.get(bindingKey)); + } + else + { + list.addAll(_wildCardBindingKey2queues.get(bindingKey)); + } + } + } + + } + if(!_simpleBindingKey2queues.isEmpty()) + { + List queues = _simpleBindingKey2queues.get(routingKey); + if(list == null) + { + if(queues == null) + { + list = Collections.EMPTY_LIST; + } + else + { + list = new ArrayList(queues); + } + } + else if(queues != null) + { + list.addAll(queues); + } + + } + + return list; + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java new file mode 100644 index 0000000000..37cd85a8f8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -0,0 +1,97 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.List; +import java.util.Map; + +public interface Exchange +{ + AMQShortString getName(); + + AMQShortString getType(); + + void initialise(VirtualHost host, AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void route(AMQMessage message) throws AMQException; + + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments + * @param routingKey + * @param arguments + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key + * @param routingKey + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, AMQQueue queue); + + /** + * Determines whether a message is routing to any queue using a specific _routing key + * @param routingKey + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey); + + boolean isBound(AMQQueue queue); + + /** + * Returns true if this exchange has at least one binding associated with it. + * @return + * @throws AMQException + */ + boolean hasBindings(); + + Map> getBindings(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java new file mode 100644 index 0000000000..0bcfec7181 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.Collection; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; + + +public interface ExchangeFactory +{ + Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException; + + void initialise(Configuration hostConfig); + + Collection> getRegisteredTypes(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java new file mode 100644 index 0000000000..c77f114428 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; + +/** + * ExchangeInUseRegistry indicates that an exchange cannot be unregistered because it is currently being used. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to unregister exchange that is in use. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo This exception is not used. However, it is part of the ExchangeRegistry interface, and looks like code is + * going to need to be added to throw/deal with this. Alternatively ExchangeResitries may be able to handle the + * issue internally. + */ +public class ExchangeInUseException extends AMQException +{ + public ExchangeInUseException(String exchangeName) + { + super("Exchange " + exchangeName + " is currently in use"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java new file mode 100644 index 0000000000..fe3b19e74e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; + +import java.util.Collection; + + +public interface ExchangeRegistry extends MessageRouter +{ + void registerExchange(Exchange exchange) throws AMQException; + + /** + * 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(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; + + Exchange getExchange(AMQShortString name); + + void setDefaultExchange(Exchange exchange); + + Exchange getDefaultExchange(); + + Collection getExchangeNames(); + + void initialise() throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java new file mode 100644 index 0000000000..0b55caa2f1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; + + +public interface ExchangeType +{ + public AMQShortString getName(); + public Class getExchangeClass(); + public T newInstance(VirtualHost host, AMQShortString name, + boolean durable, int ticket, boolean autoDelete) throws AMQException; + public AMQShortString getDefaultExchangeName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java new file mode 100644 index 0000000000..e7c887f306 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -0,0 +1,240 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class FanoutExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Fanout Exchange") + private final class FanoutExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") + public FanoutExchangeMBean() throws JMException + { + super(); + _exchangeType = "fanout"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (AMQQueue queue : _queues) + { + String queueName = queue.getName().toString(); + + Object[] bindingItemValues = {queueName, new String[]{queueName}}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(new AMQShortString(binding), null, FanoutExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new FanoutExchange.FanoutExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return FanoutExchange.class; + } + + public FanoutExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + FanoutExchange exch = new FanoutExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_NAME; + } + }; + + public Map> getBindings() + { + return null; + } + + public AMQShortString getType() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (_queues.contains(queue)) + { + _logger.debug("Queue " + queue + " is already registered"); + } + else + { + _queues.add(queue); + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); + } + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (!_queues.remove(queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); + } + } + + public void route(AMQMessage payload) throws AMQException + { + final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); + final AMQShortString routingKey = publishInfo.getRoutingKey(); + if ((_queues == null) || _queues.isEmpty()) + { + String msg = "No queues bound to " + this; + if (publishInfo.isMandatory() || publishInfo.isImmediate()) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn(msg); + } + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + _queues); + } + + payload.enqueue(new ArrayList(_queues)); + + } + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return _queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + + return (_queues != null) && !_queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + + return _queues.contains(queue); + } + + public boolean hasBindings() + { + return !_queues.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java new file mode 100644 index 0000000000..2b7df4361a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -0,0 +1,219 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.FieldTable; + +/** + * Defines binding and matching based on a set of headers. + */ +class HeadersBinding +{ + private static final Logger _logger = Logger.getLogger(HeadersBinding.class); + + private final FieldTable _mappings; + private final Set required = new HashSet(); + private final Map matches = new HashMap(); + private boolean matchAny; + + private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor + { + private Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor + { + Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if(required.contains(propertyName)) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + + + /** + * 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(FieldTable mappings) + { + _mappings = mappings; + initMappings(); + } + + private void initMappings() + { + + _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if (isSpecial(propertyName)) + { + processSpecial(propertyName, value.getValue()); + } + else if (value.getValue() == null || value.getValue().equals("")) + { + required.add(propertyName); + } + else + { + matches.put(propertyName,value.getValue()); + } + + return true; + } + + public Object getResult() + { + return null; + } + }); + } + + protected FieldTable 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(FieldTable headers) + { + if(headers == null) + { + return required.isEmpty() && matches.isEmpty(); + } + else + { + return matchAny ? or(headers) : and(headers); + } + } + + private boolean and(FieldTable headers) + { + if(headers.keys().containsAll(required)) + { + for(Map.Entry e : matches.entrySet()) + { + if(!e.getValue().equals(headers.getObject(e.getKey()))) + { + return false; + } + } + return true; + } + else + { + return false; + } + } + + + private boolean or(final FieldTable headers) + { + if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) + { + return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) + || (required.isEmpty() && matches.isEmpty()); + } + else + { + return true; + } + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java new file mode 100644 index 0000000000..68ad88c4cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -0,0 +1,360 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * An exchange that binds queues based on a set of required headers and header values + * and routes messages to these queues by matching the headers of the message against + * those with which the queues were bound. + *

      + *

      + * The Headers Exchange
      + *
      + *  Routes messages according to the value/presence of fields in the message header table.
      + *  (Basic and JMS content has a content header field called "headers" that is a table of
      + *   message header fields).
      + *
      + *  class = "headers"
      + *  routing key is not used
      + *
      + *  Has the following binding arguments:
      + *
      + *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
      + *  other fields prefixed with "X-" are ignored (and generate a console warning message).
      + *  a field with no value or empty value indicates a match on presence only.
      + *  a field with a value indicates match on field presence and specific value.
      + *
      + *  Standard instances:
      + *
      + *  amq.match - pub/sub on field content/value
      + *  
      + */ +public class HeadersExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(HeadersExchange.class); + + + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return HeadersExchange.class; + } + + public HeadersExchange newInstance(VirtualHost host, AMQShortString name, boolean durable, int ticket, + boolean autoDelete) throws AMQException + { + HeadersExchange exch = new HeadersExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + + return ExchangeDefaults.HEADERS_EXCHANGE_NAME; + } + }; + + + 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 + { + @MBeanConstructor("Creates an MBean for AMQ Headers exchange") + public HeadersExchangeMBean() throws JMException + { + super(); + _exchangeType = "headers"; + init(); + } + + /** + * initialises the OpenType objects. + */ + protected void init() throws OpenDataException + { + _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[3]; + _bindingItemTypes[0] = SimpleType.INTEGER; + _bindingItemTypes[1] = SimpleType.STRING; + _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + + public TabularData bindings() throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + int count = 1; + for (Iterator itr = _bindings.iterator(); itr.hasNext();) + { + Registration registration = itr.next(); + String queueName = registration.queue.getName().toString(); + + HeadersBinding headers = registration.binding; + FieldTable headerMappings = headers.getMappings(); + final List mappingList = new ArrayList(); + + headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + mappingList.add(propertyName + "=" + value.getValue()); + return true; + } + + public Object getResult() + { + return mappingList; + } + }); + + + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + /** + * Creates bindings. Binding pattern is as follows- + * =,=,... + * @param queueName + * @param binding + * @throws javax.management.JMException + */ + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + String[] bindings = binding.split(","); + FieldTable bindingMap = new FieldTable(); + for (int i = 0; i < bindings.length; i++) + { + String[] keyAndValue = bindings[i].split("="); + if (keyAndValue == null || keyAndValue.length < 2) + { + throw new JMException("Format for headers binding should be \"=,=\" "); + } + bindingMap.setString(keyAndValue[0], keyAndValue[1]); + } + + _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); + } + + } // End of MBean class + + public AMQShortString getType() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); + _bindings.add(new Registration(new HeadersBinding(args), queue)); + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); + if(!_bindings.remove(new Registration(new HeadersBinding(args), queue))) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with headers args " + args); + } + } + + public void route(AMQMessage payload) throws AMQException + { + FieldTable 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) + { + + String msg = "Exchange " + getName() + ": message not routable."; + + if (payload.getMessagePublishInfo().isMandatory() || payload.getMessagePublishInfo().isImmediate()) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn(msg); + } + + } + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + //fixme isBound here should take the arguements in to consideration. + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return isBound(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + return hasBindings(); + } + + public boolean isBound(AMQQueue queue) + { + for (Registration r : _bindings) + { + if (r.queue.equals(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() + { + return !_bindings.isEmpty(); + } + + protected FieldTable 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 (JMException ex) + { + _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); + throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); + } + } + + public Map> getBindings() + { + return null; + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java new file mode 100644 index 0000000000..eacdad8a8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -0,0 +1,90 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * 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>(); + + synchronized boolean add(AMQShortString 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); + } + } + + synchronized boolean remove(AMQShortString 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(AMQShortString key) + { + return _index.get(key); + } + + Map> getBindingsMap() + { + return new HashMap>(_index); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java new file mode 100644 index 0000000000..5d6d68b3c8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.queue.ManagedQueue; + +/** + * The management interface exposed to allow management of an Exchange. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedExchange +{ + static final String TYPE = "Exchange"; + + /** + * Returns the name of the managed exchange. + * @return the name of the exchange. + * @throws IOException + */ + @MBeanAttribute(name="Name", description=TYPE + " Name") + String getName() throws IOException; + + @MBeanAttribute(name="ExchangeType", description="Exchange Type") + String getExchangeType() throws IOException; + + @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") + Integer getTicketNo() throws IOException; + + /** + * Tells if the exchange is durable or not. + * @return true if the exchange is durable. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description="true if Exchange is durable") + boolean isDurable() throws IOException; + + /** + * Tells if the exchange is set for autodelete or not. + * @return true if the exchange is set as autodelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") + boolean isAutoDelete() throws IOException; + + // Operations + + /** + * Returns all the bindings this exchange has with the queues. + * @return the bindings with the exchange. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") + TabularData bindings() throws IOException, JMException; + + /** + * Creates new binding with the given queue and binding. + * @param queueName + * @param binding + * @throws JMException + */ + @MBeanOperation(name="createNewBinding", + description="create a new binding with this exchange", + impact= MBeanOperationInfo.ACTION) + void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, + @MBeanOperationParameter(name="Binding", description="New binding")String binding) + throws JMException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java new file mode 100644 index 0000000000..7508e80f7f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java new file mode 100644 index 0000000000..1d6ab3842d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message + * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report + * this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      + */ +public class NoRouteException extends RequiredDeliveryException +{ + public NoRouteException(String msg, AMQMessage message) + { + super(msg, message); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.NO_ROUTE; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java new file mode 100644 index 0000000000..fb5220f4da --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -0,0 +1,275 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * An expression which performs an operation on two expression values + */ +public abstract class ArithmeticExpression extends BinaryExpression +{ + + protected static final int INTEGER = 1; + protected static final int LONG = 2; + protected static final int DOUBLE = 3; + + /** + * @param left + * @param right + */ + public ArithmeticExpression(Expression left, Expression right) + { + super(left, right); + } + + public static Expression createPlus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof String) + { + String text = (String) lvalue; + String answer = text + rvalue; + + return answer; + } + else if (lvalue instanceof Number) + { + return plus((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "+"; + } + }; + } + + public static Expression createMinus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return minus((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "-"; + } + }; + } + + public static Expression createMultiply(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return multiply((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "*"; + } + }; + } + + public static Expression createDivide(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return divide((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "/"; + } + }; + } + + public static Expression createMod(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return mod((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "%"; + } + }; + } + + protected Number plus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() + right.intValue()); + + case LONG: + return new Long(left.longValue() + right.longValue()); + + default: + return new Double(left.doubleValue() + right.doubleValue()); + } + } + + protected Number minus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() - right.intValue()); + + case LONG: + return new Long(left.longValue() - right.longValue()); + + default: + return new Double(left.doubleValue() - right.doubleValue()); + } + } + + protected Number multiply(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() * right.intValue()); + + case LONG: + return new Long(left.longValue() * right.longValue()); + + default: + return new Double(left.doubleValue() * right.doubleValue()); + } + } + + protected Number divide(Number left, Number right) + { + return new Double(left.doubleValue() / right.doubleValue()); + } + + protected Number mod(Number left, Number right) + { + return new Double(left.doubleValue() % right.doubleValue()); + } + + private int numberType(Number left, Number right) + { + if (isDouble(left) || isDouble(right)) + { + return DOUBLE; + } + else if ((left instanceof Long) || (right instanceof Long)) + { + return LONG; + } + else + { + return INTEGER; + } + } + + private boolean isDouble(Number n) + { + return (n instanceof Float) || (n instanceof Double); + } + + protected Number asNumber(Object value) + { + if (value instanceof Number) + { + return (Number) value; + } + else + { + throw new RuntimeException("Cannot convert value: " + value + " into a number"); + } + } + + public Object evaluate(AMQMessage message) throws AMQException + { + Object lvalue = left.evaluate(message); + if (lvalue == null) + { + return null; + } + + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + return evaluate(lvalue, rvalue); + } + + /** + * @param lvalue + * @param rvalue + * @return + */ + protected abstract Object evaluate(Object lvalue, Object rvalue); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java new file mode 100644 index 0000000000..024257bea9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -0,0 +1,106 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +/** + * An expression which performs an operation on two expression values. + */ +public abstract class BinaryExpression implements Expression +{ + protected Expression left; + protected Expression right; + + public BinaryExpression(Expression left, Expression right) + { + this.left = left; + this.right = right; + } + + public Expression getLeft() + { + return left; + } + + public Expression getRight() + { + return right; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + public abstract String getExpressionSymbol(); + + /** + * @param expression + */ + public void setRight(Expression expression) + { + right = expression; + } + + /** + * @param expression + */ + public void setLeft(Expression expression) + { + left = expression; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java new file mode 100644 index 0000000000..e28ff79820 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -0,0 +1,40 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * A BooleanExpression is an expression that always + * produces a Boolean result. + */ +public interface BooleanExpression extends Expression +{ + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws AMQException + */ + public boolean matches(AMQMessage message) throws AMQException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java new file mode 100644 index 0000000000..44281a3aae --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -0,0 +1,634 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.util.HashSet; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * A filter performing a comparison of two objects + */ +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression +{ + + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) + { + return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); + } + + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) + { + return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); + } + + private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); + + static + { + REGEXP_CONTROL_CHARS.add(new Character('.')); + REGEXP_CONTROL_CHARS.add(new Character('\\')); + REGEXP_CONTROL_CHARS.add(new Character('[')); + REGEXP_CONTROL_CHARS.add(new Character(']')); + REGEXP_CONTROL_CHARS.add(new Character('^')); + REGEXP_CONTROL_CHARS.add(new Character('$')); + REGEXP_CONTROL_CHARS.add(new Character('?')); + REGEXP_CONTROL_CHARS.add(new Character('*')); + REGEXP_CONTROL_CHARS.add(new Character('+')); + REGEXP_CONTROL_CHARS.add(new Character('{')); + REGEXP_CONTROL_CHARS.add(new Character('}')); + REGEXP_CONTROL_CHARS.add(new Character('|')); + REGEXP_CONTROL_CHARS.add(new Character('(')); + REGEXP_CONTROL_CHARS.add(new Character(')')); + REGEXP_CONTROL_CHARS.add(new Character(':')); + REGEXP_CONTROL_CHARS.add(new Character('&')); + REGEXP_CONTROL_CHARS.add(new Character('<')); + REGEXP_CONTROL_CHARS.add(new Character('>')); + REGEXP_CONTROL_CHARS.add(new Character('=')); + REGEXP_CONTROL_CHARS.add(new Character('!')); + } + + static class LikeExpression extends UnaryExpression implements BooleanExpression + { + + Pattern likePattern; + + /** + * @param right + */ + public LikeExpression(Expression right, String like, int escape) + { + super(right); + + StringBuffer regexp = new StringBuffer(like.length() * 2); + regexp.append("\\A"); // The beginning of the input + for (int i = 0; i < like.length(); i++) + { + char c = like.charAt(i); + if (escape == (0xFFFF & c)) + { + i++; + if (i >= like.length()) + { + // nothing left to escape... + break; + } + + char t = like.charAt(i); + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & t)); + } + else if (c == '%') + { + regexp.append(".*?"); // Do a non-greedy match + } + else if (c == '_') + { + regexp.append("."); // match one + } + else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) + { + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & c)); + } + else + { + regexp.append(c); + } + } + + regexp.append("\\z"); // The end of the input + + likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); + } + + /** + * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() + */ + public String getExpressionSymbol() + { + return "LIKE"; + } + + /** + * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) + */ + public Object evaluate(AMQMessage message) throws AMQException + { + + Object rv = this.getRight().evaluate(message); + + if (rv == null) + { + return null; + } + + if(rv instanceof AMQShortString) + { + rv = rv.toString(); + } + + if (!(rv instanceof String)) + { + return + Boolean.FALSE; + // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); + } + + return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; + } + + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + + public static BooleanExpression createLike(Expression left, String right, String escape) + { + if ((escape != null) && (escape.length() != 1)) + { + throw new RuntimeException( + "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); + } + + int c = -1; + if (escape != null) + { + c = 0xFFFF & escape.charAt(0); + } + + return new LikeExpression(left, right, c); + } + + public static BooleanExpression createNotLike(Expression left, String right, String escape) + { + return UnaryExpression.createNOT(createLike(left, right, escape)); + } + + public static BooleanExpression createInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); + + } + + public static BooleanExpression createNotInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); + + } + + public static BooleanExpression createIsNull(Expression left) + { + return doCreateEqual(left, ConstantExpression.NULL); + } + + public static BooleanExpression createIsNotNull(Expression left) + { + return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); + } + + public static BooleanExpression createNotEqual(Expression left, Expression right) + { + return UnaryExpression.createNOT(createEqual(left, right)); + } + + public static BooleanExpression createEqual(Expression left, Expression right) + { + checkEqualOperand(left); + checkEqualOperand(right); + checkEqualOperandCompatability(left, right); + + return doCreateEqual(left, right); + } + + private static BooleanExpression doCreateEqual(Expression left, Expression right) + { + return new ComparisonExpression(left, right) + { + + public Object evaluate(AMQMessage message) throws AMQException + { + Object lv = left.evaluate(message); + Object rv = right.evaluate(message); + + // Iff one of the values is null + if ((lv == null) ^ (rv == null)) + { + return Boolean.FALSE; + } + + if ((lv == rv) || lv.equals(rv)) + { + return Boolean.TRUE; + } + + if ((lv instanceof Comparable) && (rv instanceof Comparable)) + { + return compare((Comparable) lv, (Comparable) rv); + } + + return Boolean.FALSE; + } + + protected boolean asBoolean(int answer) + { + return answer == 0; + } + + public String getExpressionSymbol() + { + return "="; + } + }; + } + + public static BooleanExpression createGreaterThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { + return answer > 0; + } + + public String getExpressionSymbol() + { + return ">"; + } + }; + } + + public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { + return answer >= 0; + } + + public String getExpressionSymbol() + { + return ">="; + } + }; + } + + public static BooleanExpression createLessThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + + protected boolean asBoolean(int answer) + { + return answer < 0; + } + + public String getExpressionSymbol() + { + return "<"; + } + + }; + } + + public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + + protected boolean asBoolean(int answer) + { + return answer <= 0; + } + + public String getExpressionSymbol() + { + return "<="; + } + }; + } + + /** + * Only Numeric expressions can be used in >, >=, < or <= expressions.s + * + * @param expr + */ + public static void checkLessThanOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value instanceof Number) + { + return; + } + + // Else it's boolean or a String.. + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + + if (expr instanceof BooleanExpression) + { + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + } + + /** + * Validates that the expression can be used in == or <> expression. + * Cannot not be NULL TRUE or FALSE litterals. + * + * @param expr + */ + public static void checkEqualOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value == null) + { + throw new RuntimeException("'" + expr + "' cannot be compared."); + } + } + } + + /** + * + * @param left + * @param right + */ + private static void checkEqualOperandCompatability(Expression left, Expression right) + { + if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) + { + if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) + { + throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); + } + } + } + + /** + * @param left + * @param right + */ + public ComparisonExpression(Expression left, Expression right) + { + super(left, right); + } + + public Object evaluate(AMQMessage message) throws AMQException + { + Comparable lv = (Comparable) left.evaluate(message); + if (lv == null) + { + return null; + } + + Comparable rv = (Comparable) right.evaluate(message); + if (rv == null) + { + return null; + } + + return compare(lv, rv); + } + + protected Boolean compare(Comparable lv, Comparable rv) + { + Class lc = lv.getClass(); + Class rc = rv.getClass(); + // If the the objects are not of the same type, + // try to convert up to allow the comparison. + if (lc != rc) + { + if(lc == AMQShortString.class) + { + if(rc == String.class) + { + rv = new AMQShortString((String) rv); + + if(right instanceof ConstantExpression) + { + ((ConstantExpression)right).setValue(rv); + } + } + else + { + return Boolean.FALSE; + } + } + else if(lc == String.class) + { + if(rc == AMQShortString.class) + { + lv = new AMQShortString((String) lv); + + if(left instanceof ConstantExpression) + { + ((ConstantExpression)left).setValue(lv); + } + } + else + { + return Boolean.FALSE; + } + + } + else if (lc == Byte.class) + { + if (rc == Short.class) + { + lv = new Short(((Number) lv).shortValue()); + } + else if (rc == Integer.class) + { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Short.class) + { + if (rc == Integer.class) + { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Integer.class) + { + if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Long.class) + { + if (rc == Integer.class) + { + rv = new Long(((Number) rv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Float.class) + { + if (rc == Integer.class) + { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Long.class) + { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Double.class) + { + if (rc == Integer.class) + { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Long.class) + { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Float.class) + { + rv = new Float(((Number) rv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else + { + return Boolean.FALSE; + } + } + + return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; + } + + protected abstract boolean asBoolean(int answer); + + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java new file mode 100644 index 0000000000..73c4c66ad7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -0,0 +1,217 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.math.BigDecimal; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Represents a constant expression + */ +public class ConstantExpression implements Expression +{ + + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression + { + public BooleanConstantExpression(Object value) + { + super(value); + } + + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + + public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); + public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); + public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); + + private Object value; + + public static ConstantExpression createFromDecimal(String text) + { + + // Strip off the 'l' or 'L' if needed. + if (text.endsWith("l") || text.endsWith("L")) + { + text = text.substring(0, text.length() - 1); + } + + Number value; + try + { + value = new Long(text); + } + catch (NumberFormatException e) + { + // The number may be too big to fit in a long. + value = new BigDecimal(text); + } + + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFromHex(String text) + { + Number value = new Long(Long.parseLong(text.substring(2), 16)); + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFromOctal(String text) + { + Number value = new Long(Long.parseLong(text, 8)); + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFloat(String text) + { + Number value = new Double(text); + + return new ConstantExpression(value); + } + + public ConstantExpression(Object value) + { + this.value = value; + } + + public Object evaluate(AMQMessage message) throws AMQException + { + return value; + } + + public Object getValue() + { + return value; + } + + public void setValue(final Object value) + { + this.value = value; + } + + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + if (value == null) + { + return "NULL"; + } + + if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; + } + + if (value instanceof String) + { + return encodeString((String) value); + } + + return value.toString(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Encodes the value of string so that it looks like it would look like + * when it was provided in a selector. + * + * @param s + * @return + */ + public static String encodeString(String s) + { + StringBuffer b = new StringBuffer(); + b.append('\''); + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + if (c == '\'') + { + b.append(c); + } + + b.append(c); + } + + b.append('\''); + + return b.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java new file mode 100644 index 0000000000..5f646c15db --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -0,0 +1,37 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Represents an expression + */ +public interface Expression +{ + + /** + * @return the value of this expression + */ + public Object evaluate(AMQMessage message) throws AMQException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java new file mode 100644 index 0000000000..c82de9fa15 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; + +public interface FilterManager +{ + void add(MessageFilter filter); + + void remove(MessageFilter filter); + + boolean allAllow(AMQMessage msg); + + boolean hasFilters(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java new file mode 100644 index 0000000000..311f0680ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.framing.FieldTable; + + +public class FilterManagerFactory +{ + //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); + private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); + + //fixme move to a common class so it can be refered to from client code. + + public static FilterManager createManager(FieldTable filters) throws AMQException + { + FilterManager manager = null; + + if (filters != null) + { + + manager = new SimpleFilterManager(); + + if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) + { + String selector = filters.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); + + if (selector != null && !selector.equals("")) + { + manager.add(new JMSSelectorFilter(selector)); + } + + } + + if (filters.containsKey(AMQPFilterTypes.NO_CONSUME.getValue())) + { + manager.add(new NoConsumerFilter()); + } + + + + //If we added no filters don't bear the overhead of having an filter manager + if (!manager.hasFilters()) + { + manager = null; + } + } + else + { + _logger.debug("No Filters found."); + } + + + return manager; + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java new file mode 100644 index 0000000000..48b6602bda --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.qpid.server.queue.AMQMessage; + + + +public class JMSSelectorFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); + + private String _selector; + private BooleanExpression _matcher; + + public JMSSelectorFilter(String selector) throws AMQException + { + _selector = selector; + _logger.info("Created JMSSelectorFilter with selector:" + _selector); + + + _matcher = new SelectorParser().parse(selector); + + + } + + public boolean matches(AMQMessage message) + { + try + { + boolean match = _matcher.matches(message); + if(_logger.isDebugEnabled()) + { + _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); + } + return match; + } + catch (AMQException e) + { + //fixme this needs to be sorted.. it shouldn't happen + e.printStackTrace(); + } + return false; + } + + public String getSelector() + { + return _selector; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java new file mode 100644 index 0000000000..c8cbdb2125 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -0,0 +1,110 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * A filter performing a comparison of two objects + */ +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression +{ + + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new LogicExpression(lvalue, rvalue) + { + + public Object evaluate(AMQMessage message) throws AMQException + { + + Boolean lv = (Boolean) left.evaluate(message); + // Can we do an OR shortcut?? + if ((lv != null) && lv.booleanValue()) + { + return Boolean.TRUE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "OR"; + } + }; + } + + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new LogicExpression(lvalue, rvalue) + { + + public Object evaluate(AMQMessage message) throws AMQException + { + + Boolean lv = (Boolean) left.evaluate(message); + + // Can we do an AND shortcut?? + if (lv == null) + { + return null; + } + + if (!lv.booleanValue()) + { + return Boolean.FALSE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "AND"; + } + }; + } + + /** + * @param left + * @param right + */ + public LogicExpression(BooleanExpression left, BooleanExpression right) + { + super(left, right); + } + + public abstract Object evaluate(AMQMessage message) throws AMQException; + + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java new file mode 100644 index 0000000000..e6bfe974d5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +public interface MessageFilter +{ + boolean matches(AMQMessage message) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java new file mode 100644 index 0000000000..47ca930d12 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +public class NoConsumerFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(NoConsumerFilter.class); + + + public NoConsumerFilter() throws AMQException + { + _logger.info("Created NoConsumerFilter"); + } + + public boolean matches(AMQMessage message) + { + return true; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java new file mode 100644 index 0000000000..e5e9acf9bb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -0,0 +1,322 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Represents a property expression + */ +public class PropertyExpression implements Expression +{ + // Constants - defined the same as JMS + private static final int NON_PERSISTENT = 1; + private static final int PERSISTENT = 2; + private static final int DEFAULT_PRIORITY = 4; + + private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); + + private static final HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); + + static + { + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() + { + public Object evaluate(AMQMessage message) + { + //TODO + return null; + } + }); + JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString replyTo = _properties.getReplyTo(); + + return (replyTo == null) ? null : replyTo; + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString type = _properties.getType(); + + return (type == null) ? null : type; + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; + if (_logger.isDebugEnabled()) + { + _logger.debug("JMSDeliveryMode is :" + mode); + } + + return mode; + } + catch (AMQException e) + { + _logger.warn(e); + } + + return NON_PERSISTENT; + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression() + { + public Object evaluate(AMQMessage message) + { + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return (int) _properties.getPriority(); + } + catch (AMQException e) + { + _logger.warn(e); + } + + return DEFAULT_PRIORITY; + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString messageId = _properties.getMessageId(); + + return (messageId == null) ? null : messageId; + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getTimestamp(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString correlationId = _properties.getCorrelationId(); + + return (correlationId == null) ? null : correlationId; + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression() + { + public Object evaluate(AMQMessage message) + { + + try + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getExpiration(); + } + catch (AMQException e) + { + _logger.warn(e); + + return null; + } + + } + }); + + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() + { + public Object evaluate(AMQMessage message) + { + return message.isRedelivered(); + } + }); + + } + + private final AMQShortString name; + private final Expression jmsPropertyExpression; + + public PropertyExpression(String name) + { + this.name = new AMQShortString(name); + jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); + } + + public Object evaluate(AMQMessage message) throws AMQException + { + + if (jmsPropertyExpression != null) + { + return jmsPropertyExpression.evaluate(message); + } + else + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + + if (_logger.isDebugEnabled()) + { + _logger.debug("Looking up property:" + name); + _logger.debug("Properties are:" + _properties.getHeaders().keySet()); + } + + return _properties.getHeaders().getObject(name); + } + } + + public AMQShortString getName() + { + return name; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return name.toString(); + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return name.equals(((PropertyExpression) o).name); + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java new file mode 100644 index 0000000000..62a45f5420 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +public class SimpleFilterManager implements FilterManager +{ + private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); + + private final ConcurrentLinkedQueue _filters; + + public SimpleFilterManager() + { + _logger.debug("Creating SimpleFilterManager"); + _filters = new ConcurrentLinkedQueue(); + } + + public void add(MessageFilter filter) + { + _filters.add(filter); + } + + public void remove(MessageFilter filter) + { + _filters.remove(filter); + } + + public boolean allAllow(AMQMessage msg) + { + for (MessageFilter filter : _filters) + { + try + { + if (!filter.matches(msg)) + { + return false; + } + } + catch (AMQException e) + { + //fixme + e.printStackTrace(); + return false; + } + } + return true; + } + + public boolean hasFilters() + { + return !_filters.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java new file mode 100644 index 0000000000..83b4ed5358 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -0,0 +1,337 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * An expression which performs an operation on two expression values + */ +public abstract class UnaryExpression implements Expression +{ + + private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); + protected Expression right; + + public static Expression createNegate(Expression left) + { + return new UnaryExpression(left) + { + public Object evaluate(AMQMessage message) throws AMQException + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue instanceof Number) + { + return negate((Number) rvalue); + } + + return null; + } + + public String getExpressionSymbol() + { + return "-"; + } + }; + } + + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + { + + // Use a HashSet if there are many elements. + Collection t; + if (elements.size() == 0) + { + t = null; + } + else if (elements.size() < 5) + { + t = elements; + } + else + { + t = new HashSet(elements); + } + + final Collection inList = t; + + return new BooleanUnaryExpression(right) + { + public Object evaluate(AMQMessage message) throws AMQException + { + + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue.getClass() != String.class) + { + return null; + } + + if (((inList != null) && inList.contains(rvalue)) ^ not) + { + return Boolean.TRUE; + } + else + { + return Boolean.FALSE; + } + + } + + public String toString() + { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count = 0; + for (Iterator i = inList.iterator(); i.hasNext();) + { + Object o = (Object) i.next(); + if (count != 0) + { + answer.append(", "); + } + + answer.append(o); + count++; + } + + answer.append(" )"); + + return answer.toString(); + } + + public String getExpressionSymbol() + { + if (not) + { + return "NOT IN"; + } + else + { + return "IN"; + } + } + }; + } + + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + { + public BooleanUnaryExpression(Expression left) + { + super(left); + } + + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + ; + + public static BooleanExpression createNOT(BooleanExpression left) + { + return new BooleanUnaryExpression(left) + { + public Object evaluate(AMQMessage message) throws AMQException + { + Boolean lvalue = (Boolean) right.evaluate(message); + if (lvalue == null) + { + return null; + } + + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + public String getExpressionSymbol() + { + return "NOT"; + } + }; + } + + public static BooleanExpression createXPath(final String xpath) + { + return new XPathExpression(xpath); + } + + public static BooleanExpression createXQuery(final String xpath) + { + return new XQueryExpression(xpath); + } + + public static BooleanExpression createBooleanCast(Expression left) + { + return new BooleanUnaryExpression(left) + { + public Object evaluate(AMQMessage message) throws AMQException + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (!rvalue.getClass().equals(Boolean.class)) + { + return Boolean.FALSE; + } + + return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + public String toString() + { + return right.toString(); + } + + public String getExpressionSymbol() + { + return ""; + } + }; + } + + private static Number negate(Number left) + { + Class clazz = left.getClass(); + if (clazz == Integer.class) + { + return new Integer(-left.intValue()); + } + else if (clazz == Long.class) + { + return new Long(-left.longValue()); + } + else if (clazz == Float.class) + { + return new Float(-left.floatValue()); + } + else if (clazz == Double.class) + { + return new Double(-left.doubleValue()); + } + else if (clazz == BigDecimal.class) + { + // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the + // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it + // as a Big decimal. But it gets Negated right away.. to here we try to covert it back + // to a Long. + BigDecimal bd = (BigDecimal) left; + bd = bd.negate(); + + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) + { + return new Long(Long.MIN_VALUE); + } + + return bd; + } + else + { + throw new RuntimeException("Don't know how to negate: " + left); + } + } + + public UnaryExpression(Expression left) + { + this.right = left; + } + + public Expression getRight() + { + return right; + } + + public void setRight(Expression expression) + { + right = expression; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + public abstract String getExpressionSymbol(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java new file mode 100644 index 0000000000..f5454afae5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -0,0 +1,126 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Used to evaluate an XPath Expression in a JMS selector. + */ +public final class XPathExpression implements BooleanExpression { + + private static final Logger log = Logger.getLogger(XPathExpression.class); + private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.qpid.server.filter.XPathEvaluatorClassName"; + private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName(); + + private static final Constructor EVALUATOR_CONSTRUCTOR; + + static { + String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); + Constructor m = null; + try { + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e) { + log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e); + cn = DEFAULT_EVALUATOR_CLASS_NAME; + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e2) { + log.error("Default XPath evaluator could not be loaded",e); + } + } + } finally { + EVALUATOR_CONSTRUCTOR = m; + } + } + + private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { + Class c = XPathExpression.class.getClassLoader().loadClass(cn); + if( !XPathEvaluator.class.isAssignableFrom(c) ) { + throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class); + } + return c.getConstructor(new Class[]{String.class}); + } + + private final String xpath; + private final XPathEvaluator evaluator; + + static public interface XPathEvaluator { + public boolean evaluate(AMQMessage message) throws AMQException; + } + + XPathExpression(String xpath) { + this.xpath = xpath; + this.evaluator = createEvaluator(xpath); + } + + private XPathEvaluator createEvaluator(String xpath2) { + try { + return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath}); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if( cause instanceof RuntimeException ) { + throw (RuntimeException)cause; + } + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } catch (Throwable e) { + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } + } + + public Object evaluate(AMQMessage message) throws AMQException { +// try { +//FIXME this is flow to disk work +// if( message.isDropped() ) +// return null; + return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE; +// } catch (IOException e) { +// +// JMSException exception = new JMSException(e.getMessage()); +// exception.initCause(e); +// throw exception; +// +// } + + } + + public String toString() { + return "XPATH "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws AMQException + */ + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java new file mode 100644 index 0000000000..f5debb607a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -0,0 +1,57 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +/** + * Used to evaluate an XQuery Expression in a JMS selector. + */ +public final class XQueryExpression implements BooleanExpression { + private final String xpath; + + XQueryExpression(String xpath) { + super(); + this.xpath = xpath; + } + + public Object evaluate(AMQMessage message) throws AMQException { + return Boolean.FALSE; + } + + public String toString() { + return "XQUERY "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws AMQException + */ + public boolean matches(AMQMessage message) throws AMQException + { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java new file mode 100644 index 0000000000..35d770fd5d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -0,0 +1,102 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.io.ByteArrayInputStream; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.xpath.CachedXPathAPI; +import org.w3c.dom.Document; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; + +public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { + + private final String xpath; + + public XalanXPathEvaluator(String xpath) { + this.xpath = xpath; + } + + public boolean evaluate(AMQMessage m) throws AMQException + { + // TODO - we would have to check the content type and then evaluate the content + // here... is this really a feature we wish to implement? - RobG + /* + + if( m instanceof TextMessage ) { + String text = ((TextMessage)m).getText(); + return evaluate(text); + } else if ( m instanceof BytesMessage ) { + BytesMessage bm = (BytesMessage) m; + byte data[] = new byte[(int) bm.getBodyLength()]; + bm.readBytes(data); + return evaluate(data); + } + */ + return false; + + } + + private boolean evaluate(byte[] data) { + try { + + InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + + } catch (Throwable e) { + return false; + } + } + + private boolean evaluate(String text) { + try { + InputSource inputSource = new InputSource(new StringReader(text)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + // We should associated the cachedXPathAPI object with the message being evaluated + // since that should speedup subsequent xpath expressions. + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + } catch (Throwable e) { + return false; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java new file mode 100644 index 0000000000..dd712a404c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -0,0 +1,65 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.AMQException; + +/** + * @author Apache Software Foundation + * + * + */ +public class AccessRequestHandler implements StateAwareMethodListener +{ + private static final AccessRequestHandler _instance = new AccessRequestHandler(); + + + public static AccessRequestHandler getInstance() + { + return _instance; + } + + private AccessRequestHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + // We don't implement access control class, but to keep clients happy that expect it + // always use the "0" ticket. + AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java new file mode 100644 index 0000000000..f90e7c3dff --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicAckBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class BasicAckMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicAckMethodHandler.class); + + private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); + + public static BasicAckMethodHandler getInstance() + { + return _instance; + } + + private BasicAckMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicAckBody body, int channelId) throws AMQException + { + AMQProtocolSession protocolSession = stateManager.getProtocolSession(); + + + if (_log.isDebugEnabled()) + { + _log.debug("Ack(Tag:" + body.getDeliveryTag() + ":Mult:" + body.getMultiple() + ") received on channel " + channelId); + } + + final AMQChannel channel = protocolSession.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + // this method throws an AMQException if the delivery tag is not known + channel.acknowledgeMessage(body.getDeliveryTag(), body.getMultiple()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java new file mode 100644 index 0000000000..bda1c16cf6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicCancelBody; +import org.apache.qpid.framing.BasicCancelOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicCancelMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicCancelMethodHandler.class); + + private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); + + public static BasicCancelMethodHandler getInstance() + { + return _instance; + } + + private BasicCancelMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicCancelBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + final AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + if (_log.isDebugEnabled()) + { + _log.debug("BasicCancel: for:" + body.getConsumerTag() + + " nowait:" + body.getNowait()); + } + + channel.unsubscribeConsumer(session, body.getConsumerTag()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + BasicCancelOkBody cancelOkBody = methodRegistry.createBasicCancelOkBody(body.getConsumerTag()); + session.writeFrame(cancelOkBody.generateFrame(channelId)); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java new file mode 100644 index 0000000000..7cd4afdb77 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ConsumerTagNotUniqueException; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicConsumeMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicConsumeMethodHandler.class); + + private static final BasicConsumeMethodHandler _instance = new BasicConsumeMethodHandler(); + + public static BasicConsumeMethodHandler getInstance() + { + return _instance; + } + + private BasicConsumeMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicConsumeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + + + AMQChannel channel = session.getChannel(channelId); + + VirtualHost vHost = session.getVirtualHost(); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("BasicConsume: from '" + body.getQueue() + + "' for:" + body.getConsumerTag() + + " nowait:" + body.getNowait() + + " args:" + body.getArguments()); + } + + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue().intern()); + + if (queue == null) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("No queue for '" + body.getQueue() + "'"); + } + if (body.getQueue() != null) + { + String msg = "No such queue, '" + body.getQueue() + "'"; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg); + } + else + { + String msg = "No queue name provided, no default queue defined."; + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg); + } + } + else + { + + final AMQShortString consumerTagName; + + //Perform ACLs + vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); + + if (body.getConsumerTag() != null) + { + consumerTagName = body.getConsumerTag().intern(); + } + else + { + consumerTagName = null; + } + + try + { + AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, session, !body.getNoAck(), + body.getArguments(), body.getNoLocal(), body.getExclusive()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + + //now allow queue to start async processing of any backlog of messages + queue.deliverAsync(); + } + catch (org.apache.qpid.AMQInvalidArgumentException ise) + { + _logger.debug("Closing connection due to invalid selector"); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelCloseBody(AMQConstant.INVALID_ARGUMENT.getCode(), + new AMQShortString(ise.getMessage()), + body.getClazz(), + body.getMethod()); + session.writeFrame(responseBody.generateFrame(channelId)); + + + } + catch (ConsumerTagNotUniqueException e) + { + AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + msg, // replytext + body.getClazz(), + body.getMethod()); + session.writeFrame(responseBody.generateFrame(0)); + } + catch (AMQQueue.ExistingExclusiveSubscription e) + { + throw body.getChannelException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " as it already has an existing exclusive consumer"); + } + catch (AMQQueue.ExistingSubscriptionPreventsExclusive e) + { + throw body.getChannelException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " exclusively as it already has a consumer"); + } + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java new file mode 100644 index 0000000000..f8f9127809 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + VirtualHost vHost = session.getVirtualHost(); + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); + + if (queue == null) + { + _log.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue()+ "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined."); + } + } + else + { + + //Perform ACLs + vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); + + if (!queue.performGet(session, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + // TODO - set clusterId + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java new file mode 100644 index 0000000000..0f99a21ee5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -0,0 +1,101 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicPublishMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicPublishMethodHandler.class); + + private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); + + + public static BasicPublishMethodHandler getInstance() + { + return _instance; + } + + private BasicPublishMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicPublishBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Publish received on channel " + channelId); + } + + AMQShortString exchange = body.getExchange(); + // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? + if (exchange == null) + { + exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; + + } + + VirtualHost vHost = session.getVirtualHost(); + Exchange e = vHost.getExchangeRegistry().getExchange(exchange); + // if the exchange does not exist we raise a channel exception + if (e == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name"); + } + 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 = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //Access Control + vHost.getAccessManager().authorise(session, Permission.PUBLISH, body, e); + + MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body); + info.setExchange(exchange); + channel.setPublishFrame(info, session, e); + } + } + +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java new file mode 100644 index 0000000000..3c95180dca --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicQosBody; +import org.apache.qpid.framing.BasicQosOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class BasicQosHandler implements StateAwareMethodListener +{ + private static final BasicQosHandler _instance = new BasicQosHandler(); + + public static BasicQosHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicQosBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setPrefetchCount(body.getPrefetchCount()); + channel.setPrefetchSize(body.getPrefetchSize()); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java new file mode 100644 index 0000000000..c7842cd643 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.BasicRecoverOkBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, BasicRecoverBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v8_0)) + { + MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java new file mode 100644 index 0000000000..3e2cab2e53 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.BasicRecoverSyncBody; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); + + private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); + + public static BasicRecoverSyncMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java new file mode 100644 index 0000000000..069cc6ea2c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -0,0 +1,130 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRejectBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicRejectMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRejectMethodHandler.class); + + private static BasicRejectMethodHandler _instance = new BasicRejectMethodHandler(); + + public static BasicRejectMethodHandler getInstance() + { + return _instance; + } + + private BasicRejectMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicRejectBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + +// if (_logger.isDebugEnabled()) +// { +// _logger.debug("Rejecting:" + evt.getMethod().deliveryTag + +// ": Requeue:" + evt.getMethod().requeue + +//// ": Resend:" + evt.getMethod().resend + +// " on channel:" + channelId); +// } + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting:" + body.getDeliveryTag() + + ": Requeue:" + body.getRequeue() + + //": Resend:" + evt.getMethod().resend + + " on channel:" + channel.debugIdentity()); + } + + long deliveryTag = body.getDeliveryTag(); + + UnacknowledgedMessage message = channel.getUnacknowledgedMessageMap().get(deliveryTag); + + if (message == null) + { + _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag); +// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known"); + } + else + { + if (message.isQueueDeleted() || message.getQueue().isDeleted()) + { + _logger.warn("Message's Queue as already been purged, unable to Reject. " + + "Dropping message should use Dead Letter Queue"); + //sendtoDeadLetterQueue(msg) + return; + } + + if (!message.getMessage().isReferenced()) + { + _logger.warn("Message as already been purged, unable to Reject."); + return; + } + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage().debugIdentity() + + ": Requeue:" + body.getRequeue() + + //": Resend:" + evt.getMethod().resend + + " on channel:" + channel.debugIdentity()); + } + + // If we haven't requested message to be resent to this consumer then reject it from ever getting it. + //if (!evt.getMethod().resend) + { + message.entry.reject(); + } + + if (body.getRequeue()) + { + channel.requeue(deliveryTag); + } + else + { + _logger.warn("Dropping message as requeue not required and there is no dead letter queue"); + //sendtoDeadLetterQueue(AMQMessage message) +// message.queue = channel.getDefaultDeadLetterQueue(); +// channel.requeue(deliveryTag); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java new file mode 100644 index 0000000000..9133cce6b7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +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, ChannelCloseBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isInfoEnabled()) + { + _logger.info("Received channel close for id " + channelId + " citing class " + body.getClassId() + + " and method " + body.getMethodId()); + } + + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel"); + } + + session.closeChannel(channelId); + // Client requested closure so we don't wait for ok we send it + stateManager.getProtocolSession().closeChannelOk(channelId); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + ChannelCloseOkBody responseBody = methodRegistry.createChannelCloseOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java new file mode 100644 index 0000000000..a857490e7e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ChannelCloseOkBody body, int channelId) throws AMQException + { + + _logger.info("Received channel-close-ok for channel-id " + channelId); + + // Let the Protocol Session know the channel is now closed. + stateManager.getProtocolSession().closeChannelOk(channelId); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java new file mode 100644 index 0000000000..696ca8a63b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ChannelFlowBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setSuspended(!body.getActive()); + _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive()); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelFlowOkBody(body.getActive()); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java new file mode 100644 index 0000000000..054674aed4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -0,0 +1,103 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.UUID; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ChannelOpenHandler implements StateAwareMethodListener +{ + private static ChannelOpenHandler _instance = new ChannelOpenHandler(); + + public static ChannelOpenHandler getInstance() + { + return _instance; + } + + private ChannelOpenHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ChannelOpenBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + + final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getMessageStore() + ); + session.addChannel(channel); + + ChannelOpenOkBody response; + + ProtocolVersion pv = session.getProtocolVersion(); + + if(pv.equals(ProtocolVersion.v8_0)) + { + MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + response = methodRegistry.createChannelOpenOkBody(); + + } + else if(pv.equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + UUID uuid = UUID.randomUUID(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + try + { + dataOut.writeLong(uuid.getMostSignificantBits()); + dataOut.writeLong(uuid.getLeastSignificantBits()); + dataOut.flush(); + dataOut.close(); + } + catch (IOException e) + { + // This *really* shouldn't happen as we're not doing any I/O + throw new RuntimeException("I/O exception when writing to byte array", e); + } + + // should really associate this channelId to the session + byte[] channelName = output.toByteArray(); + + response = methodRegistry.createChannelOpenOkBody(channelName); + } + else + { + throw new AMQException(AMQConstant.INTERNAL_ERROR, "Got channel open for protocol version not catered for: " + pv, null); + } + + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java new file mode 100644 index 0000000000..dade5d5f54 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -0,0 +1,72 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionCloseBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isInfoEnabled()) + { + _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" + + body.getReplyText() + " for " + session); + } + try + { + session.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + ConnectionCloseOkBody responseBody = methodRegistry.createConnectionCloseOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java new file mode 100644 index 0000000000..bc6e5ab403 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionCloseOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + //todo should this not do more than just log the method? + _logger.info("Received Connection-close-ok"); + + try + { + stateManager.changeState(AMQState.CONNECTION_CLOSED); + session.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java new file mode 100644 index 0000000000..f99e650979 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -0,0 +1,99 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; + +public class ConnectionOpenMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); + + private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); + + public static ConnectionOpenMethodHandler getInstance() + { + return _instance; + } + + private ConnectionOpenMethodHandler() + { + } + + private static AMQShortString generateClientID() + { + return new AMQShortString(Long.toString(System.currentTimeMillis())); + } + + public void methodReceived(AMQStateManager stateManager, ConnectionOpenBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + //ignore leading '/' + String virtualHostName; + if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/') + { + virtualHostName = new StringBuilder(body.getVirtualHost().subSequence(1, body.getVirtualHost().length())).toString(); + } + else + { + virtualHostName = body.getVirtualHost() == null ? null : String.valueOf(body.getVirtualHost()); + } + + VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); + + if (virtualHost == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'"); + } + else + { + session.setVirtualHost(virtualHost); + + //Perform ACL + virtualHost.getAccessManager().authorise(session, Permission.ACCESS ,body, virtualHost); + + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts + if (session.getContextKey() == null) + { + session.setContextKey(generateClientID()); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost()); + + stateManager.changeState(AMQState.CONNECTION_OPEN); + + session.writeFrame(responseBody.generateFrame(channelId)); + + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java new file mode 100644 index 0000000000..193c3a088b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -0,0 +1,126 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.HeartbeatConfig; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionSecureOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + //fixme Vhost not defined yet + //session.getVirtualHost().getAuthenticationManager(); + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + + SaslServer ss = session.getSaslServer(); + if (ss == null) + { + throw new AMQException("No SASL context set up in session"); + } + MethodRegistry methodRegistry = session.getMethodRegistry(); + AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); + 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); + + + ConnectionCloseBody connectionCloseBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + session.writeFrame(connectionCloseBody.generateFrame(0) ); + disposeSaslServer(session); + break; + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + + ConnectionTuneBody tuneBody = + methodRegistry.createConnectionTuneBody(0xFFFF, + ConnectionStartOkMethodHandler.getConfiguredFrameSize(), + HeartbeatConfig.getInstance().getDelay()); + session.writeFrame(tuneBody.generateFrame(0)); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + disposeSaslServer(session); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + session.writeFrame(secureBody.generateFrame(0)); + } + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java new file mode 100644 index 0000000000..f02121c89f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -0,0 +1,161 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.HeartbeatConfig; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + + +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 ConnectionStartOkMethodHandler getInstance() + { + return _instance; + } + + private ConnectionStartOkMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ConnectionStartOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.info("SASL Mechanism selected: " + body.getMechanism()); + _logger.info("Locale selected: " + body.getLocale()); + + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); + + SaslServer ss = null; + try + { + ss = authMgr.createSaslServer(String.valueOf(body.getMechanism()), session.getLocalFQDN()); + + if (ss == null) + { + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism() + ); + } + + session.setSaslServer(ss); + + AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); + + //save clientProperties + if (session.getClientProperties() == null) + { + session.setClientProperties(body.getClientProperties()); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + switch (authResult.status) + { + case ERROR: + _logger.info("Authentication failed"); + stateManager.changeState(AMQState.CONNECTION_CLOSING); + + ConnectionCloseBody closeBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + session.writeFrame(closeBody.generateFrame(0)); + disposeSaslServer(session); + break; + + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + + ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, + getConfiguredFrameSize(), + HeartbeatConfig.getInstance().getDelay()); + session.writeFrame(tuneBody.generateFrame(0)); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + session.writeFrame(secureBody.generateFrame(0)); + } + } + catch (SaslException e) + { + disposeSaslServer(session); + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java new file mode 100644 index 0000000000..0fe8c5dc92 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionTuneOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +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, ConnectionTuneOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isDebugEnabled()) + { + _logger.debug(body); + } + stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); + session.initHeartbeats(body.getHeartbeat()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java new file mode 100644 index 0000000000..491a2f80db --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -0,0 +1,180 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.exchange.Exchange; +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.virtualhost.VirtualHost; + +/** + * @author Apache Software Foundation + * + * + */ +public class ExchangeBoundHandler implements StateAwareMethodListener +{ + private static final ExchangeBoundHandler _instance = new ExchangeBoundHandler(); + + public static final int OK = 0; + + public static final int EXCHANGE_NOT_FOUND = 1; + + public static final int QUEUE_NOT_FOUND = 2; + + public static final int NO_BINDINGS = 3; + + public static final int QUEUE_NOT_BOUND = 4; + + public static final int NO_QUEUE_BOUND_WITH_RK = 5; + + public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; + + public static ExchangeBoundHandler getInstance() + { + return _instance; + } + + private ExchangeBoundHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ExchangeBoundBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MethodRegistry methodRegistry = session.getMethodRegistry(); + + + + + AMQShortString exchangeName = body.getExchange(); + AMQShortString queueName = body.getQueue(); + AMQShortString routingKey = body.getRoutingKey(); + if (exchangeName == null) + { + throw new AMQException("Exchange exchange must not be null"); + } + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + ExchangeBoundOkBody response; + if (exchange == null) + { + + + response = methodRegistry.createExchangeBoundOkBody(EXCHANGE_NOT_FOUND, + new AMQShortString("Exchange " + exchangeName + " not found")); + } + else if (routingKey == null) + { + if (queueName == null) + { + if (exchange.hasBindings()) + { + response = methodRegistry.createExchangeBoundOkBody(OK, null); + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_BINDINGS, // replyCode + null); // replyText + } + } + else + { + + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + new AMQShortString("Queue " + queueName + " not found")); // replyText + } + else + { + if (exchange.isBound(queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_BOUND, // replyCode + new AMQShortString("Queue " + queueName + " not bound to exchange " + exchangeName)); // replyText + } + } + } + } + else if (queueName != null) + { + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + new AMQShortString("Queue " + queueName + " not found")); // replyText + } + else + { + if (exchange.isBound(body.getRoutingKey(), queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode + new AMQShortString("Queue " + queueName + " not bound with routing key " + + body.getRoutingKey() + " to exchange " + exchangeName)); // replyText + } + } + } + else + { + if (exchange.isBound(body.getRoutingKey())) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_QUEUE_BOUND_WITH_RK, // replyCode + new AMQShortString("No queue bound with routing key " + body.getRoutingKey() + + " to exchange " + exchangeName)); // replyText + } + } + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java new file mode 100644 index 0000000000..9a98bc9659 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -0,0 +1,116 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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 ExchangeDeclareHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ExchangeDeclareBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + if (!body.getPassive()) + { + //Perform ACL if request is not passive + virtualHost.getAccessManager().authorise(session, Permission.CREATE, body); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + body.getExchange()); + } + synchronized(exchangeRegistry) + { + Exchange exchange = exchangeRegistry.getExchange(body.getExchange()); + + + + if (exchange == null) + { + if(body.getPassive() && ((body.getType() == null) || body.getType().length() ==0)) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + body.getExchange()); + } + else + { + try + { + + exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), + body.getType() == null ? null : body.getType().intern(), + body.getDurable(), + body.getPassive(), body.getTicket()); + exchangeRegistry.registerExchange(exchange); + } + catch(AMQUnknownExchangeType e) + { + throw body.getConnectionException(AMQConstant.COMMAND_INVALID, "Unknown exchange: " + body.getExchange(),e); + } + } + } + else if (!exchange.getType().equals(body.getType())) + { + + throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor()); + } + + } + if(!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java new file mode 100644 index 0000000000..888ffcb2e5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.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.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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, ExchangeDeleteBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.DELETE,body, + exchangeRegistry.getExchange(body.getExchange())); + + try + { + exchangeRegistry.unregisterExchange(body.getExchange(), body.getIfUnused()); + + ExchangeDeleteOkBody responseBody = session.getMethodRegistry().createExchangeDeleteOkBody(); + + session.writeFrame(responseBody.generateFrame(channelId)); + } + catch (ExchangeInUseException e) + { + // TODO: sort out consistent channel close mechanism that does all clean up etc. + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java new file mode 100644 index 0000000000..ac516b6133 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.concurrent.Executor; + +/** + * An executor that executes the task on the current thread. + */ +public class OnCurrentThreadExecutor implements Executor +{ + public void execute(Runnable command) + { + command.run(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java new file mode 100644 index 0000000000..0f6dc7a19d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidRoutingKeyException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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, QueueBindBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + + final AMQQueue queue; + final AMQShortString routingKey; + + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); + } + + if (body.getRoutingKey() == null) + { + routingKey = queue.getName(); + } + else + { + routingKey = body.getRoutingKey().intern(); + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + routingKey = body.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : body.getRoutingKey().intern(); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); + } + + + try + { + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.BIND, body, exch, queue, routingKey); + + if (!exch.isBound(routingKey, body.getArguments(), queue)) + { + queue.bind(routingKey, body.getArguments(), exch); + } + } + catch (AMQInvalidRoutingKeyException rke) + { + throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); + } + catch (AMQException e) + { + throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); + } + + if (_log.isInfoEnabled()) + { + _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java new file mode 100644 index 0000000000..7df864f189 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -0,0 +1,212 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.Configured; + +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.commons.configuration.Configuration; + +public class QueueDeclareHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(QueueDeclareHandler.class); + + private static final QueueDeclareHandler _instance = new QueueDeclareHandler(); + + public static QueueDeclareHandler getInstance() + { + return _instance; + } + + @Configured(path = "queue.auto_register", defaultValue = "true") + public boolean autoRegister; + + private final AtomicInteger _counter = new AtomicInteger(); + + + protected QueueDeclareHandler() + { + Configurator.configure(this); + } + + public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + + + if (!body.getPassive()) + { + //Perform ACL if request is not passive + virtualHost.getAccessManager().authorise(session, Permission.CREATE, body); + } + + + final AMQShortString queueName; + + // if we aren't given a queue name, we create one which we return to the client + + if ((body.getQueue() == null) || (body.getQueue().length() == 0)) + { + queueName = createName(); + } + else + { + queueName = body.getQueue().intern(); + } + + AMQQueue queue; + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + synchronized (queueRegistry) + { + + + + if (((queue = queueRegistry.getQueue(queueName)) == null)) + { + + if (body.getPassive()) + { + String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg); + } + else + { + queue = createQueue(queueName, body, virtualHost, session); + if (queue.isDurable() && !queue.isAutoDelete()) + { + store.createQueue(queue); + } + queueRegistry.registerQueue(queue); + if (autoRegister) + { + Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); + + queue.bind(queueName, null, defaultExchange); + _logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getName() + ")"); + } + } + } + else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) + { + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + queueName + "')," + + " as exclusive queue with same name " + + "declared on another client ID('" + + queue.getOwner() + "')"); + } + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //set this as the default queue on the channel: + channel.setDefaultQueue(queue); + } + + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + QueueDeclareOkBody responseBody = + methodRegistry.createQueueDeclareOkBody(queueName, + queue.getMessageCount(), + queue.getConsumerCount()); + session.writeFrame(responseBody.generateFrame(channelId)); + + _logger.info("Queue " + queueName + " declared successfully"); + } + } + + protected AMQShortString createName() + { + return new AMQShortString("tmp_" + UUID.randomUUID()); + } + + protected AMQQueue createQueue(final AMQShortString queueName, + QueueDeclareBody body, + VirtualHost virtualHost, + final AMQProtocolSession session) + throws AMQException + { + final QueueRegistry registry = virtualHost.getQueueRegistry(); + AMQShortString owner = body.getExclusive() ? session.getContextKey() : null; + final AMQQueue queue = new AMQQueue(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost); + + + if (body.getExclusive() && !body.getDurable()) + { + final AMQProtocolSession.Task deleteQueueTask = + new AMQProtocolSession.Task() + { + public void doTask(AMQProtocolSession session) throws AMQException + { + if (registry.getQueue(queueName) == queue) + { + queue.delete(); + } + } + }; + + session.addSessionCloseTask(deleteQueueTask); + + queue.addQueueDeleteTask(new AMQQueue.Task() + { + public void doTask(AMQQueue queue) + { + session.removeSessionCloseTask(deleteQueueTask); + } + }); + }// if exclusive and not durable + + Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + if (virtualHostDefaultQueueConfiguration != null) + { + Configurator.configure(queue, virtualHostDefaultQueueConfiguration); + } + + return queue; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java new file mode 100644 index 0000000000..310a73ffeb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -0,0 +1,124 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueueDeleteBody; +import org.apache.qpid.framing.QueueDeleteOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; +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.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueueDeleteHandler implements StateAwareMethodListener +{ + private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); + + public static QueueDeleteHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueueDeleteHandler() + { + this(true); + } + + public QueueDeleteHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + + } + + public void methodReceived(AMQStateManager stateManager, QueueDeleteBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + + AMQQueue queue; + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if (queue == null) + { + if (_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + if (body.getIfEmpty() && !queue.isEmpty()) + { + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is not empty."); + } + else if (body.getIfUnused() && !queue.isUnused()) + { + // TODO - Error code + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used."); + + } + else + { + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.DELETE, body, queue); + + int purged = queue.delete(body.getIfUnused(), body.getIfEmpty()); + + if (queue.isDurable()) + { + store.removeQueue(queue.getName()); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + QueueDeleteOkBody responseBody = methodRegistry.createQueueDeleteOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java new file mode 100644 index 0000000000..cce49f13c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueuePurgeBody; +import org.apache.qpid.framing.QueuePurgeOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.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.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + AMQChannel channel = session.getChannel(channelId); + + + AMQQueue queue; + if(body.getQueue() == null) + { + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); + } + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue); + + long purged = queue.clearQueue(channel.getStoreContext()); + + + if(!body.getNowait()) + { + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java new file mode 100644 index 0000000000..6b2924031a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -0,0 +1,134 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidRoutingKeyException; +import org.apache.qpid.protocol.AMQConstant; + +public class QueueUnbindHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(QueueUnbindHandler.class); + + private static final QueueUnbindHandler _instance = new QueueUnbindHandler(); + + public static QueueUnbindHandler getInstance() + { + return _instance; + } + + private QueueUnbindHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueUnbindBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + + final AMQQueue queue; + final AMQShortString routingKey; + + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); + } + + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); + + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); + } + + if (queue == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); + } + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.UNBIND, body, queue); + + try + { + queue.unBind(routingKey, body.getArguments(), exch); + } + catch (AMQInvalidRoutingKeyException rke) + { + throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); + } + catch (AMQException e) + { + if(e.getErrorCode() == AMQConstant.NOT_FOUND) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND,e.getMessage(),e); + } + throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); + } + + if (_log.isInfoEnabled()) + { + _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueueUnbindOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java new file mode 100644 index 0000000000..9475b83c8f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java @@ -0,0 +1,566 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.Map; +import java.util.HashMap; + +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.framing.*; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl implements MethodDispatcher +{ + private final AMQStateManager _stateManager; + + private static interface DispatcherFactory + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); + } + + private static final Map _dispatcherFactories = + new HashMap(); + + + static + { + _dispatcherFactories.put(ProtocolVersion.v8_0, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_8_0(stateManager); + } + }); + + _dispatcherFactories.put(ProtocolVersion.v0_9, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_0_9(stateManager); + } + }); + + } + + + private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); + private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); + private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); + private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); + private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); + private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); + private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); + private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); + private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); + private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); + private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); + private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); + private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); + private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); + private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); + private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); + private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); + private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); + private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); + private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); + private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); + private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); + private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); + private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); + private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); + private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); + private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); + private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); + private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); + + + + public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) + { + return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); + } + + + public ServerMethodDispatcherImpl(AMQStateManager stateManager) + { + _stateManager = stateManager; + } + + + protected AMQStateManager getStateManager() + { + return _stateManager; + } + + + + public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException + { + _accessRequestHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException + { + _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException + { + _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException + { + _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException + { + _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException + { + _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException + { + _basicQosHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException + { + _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException + { + _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException + { + _channelOpenHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException + { + _channelCloseHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException + { + _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException + { + _channelFlowHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException + { + _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException + { + _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException + { + _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException + { + _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException + { + _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException + { + _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException + { + _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException + { + _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException + { + _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException + { + _queueBindHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException + { + _queueDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException + { + _queueDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException + { + _queuePurgeHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException + { + _txCommitHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException + { + _txRollbackHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException + { + _txSelectHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java new file mode 100644 index 0000000000..8b1dca77ba --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_0_9.MethodDispatcher_0_9; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + + + +public class ServerMethodDispatcherImpl_0_9 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_0_9 + +{ + + private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = + BasicRecoverSyncMethodHandler.getInstance(); + private static final QueueUnbindHandler _queueUnbindHandler = + QueueUnbindHandler.getInstance(); + + + public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException + { + _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); + return true; + } + + public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException + { + _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java new file mode 100644 index 0000000000..d599ca3d4e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl_8_0 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_8_0 +{ + public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException + { + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java new file mode 100644 index 0000000000..79cc722e0e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxCommitBody; +import org.apache.qpid.framing.TxCommitOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxCommitHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(TxCommitHandler.class); + + private static TxCommitHandler _instance = new TxCommitHandler(); + + public static TxCommitHandler getInstance() + { + return _instance; + } + + private TxCommitHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxCommitBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + try + { + if (_log.isDebugEnabled()) + { + _log.debug("Commit received on channel " + channelId); + } + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.commit(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + channel.processReturns(session); + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java new file mode 100644 index 0000000000..5f402f3fda --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxRollbackBody; +import org.apache.qpid.framing.TxRollbackOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxRollbackHandler implements StateAwareMethodListener +{ + private static TxRollbackHandler _instance = new TxRollbackHandler(); + + public static TxRollbackHandler getInstance() + { + return _instance; + } + + private TxRollbackHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + try + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.rollback(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + + //Now resend all the unacknowledged messages back to the original subscribers. + //(Must be done after the TxnRollback-ok response). + // Why, are we not allowed to send messages back to client before the ok method? + channel.resend(false); + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java new file mode 100644 index 0000000000..308f5b73cf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxSelectBody; +import org.apache.qpid.framing.TxSelectOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class TxSelectHandler implements StateAwareMethodListener +{ + private static TxSelectHandler _instance = new TxSelectHandler(); + + public static TxSelectHandler getInstance() + { + return _instance; + } + + private TxSelectHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxSelectBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setLocalTransactional(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + TxSelectOkBody responseBody = methodRegistry.createTxSelectOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java new file mode 100644 index 0000000000..fb18519fe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + + +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.AMQException; + +public class UnexpectedMethodException extends AMQException +{ + public UnexpectedMethodException(AMQMethodBody body) + { + super("Unexpected method recevied: " + body.getClass().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java new file mode 100644 index 0000000000..c08fae4e4e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java @@ -0,0 +1,110 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.jms; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +public class JmsConsumer +{ + private int _prefetchValue; + + private PrefetchUnits _prefetchUnits; + + private boolean _noLocal; + + private boolean _autoAck; + + private boolean _exclusive; + + private AMQProtocolSession _protocolSession; + + public enum PrefetchUnits + { + OCTETS, + MESSAGES + } + + public int getPrefetchValue() + { + return _prefetchValue; + } + + public void setPrefetchValue(int prefetchValue) + { + _prefetchValue = prefetchValue; + } + + public PrefetchUnits getPrefetchUnits() + { + return _prefetchUnits; + } + + public void setPrefetchUnits(PrefetchUnits prefetchUnits) + { + _prefetchUnits = prefetchUnits; + } + + public boolean isNoLocal() + { + return _noLocal; + } + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + public boolean isAutoAck() + { + return _autoAck; + } + + public void setAutoAck(boolean autoAck) + { + _autoAck = autoAck; + } + + public boolean isExclusive() + { + return _exclusive; + } + + public void setExclusive(boolean exclusive) + { + _exclusive = exclusive; + } + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void setProtocolSession(AMQProtocolSession protocolSession) + { + _protocolSession = protocolSession; + } + + public void deliverMessage() throws AMQException + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java new file mode 100644 index 0000000000..a2c2bd62a2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -0,0 +1,97 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * This class provides additinal feature of Notification Broadcaster to the + * DefaultManagedObject. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public abstract class AMQManagedObject extends DefaultManagedObject + implements NotificationBroadcaster +{ + /** + * broadcaster support class + */ + protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); + + /** + * sequence number for notifications + */ + protected long _notificationSequenceNumber = 0; + + protected MBeanInfo _mbeanInfo; + + protected AMQManagedObject(Class managementInterface, String typeName) + throws NotCompliantMBeanException + { + super(managementInterface, typeName); + buildMBeanInfo(); + } + + @Override + public MBeanInfo getMBeanInfo() + { + return _mbeanInfo; + } + + private void buildMBeanInfo() throws NotCompliantMBeanException + { + _mbeanInfo = new MBeanInfo(this.getClass().getName(), + MBeanIntrospector.getMBeanDescription(this.getClass()), + MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()), + MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()), + MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()), + this.getNotificationInfo()); + } + + + + // notification broadcaster implementation + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + { + _broadcaster.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + _broadcaster.removeNotificationListener(listener); + } + + public MBeanNotificationInfo[] getNotificationInfo() + { + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java new file mode 100644 index 0000000000..84526dbc11 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -0,0 +1,191 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; + +/** + * 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 + { + getManagedObjectRegistry().registerObject(this); + } + catch (JMException e) + { + throw new AMQException("Error registering managed object " + this + ": " + e, e); + } + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + + public void unregister() throws AMQException + { + try + { + 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()); + } + + protected ObjectName getObjectNameForSingleInstanceMBean() throws MalformedObjectNameException + { + StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); + + objectName.append(":type="); + objectName.append(getHierarchicalType(this)); + + String hierarchyName = getHierarchicalName(this); + if (hierarchyName != null) + { + objectName.append(","); + objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); + } + + return new ObjectName(objectName.toString()); + } + + protected String getHierarchicalType(ManagedObject obj) + { + if (obj.getParentObject() != null) + { + String parentType = getHierarchicalType(obj.getParentObject()).toString(); + return parentType + "." + obj.getType(); + } + else + return obj.getType(); + } + + protected String getHierarchicalName(ManagedObject obj) + { + if (obj.getParentObject() != null) + { + String 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; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java new file mode 100644 index 0000000000..4caae2b26f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -0,0 +1,283 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; + +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.UnicastRemoteObject; +import java.util.HashMap; +import java.util.Map; + +/** + * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features + * implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env + * variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be + * used, which again doesn't have user authentication. + */ +public class JMXManagedObjectRegistry implements ManagedObjectRegistry +{ + private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); + + private final MBeanServer _mbeanServer; + private Registry _rmiRegistry; + private JMXServiceURL _jmxURL; + + public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; + public static final int MANAGEMENT_PORT_DEFAULT = 8999; + + public JMXManagedObjectRegistry() throws AMQException + { + _log.info("Initialising managed object registry using platform MBean server"); + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + + // Retrieve the config parameters + boolean platformServer = appRegistry.getConfiguration().getBoolean("management.platform-mbeanserver", true); + + _mbeanServer = + platformServer ? ManagementFactory.getPlatformMBeanServer() + : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + } + + + public void start() throws IOException + { + // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent + if (areOutOfTheBoxJMXOptionsSet()) + { + _log.info("JMX: Using the out of the box JMX Agent"); + return; + } + + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + + boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); + int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT); + + if (security) + { + // For SASL using JMXMP + _jmxURL = new JMXServiceURL("jmxmp", null, port); + + Map env = new HashMap(); + Map map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = null; + + for (Map.Entry entry : map.entrySet()) + { + if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) + { + db = entry.getValue(); + break; + } + else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) + { + db = entry.getValue(); + } + } + + if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); + CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + } + else if (db instanceof PlainPasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/PLAIN"); + env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); + } + + // Enable the SSL security and server authentication + /* + SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); + SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); + */ + + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL"); + + } + else + { + startJMXConnectorServer(port); + _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled"); + } + } + + /** + * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it. + * + * @param port + * + * @throws IOException + */ + private void startJMXConnectorServer(int port) throws IOException + { + startRMIRegistry(port); + _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); + cs.start(); + } + + public void registerObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.unregisterMBean(managedObject.getObjectName()); + } + + /** + * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent. + * + * @return + */ + private boolean areOutOfTheBoxJMXOptionsSet() + { + if (System.getProperty("com.sun.management.jmxremote") != null) + { + return true; + } + + if (System.getProperty("com.sun.management.jmxremote.port") != null) + { + return true; + } + + return false; + } + + /** + * Starts the rmi registry at given port + * + * @param port + * + * @throws RemoteException + */ + private void startRMIRegistry(int port) throws RemoteException + { + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port); + } + + // stops the RMIRegistry, if it was running and bound to a port + public void close() throws RemoteException + { + if (_rmiRegistry != null) + { + // Stopping the RMI registry + UnicastRemoteObject.unexportObject(_rmiRegistry, true); + } + } + + /** This class is used for SASL enabled JMXConnector for performing user authentication. */ + private class UserCallbackHandler implements CallbackHandler + { + private final PrincipalDatabase _principalDatabase; + + protected UserCallbackHandler(PrincipalDatabase database) + { + _principalDatabase = database; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + // Retrieve callbacks + NameCallback ncb = null; + PasswordCallback pcb = null; + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + ncb = (NameCallback) callbacks[i]; + } + else if (callbacks[i] instanceof PasswordCallback) + { + pcb = (PasswordCallback) callbacks[i]; + } + else if (callbacks[i] instanceof AuthorizeCallback) + { + ((AuthorizeCallback) callbacks[i]).setAuthorized(true); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + + boolean authorized = false; + // Process retrieval of password; can get password if username is available in NameCallback + if ((ncb != null) && (pcb != null)) + { + String username = ncb.getDefaultName(); + try + { + authorized = _principalDatabase.verifyPassword(username, pcb.getPassword()); + } + catch (AccountNotFoundException e) + { + IOException ioe = new IOException("User not authorized. " + e); + ioe.initCause(e); + throw ioe; + } + } + + if (!authorized) + { + throw new IOException("User not authorized."); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java new file mode 100644 index 0000000000..7d42297699 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean attributes. This should be used with getter or setter + * methods of attributes. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanAttribute +{ + String name(); + String description(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java new file mode 100644 index 0000000000..9138e03085 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean constructors. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.CONSTRUCTOR) +@Inherited +public @interface MBeanConstructor +{ + String value(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java new file mode 100644 index 0000000000..448fed3280 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean class. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface MBeanDescription { + String value(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java new file mode 100644 index 0000000000..0c2ec2aebd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -0,0 +1,388 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; + +/** + * 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()) + { + 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; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java new file mode 100644 index 0000000000..a0ecc2bd85 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -0,0 +1,239 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.server.security.access.management.UserManagement; +import org.apache.log4j.Logger; + +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.JMXPrincipal; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.JMException; +import javax.security.auth.Subject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Principal; +import java.security.AccessControlContext; +import java.util.Set; +import java.util.Properties; + +/** + * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements + * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite + * and admin users. + */ +public class MBeanInvocationHandlerImpl implements InvocationHandler +{ + private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); + + public final static String ADMIN = "admin"; + public final static String READWRITE = "readwrite"; + public final static String READONLY = "readonly"; + private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; + private MBeanServer mbs; + private static Properties _userRoles = new Properties(); + + public static MBeanServerForwarder newProxyInstance() + { + final InvocationHandler handler = new MBeanInvocationHandlerImpl(); + final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + + Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); + return MBeanServerForwarder.class.cast(proxy); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + final String methodName = method.getName(); + + if (methodName.equals("getMBeanServer")) + { + return mbs; + } + + if (methodName.equals("setMBeanServer")) + { + if (args[0] == null) + { + throw new IllegalArgumentException("Null MBeanServer"); + } + if (mbs != null) + { + throw new IllegalArgumentException("MBeanServer object already initialized"); + } + mbs = (MBeanServer) args[0]; + return null; + } + + // Retrieve Subject from current AccessControlContext + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) + { + return method.invoke(mbs, args); + } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + _logger.debug("User trying to create or unregister an MBean"); + throw new SecurityException("Access denied"); + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied"); + } + + Principal principal = principals.iterator().next(); + String identity = principal.getName(); + + if (isAdminMethod(args)) + { + if (isAdmin(identity)) + { + return method.invoke(mbs, args); + } + else + { + throw new SecurityException("Access denied"); + } + } + + // Following users can perform any operation other than "createMBean" and "unregisterMBean" + if (isAllowedToModify(identity)) + { + return method.invoke(mbs, args); + } + + // These users can only call "getAttribute" on the MBeanServerDelegate MBean + // Here we can add other fine grained permissions like specific method for a particular mbean + if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + { + return method.invoke(mbs, args); + } + + throw new SecurityException("Access denied"); + } + + private boolean isAdminMethod(Object[] args) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + return UserManagement.TYPE.equals(object.getKeyProperty("type")); + } + + return false; + } + + // Initialises the user roles + public static void setAccessRights(Properties accessRights) + { + _userRoles = accessRights; + } + + private boolean isAdmin(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isAllowedToModify(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName)) + || READWRITE.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyUser(String userName) + { + if (READONLY.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyMethod(Method method, Object[] args) + { + String methodName = method.getName(); + if (methodName.startsWith("query") || methodName.startsWith("get")) + { + return true; + } + else if (methodName.startsWith("set")) + { + return false; + } + + if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) + { + String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + return false; + } + + try + { + MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); + if (mbeanInfo != null) + { + MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); + for (MBeanOperationInfo opInfo : opInfos) + { + if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + { + return true; + } + } + } + } + catch (JMException ex) + { + ex.printStackTrace(); + } + } + + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java new file mode 100644 index 0000000000..a2dca3e51d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.management.MBeanOperationInfo; + +/** + * Annotation for MBean operations. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanOperation +{ + String name(); + String description(); + int impact() default MBeanOperationInfo.INFO; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java new file mode 100644 index 0000000000..aba5ec70d8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean operation parameters. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface MBeanOperationParameter { + String name(); + String description(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java new file mode 100644 index 0000000000..166a2a376d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +/** + * Any object that can return a related MBean should implement this interface. + * + * This enables other classes to get the managed object, which in turn is useful when + * constructing relationships between managed objects without having to maintain + * separate data structures containing MBeans. + * + */ +public interface Managable +{ + ManagedObject getManagedObject(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java new file mode 100644 index 0000000000..45e2e91ed7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.management; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; + +import org.apache.qpid.server.exchange.ManagedExchange; +import org.apache.qpid.server.queue.ManagedQueue; + +/** + * The ManagedBroker is the management interface to expose management + * features of the Broker. + * + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedBroker +{ + static final String TYPE = "VirtualHostManager"; + + /** + * Creates a new Exchange. + * @param name + * @param type + * @param durable + * @param passive + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) + void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, + @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, + @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) + throws IOException, JMException; + + /** + * unregisters all the channels, queuebindings etc and unregisters + * this exchange from managed objects. + * @param exchange + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="unregisterExchange", + description="Unregisters all the related channels and queuebindings of this exchange", + impact= MBeanOperationInfo.ACTION) + void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) + throws IOException, JMException; + + /** + * Create a new Queue on the Broker server + * @param queueName + * @param durable + * @param owner + * @param autoDelete + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) + void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, + @MBeanOperationParameter(name="owner", description="Owner name")String owner, + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) + throws IOException, JMException; + + /** + * Unregisters the Queue bindings, removes the subscriptions and unregisters + * from the managed objects. + * @param queueName + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteQueue", + description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", + impact= MBeanOperationInfo.ACTION) + void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) + throws IOException, JMException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java new file mode 100644 index 0000000000..42ea8921a4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.AMQException; + +/** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java new file mode 100644 index 0000000000..d8d87ef881 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; +import java.rmi.RemoteException; +import java.io.IOException; + +/** + * 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 start() throws IOException; + + void registerObject(ManagedObject managedObject) throws JMException; + + void unregisterObject(ManagedObject managedObject) throws JMException; + + void close() throws RemoteException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java new file mode 100644 index 0000000000..042f626e8b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.configuration.Configured; + +public class ManagementConfiguration +{ + @Configured(path = "management.enabled", + defaultValue = "true") + public boolean enabled; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java new file mode 100644 index 0000000000..b4fbed6948 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; + +import org.apache.log4j.Logger; + +import java.rmi.RemoteException; + +/** + * 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 start() + { + //no-op + } + + public void registerObject(ManagedObject managedObject) throws JMException + { + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + } + + public void close() throws RemoteException + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java new file mode 100644 index 0000000000..e01c5aabbf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public interface ProtocolOutputConverter +{ + void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); + + interface Factory + { + ProtocolOutputConverter newInstance(AMQProtocolSession session); + } + + void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException; + + void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + + byte getProtocolMinorVersion(); + + byte getProtocolMajorVersion(); + + void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException; + + void writeFrame(AMQDataBlock block); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java new file mode 100644 index 0000000000..36e7e88fd6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.ProtocolVersion; + +import java.util.Map; +import java.util.HashMap; + +public class ProtocolOutputConverterRegistry +{ + + private static final Map _registry = + new HashMap(); + + + static + { + register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); + register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); + + } + + private static void register(ProtocolVersion version, Factory converter) + { + + _registry.put(version,converter); + } + + + public static ProtocolOutputConverter getConverter(AMQProtocolSession session) + { + return _registry.get(session.getProtocolVersion()).newInstance(session); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java new file mode 100644 index 0000000000..d7a879180a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -0,0 +1,285 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final Long messageId = message.getMessageId(); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext,messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicDeliverBody deliverBody = + methodRegistry.createBasicDeliverBody(consumerTag, + deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey()); + AMQFrame deliverFrame = deliverBody.generateFrame(channelId); + + + return deliverFrame; + } + + private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicGetOkBody getOkBody = + methodRegistry.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicReturnBody basicReturnBody = + methodRegistry.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java new file mode 100644 index 0000000000..48d2ca9bc9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -0,0 +1,397 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.output.amqp0_9; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); + + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final Long messageId = message.getMessageId(); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + + if(bodyCount == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); + + CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext,messageId, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, messageId, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + + private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) + throws AMQException + { + + + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + final AMQBody returnBlock = new AMQBody() + { + + + + private final boolean _isRedelivered = messageHandle.isRedelivered(); + private final AMQShortString _exchangeName = pb.getExchange(); + private final AMQShortString _routingKey = pb.getRoutingKey(); + + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + _isRedelivered, + _exchangeName, + _routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java new file mode 100644 index 0000000000..b0ebf197f9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.plugins; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator +{ + + BundleContext _context = null; + + public void start(BundleContext ctx) throws Exception + { + _context = ctx; + } + + public void stop(BundleContext ctx) throws Exception + { + start(null); + } + + public BundleContext getContext() + { + return _context; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java new file mode 100644 index 0000000000..9191ecf6ed --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.plugins; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.felix.framework.Felix; +import org.apache.felix.framework.cache.BundleCache; +import org.apache.felix.framework.util.FelixConstants; +import org.apache.felix.framework.util.StringMap; +import org.apache.qpid.server.exchange.ExchangeType; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleException; +import org.osgi.util.tracker.ServiceTracker; + +/** + * + * @author aidan + * + * Provides access to pluggable elements, such as exchanges + */ + +public class PluginManager +{ + + private Felix _felix = null; + private ServiceTracker _exchangeTracker = null; + private Activator _activator = null; + private boolean _empty; + + public PluginManager(String plugindir) throws Exception + { + StringMap configMap = new StringMap(false); + + // Tell felix it's being embedded + configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); + // Add the bundle provided service interface package and the core OSGi + // packages to be exported from the class path via the system bundle. + configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, "org.osgi.framework; version=1.3.0," + + "org.osgi.service.packageadmin; version=1.2.0," + + "org.osgi.service.startlevel; version=1.0.0," + + "org.osgi.service.url; version=1.0.0," + + "org.apache.qpid.framing; version=0.2.1," + + "org.apache.qpid.server.exchange; version=0.2.1," + + "org.apache.qpid.server.management; version=0.2.1,"+ + "org.apache.qpid.protocol; version=0.2.1,"+ + "org.apache.qpid.server.virtualhost; version=0.2.1," + + "org.apache.qpid; version=0.2.1," + + "org.apache.qpid.server.queue; version=0.2.1," + + "javax.management.openmbean; version=1.0.0,"+ + "javax.management; version=1.0.0,"+ + "org.apache.qpid.junit.extensions.util; version=0.6.1," + ); + + if (plugindir == null) + { + _empty = true; + return; + } + + // Set the list of bundles to load + File dir = new File(plugindir); + if (!dir.exists()) + { + _empty = true; + return; + } + StringBuffer pluginJars = new StringBuffer(); + + if (dir.isDirectory()) + { + for (String child : dir.list()) + { + if (child.endsWith("jar")) + { + pluginJars.append(String.format(" file:%s%s%s", plugindir,File.separator,child)); + } + } + } + if (pluginJars.length() == 0) + { + _empty = true; + return; + } + + configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); + configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); + + List activators = new ArrayList(); + _activator = new Activator(); + activators.add(_activator); + + _felix = new Felix(configMap, activators); + try + { + _felix.start(); + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); + _exchangeTracker.open(); + } + catch (BundleException e) + { + throw new Exception("Could not create bundle"); + } + } + + public Map> getExchanges() + { + if (_empty) + { + return null; + } + Map>exchanges = new HashMap>(); + for (Object service : _exchangeTracker.getServices()) + { + if (service instanceof ExchangeType) + { + exchanges.put(service.getClass().getName(), (ExchangeType) service); + } + } + + return exchanges; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java new file mode 100644 index 0000000000..4267642b14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -0,0 +1,796 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.log4j.Logger; + +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoServiceConfig; +import org.apache.mina.common.IoSession; +import org.apache.mina.transport.vmpipe.VmPipeAddress; + +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.codec.AMQDecoder; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.*; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class AMQMinaProtocolSession implements AMQProtocolSession, Managable +{ + private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + // to save boxing the channelId and looking up in a map... cache in an array the low numbered + // channels. This value must be of the form 2^x - 1. + private static final int CHANNEL_CACHE_SIZE = 0xff; + + private final IoSession _minaProtocolSession; + + private AMQShortString _contextKey; + + private AMQShortString _clientVersion = null; + + private VirtualHost _virtualHost; + + private final Map _channelMap = new HashMap(); + + private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; + + private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); + + private final AMQStateManager _stateManager; + + private AMQCodecFactory _codecFactory; + + private AMQProtocolSessionMBean _managedObject; + + private SaslServer _saslServer; + + private Object _lastReceived; + + private Object _lastSent; + + private boolean _closed; + // maximum number of channels this session should have + private long _maxNoOfChannels = 1000; + + /* AMQP Version for this session */ + private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); + + private FieldTable _clientProperties; + private final List _taskList = new CopyOnWriteArrayList(); + + private List _closingChannelsList = new CopyOnWriteArrayList(); + private ProtocolOutputConverter _protocolOutputConverter; + private Principal _authorizedID; + private MethodDispatcher _dispatcher; + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) + throws AMQException + { + _stateManager = new AMQStateManager(virtualHostRegistry, this); + _minaProtocolSession = session; + session.setAttachment(this); + + _codecFactory = codecFactory; + + try + { + IoServiceConfig config = session.getServiceConfig(); + ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); + threadModel.getAsynchronousReadFilter().createNewJobForSession(session); + threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); + } + catch (RuntimeException e) + { + e.printStackTrace(); + throw e; + + } + } + + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, + AMQStateManager stateManager) throws AMQException + { + _stateManager = stateManager; + _minaProtocolSession = session; + session.setAttachment(this); + + _codecFactory = codecFactory; + + } + + private AMQProtocolSessionMBean createMBean() throws AMQException + { + try + { + return new AMQProtocolSessionMBean(this); + } + catch (JMException ex) + { + _logger.error("AMQProtocolSession MBean creation has failed ", ex); + throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); + } + } + + public IoSession getIOSession() + { + return _minaProtocolSession; + } + + public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) + { + return (AMQProtocolSession) minaProtocolSession.getAttachment(); + } + + public void dataBlockReceived(AMQDataBlock message) throws Exception + { + _lastReceived = message; + if (message instanceof ProtocolInitiation) + { + protocolInitiationReceived((ProtocolInitiation) message); + + } + else if (message instanceof AMQFrame) + { + AMQFrame frame = (AMQFrame) message; + frameReceived(frame); + + } + else + { + throw new UnknnownMessageTypeException(message); + } + } + + private void frameReceived(AMQFrame frame) throws AMQException + { + int channelId = frame.getChannel(); + AMQBody body = frame.getBodyFrame(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Frame Received: " + frame); + } + + // Check that this channel is not closing + if (channelAwaitingClosure(channelId)) + { + if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); + } + } + else + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure ignoring"); + } + + return; + } + } + + + + try + { + body.handle(channelId, this); + } + catch (AMQException e) + { + closeChannel(channelId); + throw e; + } + + } + + private void protocolInitiationReceived(ProtocolInitiation pi) + { + // this ensures the codec never checks for a PI message again + ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); + try + { + ProtocolVersion pv = pi.checkVersion(); // Fails if not correct + + // This sets the protocol version (and hence framing classes) for this session. + setProtocolVersion(pv); + + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + + String locales = "en_US"; + + + AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), + (short) getProtocolMinorVersion(), + null, + mechanisms.getBytes(), + locales.getBytes()); + _minaProtocolSession.write(responseBody.generateFrame(0)); + + + } + catch (AMQException e) + { + _logger.error("Received incorrect protocol initiation", e); + + _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + + // TODO: Close connection (but how to wait until message is sent?) + // ritchiem 2006-12-04 will this not do? + // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); + // future.join(); + // close connection + + } + } + + public void methodFrameReceived(int channelId, AMQMethodBody methodBody) + { + + final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); + + try + { + try + { + + boolean wasAnyoneInterested = _stateManager.methodReceived(evt); + + if (!_frameListeners.isEmpty()) + { + for (AMQMethodListener listener : _frameListeners) + { + wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; + } + } + + if (!wasAnyoneInterested) + { + throw new AMQNoMethodHandlerException(evt); + } + } + catch (AMQChannelException e) + { + if (getChannel(channelId) != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing channel due to: " + e.getMessage()); + } + + writeFrame(e.getCloseFrame(channelId)); + closeChannel(channelId); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + closeSession(); + + AMQConnectionException ce = + evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); + + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(ce.getCloseFrame(channelId)); + } + } + catch (AMQConnectionException e) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + markChannelAwaitingCloseOk(channelId); + closeSession(); + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(e.getCloseFrame(channelId)); + } + } + catch (Exception e) + { + + for (AMQMethodListener listener : _frameListeners) + { + listener.error(e); + } + + _logger.error("Unexpected exception while processing frame. Closing connection.", e); + + _minaProtocolSession.close(); + } + } + + public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException + { + + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentHeader(body, this); + + } + + public void contentBodyReceived(int channelId, ContentBody body) throws AMQException + { + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentBody(body, this); + } + + public void heartbeatBodyReceived(int channelId, HeartbeatBody body) + { + // NO - OP + } + + /** + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). + * + * @param frame the frame to write + */ + public void writeFrame(AMQDataBlock frame) + { + _lastSent = frame; + _minaProtocolSession.write(frame); + } + + public AMQShortString getContextKey() + { + return _contextKey; + } + + public void setContextKey(AMQShortString contextKey) + { + _contextKey = contextKey; + } + + public List getChannels() + { + return new ArrayList(_channelMap.values()); + } + + public AMQChannel getAndAssertChannel(int channelId) throws AMQException + { + AMQChannel channel = getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); + } + + return channel; + } + + public AMQChannel getChannel(int channelId) throws AMQException + { + final AMQChannel channel = + ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); + if ((channel == null) || channel.isClosing()) + { + return null; + } + else + { + return channel; + } + } + + public boolean channelAwaitingClosure(int channelId) + { + return _closingChannelsList.contains(channelId); + } + + public void addChannel(AMQChannel channel) throws AMQException + { + if (_closed) + { + throw new AMQException("Session is closed"); + } + + final int channelId = channel.getChannelId(); + + if (_closingChannelsList.contains(channelId)) + { + throw new AMQException("Session is marked awaiting channel close"); + } + + if (_channelMap.size() == _maxNoOfChannels) + { + String errorMessage = + toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels + + "); can't create channel"; + _logger.error(errorMessage); + throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); + } + else + { + _channelMap.put(channel.getChannelId(), channel); + } + + if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) + { + _cachedChannels[channelId] = channel; + } + + checkForNotification(); + } + + private void checkForNotification() + { + int channelsCount = _channelMap.size(); + if (channelsCount >= _maxNoOfChannels) + { + _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); + } + } + + public Long getMaximumNumberOfChannels() + { + return _maxNoOfChannels; + } + + public void setMaximumNumberOfChannels(Long value) + { + _maxNoOfChannels = value; + } + + public void commitTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.commit(); + } + } + + public void rollbackTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.rollback(); + } + } + + /** + * Close a specific channel. This will remove any resources used by the channel, including:

      • 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 = getChannel(channelId); + if (channel == null) + { + throw new IllegalArgumentException("Unknown channel id"); + } + else + { + try + { + channel.close(this); + markChannelAwaitingCloseOk(channelId); + } + finally + { + removeChannel(channelId); + } + } + } + + public void closeChannelOk(int channelId) + { + // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler. + // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory. + // We do it from the Close Handler as we are sending the OK back to the client. + // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException + // will send a close-ok.. Where we should call removeChannel. + // However, due to the poor exception handling on the client. The client-user will be notified of the + // InvalidArgument and if they then decide to close the session/connection then the there will be time + // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. + //removeChannel(channelId); + _closingChannelsList.remove(new Integer(channelId)); + } + + private void markChannelAwaitingCloseOk(int channelId) + { + _closingChannelsList.add(channelId); + } + + /** + * In our current implementation this is used by the clustering code. + * + * @param channelId The channel to remove + */ + public void removeChannel(int channelId) + { + _channelMap.remove(channelId); + if ((channelId & CHANNEL_CACHE_SIZE) == channelId) + { + _cachedChannels[channelId] = null; + } + } + + /** + * Initialise heartbeats on the session. + * + * @param delay delay in seconds (not ms) + */ + public void initHeartbeats(int delay) + { + if (delay > 0) + { + _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); + _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); + } + } + + /** + * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. + * + * @throws AMQException if an error occurs while closing any channel + */ + private void closeAllChannels() throws AMQException + { + for (AMQChannel channel : _channelMap.values()) + { + channel.close(this); + } + + _channelMap.clear(); + for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) + { + _cachedChannels[i] = null; + } + } + + /** This must be called when the session is _closed in order to free up any resources managed by the session. */ + public void closeSession() throws AMQException + { + if (!_closed) + { + _closed = true; + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + } + + for (Task task : _taskList) + { + task.doTask(this); + } + } + } + + 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; + } + + public FieldTable getClientProperties() + { + return _clientProperties; + } + + public void setClientProperties(FieldTable clientProperties) + { + _clientProperties = clientProperties; + if (_clientProperties != null) + { + if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) + { + setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); + } + + if (_clientProperties.getString(ClientProperties.version.toString()) != null) + { + _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); + } + } + } + + private void setProtocolVersion(ProtocolVersion pv) + { + _protocolVersion = pv; + + _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); + _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion); + } + + public byte getProtocolMajorVersion() + { + return _protocolVersion.getMajorVersion(); + } + + public ProtocolVersion getProtocolVersion() + { + return _protocolVersion; + } + + public byte getProtocolMinorVersion() + { + return _protocolVersion.getMinorVersion(); + } + + public boolean isProtocolVersion(byte major, byte minor) + { + return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); + } + + public MethodRegistry getRegistry() + { + return getMethodRegistry(); + } + + public Object getClientIdentifier() + { + return _minaProtocolSession.getRemoteAddress(); + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) throws AMQException + { + _virtualHost = virtualHost; + _managedObject = createMBean(); + _managedObject.register(); + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + public ProtocolOutputConverter getProtocolOutputConverter() + { + return _protocolOutputConverter; + } + + public void setAuthorizedID(Principal authorizedID) + { + _authorizedID = authorizedID; + } + + public Principal getAuthorizedID() + { + return _authorizedID; + } + + public MethodRegistry getMethodRegistry() + { + return MethodRegistry.getMethodRegistry(getProtocolVersion()); + } + + public MethodDispatcher getMethodDispatcher() + { + return _dispatcher; + } + + public String getClientVersion() + { + return (_clientVersion == null) ? null : _clientVersion.toString(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java new file mode 100644 index 0000000000..a7599a3e0d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to handle an AMQP method. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a + * Runtime. + */ +public class AMQNoMethodHandlerException extends AMQException +{ + public AMQNoMethodHandlerException(AMQMethodEvent evt) + { + super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java new file mode 100644 index 0000000000..ad1c507c04 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -0,0 +1,276 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.ReadThrottleFilterBuilder; +import org.apache.mina.filter.SSLFilter; +import org.apache.mina.filter.WriteBufferLimitFilterBuilder; +import org.apache.mina.filter.codec.QpidProtocolCodecFilter; +import org.apache.mina.filter.executor.ExecutorFilter; +import org.apache.mina.util.SessionUtil; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.ssl.SSLContextFactory; + +import java.io.IOException; +import java.net.InetSocketAddress; + +/** + * The protocol handler handles "protocol events" for all connections. The state + * associated with an individual connection is accessed through the protocol session. + * + * We delegate all frame (message) processing to the AMQProtocolSession which wraps + * the state for the connection. + */ +public class AMQPFastProtocolHandler extends IoHandlerAdapter +{ + private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); + + private final IApplicationRegistry _applicationRegistry; + + private static String DEFAULT_BUFFER_READ_LIMIT_SIZE = "262144"; + private static String DEFAULT_BUFFER_WRITE_LIMIT_SIZE = "262144"; + + private final int BUFFER_READ_LIMIT_SIZE; + private final int BUFFER_WRITE_LIMIT_SIZE; + + public AMQPFastProtocolHandler(Integer applicationRegistryInstance) + { + this(ApplicationRegistry.getInstance(applicationRegistryInstance)); + } + + public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) + { + _applicationRegistry = applicationRegistry; + + // Read the configuration from the application registry + BUFFER_READ_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE)); + BUFFER_WRITE_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE)); + + _logger.debug("AMQPFastProtocolHandler created"); + } + + protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) + { + this(handler._applicationRegistry); + } + + public void sessionCreated(IoSession protocolSession) throws Exception + { + SessionUtil.initialize(protocolSession); + final AMQCodecFactory codecFactory = new AMQCodecFactory(true); + + createSession(protocolSession, _applicationRegistry, codecFactory); + _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); + + final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory); + + ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). + getConfiguredObject(ConnectorConfiguration.class); + if (connectorConfig.enableExecutorPool) + { + if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) + { + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", + new SSLFilter(sslContextFactory.buildServerContext())); + } + protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); + } + else + { + protocolSession.getFilterChain().addLast("protocolFilter", pcf); + if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) + { + String keystorePath = connectorConfig.keystorePath; + String keystorePassword = connectorConfig.keystorePassword; + String certType = connectorConfig.certType; + SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", + new SSLFilter(sslContextFactory.buildServerContext())); + } + + } + + if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("broker.connector.protectio.enabled", false)) + { + try + { +// //Add IO Protection Filters + IoFilterChain chain = protocolSession.getFilterChain(); + + + protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter()); + + ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); + readfilter.setMaximumConnectionBufferSize(BUFFER_READ_LIMIT_SIZE); + readfilter.attach(chain); + + WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); + writefilter.setMaximumConnectionBufferSize(BUFFER_WRITE_LIMIT_SIZE); + writefilter.attach(chain); + + protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder"); + _logger.info("Using IO Read/Write Filter Protection"); + } + catch (Exception e) + { + _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage()); + } + } + } + + /** Separated into its own, protected, method to allow easier reuse */ + protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException + { + new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); + } + + public void sessionOpened(IoSession protocolSession) throws Exception + { + _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); + } + + public void sessionClosed(IoSession protocolSession) throws Exception + { + _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + //fixme -- this can be null + if (amqProtocolSession != null) + { + try + { + amqProtocolSession.closeSession(); + } + catch (AMQException e) + { + _logger.error("Caught AMQException whilst closingSession:" + e); + } + } + } + + public void sessionIdle(IoSession session, IdleStatus status) throws Exception + { + _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); + if (IdleStatus.WRITER_IDLE.equals(status)) + { + //write heartbeat frame: + session.write(HeartbeatBody.FRAME); + } + else if (IdleStatus.READER_IDLE.equals(status)) + { + //failover: + throw new IOException("Timed out while waiting for heartbeat from peer."); + } + + } + + public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception + { + AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + if (throwable instanceof AMQProtocolHeaderException) + { + + protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + + protocolSession.close(); + + _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); + } + else if (throwable instanceof IOException) + { + _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable); + } + else + { + _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); + + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(session.getProtocolVersion()); + ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); + + protocolSession.write(closeBody.generateFrame(0)); + + protocolSession.close(); + } + } + + /** + * Invoked when a message is received on a particular protocol session. Note that a + * protocol session is directly tied to a particular physical connection. + * + * @param protocolSession the protocol session that received the message + * @param message the message itself (i.e. a decoded frame) + * + * @throws Exception if the message cannot be processed + */ + public void messageReceived(IoSession protocolSession, Object message) throws Exception + { + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + + if (message instanceof AMQDataBlock) + { + amqProtocolSession.dataBlockReceived((AMQDataBlock) message); + + } + else if (message instanceof ByteBuffer) + { + throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); + } + else + { + throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); + } + } + + /** + * Called after a message has been sent out on a particular protocol session + * + * @param protocolSession the protocol session (i.e. connection) on which this + * message was sent + * @param object the message (frame) that was encoded and sent + * + * @throws Exception if we want to indicate an error + */ + public void messageSent(IoSession protocolSession, Object object) throws Exception + { + } + + protected boolean isSSLClient(ConnectorConfiguration connectionConfig, + IoSession protocolSession) + { + InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); + return addr.getPort() == connectionConfig.sslPort; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java new file mode 100644 index 0000000000..07c153bfe8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; + +/** + * The protocol provide's role is to encapsulate the initialisation of the protocol handler. + * + * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events + * such as connection closing or a frame being received. It can either do this directly + * or pass off to the protocol session in the cases where state information is required to + * deal with the event. + * + */ +public class AMQPProtocolProvider +{ + /** + * Handler for protocol events + */ + private AMQPFastProtocolHandler _handler; + + public AMQPProtocolProvider() + { + IApplicationRegistry registry = ApplicationRegistry.getInstance(); + _handler = new AMQPFastProtocolHandler(registry); + } + + public AMQPFastProtocolHandler getHandler() + { + return _handler; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java new file mode 100644 index 0000000000..c9316f7405 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -0,0 +1,179 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import javax.security.sasl.SaslServer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.security.Principal; + + +public interface AMQProtocolSession extends AMQVersionAwareProtocolSession +{ + + + + public static interface Task + { + public void doTask(AMQProtocolSession session) throws AMQException; + } + + /** + * 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; + + /** + * Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC + * 6). + * + * @return the context key + */ + AMQShortString 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(AMQShortString 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) throws AMQException; + + /** + * 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; + + /** + * Markes the specific channel as closed. This will release the lock for that channel id so a new channel can be + * created on that id. + * + * @param channelId id of the channel to close + */ + void closeChannelOk(int channelId); + + /** + * Check to see if this chanel is closing + * + * @param channelId id to check + * @return boolean with state of channel awaiting closure + */ + boolean channelAwaitingClosure(int channelId); + + /** + * 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); + + + FieldTable getClientProperties(); + + void setClientProperties(FieldTable clientProperties); + + Object getClientIdentifier(); + + VirtualHost getVirtualHost(); + + void setVirtualHost(VirtualHost virtualHost) throws AMQException; + + void addSessionCloseTask(Task task); + + void removeSessionCloseTask(Task task); + + public ProtocolOutputConverter getProtocolOutputConverter(); + + void setAuthorizedID(Principal authorizedID); + + /** @return a Principal that was used to authorized this session */ + Principal getAuthorizedID(); + + public MethodRegistry getMethodRegistry(); + + public MethodDispatcher getMethodDispatcher(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java new file mode 100644 index 0000000000..bd072985c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -0,0 +1,306 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.security.Principal; +import java.util.Date; +import java.util.List; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; + +/** + * This MBean class implements the management interface. 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") +public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection +{ + private AMQMinaProtocolSession _session = null; + private String _name = null; + + // openmbean data types for representing the channel attributes + private static final String[] _channelAtttibuteNames = + { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; + private static final String[] _indexNames = { _channelAtttibuteNames[0] }; + private static final OpenType[] _channelAttributeTypes = + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; + private static CompositeType _channelType = null; // represents the data type for channel data + private static TabularType _channelsType = null; // Data type for list of channels type + private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = + new AMQShortString("Broker Management Console has closed the connection."); + + @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") + public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException + { + super(ManagedConnection.class, ManagedConnection.TYPE); + _session = session; + String remote = getRemoteAddress(); + remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; + _name = jmxEncode(new StringBuffer(remote), 0).toString(); + init(); + } + + static + { + try + { + init(); + } + catch (JMException ex) + { + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); + } + } + + /** + * initialises the openmbean data types + */ + private static void init() throws OpenDataException + { + _channelType = + new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, + _channelAttributeTypes); + _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); + } + + public String getClientId() + { + return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); + } + + public String getAuthorizedId() + { + return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; + } + + public String getVersion() + { + return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); + } + + public Date getLastIoTime() + { + return new Date(_session.getIOSession().getLastIoTime()); + } + + public String getRemoteAddress() + { + return _session.getIOSession().getRemoteAddress().toString(); + } + + public ManagedObject getParentObject() + { + return _session.getVirtualHost().getManagedObject(); + } + + public Long getWrittenBytes() + { + return _session.getIOSession().getWrittenBytes(); + } + + public Long getReadBytes() + { + return _session.getIOSession().getReadBytes(); + } + + public Long getMaximumNumberOfChannels() + { + return _session.getMaximumNumberOfChannels(); + } + + public void setMaximumNumberOfChannels(Long value) + { + _session.setMaximumNumberOfChannels(value); + } + + public String getObjectInstanceName() + { + return _name; + } + + /** + * commits transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if commit fails + */ + public void commitTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + + _session.commitTransactions(channel); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * rollsback the transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if rollback fails + */ + public void rollbackTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + + _session.rollbackTransactions(channel); + } + 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 channels() throws OpenDataException + { + TabularDataSupport channelsList = new TabularDataSupport(_channelsType); + List list = _session.getChannels(); + + for (AMQChannel channel : list) + { + Object[] itemValues = + { + channel.getChannelId(), channel.isTransactional(), + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, + channel.getUnacknowledgedMessageMap().size() + }; + + CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); + channelsList.put(channelData); + } + + return channelsList; + } + + /** + * closes the connection. The administrator can use this management operation to close connection to free up + * resources. + * @throws JMException + */ + public void closeConnection() throws JMException + { + + MethodRegistry methodRegistry = _session.getMethodRegistry(); + ConnectionCloseBody responseBody = + methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), + // replyCode + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION, + // replyText, + 0, + 0); + + _session.writeFrame(responseBody.generateFrame(0)); + + try + { + _session.closeSession(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; + String name = MonitorNotification.class.getName(); + String description = "Channel count has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[] { info1 }; + } + + public void notifyClients(String notificationMsg) + { + Notification n = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); + _broadcaster.sendNotification(n); + } + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java new file mode 100644 index 0000000000..2abcecb6de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeType; + +public class ExchangeInitialiser +{ + public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ + for (ExchangeType type : factory.getRegisteredTypes()) + { + define (registry, factory, type.getDefaultExchangeName(), type.getName()); + } + + define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); + } + + private void define(ExchangeRegistry r, ExchangeFactory f, + AMQShortString name, AMQShortString type) throws AMQException + { + if(r.getExchange(name)== null) + { + r.registerExchange(f.createExchange(name, type, true, false, 0)); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java new file mode 100644 index 0000000000..310deaaf55 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class HeartbeatConfig +{ + @Configured(path = "heartbeat.delay", defaultValue = "5") + public int delay = 5;//in secs + @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0") + public double timeoutFactor = 2; + + public double getTimeoutFactor() + { + return timeoutFactor; + } + + public void setTimeoutFactor(double timeoutFactor) + { + this.timeoutFactor = timeoutFactor; + } + + public int getDelay() + { + return delay; + } + + public void setDelay(int delay) + { + this.delay = delay; + } + + int getTimeout(int writeDelay) + { + return (int) (timeoutFactor * writeDelay); + } + + public static HeartbeatConfig getInstance() + { + return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class); + } + + public String toString() + { + return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java new file mode 100644 index 0000000000..e6e713ac6d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -0,0 +1,135 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.protocol; + +import java.io.IOException; +import java.util.Date; +import java.security.Principal; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +/** + * The management interface exposed to allow management of Connections. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedConnection +{ + static final String TYPE = "Connection"; + + @MBeanAttribute(name = "ClientId", description = "Client Id") + String getClientId(); + + @MBeanAttribute(name = "AuthorizedId", description = "User Name") + String getAuthorizedId(); + + @MBeanAttribute(name = "Version", description = "Client Version") + String getVersion(); + + /** + * Tells the remote address of this connection. + * @return remote address + */ + @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") + String getRemoteAddress(); + + /** + * Tells the last time, the IO operation was done. + * @return last IO time. + */ + @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done") + Date getLastIoTime(); + + /** + * Tells the total number of bytes written till now. + * @return number of bytes written. + * + @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") + Long getWrittenBytes(); + */ + /** + * Tells the total number of bytes read till now. + * @return number of bytes read. + * + @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") + Long getReadBytes(); + */ + + /** + * Threshold high value for no of channels. This is useful in setting notifications or + * taking required action is there are more channels being created. + * @return threshold limit for no of channels + */ + Long getMaximumNumberOfChannels(); + + /** + * Sets the threshold high value for number of channels for a connection + * @param value + */ + @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") + void setMaximumNumberOfChannels(Long value); + + //********** Operations *****************// + + /** + * channel details of all the channels opened for this connection. + * @return general channel details + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="channels", description="Channel details for this connection") + TabularData channels() throws IOException, JMException; + + /** + * Commits the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="commitTransaction", + description="Commits the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Rollsback the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="rollbackTransactions", + description="Rollsback the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Closes all the related channels and unregisters this connection from managed objects. + */ + @MBeanOperation(name="closeConnection", + description="Closes this connection and all related channels", + impact= MBeanOperationInfo.ACTION) + void closeConnection() throws Exception; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java new file mode 100644 index 0000000000..6e72aa062f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; + +/** + * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to cast a frame to its expected type. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would + * be better just to leave that as a ClassCastException. However, check the framing layer catches this error + * first. + */ +public class UnknnownMessageTypeException extends AMQException +{ + public UnknnownMessageTypeException(AMQDataBlock message) + { + super("Unknown message type: " + message.getClass().getName() + ": " + message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java new file mode 100644 index 0000000000..f501bc27d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -0,0 +1,717 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.exchange.Exchange; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A deliverable message. + */ +public class AMQMessage +{ + /** Used for debugging purposes. */ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + /** Used in clustering. @todo What for? */ + private Set _tokens; + + /** Only use in clustering. @todo What for? */ + private AMQProtocolSession _publisher; + + private final Long _messageId; + + private final AtomicInteger _referenceCount = new AtomicInteger(1); + + private AMQMessageHandle _messageHandle; + + /** Holds the transactional context in which this message is being processed. */ + private TransactionalContext _txnContext; + + /** + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. + */ + private boolean _deliveredToConsumer; + + /** Flag to indicate that this message requires 'immediate' delivery. */ + private boolean _immediate; + + private TransientMessageData _transientMessageData = new TransientMessageData(); + + private long _expiration; + + + + + private Exchange _exchange; + private static final boolean SYNCED_CLOCKS = + ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false); + + + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; + } + + public void setExpiration() + { + long expiration = + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); + long timestamp = + ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); + + if (SYNCED_CLOCKS) + { + _expiration = expiration; + } + else + { + // Update TTL to be in broker time. + if (expiration != 0L) + { + if (timestamp != 0L) + { + // todo perhaps use arrival time + long diff = (System.currentTimeMillis() - timestamp); + + if ((diff > 1000L) || (diff < 1000L)) + { + _expiration = expiration + diff; + } + } + } + } + + } + + public boolean isReferenced() + { + return _referenceCount.get() > 0; + } + + public void setExchange(final Exchange exchange) + { + _exchange = exchange; + } + + public void route() throws AMQException + { + _exchange.route(this); + } + + public void enqueue(final List queues) + { + _transientMessageData.setDestinationQueues(queues); + } + + /** + * 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 AMQProtocolSession _protocolSession; + + private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + _channel = channel; + _protocolSession = protocolSession; + } + + public boolean hasNext() + { + try + { + return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); + } + catch (AMQException e) + { + _log.error("Unable to get body count: " + e, e); + + return false; + } + } + + public AMQDataBlock next() + { + try + { + + AMQBody cb = + getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), + _messageId, ++_index)); + + return new AMQFrame(_channel, cb); + } + catch (AMQException e) + { + // have no choice but to throw a runtime exception + throw new RuntimeException("Error getting content body: " + e, e); + } + + } + + private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() + { + return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public StoreContext getStoreContext() + { + return _txnContext.getStoreContext(); + } + + private class BodyContentIterator implements Iterator + { + + private int _index = -1; + + public boolean hasNext() + { + try + { + return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); + } + catch (AMQException e) + { + _log.error("Error getting body count: " + e, e); + + return false; + } + } + + public ContentChunk next() + { + try + { + return _messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index); + } + catch (AMQException e) + { + throw new RuntimeException("Error getting content body: " + e, e); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext) + { + _messageId = messageId; + _txnContext = txnContext; + _immediate = info.isImmediate(); + _transientMessageData.setMessagePublishInfo(info); + + } + + /** + * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal + * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to + * queues. + * + * @param messageId + * @param store + * @param factory + * + * @throws AMQException + */ + public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) + throws AMQException + { + _messageId = messageId; + _messageHandle = factory.createMessageHandle(messageId, store, true); + _txnContext = txnConext; + _transientMessageData = null; + } + + /** + * Used in testing only. This allows the passing of the content header immediately on construction. + * + * @param messageId + * @param info + * @param txnContext + * @param contentHeader + */ + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, + ContentHeaderBody contentHeader) throws AMQException + { + this(messageId, info, txnContext); + setContentHeaderBody(contentHeader); + } + + /* * + * Used in testing only. This allows the passing of the content header and some body fragments on construction. + * + * @param messageId + * @param info + * @param txnContext + * @param contentHeader + * @param destinationQueues + * @param contentBodies + * + * @throws AMQException + */ /* + public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, + ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, + MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException + { + this(messageId, info, txnContext, contentHeader); + _transientMessageData.setDestinationQueues(destinationQueues); + routingComplete(messageStore, storeContext, messageHandleFactory); + for (ContentChunk cb : contentBodies) + { + addContentBodyFrame(storeContext, cb); + } + } + */ + protected AMQMessage(AMQMessage msg) throws AMQException + { + _messageId = msg._messageId; + _messageHandle = msg._messageHandle; + _txnContext = msg._txnContext; + _deliveredToConsumer = msg._deliveredToConsumer; + _transientMessageData = msg._transientMessageData; + } + + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + return new BodyFrameIterator(protocolSession, channel); + } + + public Iterator getContentBodyIterator() + { + return new BodyContentIterator(); + } + + public ContentHeaderBody getContentHeaderBody() throws AMQException + { + if (_transientMessageData != null) + { + return _transientMessageData.getContentHeaderBody(); + } + else + { + return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); + } + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException + { + _transientMessageData.setContentHeaderBody(contentHeaderBody); + } + + public void routingComplete(MessageStore store, StoreContext storeContext, 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 : _transientMessageData.getDestinationQueues()) + { + _messageHandle.enqueue(storeContext, _messageId, q); + } + + if (_transientMessageData.getContentHeaderBody().bodySize == 0) + { + deliver(storeContext); + } + } + + public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException + { + _transientMessageData.addBodyLength(contentChunk.getSize()); + final boolean allContentReceived = isAllContentReceived(); + _messageHandle.addContentBodyFrame(storeContext, _messageId, contentChunk, allContentReceived); + if (allContentReceived) + { + deliver(storeContext); + + return true; + } + else + { + return false; + } + } + + public boolean isAllContentReceived() throws AMQException + { + return _transientMessageData.isAllContentReceived(); + } + + public Long getMessageId() + { + return _messageId; + } + + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. + */ + public AMQMessage takeReference() + { + incrementReference(); // _referenceCount.incrementAndGet(); + + return this; + } + + /** Threadsafe. Increment the reference count on the message. */ + public void incrementReference() + { + _referenceCount.incrementAndGet(); + // if (_log.isDebugEnabled()) + // { + // _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); + // } + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * @param storeContext + * + * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + public void decrementReference(StoreContext storeContext) throws MessageCleanupException + { + int count = _referenceCount.decrementAndGet(); + + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (count == 0) + { + try + { + // if (_log.isDebugEnabled()) + // { + // _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); + // } + + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + if (_messageHandle != null) + { + _messageHandle.removeMessage(storeContext, _messageId); + } + } + catch (AMQException e) + { + // to maintain consistency, we revert the count + incrementReference(); + throw new MessageCleanupException(_messageId, e); + } + } + else + { + if (count < 0) + { + throw new MessageCleanupException("Reference count for message id " + debugIdentity() + + " has gone below 0."); + } + } + } + + public void setPublisher(AMQProtocolSession publisher) + { + _publisher = publisher; + } + + public AMQProtocolSession getPublisher() + { + return _publisher; + } + + /** + * Called selectors to determin if the message has already been sent + * + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return _deliveredToConsumer; + } + + + public boolean checkToken(Object token) + { + + if (_tokens == null) + { + _tokens = new HashSet(); + } + + 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 + { + _transientMessageData.addDestinationQueue(queue); + } + + /** + * NOTE: Think about why you are using this method. Normal usages would want to do + * AMQQueue.dequeue(StoreContext, AMQMessage) + * This will keep the queue statistics up-to-date. + * Currently this method is only called _correctly_ from AMQQueue dequeue. + * Ideally we would have a better way for the queue to dequeue the message. + * Especially since enqueue isn't the recipriocal of this method. + * @deprecated + * @param storeContext + * @param queue + * @throws AMQException + */ + void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException + { + _messageHandle.dequeue(storeContext, _messageId, queue); + } + + public boolean isPersistent() throws AMQException + { + if (_transientMessageData != null) + { + return _transientMessageData.isPersistent(); + } + else + { + return _messageHandle.isPersistent(getStoreContext(), _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 + { + + if (_immediate && !_deliveredToConsumer) + { + throw new NoConsumersException(this); + } + } + + public MessagePublishInfo getMessagePublishInfo() throws AMQException + { + MessagePublishInfo pb; + if (_transientMessageData != null) + { + pb = _transientMessageData.getMessagePublishInfo(); + } + else + { + pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); + } + + return pb; + } + + public boolean isRedelivered() + { + return _messageHandle.isRedelivered(); + } + + public void setRedelivered(boolean redelivered) + { + _messageHandle.setRedelivered(redelivered); + } + + public long getArrivalTime() + { + return _messageHandle.getArrivalTime(); + } + + /** + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @param queue The queue to check the expiration against. (Currently not used) + * + * @return true if the message has expire + * + * @throws AMQException + */ + public boolean expired(AMQQueue queue) throws AMQException + { + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > _expiration); + } + + return false; + } + + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + */ + public void setDeliveredToConsumer() + { + _deliveredToConsumer = true; + } + + private void deliver(StoreContext storeContext) throws AMQException + { + // we get a reference to the destination queues now so that we can clear the + // transient message data as quickly as possible + List destinationQueues = _transientMessageData.getDestinationQueues(); + if (_log.isDebugEnabled()) + { + _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues); + } + + try + { + // first we allow the handle to know that the message has been fully received. This is useful if it is + // maintaining any calculated values based on content chunks + _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, + _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); + + // 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) + { + // Increment the references to this message for each queue delivery. + incrementReference(); + // normal deliver so add this message at the end. + _txnContext.deliver(q.createEntry(this), false); + } + } + finally + { + + // Remove refence for routing process . Reference count should now == delivered queue count + decrementReference(storeContext); + } + } + + + public AMQMessageHandle getMessageHandle() + { + return _messageHandle; + } + + public long getSize() + { + try + { + long size = getContentHeaderBody().bodySize; + + return size; + } + catch (AMQException e) + { + _log.error(e.toString(), e); + + return 0; + } + + } + + public void restoreTransientMessageData() throws AMQException + { + TransientMessageData transientMessageData = new TransientMessageData(); + transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); + transientMessageData.setContentHeaderBody(getContentHeaderBody()); + transientMessageData.addBodyLength(getContentHeaderBody().getSize()); + _transientMessageData = transientMessageData; + } + + + public String toString() + { + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; + + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java new file mode 100644 index 0000000000..ede55b3bbf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +/** + * A pluggable way of getting message data. Implementations can provide intelligent caching for example or + * even no caching at all to minimise the broker memory footprint. + * + * 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(StoreContext context, Long messageId) throws AMQException; + + /** + * @return the number of body frames associated with this message + */ + int getBodyCount(StoreContext context, Long messageId) throws AMQException; + + /** + * @return the size of the body + */ + long getBodySize(StoreContext context, 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 + */ + ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; + + void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; + + MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException; + + boolean isRedelivered(); + + void setRedelivered(boolean redelivered); + + boolean isPersistent(StoreContext context, Long messageId) throws AMQException; + + void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException; + + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + + void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; + + void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; + + long getArrivalTime(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java new file mode 100644 index 0000000000..7c6db0b4b3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -0,0 +1,1024 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.configuration.Configured; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 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, Comparable +{ + + /** + * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create a subscription, because an exclusive subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + public static final class ExistingExclusiveSubscription extends AMQException + { + + public ExistingExclusiveSubscription() + { + super(""); + } + } + + /** + * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create an exclusize subscription, as a subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + public static final class ExistingSubscriptionPreventsExclusive extends AMQException + { + public ExistingSubscriptionPreventsExclusive() + { + super(""); + } + } + + private static final Logger _logger = Logger.getLogger(AMQQueue.class); + + private final AMQShortString _name; + + /** null means shared */ + private final AMQShortString _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; + + private final AtomicInteger _subscriberCount = new AtomicInteger(); + + private final AtomicBoolean _isExclusive = new AtomicBoolean(); + + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + private List _deleteTaskList = new CopyOnWriteArrayList(); + + /** Manages message delivery. */ + private final DeliveryManager _deliveryMgr; + + /** 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; + + private final VirtualHost _virtualHost; + + /** max allowed size(KB) of a single message */ + @Configured(path = "maximumMessageSize", defaultValue = "0") + public long _maximumMessageSize; + + /** max allowed number of messages on a queue. */ + @Configured(path = "maximumMessageCount", defaultValue = "0") + public long _maximumMessageCount; + + /** max queue depth for the queue */ + @Configured(path = "maximumQueueDepth", defaultValue = "0") + public long _maximumQueueDepth; + + /** maximum message age before alerts occur */ + @Configured(path = "maximumMessageAge", defaultValue = "0") + public long _maximumMessageAge; + + /** the minimum interval between sending out consequetive alerts of the same type */ + @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") + public long _minimumAlertRepeatGap; + + /** total messages received by the queue since startup. */ + public AtomicLong _totalMessagesReceived = new AtomicLong(); + + + private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); + + + public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException + { + this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), + new SubscriptionSet(), new SubscriptionImpl.Factory()); + } + + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, + VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException + { + this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, + new SubscriptionImpl.Factory()); + } + + protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, + VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, + SubscriptionFactory subscriptionFactory) throws AMQException + { + if (name == null) + { + throw new IllegalArgumentException("Queue name must not be null"); + } + + if (virtualHost == null) + { + throw new IllegalArgumentException("Virtual Host must not be null"); + } + + _name = name; + _durable = durable; + _owner = owner; + _autoDelete = autoDelete; + _virtualHost = virtualHost; + _asyncDelivery = asyncDelivery; + + _managedObject = createMBean(); + _managedObject.register(); + + _subscribers = subscribers; + _subscriptionFactory = subscriptionFactory; + _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); + + // This ensure that the notification checks for the configured alerts are created. + setMaximumMessageAge(_maximumMessageAge); + setMaximumMessageCount(_maximumMessageCount); + setMaximumMessageSize(_maximumMessageSize); + setMaximumQueueDepth(_maximumQueueDepth); + + } + + private AMQQueueMBean createMBean() throws AMQException + { + try + { + return new AMQQueueMBean(this); + } + catch (JMException ex) + { + throw new AMQException("AMQQueue MBean creation has failed ", ex); + } + } + + public final AMQShortString getName() + { + return _name; + } + + public boolean isShared() + { + return _owner == null; + } + + public boolean isDurable() + { + return _durable; + } + + public AMQShortString getOwner() + { + return _owner; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public boolean isDeleted() + { + return _deleted.get(); + } + + /** @return no of messages(undelivered) on the queue. */ + public int getMessageCount() + { + return _deliveryMgr.getQueueMessageCount(); + } + + /** @return List of messages(undelivered) on the queue. */ + public List getMessagesOnTheQueue() + { + return _deliveryMgr.getMessages(); + } + + /** + * Returns messages within the given range of message Ids. + * + * @param fromMessageId + * @param toMessageId + * + * @return List of messages + */ + public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) + { + return _deliveryMgr.getMessages(fromMessageId, toMessageId); + } + + public long getQueueDepth() + { + return _deliveryMgr.getTotalMessageSize(); + } + + /** + * @param messageId + * + * @return QueueEntry with give id if exists. null if QueueEntry with given id doesn't exist. + */ + public QueueEntry getMessageOnTheQueue(long messageId) + { + List list = getMessagesOnTheQueue(messageId, messageId); + if ((list == null) || (list.size() == 0)) + { + return null; + } + + return list.get(0); + } + + /** + * Moves messages from this queue to another queue, and also commits the move on the message store. Delivery activity + * on the queues being moved between is suspended during the move. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param queueName The queue to move the messages to. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + + MessageStore fromStore = getVirtualHost().getMessageStore(); + MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + + if (toStore != fromStore) + { + throw new RuntimeException("Can only move messages between queues on the same message store."); + } + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + toQueue.startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : foundMessagesList) + { + AMQMessage message = entry.getMessage(); + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity + * on the queues being moved between is suspended during the move. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param queueName The queue to move the messages to. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + + MessageStore fromStore = getVirtualHost().getMessageStore(); + MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + + if (toStore != fromStore) + { + throw new RuntimeException("Can only move messages between queues on the same message store."); + } + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + toQueue.startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : foundMessagesList) + { + AMQMessage message = entry.getMessage(); + toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); + message.takeReference(); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // Move the messages on the in-memory queues. + toQueue.enqueueMovedMessages(storeContext, foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + toQueue.stopMovingMessages(); + stopMovingMessages(); + } + } + + /** + * Removes messages from this queue, and also commits the remove on the message store. Delivery activity + * on the queues being moved between is suspended during the remove. + * + * @param fromMessageId The first message id to move. + * @param toMessageId The last message id to move. + * @param storeContext The context of the message store under which to perform the move. This is associated with + * the stores transactional context. + */ + public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + { + MessageStore fromStore = getVirtualHost().getMessageStore(); + + try + { + // Obtain locks to prevent activity on the queues being moved between. + startMovingMessages(); + + // Get the list of messages to move. + List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); + + try + { + fromStore.beginTran(storeContext); + + // remove the messages in on the message store. + for (QueueEntry entry : foundMessagesList) + { + AMQMessage message = entry.getMessage(); + fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); + } + + // Commit and flush the move transcations. + try + { + fromStore.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + + // remove the messages on the in-memory queues. + _deliveryMgr.removeMovedMessages(foundMessagesList); + } + // Abort the move transactions on move failures. + catch (AMQException e) + { + try + { + fromStore.abortTran(storeContext); + } + catch (AMQException ae) + { + throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); + } + } + } + // Release locks to allow activity on the queues being moved between to continue. + finally + { + stopMovingMessages(); + } + } + + public void startMovingMessages() + { + _deliveryMgr.startMovingMessages(); + } + + private void enqueueMovedMessages(StoreContext storeContext, List messageList) + { + _deliveryMgr.enqueueMovedMessages(storeContext, messageList); + _totalMessagesReceived.addAndGet(messageList.size()); + } + + public void stopMovingMessages() + { + _deliveryMgr.stopMovingMessages(); + _deliveryMgr.processAsync(_asyncDelivery); + } + + /** @return MBean object associated with this Queue */ + public ManagedObject getManagedObject() + { + return _managedObject; + } + + public long getMaximumMessageSize() + { + return _maximumMessageSize; + } + + public void setMaximumMessageSize(final long maximumMessageSize) + { + _maximumMessageSize = maximumMessageSize; + if(maximumMessageSize == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT); + } + } + + public int getConsumerCount() + { + return _subscribers.size(); + } + + public int getActiveConsumerCount() + { + return _subscribers.getWeight(); + } + + public long getReceivedMessageCount() + { + return _totalMessagesReceived.get(); + } + + public long getMaximumMessageCount() + { + return _maximumMessageCount; + } + + public void setMaximumMessageCount(final long maximumMessageCount) + { + _maximumMessageCount = maximumMessageCount; + if(maximumMessageCount == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); + } + + + + } + + public long getMaximumQueueDepth() + { + return _maximumQueueDepth; + } + + // Sets the queue depth, the max queue size + public void setMaximumQueueDepth(final long maximumQueueDepth) + { + _maximumQueueDepth = maximumQueueDepth; + if(maximumQueueDepth == 0L) + { + _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT); + } + + } + + public long getOldestMessageArrivalTime() + { + return _deliveryMgr.getOldestMessageArrival(); + + } + + /** Removes the QueueEntry from the top of the queue. */ + public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException + { + _deliveryMgr.removeAMessageFromTop(storeContext, this); + } + + /** removes all the messages from the queue. */ + public synchronized long clearQueue(StoreContext storeContext) throws AMQException + { + return _deliveryMgr.clearAllMessages(storeContext); + } + + public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException + { + exchange.registerQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + } + + _bindings.addBinding(routingKey, arguments, exchange); + } + + public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException + { + exchange.deregisterQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + } + + _bindings.remove(routingKey, arguments, exchange); + } + + public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException + { + if (incrementSubscriberCount() > 1) + { + if (isExclusive()) + { + decrementSubscriberCount(); + throw new ExistingExclusiveSubscription(); + } + else if (exclusive) + { + decrementSubscriberCount(); + throw new ExistingSubscriptionPreventsExclusive(); + } + + } + else if (exclusive) + { + setExclusive(true); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format("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, filters, noLocal, this); + + if (subscription.filtersMessages()) + { + if (_deliveryMgr.hasQueuedMessages()) + { + _deliveryMgr.populatePreDeliveryQueue(subscription); + } + } + + _subscribers.addSubscriber(subscription); + if(exclusive) + { + _subscribers.setExclusive(true); + } + + subscription.start(); + } + + private boolean isExclusive() + { + return _isExclusive.get(); + } + + private void setExclusive(boolean exclusive) + { + _isExclusive.set(exclusive); + } + + private int incrementSubscriberCount() + { + return _subscriberCount.incrementAndGet(); + } + + private int decrementSubscriberCount() + { + return _subscriberCount.decrementAndGet(); + } + + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException + { + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format( + "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", + ps, channel, consumerTag, this)); + } + + _subscribers.setExclusive(false); + 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); + } + + removedSubscription.close(); + setExclusive(false); + decrementSubscriberCount(); + + // if we are eligible for auto deletion, unregister from the queue registry + if (_autoDelete && _subscribers.isEmpty()) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Auto-deleteing queue:" + this); + } + + 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 boolean isUnused() + { + return _subscribers.isEmpty(); + } + + public boolean isEmpty() + { + return !_deliveryMgr.hasQueuedMessages(); + } + + public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException + { + if (checkUnused && !_subscribers.isEmpty()) + { + _logger.info("Will not delete " + this + " as it is in use."); + + return 0; + } + else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) + { + _logger.info("Will not delete " + this + " as it is not empty."); + + return 0; + } + else + { + delete(); + + return _deliveryMgr.getQueueMessageCount(); + } + } + + public void delete() throws AMQException + { + if (!_deleted.getAndSet(true)) + { + _subscribers.queueDeleted(this); + _bindings.deregister(); + _virtualHost.getQueueRegistry().unregisterQueue(_name); + _managedObject.unregister(); + for (Task task : _deleteTaskList) + { + task.doTask(this); + } + + _deleteTaskList.clear(); + } + } + + protected void autodelete() throws AMQException + { + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format("autodeleting {0}", this)); + } + + delete(); + } + + /*public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException + { + // fixme not sure what this is doing. should we be passing deliverFirst through here? + // This code is not used so when it is perhaps it should + _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); + try + { + msg.checkDeliveredToConsumer(); + updateReceivedMessageCount(msg); + } + catch (NoConsumersException e) + { + // as this message will be returned, it should be removed + // from the queue: + dequeue(storeContext, msg); + } + }*/ + + // public DeliveryManager getDeliveryManager() + // { + // return _deliveryMgr; + // } + + public void process(StoreContext storeContext, QueueEntry entry, boolean deliverFirst) throws AMQException + { + AMQMessage msg = entry.getMessage(); + _deliveryMgr.deliver(storeContext, _name, entry, deliverFirst); + try + { + msg.checkDeliveredToConsumer(); + updateReceivedMessageCount(entry); + } + catch (NoConsumersException e) + { + // as this message will be returned, it should be removed + // from the queue: + dequeue(storeContext, entry); + } + } + + public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + { + try + { + entry.getMessage().dequeue(storeContext, this); + } + catch (MessageCleanupException e) + { + // Message was dequeued, but could not then be deleted + // though it is no longer referenced. This should be very + // rare and can be detected and cleaned up on recovery or + // done through some form of manual intervention. + _logger.error(e, e); + } + catch (AMQException e) + { + throw new FailedDequeueException(_name.toString(), e); + } + } + + public void deliverAsync() + { + _deliveryMgr.processAsync(_asyncDelivery); + } + + protected SubscriptionManager getSubscribers() + { + return _subscribers; + } + + protected void updateReceivedMessageCount(QueueEntry entry) throws AMQException + { + AMQMessage msg = entry.getMessage(); + + if (!msg.isRedelivered()) + { + _totalMessagesReceived.incrementAndGet(); + } + + try + { + _managedObject.checkForNotification(msg); + } + catch (JMException e) + { + throw new AMQException("Unable to get notification from manage queue: " + e, e); + } + } + + 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); + } + + public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException + { + return _deliveryMgr.performGet(session, channel, acks); + } + + public QueueRegistry getQueueRegistry() + { + return _virtualHost.getQueueRegistry(); + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public static interface Task + { + public void doTask(AMQQueue queue) throws AMQException; + } + + public void addQueueDeleteTask(Task task) + { + _deleteTaskList.add(task); + } + + public long getMinimumAlertRepeatGap() + { + return _minimumAlertRepeatGap; + } + + public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) + { + _minimumAlertRepeatGap = minimumAlertRepeatGap; + } + + public long getMaximumMessageAge() + { + return _maximumMessageAge; + } + + public void setMaximumMessageAge(long maximumMessageAge) + { + _maximumMessageAge = maximumMessageAge; + if(maximumMessageAge == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT); + } + } + + public void subscriberHasPendingResend(boolean hasContent, SubscriptionImpl subscription, QueueEntry entry) + { + _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, entry); + } + + public QueueEntry createEntry(AMQMessage amqMessage) + { + return new QueueEntry(this, amqMessage); + } + + public int compareTo(Object o) + { + return _name.compareTo(((AMQQueue) o).getName()); + } + + + public void removeExpiredIfNoSubscribers() throws AMQException + { + synchronized(_subscribers.getChangeLock()) + { + if(_subscribers.isEmpty()) + { + _deliveryMgr.removeExpired(); + } + } + } + + public final Set getNotificationChecks() + { + return _notificationChecks; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java new file mode 100644 index 0000000000..348a136f9d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -0,0 +1,479 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.store.StoreContext; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.OperationsException; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * AMQQueueMBean is the management bean for an {@link AMQQueue}. + * + *

      CRC Caption + * Responsibilities Collaborations + * + */ +@MBeanDescription("Management Interface for AMQQueue") +public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener +{ + /** Used for debugging purposes. */ + private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + + private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); + + /** + * Since the MBean is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + private StoreContext _storeContext = new StoreContext(); + + private AMQQueue _queue = null; + private String _queueName = null; + // OpenMBean data types for viewMessages method + private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; + private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; + private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + + // OpenMBean data types for viewMessageContent method + private static CompositeType _msgContentType = null; + private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; + private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; + private Notification _lastNotification = null; + + + + + @MBeanConstructor("Creates an MBean exposing an AMQQueue") + public AMQQueueMBean(AMQQueue queue) throws JMException + { + super(ManagedQueue.class, ManagedQueue.TYPE); + _queue = queue; + _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); + } + + public ManagedObject getParentObject() + { + return _queue.getVirtualHost().getManagedObject(); + } + + static + { + try + { + init(); + } + catch (JMException ex) + { + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); + } + } + + /** + * initialises the openmbean data types + */ + private static void init() throws OpenDataException + { + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = + new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, + _msgContentAttributeTypes); + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = + new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); + } + + public String getObjectInstanceName() + { + return _queueName; + } + + public String getName() + { + return _queueName; + } + + public boolean isDurable() + { + return _queue.isDurable(); + } + + public String getOwner() + { + return String.valueOf(_queue.getOwner()); + } + + public boolean isAutoDelete() + { + return _queue.isAutoDelete(); + } + + public Integer getMessageCount() + { + return _queue.getMessageCount(); + } + + public Long getMaximumMessageSize() + { + return _queue.getMaximumMessageSize(); + } + + public Long getMaximumMessageAge() + { + return _queue.getMaximumMessageAge(); + } + + public void setMaximumMessageAge(Long maximumMessageAge) + { + _queue.setMaximumMessageAge(maximumMessageAge); + } + + public void setMaximumMessageSize(Long value) + { + _queue.setMaximumMessageSize(value); + } + + public Integer getConsumerCount() + { + return _queue.getConsumerCount(); + } + + public Integer getActiveConsumerCount() + { + return _queue.getActiveConsumerCount(); + } + + public Long getReceivedMessageCount() + { + return _queue.getReceivedMessageCount(); + } + + public Long getMaximumMessageCount() + { + return _queue.getMaximumMessageCount(); + } + + public void setMaximumMessageCount(Long value) + { + _queue.setMaximumMessageCount(value); + } + + public Long getMaximumQueueDepth() + { + long queueDepthInBytes = _queue.getMaximumQueueDepth(); + + return queueDepthInBytes >> 10; + } + + public void setMaximumQueueDepth(Long value) + { + _queue.setMaximumQueueDepth(value); + } + + /** + * returns the size of messages(KB) in the queue. + */ + public Long getQueueDepth() throws JMException + { + long queueBytesSize = _queue.getQueueDepth(); + + return queueBytesSize >> 10; + } + + /** + * Checks if there is any notification to be send to the listeners + */ + public void checkForNotification(AMQMessage msg) throws AMQException, JMException + { + + final Set notificationChecks = _queue.getNotificationChecks(); + + if(!notificationChecks.isEmpty()) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); + + for (NotificationCheck check : notificationChecks) + { + if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) + { + if (check.notifyIfNecessary(msg, _queue, this)) + { + _lastNotificationTimes[check.ordinal()] = currentTime; + } + } + } + } + + } + + /** + * Sends the notification to the listeners + */ + public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) + { + // important : add log to the log file - monitoring tools may be looking for this + _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); + notificationMsg = notification.name() + " " + notificationMsg; + + _lastNotification = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); + + _broadcaster.sendNotification(_lastNotification); + } + + public Notification getLastNotification() + { + return _lastNotification; + } + + /** + * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop + */ + public void deleteMessageFromTop() throws JMException + { + try + { + _queue.deleteMessageFromTop(_storeContext); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * @see org.apache.qpid.server.queue.AMQQueue#clearQueue + */ + public void clearQueue() throws JMException + { + try + { + _queue.clearQueue(_storeContext); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * returns message content as byte array and related attributes for the given message id. + */ + public CompositeData viewMessageContent(long msgId) throws JMException + { + QueueEntry entry = _queue.getMessageOnTheQueue(msgId); + + if (entry == null) + { + throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); + } + + AMQMessage msg = entry.getMessage(); + // get message content + Iterator cBodies = msg.getContentBodyIterator(); + List msgContent = new ArrayList(); + while (cBodies.hasNext()) + { + ContentChunk body = cBodies.next(); + if (body.getSize() != 0) + { + if (body.getSize() != 0) + { + ByteBuffer slice = body.getData().slice(); + for (int j = 0; j < slice.limit(); j++) + { + msgContent.add(slice.get()); + } + } + } + } + + try + { + // Create header attributes list + CommonContentHeaderProperties headerProperties = + (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; + String mimeType = null, encoding = null; + if (headerProperties != null) + { + AMQShortString mimeTypeShortSting = headerProperties.getContentType(); + mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); + encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); + } + + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + } + catch (AMQException e) + { + JMException jme = new JMException("Error creating header attributes list: " + e); + jme.initCause(e); + throw jme; + } + } + + /** + * Returns the header contents of the messages stored in this queue in tabular form. + */ + public TabularData viewMessages(int beginIndex, int endIndex) throws JMException + { + if ((beginIndex > endIndex) || (beginIndex < 1)) + { + throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + } + + List list = _queue.getMessagesOnTheQueue(); + TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); + + try + { + // Create the tabular list of message header contents + for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) + { + AMQMessage msg = list.get(i - 1).getMessage(); + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + String[] headerAttributes = getMessageHeaderProperties(headerBody); + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + _messageList.put(messageData); + } + } + catch (AMQException e) + { + JMException jme = new JMException("Error creating message contents: " + e); + jme.initCause(e); + throw jme; + } + + return _messageList; + } + + private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) + { + List list = new ArrayList(); + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + list.add("reply-to = " + headerProperties.getReplyToAsString()); + list.add("propertyFlags = " + headerProperties.getPropertyFlags()); + list.add("ApplicationID = " + headerProperties.getAppIdAsString()); + list.add("ClusterID = " + headerProperties.getClusterIdAsString()); + list.add("UserId = " + headerProperties.getUserIdAsString()); + list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); + list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); + + int delMode = headerProperties.getDeliveryMode(); + list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); + + list.add("JMSPriority = " + headerProperties.getPriority()); + list.add("JMSType = " + headerProperties.getType()); + + long longDate = headerProperties.getExpiration(); + String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSExpiration = " + strDate); + + longDate = headerProperties.getTimestamp(); + strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSTimestamp = " + strDate); + + return list.toArray(new String[list.size()]); + } + + /** + * @see ManagedQueue#moveMessages + * @param fromMessageId + * @param toMessageId + * @param toQueueName + * @throws JMException + */ + public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + } + + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + } + + /** + * returns Notifications sent by this MBean. + */ + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; + String name = MonitorNotification.class.getName(); + String description = "Either Message count or Queue depth or Message size has reached threshold high value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[] { info1 }; + } + +} // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java new file mode 100644 index 0000000000..290fedcf7b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java @@ -0,0 +1,56 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class AsyncDeliveryConfig +{ + private Executor _executor; + + @Configured(path = "delivery.poolsize", defaultValue = "0") + public int poolSize; + + public Executor getExecutor() + { + if (_executor == null) + { + if (poolSize > 0) + { + _executor = Executors.newFixedThreadPool(poolSize); + } + else + { + _executor = Executors.newCachedThreadPool(); + } + } + return _executor; + } + + public static Executor getAsyncDeliveryExecutor() + { + return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java new file mode 100644 index 0000000000..7dfcae95c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -0,0 +1,1061 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; +import org.apache.qpid.util.MessageQueue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; + + +/** Manages delivery of messages on behalf of a queue */ +public class ConcurrentSelectorDeliveryManager implements DeliveryManager +{ + private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class); + + @Configured(path = "advanced.compressBufferOnQueue", + defaultValue = "false") + public boolean compressBufferOnQueue; + /** Holds any queued messages */ + private final MessageQueue _messages = new ConcurrentLinkedMessageQueueAtomicSize(); + + /** Ensures that only one asynchronous task is running for this manager at any time. */ + private final AtomicBoolean _processing = new AtomicBoolean(); + /** The subscriptions on the queue to whom messages are delivered */ + private final SubscriptionManager _subscriptions; + + /** + * A reference to the queue we are delivering messages for. We need this to be able to pass the code that handles + * acknowledgements a handle on the queue. + */ + private final AMQQueue _queue; + + /** + * Flag used while moving messages from this queue to another. For moving messages the async delivery should also + * stop. This flat should be set to true to stop async delivery and set to false to enable async delivery again. + */ + private AtomicBoolean _movingMessages = new AtomicBoolean(); + + /** + * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced + * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be + * delivered via the async thread.

      Lock is used to control access to hasQueuedMessages() and over the addition + * of messages to the queue. + */ + private ReentrantLock _lock = new ReentrantLock(); + private AtomicLong _totalMessageSize = new AtomicLong(); + private AtomicInteger _extraMessages = new AtomicInteger(); + private Set _hasContent = Collections.synchronizedSet(new HashSet()); + private final Object _queueHeadLock = new Object(); + private String _processingThreadName = ""; + + + /** Used by any reaping thread to purge messages */ + private StoreContext _reapingStoreContext = new StoreContext(); + + ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) + { + + //Set values from configuration + Configurator.configure(this); + + if (compressBufferOnQueue) + { + _log.warn("Compressing Buffers on queue."); + } + + _subscriptions = subscriptions; + _queue = queue; + } + + + private boolean addMessageToQueue(QueueEntry entry, boolean deliverFirst) + { + AMQMessage msg = entry.getMessage(); + // Shrink the ContentBodies to their actual size to save memory. + if (compressBufferOnQueue) + { + Iterator it = msg.getContentBodyIterator(); + while (it.hasNext()) + { + ContentChunk cb = it.next(); + cb.reduceToFit(); + } + } + + if (deliverFirst) + { + synchronized (_queueHeadLock) + { + _messages.pushHead(entry); + } + } + else + { + _messages.offer(entry); + } + + _totalMessageSize.addAndGet(msg.getSize()); + + return true; + } + + + public boolean hasQueuedMessages() + { + _lock.lock(); + try + { + return !(_messages.isEmpty() && _hasContent.isEmpty()); + } + finally + { + _lock.unlock(); + } + } + + public int getQueueMessageCount() + { + return getMessageCount(); + } + + /** + * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine + * size. The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. + * + * @return int the number of messages in the delivery queue. + */ + private int getMessageCount() + { + return _messages.size() + _extraMessages.get(); + } + + + public long getTotalMessageSize() + { + return _totalMessageSize.get(); + } + + public long getOldestMessageArrival() + { + QueueEntry entry = _messages.peek(); + return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); + } + + public void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry entry) + { + _lock.lock(); + try + { + if (hasContent) + { + _log.debug("Queue has adding subscriber content"); + _hasContent.add(subscription); + _totalMessageSize.addAndGet(entry.getSize()); + _extraMessages.addAndGet(1); + } + else + { + _log.debug("Queue has removing subscriber content"); + if (entry == null) + { + _hasContent.remove(subscription); + } + else + { + _totalMessageSize.addAndGet(-entry.getSize()); + _extraMessages.addAndGet(-1); + } + } + } + finally + { + _lock.unlock(); + } + } + + /** + * NOTE : This method should only be called when there are no active subscribers + */ + public void removeExpired() throws AMQException + { + _lock.lock(); + + + for(Iterator iter = _messages.iterator(); iter.hasNext();) + { + QueueEntry entry = iter.next(); + if(entry.expired()) + { + // fixme: Currently we have to update the total byte size here for the data in the queue + _totalMessageSize.addAndGet(-entry.getSize()); + _queue.dequeue(_reapingStoreContext,entry); + iter.remove(); + } + } + + + _lock.unlock(); + } + + /** @return the state of the async processor. */ + public boolean isProcessingAsync() + { + return _processing.get(); + } + + /** + * Returns all the messages in the Queue + * + * @return List of messages + */ + public List getMessages() + { + _lock.lock(); + List list = new ArrayList(); + + for (QueueEntry entry : _messages) + { + list.add(entry); + } + _lock.unlock(); + + return list; + } + + /** + * Returns messages within the range of given messageIds + * + * @param fromMessageId + * @param toMessageId + * + * @return + */ + public List getMessages(long fromMessageId, long toMessageId) + { + if (fromMessageId <= 0 || toMessageId <= 0) + { + return null; + } + + long maxMessageCount = toMessageId - fromMessageId + 1; + + _lock.lock(); + + List foundMessagesList = new ArrayList(); + + for (QueueEntry entry : _messages) + { + long msgId = entry.getMessage().getMessageId(); + if (msgId >= fromMessageId && msgId <= toMessageId) + { + foundMessagesList.add(entry); + } + // break if the no of messages are found + if (foundMessagesList.size() == maxMessageCount) + { + break; + } + } + _lock.unlock(); + + return foundMessagesList; + } + + public void populatePreDeliveryQueue(Subscription subscription) + { + if (_log.isDebugEnabled()) + { + _log.debug("Populating PreDeliveryQueue for Subscription(" + System.identityHashCode(subscription) + ")"); + } + + Iterator currentQueue = _messages.iterator(); + + while (currentQueue.hasNext()) + { + QueueEntry entry = currentQueue.next(); + + if (subscription.hasInterest(entry)) + { + subscription.enqueueForPreDelivery(entry, false); + } + + } + } + + public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException + { + QueueEntry entry = getNextMessage(); + if (entry == null) + { + return false; + } + else + { + + try + { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + if (!acks) + { + if (_log.isDebugEnabled()) + { + _log.debug("No ack mode so dequeuing message immediately: " + entry.getMessage().getMessageId()); + } + _queue.dequeue(channel.getStoreContext(), entry); + } + synchronized (channel) + { + long deliveryTag = channel.getNextDeliveryTag(); + + if (acks) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, null); + } + + protocolSession.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(), + deliveryTag, _queue.getMessageCount()); + + } + _totalMessageSize.addAndGet(-entry.getSize()); + + if (!acks) + { + entry.getMessage().decrementReference(channel.getStoreContext()); + } + } + finally + { + entry.setDeliveredToConsumer(); + } + return true; + + } + } + + /** + * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, so that + * the asyn delivery is also stopped. + */ + public void startMovingMessages() + { + _movingMessages.set(true); + } + + /** + * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, so that + * the async delivery can start again. + */ + public void stopMovingMessages() + { + _movingMessages.set(false); + if (_lock.isHeldByCurrentThread()) + { + _lock.unlock(); + } + } + + /** + * Messages will be removed from this queue and all preDeliveryQueues + * + * @param messageList + */ + public void removeMovedMessages(List messageList) + { + // Remove from the + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + if (hasSubscribers) + { + for (Subscription sub : _subscriptions.getSubscriptions()) + { + if (!sub.isSuspended() && sub.filtersMessages()) + { + Queue preDeliveryQueue = sub.getPreDeliveryQueue(); + for (QueueEntry entry : messageList) + { + preDeliveryQueue.remove(entry); + } + } + } + } + + for (QueueEntry entry : messageList) + { + if (_messages.remove(entry)) + { + _totalMessageSize.getAndAdd(-entry.getSize()); + } + } + } + + /** + * Now with implementation of predelivery queues, this method will mark the message on the top as taken. + * + * @param storeContext + * + * @throws AMQException + */ + public void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException + { + _lock.lock(); + + QueueEntry entry = _messages.poll(); + + if (entry != null) + { + queue.dequeue(storeContext, entry); + + _totalMessageSize.addAndGet(-entry.getSize()); + + //If this causes ref count to hit zero then data will be purged so message.getSize() will NPE. + entry.getMessage().decrementReference(storeContext); + + } + + _lock.unlock(); + } + + public long clearAllMessages(StoreContext storeContext) throws AMQException + { + long count = 0; + _lock.lock(); + + synchronized (_queueHeadLock) + { + QueueEntry entry = getNextMessage(); + while (entry != null) + { + //and remove it + _messages.poll(); + + _queue.dequeue(storeContext, entry); + + entry.getMessage().decrementReference(_reapingStoreContext); + + entry = getNextMessage(); + count++; + } + _totalMessageSize.set(0L); + } + _lock.unlock(); + return count; + } + + /** + * This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. + * + * @return the next message or null + * + * @throws org.apache.qpid.AMQException + */ + private QueueEntry getNextMessage() throws AMQException + { + return getNextMessage(_messages, null, false); + } + + private QueueEntry getNextMessage(Queue messages, Subscription sub, boolean purgeOnly) throws AMQException + { + QueueEntry entry = messages.peek(); + + //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) + while (purgeMessage(entry, sub, purgeOnly)) + { + AMQMessage message = entry.getMessage(); + + //remove the already taken message or expired + QueueEntry removed = messages.poll(); + + assert removed == entry; + + // if the message expired then the _totalMessageSize needs adjusting + if (message.expired(_queue) && !entry.taken(sub)) + { + _totalMessageSize.addAndGet(-entry.getSize()); + + // Use the reapingStoreContext as any sub(if we have one) may be in a tx. + _queue.dequeue(_reapingStoreContext, entry); + + message.decrementReference(_reapingStoreContext); + + if (_log.isInfoEnabled()) + { + _log.info(debugIdentity() + " Doing clean up of the main _message queue."); + } + } + + //else the clean up is not required as the message has already been taken for this queue therefore + // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. + + if (_log.isDebugEnabled()) + { + _log.debug("Removed taken message:" + message.debugIdentity()); + } + + // try the next message + entry = messages.peek(); + } + + return entry; + } + + /** + * This method will return true if the message is to be purged from the queue. + * + * + * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) + * + * @param message + * @param sub + * + * @return + * + * @throws AMQException + */ + private boolean purgeMessage(QueueEntry message, Subscription sub) throws AMQException + { + return purgeMessage(message, sub, false); + } + + /** + * This method will return true if the message is to be purged from the queue. + * \ + * SIDE-EFFECT: The msg will be taken by the Subscription(sub) for the current Queue(_queue) when purgeOnly is false + * + * @param message + * @param sub + * @param purgeOnly When set to false the message will be taken by the given Subscription. + * + * @return if the msg should be purged + * + * @throws AMQException + */ + private boolean purgeMessage(QueueEntry message, Subscription sub, boolean purgeOnly) throws AMQException + { + //Original.. complicated while loop control +// (message != null +// && ( +// ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) +// || sub == null) +// && message.taken(_queue, sub)); + + boolean purge = false; + + // if the message is null then don't purge as we have no messagse. + if (message != null) + { + // Check that the message hasn't expired. + if (message.expired()) + { + return true; + } + + // if we have a subscriber perform message checks + if (sub != null) + { + // if we have a queue browser(we don't purge) so check mark the message as taken + purge = ((!sub.isBrowser() || message.isTaken())); + } + else + { + // if there is no subscription we are doing + // a get or purging so mark message as taken. + message.isTaken(); + // and then ensure that it gets purged + purge = true; + } + } + + if (purgeOnly) + { + // If we are simply purging the queue don't take the message + // just purge up to the next non-taken msg. + return purge && message.isTaken(); + } + else + { + // if we are purging then ensure we mark this message taken for the current subscriber + // the current subscriber may be null in the case of a get or a purge but this is ok. + return purge && message.taken(sub); + } + } + + public void sendNextMessage(Subscription sub, AMQQueue queue) + { + + Queue messageQueue = sub.getNextQueue(_messages); + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Async sendNextMessage for sub (" + System.identityHashCode(sub) + + ") from queue (" + System.identityHashCode(messageQueue) + + ") AMQQueue (" + System.identityHashCode(queue) + ")"); + } + + if (messageQueue == null) + { + // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector + if (_log.isInfoEnabled()) + { + _log.info(debugIdentity() + sub + ": asked to send messages but has none on given queue:" + queue); + } + return; + } + + QueueEntry entry = null; + QueueEntry removed = null; + try + { + synchronized (_queueHeadLock) + { + entry = getNextMessage(messageQueue, sub, false); + + // message will be null if we have no messages in the messageQueue. + if (entry == null) + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); + } + return; + } + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Async Delivery Message :" + entry + "(" + System.identityHashCode(entry) + + ") by :" + System.identityHashCode(this) + + ") to :" + System.identityHashCode(sub)); + } + + + if (messageQueue == _messages) + { + _totalMessageSize.addAndGet(-entry.getSize()); + } + + sub.send(entry, _queue); + + //remove sent message from our queue. + removed = messageQueue.poll(); + //If we don't remove the message from _messages + // Otherwise the Async send will never end + } + + if (removed != entry) + { + _log.error("Just send message:" + entry.getMessage().debugIdentity() + " BUT removed this from queue:" + removed); + } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.getMessage().debugIdentity() + "d:" + entry + + ") by :" + System.identityHashCode(this) + + ") to :" + System.identityHashCode(sub)); + } + + + if (messageQueue == sub.getResendQueue()) + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "All messages sent from resendQueue for " + sub); + } + if (messageQueue.isEmpty()) + { + subscriberHasPendingResend(false, sub, null); + //better to use the above method as this keeps all the tracking in one location. + // _hasContent.remove(sub); + } + + _extraMessages.decrementAndGet(); + } + else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser()) + { + if (_log.isInfoEnabled()) + { + //fixme - we should do the clean up as the message remains on the _message queue + // this is resulting in the next consumer receiving the message and then attempting to purge it + // + cleanMainQueue(sub); + } + } + + } + catch (AMQException e) + { + if (entry != null) + { + entry.release(); + } + else + { + _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); + } + _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); + } + } + + private void cleanMainQueue(Subscription sub) + { + try + { + getNextMessage(_messages, sub, true); + } + catch (AMQException e) + { + _log.warn("Problem during main queue purge:" + e.getMessage()); + } + } + + /** + * enqueues the messages in the list on the queue and all required predelivery queues + * + * @param storeContext + * @param movedMessageList + */ + public void enqueueMovedMessages(StoreContext storeContext, List movedMessageList) + { + _lock.lock(); + for (QueueEntry entry : movedMessageList) + { + addMessageToQueue(entry, false); + } + + // enqueue on the pre delivery queues + for (Subscription sub : _subscriptions.getSubscriptions()) + { + for (QueueEntry entry : movedMessageList) + { + // Only give the message to those that want them. + if (sub.hasInterest(entry)) + { + sub.enqueueForPreDelivery(entry, true); + } + } + } + _lock.unlock(); + } + + /** + * Only one thread should ever execute this method concurrently, but it can do so while other threads invoke + * deliver(). + */ + private void processQueue() + { + //record thread name + if (_log.isDebugEnabled()) + { + _processingThreadName = Thread.currentThread().getName(); + } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Running process Queue." + currentStatus()); + } + + // Continue to process delivery while we haveSubscribers and messages + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + + while (hasSubscribers && hasQueuedMessages() && !_movingMessages.get()) + { + hasSubscribers = false; + + for (Subscription sub : _subscriptions.getSubscriptions()) + { + synchronized (sub.getSendLock()) + { + if (!sub.isSuspended()) + { + sendNextMessage(sub, _queue); + + hasSubscribers = true; + } + } + } + } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Done process Queue." + currentStatus()); + } + + } + + public void deliver(StoreContext context, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws AMQException + { + + final boolean debugEnabled = _log.isDebugEnabled(); + if (debugEnabled) + { + _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + entry); + } + + //Check if we have someone to deliver the message to. + _lock.lock(); + try + { + Subscription s = _subscriptions.nextSubscriber(entry); + + if (s == null || (!s.filtersMessages() && hasQueuedMessages())) //no-one can take the message right now or we're queueing + { + if (debugEnabled) + { + _log.debug(debugIdentity() + "Testing Message(" + entry + ") for Queued Delivery:" + currentStatus()); + } + if (!entry.getMessage().getMessagePublishInfo().isImmediate()) + { + addMessageToQueue(entry, deliverFirst); + + //release lock now message is on queue. + _lock.unlock(); + + //Pre Deliver to all subscriptions + if (debugEnabled) + { + _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() + + " subscribers to give the message to:" + currentStatus()); + } + for (Subscription sub : _subscriptions.getSubscriptions()) + { + + // Only give the message to those that want them. + if (sub.hasInterest(entry)) + { + if (debugEnabled) + { + _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(entry) + + ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); + } + sub.enqueueForPreDelivery(entry, deliverFirst); + } + } + + //if we have a non-filtering subscriber but queued messages && we're not Async && we have other Active subs then something is wrong! + if ((s != null && hasQueuedMessages()) && !isProcessingAsync() && _subscriptions.hasActiveSubscribers()) + { + _queue.deliverAsync(); + } + + } + } + else + { + + if (s.filtersMessages()) + { + if (s.getPreDeliveryQueue().size() > 0) + { + _log.error("Direct delivery from PDQ with queued msgs:" + s.getPreDeliveryQueue().size()); + } + } + else if (_messages.size() > 0) + { + _log.error("Direct delivery from MainQueue queued msgs:" + _messages.size()); + } + + //release lock now + _lock.unlock(); + synchronized (s.getSendLock()) + { + if (!s.isSuspended()) + { + if (debugEnabled) + { + _log.debug(debugIdentity() + "Delivering Message:" + entry.getMessage().debugIdentity() + " to(" + + System.identityHashCode(s) + ") :" + s); + } + + if (entry.taken(s)) + { + //Message has been delivered so don't redeliver. + // This can currently occur because of the recursive call below + // During unit tests the send can occur + // client then rejects + // this reject then releases the message by the time the + // if(!msg.isTaken()) call is made below + // the message has been released so that thread loops to send the message again + // of course by the time it gets back to here. the thread that released the + // message is now ready to send it. Here is a sample trace for reference +//1192627162613:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false] +//1192627162613:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null} +//1192627162613:Thread[pool-917-thread-4,5,main]:28398657 Sent :dt:214 msg:(HC:5529738 ID:145 Ref:1) +//1192627162613:Thread[pool-917-thread-2,5,main]:Reject message by:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false] +//1192627162613:Thread[pool-917-thread-2,5,main]:Releasing Message:(HC:5529738 ID:145 Ref:1) +//1192627162613:Thread[pool-917-thread-2,5,main]:Msg:Release:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:This:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]} +//1192627162613:Thread[pool-917-thread-2,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false] +//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:suspended: Message((HC:5529738 ID:145 Ref:1)) has not been taken so recursing!: Subscriber:28398657 +//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false] +//1192627162629:Thread[pool-917-thread-2,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null} +//1192627162629:Thread[pool-917-thread-2,5,main]:25386607 Sent :dt:172 msg:(HC:5529738 ID:145 Ref:1) +//1192627162629:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=true} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]} + // Note: In the last request to take the message from thread 4,5 the message has been + // taken by the previous call done by thread 2,5 + + + return; + } + //Deliver the message + s.send(entry, _queue); + } + else + { + if (debugEnabled) + { + _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + + "suspended between nextSubscriber and send for message:" + entry.getMessage().debugIdentity()); + } + } + } + + // + // Why do we do this? What was the reasoning? We should have a better approach + // than recursion and rejecting if someone else sends it before we do. + // + if (!entry.isTaken()) + { + if (debugEnabled) + { + _log.debug(debugIdentity() + " Message(" + entry.getMessage().debugIdentity() + ") has not been taken so recursing!:" + + " Subscriber:" + System.identityHashCode(s)); + } + + deliver(context, name, entry, deliverFirst); + } + else + { + if (debugEnabled) + { + _log.debug(debugIdentity() + " Message(" + entry.toString() + + ") has been taken so disregarding deliver request to Subscriber:" + + System.identityHashCode(s)); + } + } + } + + } + finally + { + //ensure lock is released + if (_lock.isHeldByCurrentThread()) + { + _lock.unlock(); + } + } + } + + private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")"; + + private String debugIdentity() + { + return id; + } + + final Runner _asyncDelivery = new Runner(); + + private class Runner implements Runnable + { + public void run() + { + String startName = Thread.currentThread().getName(); + Thread.currentThread().setName("CSDM-AsyncDelivery:" + startName); + boolean running = true; + while (running && !_movingMessages.get()) + { + processQueue(); + + //Check that messages have not been added since we did our last peek(); + // Synchronize with the thread that adds to the queue. + // If the queue is still empty then we can exit + synchronized (_asyncDelivery) + { + if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) + { + running = false; + _processing.set(false); + } + } + } + Thread.currentThread().setName(startName); + } + } + + public void processAsync(Executor executor) + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Processing Async." + currentStatus()); + } + + synchronized (_asyncDelivery) + { + if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) + { + //are we already running? if so, don't re-run + if (_processing.compareAndSet(false, true)) + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Executing Async process."); + } + executor.execute(_asyncDelivery); + } + } + } + } + + private String currentStatus() + { + return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains(H:M)") + + "(" + ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize() + + ":" + (_messages.size() - ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize()) + ") " + + " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") + + "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + (_processing.get() ? " true : Processing Thread: " + _processingThreadName : " false"); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java new file mode 100644 index 0000000000..cbe9246f09 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class DefaultQueueRegistry implements QueueRegistry +{ + private ConcurrentMap _queueMap = new ConcurrentHashMap(); + + private final VirtualHost _virtualHost; + + public DefaultQueueRegistry(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void registerQueue(AMQQueue queue) throws AMQException + { + _queueMap.put(queue.getName(), queue); + } + + public void unregisterQueue(AMQShortString name) throws AMQException + { + _queueMap.remove(name); + } + + public AMQQueue getQueue(AMQShortString name) + { + return _queueMap.get(name); + } + + public Collection getQueueNames() + { + return _queueMap.keySet(); + } + + public Collection getQueues() + { + return _queueMap.values(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java new file mode 100644 index 0000000000..1568f58e2e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java @@ -0,0 +1,102 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.List; +import java.util.concurrent.Executor; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; + +interface DeliveryManager +{ + /** + * Determines whether there are queued messages. Sets _queueing to false if there are no queued messages. This needs + * to be atomic. + * + * @return true if there are queued messages + */ + boolean hasQueuedMessages(); + + /** + * This method should not be used to determin if there are messages in the queue. + * + * @return int The number of messages in the queue + * + * @use hasQueuedMessages() for all controls relating to having messages on the queue. + */ + int getQueueMessageCount(); + + /** + * Requests that the delivery manager start processing the queue asynchronously if there is work that can be done + * (i.e. there are messages queued up and subscribers that can receive them.

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

      + * + * @param executor the executor on which the delivery should take place + */ + void processAsync(Executor executor); + + /** + * Handles message delivery. The delivery manager is always in one of two modes; it is either queueing messages for + * asynchronous delivery or delivering directly. + * + * @param storeContext + * @param name the name of the entity on whose behalf we are delivering the message + * @param entry the message to deliver + * @param deliverFirst + * + * @throws org.apache.qpid.server.queue.FailedDequeueException + * if the message could not be dequeued + */ + void deliver(StoreContext storeContext, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws FailedDequeueException, AMQException; + + void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException; + + long clearAllMessages(StoreContext storeContext) throws AMQException; + + void startMovingMessages(); + + void enqueueMovedMessages(StoreContext context, List messageList); + + void stopMovingMessages(); + + void removeMovedMessages(List messageListToRemove); + + List getMessages(); + + List getMessages(long fromMessageId, long toMessageId); + + void populatePreDeliveryQueue(Subscription subscription); + + boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; + + long getTotalMessageSize(); + + long getOldestMessageArrival(); + + void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry msg); + + void removeExpired() throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java new file mode 100644 index 0000000000..e6377b33da --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -0,0 +1,135 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; + +/** + * 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 +{ + private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + + static class ExchangeBinding + { + private final Exchange _exchange; + private final AMQShortString _routingKey; + private final FieldTable _arguments; + + ExchangeBinding(AMQShortString routingKey, Exchange exchange) + { + this(routingKey, exchange, EMPTY_ARGUMENTS); + } + + ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) + { + _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; + _exchange = exchange; + _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; + } + + void unbind(AMQQueue queue) throws AMQException + { + _exchange.deregisterQueue(_routingKey, queue, _arguments); + } + + public Exchange getExchange() + { + return _exchange; + } + + public AMQShortString getRoutingKey() + { + return _routingKey; + } + + public int hashCode() + { + return (_exchange == null ? 0 : _exchange.hashCode()) + + (_routingKey == null ? 0 : _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(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + { + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); + } + + + public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + { + _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); + } + + + /** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java new file mode 100644 index 0000000000..6466e81dd2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * Signals that the dequeue of a message from a queue failed. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Indicates the a message could not be dequeued from a queue. + *
      + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Happens as a consequence of a message store failure, or reference counting error. Both of which migh become + * runtime exceptions, as unrecoverable conditions? In which case this one might be dropped too. + */ +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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java new file mode 100644 index 0000000000..0b40f01f1a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -0,0 +1,144 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.store.StoreContext; + +/** + */ +public class InMemoryMessageHandle implements AMQMessageHandle +{ + + private ContentHeaderBody _contentHeaderBody; + + private MessagePublishInfo _messagePublishInfo; + + private List _contentBodies = new ArrayList(); + + private boolean _redelivered; + + private long _arrivalTime; + + public InMemoryMessageHandle() + { + } + + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException + { + return _contentHeaderBody; + } + + public int getBodyCount(StoreContext context, Long messageId) + { + return _contentBodies.size(); + } + + public long getBodySize(StoreContext context, Long messageId) throws AMQException + { + return getContentHeaderBody(context, messageId).bodySize; + } + + public ContentChunk getContentChunk(StoreContext context, 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(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) + throws AMQException + { + _contentBodies.add(contentBody); + } + + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException + { + return _messagePublishInfo; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public boolean isPersistent(StoreContext context, Long messageId) throws AMQException + { + //todo remove literal values to a constant file such as AMQConstants in common + ContentHeaderBody chb = getContentHeaderBody(context, messageId); + return chb.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + } + + /** + * This is called when all the content has been received. + * @param messagePublishInfo + * @param contentHeaderBody + * @throws AMQException + */ + public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + _messagePublishInfo = messagePublishInfo; + _contentHeaderBody = contentHeaderBody; + _arrivalTime = System.currentTimeMillis(); + } + + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + { + // NO OP + } + + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + { + // NO OP + } + + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + { + // NO OP + } + + public long getArrivalTime() + { + return _arrivalTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java new file mode 100644 index 0000000000..061ab56024 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -0,0 +1,245 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +/** + * The management interface exposed to allow management of a queue. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedQueue +{ + static final String TYPE = "Queue"; + + /** + * Returns the Name of the ManagedQueue. + * @return the name of the managedQueue. + * @throws IOException + */ + @MBeanAttribute(name="Name", description = TYPE + " Name") + String getName() throws IOException; + + /** + * Total number of messages on the queue, which are yet to be delivered to the consumer(s). + * @return number of undelivered message in the Queue. + * @throws IOException + */ + @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") + Integer getMessageCount() throws IOException; + + /** + * Tells the total number of messages receieved by the queue since startup. + * @return total number of messages received. + * @throws IOException + */ + @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") + Long getReceivedMessageCount() throws IOException; + + /** + * Size of messages in the queue + * @return + * @throws IOException + */ + @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue") + Long getQueueDepth() throws IOException, JMException; + + /** + * Returns the total number of active subscribers to the queue. + * @return the number of active subscribers + * @throws IOException + */ + @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") + Integer getActiveConsumerCount() throws IOException; + + /** + * Returns the total number of subscribers to the queue. + * @return the number of subscribers. + * @throws IOException + */ + @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") + Integer getConsumerCount() throws IOException; + + /** + * Tells the Owner of the ManagedQueue. + * @return the owner's name. + * @throws IOException + */ + @MBeanAttribute(name="Owner", description = "Owner") + String getOwner() throws IOException; + + /** + * Tells whether this ManagedQueue is durable or not. + * @return true if this ManagedQueue is a durable queue. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") + boolean isDurable() throws IOException; + + /** + * Tells if the ManagedQueue is set to AutoDelete. + * @return true if the ManagedQueue is set to AutoDelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") + boolean isAutoDelete() throws IOException; + + /** + * Returns the maximum age of a message (expiration time) + * @return the maximum age + * @throws IOException + */ + Long getMaximumMessageAge() throws IOException; + + /** + * Sets the maximum age of a message + * @param age maximum age of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on thr broker") + void setMaximumMessageAge(Long age) throws IOException; + + /** + * Returns the maximum size of a message (in kbytes) allowed to be accepted by the + * ManagedQueue. This is useful in setting notifications or taking + * appropriate action, if the size of the message received is more than + * the allowed size. + * @return the maximum size of a message allowed to be aceepted by the + * ManagedQueue. + * @throws IOException + */ + Long getMaximumMessageSize() throws IOException; + + /** + * Sets the maximum size of the message (in kbytes) that is allowed to be + * accepted by the Queue. + * @param size maximum size of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(KB) for a message size") + void setMaximumMessageSize(Long size) throws IOException; + + /** + * Tells the maximum number of messages that can be stored in the queue. + * This is useful in setting the notifications or taking required + * action is the number of message increase this limit. + * @return maximum muber of message allowed to be stored in the queue. + * @throws IOException + */ + Long getMaximumMessageCount() throws IOException; + + /** + * Sets the maximum number of messages allowed to be stored in the queue. + * @param value the maximum number of messages allowed to be stored in the queue. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") + void setMaximumMessageCount(Long value) throws IOException; + + /** + * This is useful for setting notifications or taking required action if the size of messages + * stored in the queue increases over this limit. + * @return threshold high value for Queue Depth + * @throws IOException + */ + Long getMaximumQueueDepth() throws IOException; + + /** + * Sets the maximum size of all the messages together, that can be stored + * in the queue. + * @param value + * @throws IOException + */ + @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth") + void setMaximumQueueDepth(Long value) throws IOException; + + + + //********** Operations *****************// + + + /** + * Returns a subset of all the messages stored in the queue. The messages + * are returned based on the given index numbers. + * @param fromIndex + * @param toIndex + * @return + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="viewMessages", + description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") + TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, + @MBeanOperationParameter(name="to index", description="to index")int toIndex) + throws IOException, JMException, AMQException; + + @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") + CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) + throws IOException, JMException; + + /** + * Deletes the first message from top. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", + impact= MBeanOperationInfo.ACTION) + void deleteMessageFromTop() throws IOException, JMException; + + /** + * Clears the queue by deleting all the undelivered messages from the queue. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="clearQueue", + description="Clears the queue by deleting all the undelivered messages from the queue", + impact= MBeanOperationInfo.ACTION) + void clearQueue() throws IOException, JMException; + + /** + * Moves the messages in given range of message Ids to given Queue. QPID-170 + * @param fromMessageId first in the range of message ids + * @param toMessageId last in the range of message ids + * @param toQueue where the messages are to be moved + * @throws IOException + * @throws JMException + * @throws AMQException + */ + @MBeanOperation(name="moveMessages", + description="You can move messages to another queue from this queue ", + impact= MBeanOperationInfo.ACTION) + void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, + @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, + @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) + throws IOException, JMException, AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java new file mode 100644 index 0000000000..090096d3c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * MessageCleanupException represents the failure to perform reference counting on messages correctly. This should not + * happen, but there may be programming errors giving race conditions that cause the reference counting to go wrong. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Signals that the reference count of a message has gone below zero. + *
      Indicates that a message store has lost a message which is still referenced. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo The race conditions leading to this error should be cleaned up, and a runtime exception used instead. If the + * message store loses messages, then something is seriously wrong and it would be sensible to terminate the + * broker. This may be disguising out of memory errors. + */ +public class MessageCleanupException extends AMQException +{ + public MessageCleanupException(long messageId, AMQException e) + { + super("Failed to cleanup message with id " + messageId, e); + } + + public MessageCleanupException(String message) + { + super(message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java new file mode 100644 index 0000000000..94ab935115 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java new file mode 100644 index 0000000000..6118a4c11f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +/** + * Encapsulates a publish body and a content header. In the context of the message store these are treated as a + * single unit. + */ +public class MessageMetaData +{ + private MessagePublishInfo _messagePublishInfo; + + private ContentHeaderBody _contentHeaderBody; + + private int _contentChunkCount; + + private long _arrivalTime; + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); + } + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) + { + _contentHeaderBody = contentHeaderBody; + _messagePublishInfo = publishBody; + _contentChunkCount = contentChunkCount; + _arrivalTime = arrivalTime; + } + + public int getContentChunkCount() + { + return _contentChunkCount; + } + + public void setContentChunkCount(int contentChunkCount) + { + _contentChunkCount = contentChunkCount; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void setArrivalTime(long arrivalTime) + { + _arrivalTime = arrivalTime; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java new file mode 100644 index 0000000000..d6fd1eec89 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; + +/** + * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate + * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is + * always used to report this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      + */ +public class NoConsumersException extends RequiredDeliveryException +{ + public NoConsumersException(AMQMessage message) + { + super("Immediate delivery is not possible.", message); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.NO_CONSUMERS; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java new file mode 100644 index 0000000000..6f9efd3200 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +public enum NotificationCheck +{ + + MESSAGE_COUNT_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + int msgCount; + final long maximumMessageCount = queue.getMaximumMessageCount(); + if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) + { + listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); + return true; + } + return false; + } + }, + MESSAGE_SIZE_ALERT(true) + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + final long maximumMessageSize = queue.getMaximumMessageSize(); + if(maximumMessageSize != 0) + { + // Check for threshold message size + long messageSize; + try + { + messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + messageSize = 0; + } + + + if (messageSize >= maximumMessageSize) + { + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + return true; + } + } + return false; + } + + }, + QUEUE_DEPTH_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + // Check for threshold queue depth in bytes + final long maximumQueueDepth = queue.getMaximumQueueDepth(); + + if(maximumQueueDepth != 0) + { + final long queueDepth = queue.getQueueDepth(); + + if (queueDepth >= maximumQueueDepth) + { + listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); + return true; + } + } + return false; + } + + }, + MESSAGE_AGE_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + + final long maxMessageAge = queue.getMaximumMessageAge(); + if(maxMessageAge != 0) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - maxMessageAge; + final long firstArrivalTime = queue.getOldestMessageArrivalTime(); + + if(firstArrivalTime < thresholdTime) + { + long oldestAge = currentTime - firstArrivalTime; + listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); + + return true; + } + } + return false; + + } + + } + ; + + private final boolean _messageSpecific; + + NotificationCheck() + { + this(false); + } + + NotificationCheck(boolean messageSpecific) + { + _messageSpecific = messageSpecific; + } + + public boolean isMessageSpecific() + { + return _messageSpecific; + } + + abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java new file mode 100644 index 0000000000..8553db3e09 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -0,0 +1,173 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.log4j.Logger; + +import java.util.Set; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicReference; + + +public class QueueEntry +{ + + /** + * Used for debugging purposes. + */ + private static final Logger _log = Logger.getLogger(QueueEntry.class); + + private final AMQQueue _queue; + private final AMQMessage _message; + + private Set _rejectedBy = null; + + private AtomicReference _owner = new AtomicReference(); + + + public QueueEntry(AMQQueue queue, AMQMessage message) + { + _queue = queue; + _message = message; + } + + + public AMQQueue getQueue() + { + return _queue; + } + + public AMQMessage getMessage() + { + return _message; + } + + public long getSize() + { + return getMessage().getSize(); + } + + public boolean getDeliveredToConsumer() + { + return getMessage().getDeliveredToConsumer(); + } + + public boolean expired() throws AMQException + { + return getMessage().expired(_queue); + } + + public boolean isTaken() + { + return _owner.get() != null; + } + + public boolean taken(Subscription sub) + { + return !(_owner.compareAndSet(null, sub == null ? this : sub)); + } + + public void setDeliveredToConsumer() + { + getMessage().setDeliveredToConsumer(); + } + + public void release() + { + _owner.set(null); + } + + public String debugIdentity() + { + return getMessage().debugIdentity(); + } + + public void process(StoreContext storeContext, boolean deliverFirst) throws AMQException + { + _queue.process(storeContext, this, deliverFirst); + } + + public void checkDeliveredToConsumer() throws NoConsumersException + { + _message.checkDeliveredToConsumer(); + } + + public void setRedelivered(boolean b) + { + getMessage().setRedelivered(b); + } + + public Subscription getDeliveredSubscription() + { + synchronized (this) + { + Object owner = _owner.get(); + if (owner instanceof Subscription) + { + return (Subscription) owner; + } + else + { + return null; + } + } + } + + public void reject() + { + reject(getDeliveredSubscription()); + } + + public void reject(Subscription subscription) + { + if (subscription != null) + { + if (_rejectedBy == null) + { + _rejectedBy = new HashSet(); + } + + _rejectedBy.add(subscription); + } + else + { + _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + } + } + + public boolean isRejectedBy(Subscription subscription) + { + boolean rejected = _rejectedBy != null; + + if (rejected) // We have subscriptions that rejected this message + { + return _rejectedBy.contains(subscription); + } + else // This messasge hasn't been rejected yet. + { + return rejected; + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java new file mode 100644 index 0000000000..959ca03c80 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -0,0 +1,27 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + + +public interface QueueNotificationListener +{ + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java new file mode 100644 index 0000000000..1210f0e97c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; + +public interface QueueRegistry +{ + VirtualHost getVirtualHost(); + + void registerQueue(AMQQueue queue) throws AMQException; + + void unregisterQueue(AMQShortString name) throws AMQException; + + AMQQueue getQueue(AMQShortString name); + + Collection getQueueNames(); + + Collection getQueues(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java new file mode 100644 index 0000000000..96ce6743ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.Queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.AMQChannel; + +public interface Subscription +{ + void send(QueueEntry msg, AMQQueue queue) throws AMQException; + + boolean isSuspended(); + + void queueDeleted(AMQQueue queue) throws AMQException; + + boolean filtersMessages(); + + boolean hasInterest(QueueEntry msg); + + Queue getPreDeliveryQueue(); + + Queue getResendQueue(); + + Queue getNextQueue(Queue messages); + + void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst); + + void close(); + + boolean isClosed(); + + boolean isBrowser(); + + boolean wouldSuspend(QueueEntry msg); + + void addToResendQueue(QueueEntry msg); + + Object getSendLock(); + + AMQChannel getChannel(); + + void start(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java new file mode 100644 index 0000000000..917f7c4e97 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +/** + * 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, AMQShortString consumerTag, boolean acks, + FieldTable filters, boolean noLocal, AMQQueue queue) throws AMQException; + + + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) + throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java new file mode 100644 index 0000000000..05cd461582 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -0,0 +1,680 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.Queue; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; +import org.apache.qpid.util.MessageQueue; +import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; + +/** + * 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 _suspensionlogger = Logger.getLogger("Suspension"); + private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); + + public final AMQChannel channel; + + public final AMQProtocolSession protocolSession; + + public final AMQShortString consumerTag; + + private final Object _sessionKey; + + private MessageQueue _messages; + + private Queue _resendQueue; + + private final boolean _noLocal; + + /** True if messages need to be acknowledged */ + private final boolean _acks; + private FilterManager _filters; + private final boolean _isBrowser; + private final Boolean _autoClose; + private boolean _sentClose = false; + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + private AMQQueue _queue; + private final AtomicBoolean _sendLock = new AtomicBoolean(false); + + + public static class Factory implements SubscriptionFactory + { + public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, AMQQueue queue) throws AMQException + { + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal, queue); + } + + public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) + throws AMQException + { + return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false, null); + } + } + + public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks) + throws AMQException + { + this(channelId, protocolSession, consumerTag, acks, null, false, null); + } + + public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, AMQQueue queue) + throws AMQException + { + AMQChannel channel = protocolSession.getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); + } + + this.channel = channel; + this.protocolSession = protocolSession; + this.consumerTag = consumerTag; + _sessionKey = protocolSession.getKey(); + _acks = acks; + _noLocal = noLocal; + _queue = queue; + + _filters = FilterManagerFactory.createManager(filters); + + + if (_filters != null) + { + Object isBrowser = filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); + if (isBrowser != null) + { + _isBrowser = (Boolean) isBrowser; + } + else + { + _isBrowser = false; + } + } + else + { + _isBrowser = false; + } + + + if (_filters != null) + { + Object autoClose = filters.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); + if (autoClose != null) + { + _autoClose = (Boolean) autoClose; + } + else + { + _autoClose = false; + } + } + else + { + _autoClose = false; + } + + + if (filtersMessages()) + { + _messages = new ConcurrentLinkedMessageQueueAtomicSize(); + } + else + { + // Reference the DeliveryManager + _messages = null; + } + } + + + public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, + AMQShortString 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. + * + * @param psc The subscriptionImpl to compare + * + * @return equality + */ + 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() + { + String subscriber = "[channel=" + channel + + ", consumerTag=" + consumerTag + + ", session=" + protocolSession.getKey() + + ", resendQueue=" + (_resendQueue != null); + + if (_resendQueue != null) + { + subscriber += ", resendSize=" + _resendQueue.size(); + } + + + return subscriber + "]"; + } + + /** + * 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 The message to send + * @param queue the Queue it has been sent from + * + * @throws AMQException + */ + public void send(QueueEntry msg, AMQQueue queue) throws AMQException + { + if (msg != null) + { + if (_isBrowser) + { + sendToBrowser(msg, queue); + } + else + { + sendToConsumer(channel.getStoreContext(), msg, queue); + } + } + else + { + _logger.error("Attempt to send Null message", new NullPointerException()); + } + } + + private void sendToBrowser(QueueEntry msg, AMQQueue queue) throws AMQException + { + // We don't decrement the reference here as we don't want to consume the message + // but we do want to send it to the client. + + synchronized (channel) + { + long deliveryTag = channel.getNextDeliveryTag(); + + if (_sendLock.get()) + { + _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); + } + + protocolSession.getProtocolOutputConverter().writeDeliver(msg.getMessage(), channel.getChannelId(), deliveryTag, consumerTag); + } + } + + private void sendToConsumer(StoreContext storeContext, QueueEntry entry, AMQQueue queue) + throws AMQException + { + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + final AMQMessage message = entry.getMessage(); + + if (!_acks) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("No ack mode so dequeuing message immediately: " + message.getMessageId()); + } + queue.dequeue(storeContext, entry); + } + + final ProtocolOutputConverter outputConverter = protocolSession.getProtocolOutputConverter(); + final int channelId = channel.getChannelId(); + + synchronized (channel) + { + final long deliveryTag = channel.getNextDeliveryTag(); + + + if (_acks) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, consumerTag); + } + + outputConverter.writeDeliver(message, channelId, deliveryTag, consumerTag); + + + } + if (!_acks) + { + message.decrementReference(storeContext); + } + } + finally + { + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. + // Is this what we want? + + entry.setDeliveredToConsumer(); + } + } + + public boolean isSuspended() + { +// if (_suspensionlogger.isInfoEnabled()) +// { +// if (channel.isSuspended()) +// { +// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") channel's is susupended"); +// } +// if (_sendLock.get()) +// { +// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") has sendLock set so closing."); +// } +// } + return channel.isSuspended() || _sendLock.get(); + } + + /** + * Callback indicating that a queue has been deleted. + * + * @param queue The queue to delete + */ + public void queueDeleted(AMQQueue queue) throws AMQException + { + channel.queueDeleted(queue); + } + + public boolean filtersMessages() + { + return _filters != null || _noLocal; + } + + public boolean hasInterest(QueueEntry entry) + { + //check that the message hasn't been rejected + if (entry.isRejectedBy(this)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); + } +// return false; + } + + + + //todo - client id should be recoreded and this test removed but handled below + if (_noLocal) + { + + final AMQProtocolSession publisher = entry.getMessage().getPublisher(); + if(publisher != null) + + { + // We don't want local messages so check to see if message is one we sent + Object localInstance; + Object msgInstance; + + if ((protocolSession.getClientProperties() != null) && + (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + { + + if ((publisher.getClientProperties() != null) && + (msgInstance = publisher.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + { + if (localInstance == msgInstance || localInstance.equals(msgInstance)) + { + // if (_logger.isTraceEnabled()) + // { + // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + + // msg.debugIdentity() + ")"); + // } + return false; + } + } + } + else + { + + localInstance = protocolSession.getClientIdentifier(); + //todo - client id should be recoreded and this test removed but handled here + + msgInstance = publisher.getClientIdentifier(); + if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) + { + // if (_logger.isTraceEnabled()) + // { + // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + + // msg.debugIdentity() + ")"); + // } + return false; + } + } + + } + } + + + return checkFilters(entry); + + } + + private String id = String.valueOf(System.identityHashCode(this)); + + private String debugIdentity() + { + return id; + } + + private boolean checkFilters(QueueEntry msg) + { + return (_filters == null) || _filters.allAllow(msg.getMessage()); + } + + public Queue getPreDeliveryQueue() + { + return _messages; + } + + public void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst) + { + if (_messages != null) + { + if (deliverFirst) + { + _messages.pushHead(msg); + } + else + { + _messages.offer(msg); + } + } + } + + private boolean isAutoClose() + { + return _autoClose; + } + + public void close() + { + boolean closed = false; + synchronized (_sendLock) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Setting SendLock true:" + debugIdentity()); + } + + closed = _sendLock.getAndSet(true); + } + + if (closed) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Called close() on a closed subscription"); + } + + return; + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing subscription (" + debugIdentity() + "):" + this); + } + + if (_resendQueue != null && !_resendQueue.isEmpty()) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Requeuing closing subscription (" + debugIdentity() + "):" + this); + } + requeue(); + } + + //remove references in PDQ + if (_messages != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Clearing PDQ (" + debugIdentity() + "):" + this); + } + + _messages.clear(); + } + } + + private void autoclose() + { + close(); + + if (_autoClose && !_sentClose) + { + _logger.info("Closing autoclose subscription (" + debugIdentity() + "):" + this); + + boolean unregisteredOK = false; + try + { + unregisteredOK = channel.unsubscribeConsumer(protocolSession, consumerTag); + } + catch (AMQException e) + { + // Occurs if we cannot find the subscriber in the channel with protocolSession and consumerTag. + _logger.info("Unable to UnsubscribeConsumer :" + consumerTag +" so not going to send CancelOK."); + } + + if (unregisteredOK) + { + ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag); + _sentClose = true; + } + + } + } + + private void requeue() + { + if (_queue != null) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Requeuing :" + _resendQueue.size() + " messages"); + } + + while (!_resendQueue.isEmpty()) + { + QueueEntry resent = _resendQueue.poll(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Removed for resending:" + resent.debugIdentity()); + } + + resent.release(); + _queue.subscriberHasPendingResend(false, this, resent); + + try + { + channel.getTransactionalContext().deliver(resent, true); + } + catch (AMQException e) + { + _logger.error("MESSAGE LOSS : Unable to re-deliver messages", e); + } + } + + if (!_resendQueue.isEmpty()) + { + _logger.error("[MESSAGES LOST]Unable to re-deliver messages as queue is null."); + } + + _queue.subscriberHasPendingResend(false, this, null); + } + else + { + if (!_resendQueue.isEmpty()) + { + _logger.error("Unable to re-deliver messages as queue is null."); + } + } + + // Clear the messages + _resendQueue = null; + } + + + public boolean isClosed() + { + return _sendLock.get(); // This rather than _close is used to signify the subscriber is now closed. + } + + public boolean isBrowser() + { + return _isBrowser; + } + + public boolean wouldSuspend(QueueEntry msg) + { + return _acks && channel.wouldSuspend(msg.getMessage()); + } + + public Queue getResendQueue() + { + if (_resendQueue == null) + { + _resendQueue = new ConcurrentLinkedQueueAtomicSize(); + } + return _resendQueue; + } + + + public Queue getNextQueue(Queue messages) + { + if (_resendQueue != null && !_resendQueue.isEmpty()) + { + return _resendQueue; + } + + if (filtersMessages()) + { + if (isAutoClose()) + { + if (_messages.isEmpty()) + { + autoclose(); + return null; + } + } + return _messages; + } + else // we want the DM queue + { + return messages; + } + } + + public void addToResendQueue(QueueEntry msg) + { + // add to our resend queue + getResendQueue().add(msg); + + // Mark Queue has having content. + if (_queue == null) + { + _logger.error("Queue is null won't be able to resend messages"); + } + else + { + _queue.subscriberHasPendingResend(true, this, msg); + } + } + + public Object getSendLock() + { + return _sendLock; + } + + public AMQChannel getChannel() + { + return channel; + } + + public void start() + { + //Check to see if we need to autoclose + if (filtersMessages()) + { + if (isAutoClose()) + { + if (_messages.isEmpty()) + { + autoclose(); + } + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java new file mode 100644 index 0000000000..bc17bcca9c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.List; + +/** + * Abstraction of actor that will determine the subscriber to whom + * a message will be sent. + */ +public interface SubscriptionManager +{ + public List getSubscriptions(); + public boolean hasActiveSubscribers(); + public Subscription nextSubscriber(QueueEntry entry); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java new file mode 100644 index 0000000000..882efd380d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -0,0 +1,274 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; + +/** 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; + + private final Object _changeLock = new Object(); + private volatile boolean _exclusive; + + + /** Accessor for unit tests. */ + int getCurrentSubscriber() + { + return _currentSubscriber; + } + + public void addSubscriber(Subscription subscription) + { + synchronized (_changeLock) + { + _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) + { + // TODO: possibly need O(1) operation here. + + Subscription sub = null; + synchronized (_changeLock) + { + int subIndex = _subscriptions.indexOf(subscription); + + if (subIndex != -1) + { + //we can't just return the passed in subscription as it is a new object + // and doesn't contain the stored state we need. + //NOTE while this may be removed now anyone with an iterator will still have it in the list!! + sub = _subscriptions.remove(subIndex); + } + else + { + _log.error("Unable to remove from index(" + subIndex + ")subscription:" + subscription); + } + } + if (sub != null) + { + return sub; + } + 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(QueueEntry msg) + { + + + try + { + final Subscription result = nextSubscriberImpl(msg); + if (result == null) + { + _currentSubscriber = 0; + return nextSubscriberImpl(msg); + } + else + { + return result; + } + } + catch (IndexOutOfBoundsException e) + { + _currentSubscriber = 0; + return nextSubscriber(msg); + } + } + + private Subscription nextSubscriberImpl(QueueEntry msg) + { + if(_exclusive) + { + try + { + Subscription subscription = _subscriptions.get(0); + subscriberScanned(); + + if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) + { + if (subscription.hasInterest(msg)) + { + // if the queue is not empty then this client is ready to receive a message. + //FIXME the queue could be full of sent messages. + // Either need to clean all PDQs after sending a message + // OR have a clean up thread that runs the PDQs expunging the messages. + if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) + { + return subscription; + } + } + } + } + catch(IndexOutOfBoundsException e) + { + } + return null; + } + else + { + if (_subscriptions.isEmpty()) + { + return null; + } + final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); + while (iterator.hasNext()) + { + Subscription subscription = iterator.next(); + ++_currentSubscriber; + subscriberScanned(); + + if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) + { + if (subscription.hasInterest(msg)) + { + // if the queue is not empty then this client is ready to receive a message. + //FIXME the queue could be full of sent messages. + // Either need to clean all PDQs after sending a message + // OR have a clean up thread that runs the PDQs expunging the messages. + if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) + { + return subscription; + } + } + } + } + + return null; + } + } + + /** Overridden in test classes. */ + protected void subscriberScanned() + { + } + + public boolean isEmpty() + { + return _subscriptions.isEmpty(); + } + + public List getSubscriptions() + { + return _subscriptions; + } + + 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(); + } + + + public Object getChangeLock() + { + return _changeLock; + } + + public void setExclusive(final boolean exclusive) + { + _exclusive = exclusive; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java new file mode 100644 index 0000000000..9b91c71a1d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -0,0 +1,127 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; + +/** + * Contains data that is only used in AMQMessage transiently, e.g. while the content + * body fragments are arriving. + * + * Having this data stored in a separate class means that the AMQMessage class avoids + * the small overhead of numerous guaranteed-null references. + * + * @author Apache Software Foundation + */ +public class TransientMessageData +{ + /** + * Stored temporarily until the header has been received at which point it is used when + * constructing the handle + */ + private MessagePublishInfo _messagePublishInfo; + + /** + * Also stored temporarily. + */ + private ContentHeaderBody _contentHeaderBody; + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + /** + * This is stored during routing, to know the queues to which this message should immediately be + * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done + * by the message handle. + */ + private List _destinationQueues; + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public List getDestinationQueues() + { + return _destinationQueues == null ? (List) Collections.EMPTY_LIST : _destinationQueues; + } + + public void setDestinationQueues(List destinationQueues) + { + _destinationQueues = destinationQueues; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public long getBodyLengthReceived() + { + return _bodyLengthReceived; + } + + public void addBodyLength(int value) + { + _bodyLengthReceived += value; + } + + public boolean isAllContentReceived() throws AMQException + { + return _bodyLengthReceived == _contentHeaderBody.bodySize; + } + + public void addDestinationQueue(AMQQueue queue) + { + if(_destinationQueues == null) + { + _destinationQueues = new ArrayList(); + } + _destinationQueues.add(queue); + } + + public boolean isPersistent() + { + //todo remove literal values to a constant file such as AMQConstants in common + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java new file mode 100644 index 0000000000..373a64e2eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -0,0 +1,227 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class WeakReferenceMessageHandle implements AMQMessageHandle +{ + private WeakReference _contentHeaderBody; + + private WeakReference _messagePublishInfo; + + private List> _contentBodies; + + private boolean _redelivered; + + private final MessageStore _messageStore; + + private long _arrivalTime; + + + public WeakReferenceMessageHandle(MessageStore messageStore) + { + _messageStore = messageStore; + } + + public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException + { + ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); + if (chb == null) + { + MessageMetaData mmd = loadMessageMetaData(context, messageId); + chb = mmd.getContentHeaderBody(); + } + return chb; + } + + private MessageMetaData loadMessageMetaData(StoreContext context, Long messageId) + throws AMQException + { + MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); + populateFromMessageMetaData(mmd); + return mmd; + } + + private void populateFromMessageMetaData(MessageMetaData mmd) + { + _arrivalTime = mmd.getArrivalTime(); + _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); + _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); + } + + public int getBodyCount(StoreContext context, Long messageId) throws AMQException + { + if (_contentBodies == null) + { + MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); + int chunkCount = mmd.getContentChunkCount(); + _contentBodies = new ArrayList>(chunkCount); + for (int i = 0; i < chunkCount; i++) + { + _contentBodies.add(new WeakReference(null)); + } + } + return _contentBodies.size(); + } + + public long getBodySize(StoreContext context, Long messageId) throws AMQException + { + return getContentHeaderBody(context, messageId).bodySize; + } + + public ContentChunk getContentChunk(StoreContext context, 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); + ContentChunk cb = wr.get(); + if (cb == null) + { + cb = _messageStore.getContentBodyChunk(context, messageId, index); + _contentBodies.set(index, new WeakReference(cb)); + } + return cb; + } + + /** + * Content bodies are set before the publish and header frames + * + * @param storeContext + * @param messageId + * @param contentChunk + * @param isLastContentBody + * @throws AMQException + */ + public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException + { + if (_contentBodies == null && isLastContentBody) + { + _contentBodies = new ArrayList>(1); + } + else + { + if (_contentBodies == null) + { + _contentBodies = new LinkedList>(); + } + } + _contentBodies.add(new WeakReference(contentChunk)); + _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, + contentChunk, isLastContentBody); + } + + public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException + { + MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); + if (bpb == null) + { + MessageMetaData mmd = loadMessageMetaData(context, messageId); + + bpb = mmd.getMessagePublishInfo(); + } + return bpb; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public boolean isPersistent(StoreContext context, Long messageId) throws AMQException + { + //todo remove literal values to a constant file such as AMQConstants in common + ContentHeaderBody chb = getContentHeaderBody(context, 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(StoreContext storeContext, Long messageId, MessagePublishInfo publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + // if there are no content bodies the list will be null so we must + // create en empty list here + if (contentHeaderBody.bodySize == 0) + { + _contentBodies = new LinkedList>(); + } + + final long arrivalTime = System.currentTimeMillis(); + + + MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); + + _messageStore.storeMessageMetaData(storeContext, messageId, mmd); + + populateFromMessageMetaData(mmd); + } + + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + { + _messageStore.removeMessage(storeContext, messageId); + } + + public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + { + _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); + } + + public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + { + _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); + } + + public long getArrivalTime() + { + return _arrivalTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java new file mode 100644 index 0000000000..6c71571807 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +public interface WeightedSubscriptionManager extends SubscriptionManager +{ + public int getWeight(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java new file mode 100644 index 0000000000..455983c6d8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -0,0 +1,203 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.HashMap; +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..."); + removeAll(); + } + } + + 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 + { + _instanceMap.get(instanceID).close(); + } + catch (Exception e) + { + _logger.error("Error shutting down message store: " + e, e); + + } + finally + { + _instanceMap.remove(instanceID); + } + } + + public static void removeAll() + { + Object[] keys = _instanceMap.keySet().toArray(); + for (Object k : keys) + { + remove((Integer) k); + } + } + + protected ApplicationRegistry(Configuration configuration) + { + _configuration = configuration; + } + + public static IApplicationRegistry getInstance() + { + return getInstance(DEFAULT_INSTANCE); + } + + public static IApplicationRegistry getInstance(int instanceID) + { + synchronized (IApplicationRegistry.class) + { + IApplicationRegistry instance = _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", e); + } + } + else + { + return instance; + } + } + } + + public void close() throws Exception + { + for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) + { + virtualHost.close(); + } + + // close the rmi registry(if any) started for management + if (getInstance().getManagedObjectRegistry() != null) + { + getInstance().getManagedObjectRegistry().close(); + } + } + + 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", e); + } + Configurator.configure(instance); + _configuredObjects.put(instanceType, instance); + } + return instance; + } + + + public static void setDefaultApplicationRegistry(String clazz) + { + _APPLICATION_REGISTRY = clazz; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java new file mode 100644 index 0000000000..748e33ba7a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import java.io.File; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.SystemConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.ManagementConfiguration; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.AMQException; + +public class ConfigurationFileApplicationRegistry extends ApplicationRegistry +{ + + private ManagedObjectRegistry _managedObjectRegistry; + + private AuthenticationManager _authenticationManager; + + private ACLPlugin _accessManager; + + private PrincipalDatabaseManager _databaseManager; + + private VirtualHostRegistry _virtualHostRegistry; + + private PluginManager _pluginManager; + + + public ConfigurationFileApplicationRegistry(Configuration configuration) + { + super(configuration); + } + + 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); + } + } + + public 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(); + + _virtualHostRegistry = new VirtualHostRegistry(); + + _accessManager = ACLManager.loadACLManager("default", _configuration); + + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + + _databaseManager.initialiseManagement(_configuration); + + _managedObjectRegistry.start(); + + _pluginManager = new PluginManager(_configuration.getString("plugin-directory")); + + initialiseVirtualHosts(); + + } + + private void initialiseVirtualHosts() throws Exception + { + for (String name : getVirtualHostNames()) + { + + _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name))); + } + } + + private void initialiseManagedObjectRegistry() throws AMQException + { + ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); + if (config.enabled) + { + _managedObjectRegistry = new JMXManagedObjectRegistry(); + } + else + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + } + } + + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public ACLPlugin getAccessManager() + { + return _accessManager; + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public Collection getVirtualHostNames() + { + return getConfiguration().getList("virtualhosts.virtualhost.name"); + } + + public PluginManager getPluginManager() + { + return _pluginManager; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java new file mode 100644 index 0000000000..ca10fbdba2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import java.util.Collection; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +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; + + void close() throws Exception; + + /** + * This gets access to a "configured object". A configured object has fields populated from a the configuration + * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields. + * Application registry implementations can choose the refresh strategy or caching approach. + * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only + * have a single object of this type in the system. + * @return the configured object + */ + T 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(); + + ManagedObjectRegistry getManagedObjectRegistry(); + + PrincipalDatabaseManager getDatabaseManager(); + + AuthenticationManager getAuthenticationManager(); + + Collection getVirtualHostNames(); + + VirtualHostRegistry getVirtualHostRegistry(); + + ACLPlugin getAccessManager(); + + PluginManager getPluginManager(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java new file mode 100644 index 0000000000..539f32a732 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.plugins.DenyAll; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.log4j.Logger; + +import java.util.List; +import java.lang.reflect.Method; + +public class ACLManager +{ + private static final Logger _logger = Logger.getLogger(ACLManager.class); + + public static ACLPlugin loadACLManager(String name, Configuration hostConfig) throws ConfigurationException + { + ACLPlugin aclPlugin = ApplicationRegistry.getInstance().getAccessManager(); + + if (hostConfig == null) + { + _logger.warn("No Configuration specified. Using default ACLPlugin '" + aclPlugin.getPluginName() + + "' for VirtualHost:'" + name + "'"); + return aclPlugin; + } + + String accessClass = hostConfig.getString("security.access.class"); + if (accessClass == null) + { + + _logger.warn("No ACL Plugin specified. Using default ACL Plugin '" + aclPlugin.getPluginName() + + "' for VirtualHost:'" + name + "'"); + return aclPlugin; + } + + Object o; + try + { + o = Class.forName(accessClass).newInstance(); + } + catch (Exception e) + { + throw new ConfigurationException("Error initialising ACL: " + e, e); + } + + if (!(o instanceof ACLPlugin)) + { + throw new ConfigurationException("ACL Plugins must implement the ACLPlugin interface"); + } + + initialiseAccessControl((ACLPlugin) o, hostConfig); + + aclPlugin = getManager((ACLPlugin) o); + if (_logger.isInfoEnabled()) + { + _logger.info("Initialised ACL Plugin '" + aclPlugin.getPluginName() + + "' for virtualhost '" + name + "' successfully"); + } + + return aclPlugin; + } + + + private static void initialiseAccessControl(ACLPlugin accessManager, Configuration config) + throws ConfigurationException + { + //First provide the ACLPlugin with the host configuration + + accessManager.setConfiguaration(config); + + //Provide additional attribute customisation. + String baseName = "security.access.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 ConfigurationException("Access Control 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 = null; + try + { + method = accessManager.getClass().getMethod(methodName, String.class); + } + catch (NoSuchMethodException e) + { + //do nothing as method will be null + } + + if (method == null) + { + throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() + + " hence unable to configure access control. The method must be public and " + + "have a single String argument with a void return type"); + } + try + { + method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception e) + { + ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause()); + ce.initCause(e); + throw ce; + } + } + } + + + private static ACLPlugin getManager(ACLPlugin manager) + { + if (manager == null) + { + if (ApplicationRegistry.getInstance().getAccessManager() == null) + { + return new DenyAll(); + } + else + { + return ApplicationRegistry.getInstance().getAccessManager(); + } + } + else + { + return manager; + } + } + + public static Logger getLogger() + { + return _logger; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java new file mode 100644 index 0000000000..7855f147b4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQMethodBody; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQConnectionException; +import org.apache.commons.configuration.Configuration; + + +public interface ACLPlugin +{ + /** + * Pseudo-Code: + * Identify requested RighConnectiont + * Lookup users ability for that right. + * if rightsExists + * Validate right on object + * Return result + * e.g + * User, CONSUME , Queue + * User, CONSUME , Exchange + RoutingKey + * User, PUBLISH , Exchange + RoutingKey + * User, CREATE , Exchange || Queue + * User, BIND , Exchange + RoutingKey + Queue + * + * @param session - The session requesting access + * @param permission - The permission requested + * @param parameters - The above objects that are used to authorise the request. + * @return The AccessResult decision + */ + //todo potential refactor this ConnectionException Out of here + AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException; + + String getPluginName(); + + void setConfiguaration(Configuration config); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java new file mode 100644 index 0000000000..89cead69b3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessResult +{ + public enum AccessStatus + { + GRANTED, REFUSED + } + + StringBuilder _authorizer; + AccessStatus _status; + + public AccessResult(ACLPlugin authorizer, AccessStatus status) + { + _status = status; + _authorizer = new StringBuilder(authorizer.getPluginName()); + } + + public void setAuthorizer(ACLPlugin authorizer) + { + _authorizer.append(authorizer.getPluginName()); + } + + public String getAuthorizer() + { + return _authorizer.toString(); + } + + public void setStatus(AccessStatus status) + { + _status = status; + } + + public AccessStatus getStatus() + { + return _status; + } + + public void addAuthorizer(ACLPlugin accessManager) + { + _authorizer.insert(0, "->"); + _authorizer.insert(0, accessManager.getPluginName()); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java new file mode 100644 index 0000000000..1b79a5a0e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessRights +{ + public enum Rights + { + ANY, + READ, + WRITE, + READWRITE + } + + Rights _right; + + public AccessRights(Rights right) + { + _right = right; + } + + public boolean allows(Rights rights) + { + switch (_right) + { + case ANY: + return (rights.equals(Rights.WRITE) + || rights.equals(Rights.READ) + || rights.equals(Rights.READWRITE) + || rights.equals(Rights.ANY)); + case READ: + return rights.equals(Rights.READ) || rights.equals(Rights.ANY); + case WRITE: + return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); + case READWRITE: + return true; + } + return false; + } + + public Rights getRights() + { + return _right; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java new file mode 100644 index 0000000000..f51cf24caa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public interface Accessable +{ + void setAccessableName(String name); + String getAccessableName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java new file mode 100644 index 0000000000..5d439a99eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +public enum Permission +{ + CONSUME, + PUBLISH, + CREATE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java new file mode 100755 index 0000000000..23073e0613 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -0,0 +1,579 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.QueueBindBody; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.Exchange; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class PrincipalPermissions +{ + + private static final Object CONSUME_QUEUES_KEY = new Object(); + private static final Object CONSUME_TEMPORARY_KEY = new Object(); + private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object(); + + private static final Object CREATE_QUEUES_KEY = new Object(); + private static final Object CREATE_EXCHANGES_KEY = new Object(); + + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); + private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); + private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); + + private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object(); + private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); + + private static final int PUBLISH_EXCHANGES_KEY = 0; + + private Map _permissions; + + private String _user; + + + public PrincipalPermissions(String user) + { + _user = user; + _permissions = new ConcurrentHashMap(); + } + + public void grant(Permission permission, Object... parameters) + { + switch (permission) + { + case ACCESS: + break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS + case BIND: + break; // All the details are currently included in the create setup. + case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly + Map consumeRights = (Map) _permissions.get(permission); + + if (consumeRights == null) + { + consumeRights = new ConcurrentHashMap(); + _permissions.put(permission, consumeRights); + } + + //if we have parametsre + if (parameters.length > 0) + { + AMQShortString queueName = (AMQShortString) parameters[0]; + Boolean temporary = (Boolean) parameters[1]; + Boolean ownQueueOnly = (Boolean) parameters[2]; + + if (temporary) + { + consumeRights.put(CONSUME_TEMPORARY_KEY, true); + } + else + { + consumeRights.put(CONSUME_TEMPORARY_KEY, false); + } + + if (ownQueueOnly) + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); + } + else + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); + } + + + LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); + if (queues == null) + { + queues = new LinkedList(); + consumeRights.put(CONSUME_QUEUES_KEY, queues); + } + + if (queueName != null) + { + queues.add(queueName); + } + } + + + break; + case CREATE: // Parameters : Boolean temporary, AMQShortString queueName + // , AMQShortString exchangeName , AMQShortString routingKey + // || AMQShortString exchangeName , AMQShortString Class + + Map createRights = (Map) _permissions.get(permission); + + if (createRights == null) + { + createRights = new ConcurrentHashMap(); + _permissions.put(permission, createRights); + + } + + //The existence of the empty map mean permission to all. + if (parameters.length == 0) + { + return; + } + + + if (parameters[0] instanceof Boolean) //Create Queue : + // Boolean temporary, [AMQShortString queueName, AMQShortString exchangeName , AMQShortString routingKey] + { + Boolean temporary = (Boolean) parameters[0]; + + AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName; + + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } + + //Allow all temp queues to be created + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } + + // We are granting CREATE rights to all temporary queues only + if (parameters.length == 1) + { + return; + } + + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) + { + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); + } + + if (exchangeName != null) + { + queue.put(exchangeName, routingKey); + } + + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } + + // Store the exchange that we are being granted rights to. This will be used as part of binding + + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } + + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + + if (exchanges == null) + { + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); + } + + //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY + exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) + { + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); + + if (rKeys == null) + { + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); + } + + rKeys.put(queueName, routingKey); + } + } + } + else // Create Exchange : AMQShortString exchangeName , AMQShortString Class + { + Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY); + + if (create_exchanges == null) + { + create_exchanges = new ConcurrentHashMap(); + createRights.put(CREATE_EXCHANGES_KEY, create_exchanges); + } + + //Should perhaps error if parameters[0] is null; + AMQShortString exchangeName = parameters.length > 0 ? (AMQShortString) parameters[0] : null; + AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + + //Store the exchangeName / class mapping if the mapping is null + createRights.put(exchangeName, className); + } + break; + case DELETE: + break; + + case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + publishRights = new ConcurrentHashMap(); + _permissions.put(permission, publishRights); + } + + if (parameters == null || parameters.length == 0) + { + //If we have no parameters then allow publish to all destinations + // this is signified by having a null value for publish_exchanges + } + else + { + Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + if (publish_exchanges == null) + { + publish_exchanges = new ConcurrentHashMap(); + publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); + } + + + HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); + + // Check to see if we have a routing key + if (parameters.length == 2) + { + if (routingKeys == null) + { + routingKeys = new HashSet(); + } + //Add routing key to permitted publish destinations + routingKeys.add(parameters[1]); + } + + // Add the updated routingkey list or null if all values allowed + publish_exchanges.put(parameters[0], routingKeys); + } + break; + case PURGE: + break; + case UNBIND: + break; + } + + } + + public boolean authorise(Permission permission, Object... parameters) + { + + switch (permission) + { + case ACCESS: + return true; // This is here for completeness but the SimpleXML ACLManager never calls it. + // The existence of this user specific PP can be validated in the map SimpleXML maintains. + case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey + + Exchange exchange = (Exchange) parameters[1]; + + AMQQueue bind_queueName = (AMQQueue) parameters[2]; + AMQShortString routingKey = (AMQShortString) parameters[3]; + + //Get all Create Rights for this user + Map bindCreateRights = (Map) _permissions.get(Permission.CREATE); + + //Look up the Queue Creation Rights + Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues + Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); + + // Check and see if we have a queue white list to check + if (bind_create_queues_queues != null) + { + //There a white list for queues + Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); + + if (exchangeDetails == null) //Then all queue can be bound to all exchanges. + { + return true; + } + + // Check to see if we have a white list of routingkeys to check + Map rkeys = (Map) exchangeDetails.get(exchange.getName()); + + // if keys is null then any rkey is allowed on this exchange + if (rkeys == null) + { + // There is no routingkey white list + return true; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = rkeys.keySet().iterator(); + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + if (rkey.endsWith("*")) + { + matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); + } + else + { + matched = routingKey.equals(rkey); + } + } + + + return matched; + } + + + } + else + { + //There a is no white list for queues + + // So can allow all queues to be bound + // but we should first check and see if we have a temp queue and validate that we are allowed + // to bind temp queues. + + //Check to see if we have a temporary queue + if (bind_queueName.isAutoDelete()) + { + // Check and see if we have an exchange white list. + Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + // If the exchange exists then we must check to see if temporary queues are allowed here + if (bind_exchanges != null) + { + // Check to see if the requested exchange is allowed. + Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); + + return (Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY); + } + + //no white list so all allowed, drop through to return true below. + } + + // not a temporary queue and no white list so all allowed. + return true; + } + + case CREATE:// Paramters : QueueDeclareBody || ExchangeDeclareBody + + Map createRights = (Map) _permissions.get(permission); + + // If there are no create rights then deny request + if (createRights == null) + { + return false; + } + + if (parameters.length == 1) + { + if (parameters[0] instanceof QueueDeclareBody) + { + QueueDeclareBody body = (QueueDeclareBody) parameters[0]; + + //Look up the Queue Creation Rights + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues allowed to be created + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + + AMQShortString queueName = body.getQueue(); + + + if (body.getAutoDelete())// we have a temporary queue + { + return (Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY); + } + else + { + // If there is a white list then check + return create_queues_queues == null || create_queues_queues.containsKey(queueName); + } + + } + else if (parameters[0] instanceof ExchangeDeclareBody) + { + ExchangeDeclareBody body = (ExchangeDeclareBody) parameters[0]; + + AMQShortString exchangeName = body.getExchange(); + + Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY); + + // If the exchange list is doesn't exist then all is allowed else check the valid exchanges + return create_exchanges == null || create_exchanges.containsKey(exchangeName); + } + } + break; + case CONSUME: // Parameters : AMQQueue + + if (parameters.length == 1 && parameters[0] instanceof AMQQueue) + { + AMQQueue queue = ((AMQQueue) parameters[0]); + Map queuePermissions = (Map) _permissions.get(permission); + + List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); + + Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); + Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); + + // If user is allowed to publish to temporary queues and this is a temp queue then allow it. + if (temporayQueues) + { + if (queue.isAutoDelete()) + // This will allow consumption from any temporary queue including ones not owned by this user. + // Of course the exclusivity will not be broken. + { + // if not limited to ownQueuesOnly then ok else check queue Owner. + return !ownQueuesOnly || queue.getOwner().equals(_user); + } + else + { + return false; + } + } + + // if queues are white listed then ensure it is ok + if (queues != null) + { + // if no queues are listed then ALL are ok othereise it must be specified. + if (ownQueuesOnly) + { + if (queue.getOwner().equals(_user)) + { + return queues.size() == 0 || queues.contains(queue.getName()); + } + else + { + return false; + } + } + + // If we are + return queues.size() == 0 || queues.contains(queue.getName()); + } + } + + // Can't authenticate without the right parameters + return false; + case DELETE: + break; + + case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + return false; + } + + Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + // Having no exchanges listed gives full publish rights to all exchanges + if (exchanges == null) + { + return true; + } + // Otherwise exchange must be listed in the white list + + // If the map doesn't have the exchange then it isn't allowed + if (!exchanges.containsKey(parameters[0])) + { + return false; + } + else + { + + // Get valid routing keys + HashSet routingKeys = (HashSet) exchanges.get(parameters[0]); + + // Having no routingKeys in the map then all are allowed. + if (routingKeys == null) + { + return true; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = routingKeys.iterator(); + + + AMQShortString publishRKey = (AMQShortString)parameters[1]; + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + + if (rkey.endsWith("*")) + { + matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); + } + else + { + matched = publishRKey.equals(rkey); + } + } + return matched; + } + } + case PURGE: + break; + case UNBIND: + break; + + } + + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java new file mode 100644 index 0000000000..13151a66b8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class VirtualHostAccess +{ + private String _vhost; + private AccessRights _rights; + + public VirtualHostAccess(String vhostaccess) + { + //format () + int hostend = vhostaccess.indexOf('('); + + if (hostend == -1) + { + throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); + } + + _vhost = vhostaccess.substring(0, hostend); + + String rights = vhostaccess.substring(hostend); + + if (rights.indexOf('r') != -1) + { + if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.READWRITE); + } + else + { + _rights = new AccessRights(AccessRights.Rights.READ); + } + } + else if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.WRITE); + } + } + + public AccessRights getAccessRights() + { + return _rights; + } + + public String getVirtualHost() + { + return _vhost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java new file mode 100644 index 0000000000..a8ae03cc5d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.management; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.access.management.UserManagement; +import org.apache.log4j.Logger; +import org.apache.commons.configuration.ConfigurationException; + +import javax.management.JMException; +import javax.management.remote.JMXPrincipal; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.auth.Subject; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.List; +import java.util.Enumeration; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; +import java.security.AccessControlContext; +import java.security.AccessController; + +/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ +@MBeanDescription("User Management Interface") +public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement +{ + + private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + + private PrincipalDatabase _principalDatabase; + private String _accessFileName; + private Properties _accessRights; + // private File _accessFile; + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); + + // Setup for the TabularType + static TabularType _userlistDataType; // Datatype for representing User Lists + + static CompositeType _userDataType; // Composite type for representing User + static String[] _userItemNames = {"Username", "read", "write", "admin"}; + + static + { + String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", + "Management Console Write Permission", "Management Console Admin Permission"}; + + OpenType[] userItemTypes = new OpenType[4]; // User item types. + userItemTypes[0] = SimpleType.STRING; // For Username + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + String[] userDataIndex = {_userItemNames[0]}; + + try + { + _userDataType = + new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); + + _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing users incorrect."); + _userlistDataType = null; + } + } + + + public AMQUserManagementMBean() throws JMException + { + super(UserManagement.class, UserManagement.TYPE); + } + + public String getObjectInstanceName() + { + return UserManagement.TYPE; + } + + public boolean setPassword(String username, char[] password) + { + try + { + //delegate password changes to the Principal Database + return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + return false; + } + } + + public boolean setRights(String username, boolean read, boolean write, boolean admin) + { + + if (_accessRights.get(username) == null) + { + // If the user doesn't exist in the user rights file check that they at least have an account. + if (_principalDatabase.getUser(username) == null) + { + return false; + } + } + + try + { + + _accessRightsUpdate.lock(); + + // Update the access rights + if (admin) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); + } + else + { + if (read | write) + { + if (read) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); + } + if (write) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); + } + } + else + { + _accessRights.remove(username); + } + } + + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + return true; + } + + public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) + { + _accessRights.put(username, ""); + + return setRights(username, read, write, admin); + } + + return false; + } + + public boolean deleteUser(String username) + { + + try + { + if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) + { + try + { + _accessRightsUpdate.lock(); + + _accessRights.remove(username); + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + return true; + } + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + } + + return false; + } + + public boolean reloadData() + { + try + { + try + { + loadAccessFile(); + } + catch (ConfigurationException e) + { + _logger.info("Reload failed due to:" + e); + return false; + } + + // Reload successful + return true; + } + catch (IOException e) + { + _logger.info("Reload failed due to:" + e); + // Reload unsuccessful + return false; + } + } + + + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + public TabularData viewUsers() + { + // Table of users + // Username(string), Access rights Read,Write,Admin(bool,bool,bool) + + if (_userlistDataType == null) + { + _logger.warn("TabluarData not setup correctly"); + return null; + } + + List users = _principalDatabase.getUsers(); + + TabularDataSupport userList = new TabularDataSupport(_userlistDataType); + + try + { + // Create the tabular list of message header contents + for (Principal user : users) + { + // Create header attributes list + + String rights = (String) _accessRights.get(user.getName()); + + Boolean read = false; + Boolean write = false; + Boolean admin = false; + + if (rights != null) + { + read = rights.equals(MBeanInvocationHandlerImpl.READONLY) + || rights.equals(MBeanInvocationHandlerImpl.READWRITE); + write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); + admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); + } + + Object[] itemData = {user.getName(), read, write, admin}; + CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); + userList.put(messageData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create user list due to :" + e); + return null; + } + + return userList; + } + + /*** Broker Methods **/ + + /** + * setPrincipalDatabase + * + * @param database set The Database to use for user lookup + */ + public void setPrincipalDatabase(PrincipalDatabase database) + { + _principalDatabase = database; + } + + /** + * setAccessFile + * + * @param accessFile the file to use for updating. + * + * @throws java.io.IOException If the file cannot be accessed + * @throws org.apache.commons.configuration.ConfigurationException + * if checks on the file fail. + */ + public void setAccessFile(String accessFile) throws IOException, ConfigurationException + { + _accessFileName = accessFile; + + if (_accessFileName != null) + { + loadAccessFile(); + } + else + { + _logger.warn("Access rights file specified is null. Access rights not changed."); + } + } + + private void loadAccessFile() throws IOException, ConfigurationException + { + try + { + _accessRightsUpdate.lock(); + + Properties accessRights = new Properties(); + + File accessFile = new File(_accessFileName); + + if (!accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFileName + "' does not exist"); + } + + if (!accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFileName + "'."); + } + + if (!accessFile.canWrite()) + { + _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved."); + } + + accessRights.load(new FileInputStream(accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + private void checkAccessRights(Properties accessRights) + { + Enumeration values = accessRights.propertyNames(); + + while (values.hasMoreElements()) + { + String user = (String) values.nextElement(); + + if (_principalDatabase.getUser(user) == null) + { + _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); + } + } + } + + private void saveAccessFile() + { + try + { + _accessRightsUpdate.lock(); + try + { + // remove old temporary file + File tmp = new File(_accessFileName + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + + //remove old backup + File old = new File(_accessFileName + ".old"); + if (old.exists()) + { + old.delete(); + } + + // Rename current file + File rights = new File(_accessFileName); + rights.renameTo(old); + + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); + output.close(); + + // Rename new file to main file + tmp.renameTo(rights); + + // delete tmp + tmp.delete(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e); + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + private String getCurrentJMXUser() + { + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + return "Unknown user principals were null"; + } + + Principal principal = principals.iterator().next(); + return principal.getName(); + } + + /** + * user=read user=write user=readwrite user=admin + * + * @param accessRights The properties list of access rights to process + */ + private void setAccessRights(Properties accessRights) + { + _logger.debug("Setting Access Rights:" + accessRights); + _accessRights = accessRights; + MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java new file mode 100644 index 0000000000..658d7ebbd3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.management; + +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.AMQException; + +import javax.management.openmbean.TabularData; +import javax.management.openmbean.CompositeData; +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import java.io.IOException; + +public interface UserManagement +{ + String TYPE = "UserManagement"; + + //********** Operations *****************// + /** + * set password for user + * + * @param username The username to create + * @param password The password for the user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setPassword", description = "Set password for user.", + impact = MBeanOperationInfo.ACTION) + boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")char[] password); + + /** + * set rights for users with given details + * + * @param username The username to create + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setRights", description = "Set access rights for user.", + impact = MBeanOperationInfo.ACTION) + boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * Create users with given details + * + * @param username The username to create + * @param password The password for the user + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "createUser", description = "Create new user from system.", + impact = MBeanOperationInfo.ACTION) + boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")char[] password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * View users returns all the users that are currently available to the system. + * + * @param username The user to delete + * + * @return The result of the operation + */ + @MBeanOperation(name = "deleteUser", description = "Delete user from system.", + impact = MBeanOperationInfo.ACTION) + boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); + + + /** + * Reload the date from disk + * + * @return The result of the operation + */ + @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", + impact = MBeanOperationInfo.ACTION) + boolean reloadData(); + + /** + * View users returns all the users that are currently available to the system. + * + * @return a table of users data (Username, read, write, admin) + */ + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", + impact = MBeanOperationInfo.INFO) + TabularData viewUsers(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java new file mode 100644 index 0000000000..dee1676632 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.access.Permission; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; + +public class AllowAll implements ACLPlugin +{ + + private static final Logger _logger = ACLManager.getLogger(); + + public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Allowing user:" + session.getAuthorizedID() + " for :" + permission.toString() + + " on " + body.getClass().getSimpleName() + + (parameters == null || parameters.length == 0 ? "" : "-" + accessablesToString(parameters))); + } + + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + + public static String accessablesToString(Object[] accessObject) + { + StringBuilder sb = new StringBuilder(); + + for (Object access : accessObject) + { + sb.append(access.getClass().getSimpleName() + ":" + access.toString() + ", "); + } + + return sb.delete(sb.length() - 2, sb.length()).toString(); + } + + public String getPluginName() + { + return "AllowAll"; + } + + public void setConfiguaration(Configuration config) + { + //no-op + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java new file mode 100644 index 0000000000..80c125e737 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.AMQConnectionException; +import org.apache.commons.configuration.Configuration; + +public class DenyAll implements ACLPlugin +{ + public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException + { + + if (ACLManager.getLogger().isInfoEnabled()) + { + } + ACLManager.getLogger().info("Denying user:" + session.getAuthorizedID() + " for :" + permission.toString() + + " on " + body.getClass().getSimpleName() + + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters))); + + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "DenyAll Plugin"); + } + + public String getPluginName() + { + return "DenyAll"; + } + + public void setConfiguaration(Configuration config) + { + //no-op + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java new file mode 100644 index 0000000000..251f4e6330 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -0,0 +1,342 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicConsumeBody; +import org.apache.qpid.framing.BasicPublishBody; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.security.access.PrincipalPermissions; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This uses the default + */ +public class SimpleXML implements ACLPlugin +{ + private Map _users; + private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); + + public SimpleXML() + { + _users = new ConcurrentHashMap(); + } + + public void setConfiguaration(Configuration config) + { + processConfig(config); + } + + private void processConfig(Configuration config) + { + processPublish(config); + + processConsume(config); + + processCreate(config); + } + + /** + * Publish format takes + * Exchange + Routing Key Pairs + * + * @param config XML Configuration + */ + private void processPublish(Configuration config) + { + Configuration publishConfig = config.subset("security.access_control_list.publish"); + + //Process users that have full publish permission + String[] users = publishConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user); + } + + // Process exchange limited users + int exchangeCount = 0; + Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + //Get Exchange Name + AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); + + //Get Routing Keys + int keyCount = 0; + Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + + while (!routingkeyConfig.isEmpty()) + { + //Get RoutingKey Value + AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); + + //Apply Exchange + RoutingKey permissions to Users + users = routingkeyConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); + } + + //Apply permissions to Groups + + // Check for more configs + keyCount++; + routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + } + + //Apply Exchange wide permissions to Users + users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName); + } + + //Apply permissions to Groups + exchangeCount++; + exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + } + + private void grant(Permission permission, String user, Object... parameters) + { + PrincipalPermissions permissions = _users.get(user); + + if (permissions == null) + { + permissions = new PrincipalPermissions(user); + } + + _users.put(user, permissions); + permissions.grant(permission, parameters); + } + + private void processConsume(Configuration config) + { + Configuration consumeConfig = config.subset("security.access_control_list.consume"); + + // Process queue limited users + int queueCount = 0; + Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + //Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + // if there is no name then there may be a temporary element + boolean temporary = queueConfig.containsKey("temporary"); + boolean ownQueues = queueConfig.containsKey("own_queues"); + + //Process permissions for this queue + String[] users = queueConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CONSUME, user, queueName, temporary, ownQueues); + } + + //See if we have another config + queueCount++; + queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process users that have full consume permission + String[] users = consumeConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CONSUME, user); + } + } + + private void processCreate(Configuration config) + { + Configuration createConfig = config.subset("security.access_control_list.create"); + + // Process create permissions for queue creation + int queueCount = 0; + Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + //Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + + // if there is no name then there may be a temporary element + boolean temporary = queueConfig.containsKey("temporary"); + + int exchangeCount = 0; + Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); + + //Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CREATE, user, temporary, + (queueName.equals("") ? null : queueName), + (exchange.equals("") ? null : exchange), + (routingKey.equals("") ? null : routingKey)); + } + + //See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that are not bound to an exchange + String[] users = queueConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATE, user, temporary, queueName); + } + + //See if we have another config + queueCount++; + queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process create permissions for exchange creation + int exchangeCount = 0; + Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); + + //Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CREATE, user, exchange, clazz); + } + + //See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that have full create permission + String[] users = createConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATE, user); + } + + + } + + public String getPluginName() + { + return "Simple"; + } + + public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException + { + String error = ""; + + if (ACLManager.getLogger().isInfoEnabled()) + { + ACLManager.getLogger().info("Simple Authorisation processing user:" + session.getAuthorizedID() + " for :" + permission.toString() + + " on " + body.getClass().getSimpleName() + + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters))); + } + + String username = session.getAuthorizedID().getName(); + + //Get the Users Permissions + PrincipalPermissions permissions = _users.get(username); + + if (permissions != null) + { + switch (permission) + { + case ACCESS: + return GRANTED; + case BIND: // Body QueueDeclareBody - Parameters : Exchange, Queue, QueueName + // Body QueueBindBody - Paramters : Exchange, Queue, QueueName + if (parameters.length == 3) + { + // Parameters : Exchange, Queue, RoutingKey + if (permissions.authorise(Permission.BIND, body, parameters[0], parameters[1], parameters[2])) + { + return GRANTED; + } + } + break; + case CONSUME: // Parameters : none + if (parameters.length == 1 && permissions.authorise(Permission.CONSUME, parameters[0])) + { + return GRANTED; + } + break; + case CREATE: // Body : QueueDeclareBody | ExchangeDeclareBody - Parameters : none + if (permissions.authorise(Permission.CREATE, body)) + { + return GRANTED; + } + break; + case PUBLISH: // Body : BasicPublishBody Parameters : exchange + if (parameters.length == 1 && parameters[0] instanceof Exchange) + { + if (permissions.authorise(Permission.PUBLISH, ((Exchange) parameters[0]).getName(), + ((BasicPublishBody) body).getRoutingKey())) + { + return GRANTED; + } + } + break; + case PURGE: + break; + case DELETE: + break; + case UNBIND: + break; + } + } + + //todo potential refactor this ConnectionException Out of here + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, error); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java new file mode 100644 index 0000000000..0e3aea4de0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +public class AuthenticationResult +{ + public enum AuthenticationStatus + { + SUCCESS, CONTINUE, ERROR + } + + public AuthenticationStatus status; + public byte[] challenge; + + public AuthenticationResult(byte[] challenge, AuthenticationStatus status) + { + this.status = status; + this.challenge = challenge; + } + + public AuthenticationResult(AuthenticationStatus status) + { + this.status = status; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..348bccb4e9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -0,0 +1,598 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; +import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.EncoderException; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.UnsupportedEncodingException; +import java.io.PrintStream; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; +import java.security.NoSuchAlgorithmException; + +/** + * 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 Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + AMQUserManagementMBean _mbean; + private static final String DEFAULT_ENCODING = "utf-8"; + private Map _users = new HashMap(); + private ReentrantLock _userUpdate = new ReentrantLock(); + + public Base64MD5PasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); + cram.initialise(this); + _saslServers.put(cram.getMechanismName(), cram); + + //fixme The PDs should setup a PD Mangement MBean +// try +// { +// _mbean = new AMQUserManagementMBean(); +// _mbean.setPrincipalDatabase(this); +// } +// catch (JMException e) +// { +// _logger.warn("User management disabled as unable to create MBean:" + e); +// } + } + + public void setPasswordFile(String passwordFile) throws IOException + { + 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."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannont be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws 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); + } + } + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + char[] pwd = lookupPassword(principal); + + int index = 0; + boolean verified = true; + + while (verified & index < password.length) + { + verified = (pwd[index] == password[index]); + index++; + } + return verified; + } + + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + try + { + _userUpdate.lock(); + char[] orig = user.getPassword(); + user.setPassword(password); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user'" + + principal + "' will revert at restart"); + //revert the password change + user.setPassword(orig); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (Exception e) + { + return false; + } + } + + public boolean createPrincipal(Principal principal, char[] password) + { + if (_users.get(principal.getName()) != null) + { + return false; + } + + User user = new User(principal.getName(), password); + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + //remove the use on failure. + _users.remove(user.getName()); + return false; + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; + } + + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(_users.values()); + } + + public Principal getUser(String username) + { + if (_users.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + /** + * 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 The principal name to lookup + * + * @return a char[] for use in SASL. + */ + private char[] lookupPassword(String name) + { + User user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + 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 || result[0].startsWith("#")) + { + continue; + } + + User user = new User(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + continue; + } + + User user = _users.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + try + { + byte[] encodedPassword = user.getEncodePassword(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to encode new password reverting to old password."); + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + } + } + } + + for (User user : _users.values()) + { + if (user.isModified()) + { + byte[] encodedPassword; + try + { + encodedPassword = user.getEncodePassword(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); + } + } + } + } + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private class User implements Principal + { + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + User(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be lenght 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public User(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + if (_logger.isDebugEnabled()) + { + return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); + } + else + { + return _name; + } + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + + byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + _encodedPassword = (new Base64()).encode(byteArray); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java new file mode 100644 index 0000000000..15c62a62e4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -0,0 +1,235 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.AMQException; + +import javax.management.JMException; + +public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager +{ + private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); + + private static final String _base = "security.principal-databases.principal-database"; + + Map _databases; + + public ConfigurationFilePrincipalDatabaseManager(Configuration configuration) throws Exception + { + _logger.info("Initialising PrincipleDatabase authentication manager"); + _databases = initialisePrincipalDatabases(configuration); + } + + private Map initialisePrincipalDatabases(Configuration configuration) throws Exception + { + List databaseNames = configuration.getList(_base + ".name"); + List databaseClasses = configuration.getList(_base + ".class"); + Map databases = new HashMap(); + + if (databaseNames.size() == 0) + { + _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); + } + + 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, configuration, 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 not provided"); + } + + _logger.info("Initialised principal database '" + name + "' successfully"); + databases.put(name, (PrincipalDatabase) o); + } + + return databases; + } + + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) + throws FileNotFoundException, ConfigurationException + { + String baseName = _base + "(" + 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 ConfigurationException("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 = null; + try + { + method = principalDatabase.getClass().getMethod(methodName, String.class); + } + catch (Exception e) + { + // do nothing.. as on error method will be null + } + + if (method == null) + { + throw new ConfigurationException("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"); + } + + try + { + method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception ite) + { + if (ite instanceof ConfigurationException) + { + throw(ConfigurationException) ite; + } + else + { + throw new ConfigurationException(ite.getMessage(), ite); + } + } + } + } + + public Map getDatabases() + { + return _databases; + } + + public void initialiseManagement(Configuration config) throws ConfigurationException + { + try + { + AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); + + String baseSecurity = "security.jmx"; + List principalDBs = config.getList(baseSecurity + ".principal-database"); + + if (principalDBs.size() == 0) + { + throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)"); + } + + String databaseName = principalDBs.get(0); + + PrincipalDatabase database = getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); + } + + _mbean.setPrincipalDatabase(database); + + List jmxaccesslist = config.getList(baseSecurity + ".access"); + + if (jmxaccesslist.size() == 0) + { + throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)"); + } + + String jmxaccesssFile = null; + + try + { + jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); + } + catch (PropertyException e) + { + throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); + } + + try + { + _mbean.setAccessFile(jmxaccesssFile); + } + catch (IOException e) + { + _logger.warn("Unable to load access file:" + jmxaccesssFile); + } + + try + { + _mbean.register(); + } + catch (AMQException e) + { + _logger.warn("Unable to register user management MBean"); + } + } + catch (JMException e) + { + _logger.warn("User management disabled as unable to create MBean:" + e); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..352d41a0ba --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.security.Principal; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +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 PlainPasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); + + protected File _passwordFile; + + protected Pattern _regexp = Pattern.compile(":"); + + protected Map _saslServers; + + public PlainPasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for Plain Password file. + */ + + // Accept AMQPlain incomming and compare it to the file. + AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); + amqplain.initialise(this); + + // Accept Plain incomming and compare it to the file. + PlainInitialiser plain = new PlainInitialiser(); + plain.initialise(this); + + // Accept MD5 incomming and Hash file value for comparison + CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); + cram.initialise(this); + + _saslServers.put(amqplain.getMechanismName(), amqplain); + _saslServers.put(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + File f = new File(passwordFile); + _logger.info("PlainPasswordFile 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); + } + } + + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + try + { + char[] pwd = lookupPassword(principal); + + return compareCharArray(pwd, password); + } + catch (IOException e) + { + return false; + } + } + + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, char[] password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(); //todo + } + + public Principal getUser(String username) + { + try + { + if (lookupPassword(username) != null) + { + return new UsernamePrincipal(username); + } + } + catch (IOException e) + { + //fall through to null return + } + return null; + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + + /** + * 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 the name of the principal to lookup + * + * @return char[] of the password + * + * @throws java.io.IOException whilst accessing the file + */ + private char[] lookupPassword(String name) throws IOException + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + if (!line.startsWith("#")) + { + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java new file mode 100644 index 0000000000..a82f9ed40b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -0,0 +1,100 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Map; +import java.util.List; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; + +/** 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; + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * @param principal The principal to authenticate + * @param password The password to check + * @return true if password is correct + * @throws AccountNotFoundException if the principal cannot be found + */ + boolean verifyPassword(String principal, char[] password) + throws AccountNotFoundException; + + /** + * Update(Change) the password for the given principal + * @param principal Who's password is to be changed + * @param password The new password to use + * @return True if change was successful + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean updatePassword(Principal principal, char[] password) + throws AccountNotFoundException; + + /** + * Create a new principal in the database + * @param principal The principal to create + * @param password The password to set for the principal + * @return True on a successful creation + */ + boolean createPrincipal(Principal principal, char[] password); + + /** + * Delete a principal + * @param principal The principal to delete + * @return True on a successful creation + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean deletePrincipal(Principal principal) + throws AccountNotFoundException; + + /** + * Get the principal from the database with the given username + * @param username of the principal to lookup + * @return The Principal object for the given username or null if not found. + */ + Principal getUser(String username); + + + public Map getMechanisms(); + + + List getUsers(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java new file mode 100644 index 0000000000..2c553ae76a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +import java.util.Map; + +public interface PrincipalDatabaseManager +{ + public Map getDatabases(); + + public void initialiseManagement(Configuration config) throws ConfigurationException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java new file mode 100644 index 0000000000..c8a4add0f1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.util.Properties; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.security.Principal; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class PropertiesPrincipalDatabase implements PrincipalDatabase +{ + private Properties _users; + + private Map _saslServers; + + public PropertiesPrincipalDatabase(Properties users) + { + _users = users; + + _saslServers = new HashMap(); + + /** + * Create Authenticators for Properties Principal Database. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException + { + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + + + + final String pwd = _users.getProperty(principal.getName()); + + if (pwd != null) + { + callback.setPassword(pwd.toCharArray()); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + //fixme this is not correct as toCharArray is not safe based on the type of string. + char[] pwd = _users.getProperty(principal).toCharArray(); + + return compareCharArray(pwd, password); + } + + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, char[] password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(); //todo + } + + public Principal getUser(String username) + { + if (_users.getProperty(username) != null) + { + return new UsernamePrincipal(username); + } + else + { + return null; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java new file mode 100644 index 0000000000..6b86a46bd2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.configuration.Configuration; + +import java.util.Map; +import java.util.Properties; +import java.util.HashMap; + +public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager +{ + + Map _databases = new HashMap(); + + public PropertiesPrincipalDatabaseManager(String name, Properties users) + { + _databases.put(name, new PropertiesPrincipalDatabase(users)); + } + + public Map getDatabases() + { + return _databases; + } + + public void initialiseManagement(Configuration config) + { + //todo + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java new file mode 100644 index 0000000000..bb94e0b7bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java new file mode 100644 index 0000000000..f589140e8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.SubsetConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.JCAProvider; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; +import java.security.Security; + +public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.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>(); + + private AuthenticationManager _default = null; + + public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception + { + _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") + + " PrincipleDatabase authentication manager."); + + // Fixme This should be done per Vhost but allowing global hack isn't right but ... + // required as authentication is done before Vhost selection + + Map> providerMap = new TreeMap>(); + + + if (name == null || hostConfig == null) + { + initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); + } + else + { + String databaseName = hostConfig.getString("security.authentication.name"); + + if (databaseName == null) + { + + _default = ApplicationRegistry.getInstance().getAuthenticationManager(); + return; + } + else + { + PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Requested database:" + databaseName + " was not found"); + } + + initialiseAuthenticationMechanisms(providerMap, database); + } + } + + if (providerMap.size() > 0) + { + // Ensure we are used before the defaults + if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1) + { + _logger.warn("Unable to set order of providers."); + } + } + else + { + _logger.warn("No additional SASL providers registered."); + } + + } + + + private void initialiseAuthenticationMechanisms(Map> providerMap, 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. + + + if (databases.size() > 1) + { + _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); + } + + for (Map.Entry entry : databases.entrySet()) + { + + // fixme As the database now provide the mechanisms they support, they will ... + // overwrite each other in the map. There should only be one database per vhost. + // But currently we must have authentication before vhost definition. + initialiseAuthenticationMechanisms(providerMap, entry.getValue()); + } + + } + + private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception + { + if (database == null || database.getMechanisms().size() == 0) + { + _logger.warn("No Database or no mechanisms to initialise authentication"); + return; + } + + for (Map.Entry mechanism : database.getMechanisms().entrySet()) + { + initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); + } + } + + private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, + Map> providerMap) + throws Exception + { + 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); + } + _logger.info("Initialised " + mechanism + " SASL provider successfully"); + } + + public String getMechanisms() + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.getMechanisms(); + } + else + { + return _mechanisms; + } + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.createSaslServer(mechanism, localFQDN); + } + else + { + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); + } + + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + // Use the default AuthenticationManager if present + if (_default != null) + { + return _default.authenticate(server, 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); + } + } + + public AuthenticationResult isAuthorize(VirtualHost vhost, String username) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java new file mode 100644 index 0000000000..89e545d6f5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +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 + * @throws Exception needs refined Exception is too broad. + */ + void initialise(String baseConfigPath, Configuration configuration, + Map principalDatabases) throws Exception; + + /** + * Initialise the authentication provider. + * @param db The principal database to initialise with + */ + void initialise(PrincipalDatabase db); + + + /** + * @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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java new file mode 100644 index 0000000000..fd4ad86055 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.security.Provider; +import java.security.Security; +import java.util.Map; + +import javax.security.sasl.SaslServerFactory; + +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()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java new file mode 100644 index 0000000000..dd0bd096c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -0,0 +1,123 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; + +import org.apache.commons.configuration.Configuration; + +import org.apache.log4j.Logger; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser +{ + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + + 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 + IOException ioe = new IOException("Error looking up user " + e); + ioe.initCause(e); + throw ioe; + } + } + 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); + + initialise(db); + } + + public void initialise(PrincipalDatabase db) + { + if (db == null) + { + throw new NullPointerException("Cannot initialise with a null Principal database."); + } + + _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java new file mode 100644 index 0000000000..d7c8383690 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +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; + } + + public String toString() + { + return _name; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java new file mode 100644 index 0000000000..7acc6322d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class AmqPlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "AMQPLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return AmqPlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java new file mode 100644 index 0000000000..7842f376fb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java @@ -0,0 +1,129 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); + String username = (String) ft.getString("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.getString("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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java new file mode 100644 index 0000000000..67d20136bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java new file mode 100644 index 0000000000..97f9a4e91a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return CRAMMD5HashedSaslServer.MECHANISM; + } + + public Class getServerFactoryClassForJCARegistration() + { + return CRAMMD5HashedServerFactory.class; + } + + public void initialise(PrincipalDatabase passwordFile) + { + super.initialise(passwordFile); + } + + public Map getProperties() + { + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java new file mode 100644 index 0000000000..f6cab084ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.CallbackHandler; +import java.util.Enumeration; +import java.util.Map; + +public class CRAMMD5HashedSaslServer implements SaslServer +{ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + private SaslServer _realServer; + + public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + Enumeration factories = Sasl.getSaslServerFactories(); + + while (factories.hasMoreElements()) + { + SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); + + if (factory instanceof CRAMMD5HashedServerFactory) + { + continue; + } + + String[] mechs = factory.getMechanismNames(props); + + for (String mech : mechs) + { + if (mech.equals("CRAM-MD5")) + { + _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); + return; + } + } + } + + throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return _realServer.evaluateResponse(response); + } + + public boolean isComplete() + { + return _realServer.isComplete(); + } + + public String getAuthorizationID() + { + return _realServer.getAuthorizationID(); + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return _realServer.unwrap(incoming, offset, len); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return _realServer.wrap(outgoing, offset, len); + } + + public Object getNegotiatedProperty(String propName) + { + return _realServer.getNegotiatedProperty(propName); + } + + public void dispose() throws SaslException + { + _realServer.dispose(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java new file mode 100644 index 0000000000..5298b5cc63 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5HashedServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) + { + return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java new file mode 100644 index 0000000000..264832888d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5Initialiser extends UsernamePasswordInitialiser +{ + private HashDirection _hashDirection; + + public enum HashDirection + { + INCOMMING, PASSWORD_FILE + } + + + 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. + if (_hashDirection == HashDirection.PASSWORD_FILE) + { + return null; + } + else + { + //fixme we need a server that will correctly has the incomming plain text for comparison to file. + _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); + return null; + } + } + + public void initialise(PrincipalDatabase passwordFile) + { + initialise(passwordFile, HashDirection.PASSWORD_FILE); + } + + public void initialise(PrincipalDatabase passwordFile, HashDirection direction) + { + super.initialise(passwordFile); + + _hashDirection = direction; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java new file mode 100644 index 0000000000..1d16cd8755 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class PlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "PLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return PlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java new file mode 100644 index 0000000000..36aeb77fe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -0,0 +1,149 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java new file mode 100644 index 0000000000..f0dd9eeb6d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java new file mode 100644 index 0000000000..f427cc7206 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +/** + * States used in the AMQ protocol. Used by the finite state machine to determine + * valid responses. + */ +public enum AMQState +{ + CONNECTION_NOT_STARTED, + CONNECTION_NOT_AUTH, + CONNECTION_NOT_TUNED, + CONNECTION_NOT_OPENED, + CONNECTION_OPEN, + CONNECTION_CLOSING, + CONNECTION_CLOSED +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java new file mode 100644 index 0000000000..c5b3099f58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -0,0 +1,263 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.handler.BasicAckMethodHandler; +import org.apache.qpid.server.handler.BasicCancelMethodHandler; +import org.apache.qpid.server.handler.BasicConsumeMethodHandler; +import org.apache.qpid.server.handler.BasicGetMethodHandler; +import org.apache.qpid.server.handler.BasicPublishMethodHandler; +import org.apache.qpid.server.handler.BasicQosHandler; +import org.apache.qpid.server.handler.BasicRecoverMethodHandler; +import org.apache.qpid.server.handler.BasicRejectMethodHandler; +import org.apache.qpid.server.handler.ChannelCloseHandler; +import org.apache.qpid.server.handler.ChannelCloseOkHandler; +import org.apache.qpid.server.handler.ChannelFlowHandler; +import org.apache.qpid.server.handler.ChannelOpenHandler; +import org.apache.qpid.server.handler.ConnectionCloseMethodHandler; +import org.apache.qpid.server.handler.ConnectionCloseOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionOpenMethodHandler; +import org.apache.qpid.server.handler.ConnectionSecureOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionStartOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionTuneOkMethodHandler; +import org.apache.qpid.server.handler.ExchangeBoundHandler; +import org.apache.qpid.server.handler.ExchangeDeclareHandler; +import org.apache.qpid.server.handler.ExchangeDeleteHandler; +import org.apache.qpid.server.handler.QueueBindHandler; +import org.apache.qpid.server.handler.QueueDeclareHandler; +import org.apache.qpid.server.handler.QueueDeleteHandler; +import org.apache.qpid.server.handler.QueuePurgeHandler; +import org.apache.qpid.server.handler.TxCommitHandler; +import org.apache.qpid.server.handler.TxRollbackHandler; +import org.apache.qpid.server.handler.TxSelectHandler; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +/** + * 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); + + private final VirtualHostRegistry _virtualHostRegistry; + private final AMQProtocolSession _protocolSession; + /** The current state */ + private AMQState _currentState; + + /** + * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of + * AMQFrame. + */ +/* private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = + new EnumMap, StateAwareMethodListener>>( + AMQState.class); + */ + + + private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); + + public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) + { + + _virtualHostRegistry = virtualHostRegistry; + _protocolSession = protocolSession; + _currentState = AMQState.CONNECTION_NOT_STARTED; + + } + + /* + protected void registerListeners() + { + Map, StateAwareMethodListener> frame2handlerMap; + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_AUTH, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _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>(); + ChannelOpenHandler.getInstance(); + ChannelCloseHandler.getInstance(); + ChannelCloseOkHandler.getInstance(); + ConnectionCloseMethodHandler.getInstance(); + ConnectionCloseOkMethodHandler.getInstance(); + ConnectionTuneOkMethodHandler.getInstance(); + ConnectionSecureOkMethodHandler.getInstance(); + ConnectionStartOkMethodHandler.getInstance(); + ExchangeDeclareHandler.getInstance(); + ExchangeDeleteHandler.getInstance(); + ExchangeBoundHandler.getInstance(); + BasicAckMethodHandler.getInstance(); + BasicRecoverMethodHandler.getInstance(); + BasicConsumeMethodHandler.getInstance(); + BasicGetMethodHandler.getInstance(); + BasicCancelMethodHandler.getInstance(); + BasicPublishMethodHandler.getInstance(); + BasicQosHandler.getInstance(); + QueueBindHandler.getInstance(); + QueueDeclareHandler.getInstance(); + QueueDeleteHandler.getInstance(); + QueuePurgeHandler.getInstance(); + ChannelFlowHandler.getInstance(); + TxSelectHandler.getInstance(); + TxCommitHandler.getInstance(); + TxRollbackHandler.getInstance(); + BasicRejectMethodHandler.getInstance(); + + _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + + _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(Exception e) + { + _logger.error("State manager received error notification[Current State:" + _currentState + "]: " + e, e); + for (StateListener l : _stateListeners) + { + l.error(e); + } + } + + public boolean methodReceived(AMQMethodEvent evt) throws AMQException + { + MethodDispatcher dispatcher = _protocolSession.getMethodDispatcher(); + + final int channelId = evt.getChannelId(); + B body = evt.getMethod(); + + if(channelId != 0 && _protocolSession.getChannel(channelId)== null) + { + + if(! ((body instanceof ChannelOpenBody) + || (body instanceof ChannelCloseOkBody) + || (body instanceof ChannelCloseBody))) + { + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "channel is closed"); + } + + } + + return body.execute(dispatcher, channelId); + + } + + private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) + throws AMQException + { + if ((evt.getChannelId() != 0) && !(evt.getMethod() instanceof ChannelOpenBody) + && (protocolSession.getChannel(evt.getChannelId()) == null) + && !protocolSession.channelAwaitingClosure(evt.getChannelId())) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + } + +/* + protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, + B frame) + // throws IllegalStateTransitionException + { + final Map, StateAwareMethodListener> classToHandlerMap = + _state2HandlersMap.get(currentState); + + final StateAwareMethodListener handler = + (classToHandlerMap == null) ? null : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); + + if (handler == null) + { + _logger.debug("No state transition handler defined for receiving frame " + frame); + + return null; + } + else + { + return handler; + } + } +*/ + + public void addStateListener(StateListener listener) + { + _logger.debug("Adding state listener"); + _stateListeners.add(listener); + } + + public void removeStateListener(StateListener listener) + { + _stateListeners.remove(listener); + } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java new file mode 100644 index 0000000000..cec67a8a6d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; + +/** + * @todo Not an AMQP exception as no status code. + * + * @todo Not used! Delete. + */ +public class IllegalStateTransitionException extends AMQException +{ + private AMQState _originalState; + + private Class _frame; + + public IllegalStateTransitionException(AMQState originalState, Class frame) + { + super("No valid state transition defined for receiving frame " + frame + " from state " + originalState); + _originalState = originalState; + _frame = frame; + } + + public AMQState getOriginalState() + { + return _originalState; + } + + public Class getFrameClass() + { + return _frame; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java new file mode 100644 index 0000000000..3c11bb8a9c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * 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, B evt, int channelId) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java new file mode 100644 index 0000000000..00fc09867b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; + +public interface StateListener +{ + void stateChanged(AMQState oldState, AMQState newState) throws AMQException; + + void error(Throwable t); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java new file mode 100644 index 0000000000..4664fd5e14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -0,0 +1,1445 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.QueueRegistry; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +import java.io.File; +import java.io.ByteArrayInputStream; +import java.sql.DriverManager; +import java.sql.Driver; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Blob; +import java.sql.Types; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; + + +public class DerbyMessageStore implements MessageStore +{ + + private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); + + private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; + + + private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; + + private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION"; + + private static final String EXCHANGE_TABLE_NAME = "QPID_EXCHANGE"; + private static final String QUEUE_TABLE_NAME = "QPID_QUEUE"; + private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS"; + private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY"; + private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA"; + private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; + + private static final int DB_VERSION = 1; + + + + private VirtualHost _virtualHost; + private static Class DRIVER_CLASS; + + private final AtomicLong _messageId = new AtomicLong(1); + private AtomicBoolean _closed = new AtomicBoolean(false); + + private String _connectionURL; + + + + private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; + private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; + private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; + private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; + private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; + private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; + private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; + private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; + private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; + private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; + private static final String SELECT_FROM_BINDINGS = + "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; + private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; + private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; + private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; + private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; + private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; + private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; + private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; + private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; + private static final String SELECT_FROM_MESSAGE_META_DATA = + "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_FROM_MESSAGE_CONTENT = + "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; + private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; + private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; + + + private enum State + { + INITIAL, + CONFIGURING, + RECOVERING, + STARTED, + CLOSING, + CLOSED + } + + private State _state = State.INITIAL; + + + public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception + { + stateTransition(State.INITIAL, State.CONFIGURING); + + initialiseDriver(); + + _virtualHost = virtualHost; + + _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + final String databasePath = config.getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + + File environmentPath = new File(databasePath); + if (!environmentPath.exists()) + { + if (!environmentPath.mkdirs()) + { + throw new IllegalArgumentException("Environment path " + environmentPath + " could not be read or created. " + + "Ensure the path is correct and that the permissions are correct."); + } + } + + createOrOpenDatabase(databasePath); + + // this recovers durable queues and persistent messages + + recover(); + + stateTransition(State.RECOVERING, State.STARTED); + + } + + private static synchronized void initialiseDriver() throws ClassNotFoundException + { + if(DRIVER_CLASS == null) + { + DRIVER_CLASS = (Class) Class.forName(SQL_DRIVER_NAME); + } + } + + private void createOrOpenDatabase(final String environmentPath) throws SQLException + { + _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; + + Connection conn = newConnection(); + + createVersionTable(conn); + createExchangeTable(conn); + createQueueTable(conn); + createBindingsTable(conn); + createQueueEntryTable(conn); + createMessageMetaDataTable(conn); + createMessageContentTable(conn); + + conn.close(); + } + + + + private void createVersionTable(final Connection conn) throws SQLException + { + if(!tableExists(DB_VERSION_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + + stmt.execute(CREATE_DB_VERSION_TABLE); + stmt.close(); + + PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); + pstmt.setInt(1, DB_VERSION); + pstmt.execute(); + pstmt.close(); + } + + } + + + private void createExchangeTable(final Connection conn) throws SQLException + { + if(!tableExists(EXCHANGE_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + + stmt.execute(CREATE_EXCHANGE_TABLE); + stmt.close(); + } + } + + private void createQueueTable(final Connection conn) throws SQLException + { + if(!tableExists(QUEUE_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_QUEUE_TABLE); + stmt.close(); + } + } + + private void createBindingsTable(final Connection conn) throws SQLException + { + if(!tableExists(BINDINGS_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_BINDINGS_TABLE); + + stmt.close(); + } + + } + + private void createQueueEntryTable(final Connection conn) throws SQLException + { + if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_QUEUE_ENTRY_TABLE); + + stmt.close(); + } + + } + + private void createMessageMetaDataTable(final Connection conn) throws SQLException + { + if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); + + stmt.close(); + } + + } + + + private void createMessageContentTable(final Connection conn) throws SQLException + { + if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); + + stmt.close(); + } + + } + + + + private boolean tableExists(final String tableName, final Connection conn) throws SQLException + { + PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); + stmt.setString(1, tableName); + ResultSet rs = stmt.executeQuery(); + boolean exists = rs.next(); + rs.close(); + stmt.close(); + return exists; + } + + public void recover() throws AMQException + { + stateTransition(State.CONFIGURING, State.RECOVERING); + + _logger.info("Recovering persistent state..."); + StoreContext context = new StoreContext(); + + try + { + Map queues = loadQueues(); + + recoverExchanges(); + + try + { + + beginTran(context); + + deliverMessages(context, queues); + _logger.info("Persistent state recovered successfully"); + commitTran(context); + + } + finally + { + if(inTran(context)) + { + abortTran(context); + } + } + } + catch (SQLException e) + { + + throw new AMQException("Error recovering persistent state: " + e, e); + } + + } + + private Map loadQueues() throws SQLException, AMQException + { + Connection conn = newConnection(); + + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); + Map queueMap = new HashMap(); + while(rs.next()) + { + String queueName = rs.getString(1); + String owner = rs.getString(2); + AMQShortString queueNameShortString = new AMQShortString(queueName); + AMQQueue q = new AMQQueue(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost); + _virtualHost.getQueueRegistry().registerQueue(q); + queueMap.put(queueNameShortString,q); + + } + return queueMap; + } + + private void recoverExchanges() throws AMQException, SQLException + { + for (Exchange exchange : loadExchanges()) + { + recoverExchange(exchange); + } + } + + + private List loadExchanges() throws AMQException, SQLException + { + + List exchanges = new ArrayList(); + Connection conn = null; + try + { + conn = newConnection(); + + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); + + Exchange exchange; + while(rs.next()) + { + String exchangeName = rs.getString(1); + String type = rs.getString(2); + boolean autoDelete = rs.getShort(3) != 0; + + exchange = _virtualHost.getExchangeFactory().createExchange(new AMQShortString(exchangeName), new AMQShortString(type), true, autoDelete, 0); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + exchanges.add(exchange); + + } + return exchanges; + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + + } + + private void recoverExchange(Exchange exchange) throws AMQException, SQLException + { + _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "..."); + + QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + + Connection conn = null; + try + { + conn = newConnection(); + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); + stmt.setString(1, exchange.getName().toString()); + + ResultSet rs = stmt.executeQuery(); + + + while(rs.next()) + { + String queueName = rs.getString(1); + String bindingKey = rs.getString(2); + Blob arguments = rs.getBlob(3); + + + AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " + + exchange.getName()); + } + else + { + _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + arguments + + ")"); + + FieldTable argumentsFT = null; + if(arguments != null) + { + byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length()); + ByteBuffer buf = ByteBuffer.wrap(argumentBytes); + argumentsFT = new FieldTable(buf,arguments.length()); + } + + queue.bind(bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT, exchange); + } + } + } + finally + { + if(conn != null) + { + conn.close(); + } + } + } + + public void close() throws Exception + { + _closed.getAndSet(true); + } + + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + { + + boolean localTx = getOrCreateTransaction(storeContext); + + Connection conn = getConnection(storeContext); + ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload(); + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Message Id: " + messageId + " Removing"); + } + + // first we need to look up the header to get the chunk count + MessageMetaData mmd = getMessageMetaData(storeContext, messageId); + try + { + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + wrapper.setRequiresCommit(); + int results = stmt.executeUpdate(); + + if (results == 0) + { + if (localTx) + { + abortTran(storeContext); + } + + throw new AMQException("Message metadata not found for message id " + messageId); + } + stmt.close(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Deleted metadata for message " + messageId); + } + + stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + results = stmt.executeUpdate(); + + if(results != mmd.getContentChunkCount()) + { + if (localTx) + { + abortTran(storeContext); + } + throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results); + + } + + if (localTx) + { + commitTran(storeContext); + } + } + catch (SQLException e) + { + if ((conn != null) && localTx) + { + abortTran(storeContext); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (_state != State.RECOVERING) + { + try + { + Connection conn = null; + + try + { + conn = newConnection(); + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + stmt.setString(1, exchange.getName().toString()); + stmt.setString(2, exchange.getType().toString()); + stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); + stmt.execute(); + stmt.close(); + conn.commit(); + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + } + catch (SQLException e) + { + throw new AMQException("Error writing Exchange with name " + exchange.getName() + " to database: " + e, e); + } + } + + } + + public void removeExchange(Exchange exchange) throws AMQException + { + Connection conn = null; + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); + stmt.setString(1, exchange.getName().toString()); + int results = stmt.executeUpdate(); + if(results == 0) + { + throw new AMQException("Exchange " + exchange.getName() + " not found"); + } + else + { + conn.commit(); + stmt.close(); + } + } + catch (SQLException e) + { + throw new AMQException("Error writing deleting with name " + exchange.getName() + " from database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + throws AMQException + { + if (_state != State.RECOVERING) + { + Connection conn = null; + + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + stmt.setString(1, exchange.getName().toString() ); + stmt.setString(2, queue.getName().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + if(args != null) + { + /* This would be the Java 6 way of setting a Blob + Blob blobArgs = conn.createBlob(); + blobArgs.setBytes(0, args.getDataAsBytes()); + stmt.setBlob(4, blobArgs); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(args.getDataAsBytes()); + stmt.setBinaryStream(4, bis); + } + else + { + stmt.setNull(4, Types.BLOB); + } + + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing binding for AMQQueue with name " + queue.getName() + " to exchange " + + exchange.getName() + " to database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + } + + + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + throws AMQException + { + Connection conn = null; + + + try + { + conn = newConnection(); + // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); + stmt.setString(1, exchange.getName().toString() ); + stmt.setString(2, queue.getName().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + + + if(stmt.executeUpdate() != 1) + { + throw new AMQException("Queue binding for queue with name " + queue.getName() + " to exchange " + + exchange.getName() + " not found"); + } + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error removing binding for AMQQueue with name " + queue.getName() + " to exchange " + + exchange.getName() + " in database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + + } + + public void createQueue(AMQQueue queue) throws AMQException + { + _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); + + if (_state != State.RECOVERING) + { + try + { + Connection conn = newConnection(); + + PreparedStatement stmt = + conn.prepareStatement(INSERT_INTO_QUEUE); + + stmt.setString(1, queue.getName().toString()); + stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); + + stmt.execute(); + + stmt.close(); + + conn.commit(); + + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing AMQQueue with name " + queue.getName() + " to database: " + e, e); + } + } + } + + private Connection newConnection() throws SQLException + { + final Connection connection = DriverManager.getConnection(_connectionURL); + return connection; + } + + public void removeQueue(AMQShortString name) throws AMQException + { + + _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); + Connection conn = null; + + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); + stmt.setString(1, name.toString()); + int results = stmt.executeUpdate(); + + + if (results == 0) + { + throw new AMQException("Queue " + name + " not found"); + } + + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing deleting with name " + name + " from database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + + } + + public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + { + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); + stmt.setString(1,name.toString()); + stmt.setLong(2,messageId); + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + _logger.error("Failed to enqueue: " + e, e); + throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name + + " to database", e); + } + + } + + public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + { + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); + stmt.setString(1,name.toString()); + stmt.setLong(2,messageId); + int results = stmt.executeUpdate(); + + connWrapper.requiresCommit(); + + if(results != 1) + { + throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); + } + + if(localTx) + { + commitTran(context); + } + + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + _logger.error("Failed to dequeue: " + e, e); + throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name + + " from database", e); + } + + } + + private static final class ConnectionWrapper + { + private final Connection _connection; + private boolean _requiresCommit; + + public ConnectionWrapper(Connection conn) + { + _connection = conn; + } + + public void setRequiresCommit() + { + _requiresCommit = true; + } + + public boolean requiresCommit() + { + return _requiresCommit; + } + + public Connection getConnection() + { + return _connection; + } + } + + public void beginTran(StoreContext context) throws AMQException + { + if (context.getPayload() != null) + { + throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: " + + context.getPayload()); + } + else + { + try + { + Connection conn = newConnection(); + + + context.setPayload(new ConnectionWrapper(conn)); + } + catch (SQLException e) + { + throw new AMQException("Error starting transaction: " + e, e); + } + } + } + + public void commitTran(StoreContext context) throws AMQException + { + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + if (connWrapper == null) + { + throw new AMQException("Fatal internal error: transactional context is empty at commitTran"); + } + + try + { + Connection conn = connWrapper.getConnection(); + if(connWrapper.requiresCommit()) + { + conn.commit(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("commit tran completed"); + } + + } + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error commit tx: " + e, e); + } + finally + { + context.setPayload(null); + } + } + + public void abortTran(StoreContext context) throws AMQException + { + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + if (connWrapper == null) + { + throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("abort tran called: " + connWrapper.getConnection()); + } + + try + { + Connection conn = connWrapper.getConnection(); + if(connWrapper.requiresCommit()) + { + conn.rollback(); + } + + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error aborting transaction: " + e, e); + } + finally + { + context.setPayload(null); + } + } + + public boolean inTran(StoreContext context) + { + return context.getPayload() != null; + } + + public Long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public void storeContentBodyChunk(StoreContext context, + Long messageId, + int index, + ContentChunk contentBody, + boolean lastContentBody) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, index); + byte[] chunkData = new byte[contentBody.getSize()]; + contentBody.getData().duplicate().get(chunkData); + /* this would be the Java 6 way of doing things + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, chunkData); + stmt.setBlob(3, dataAsBlob); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); + stmt.setBinaryStream(3, bis); + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd) + throws AMQException + { + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); + stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); + stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0); + stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0); + + ContentHeaderBody headerBody = mmd.getContentHeaderBody(); + final int bodySize = headerBody.getSize(); + byte[] underlying = new byte[bodySize]; + ByteBuffer buf = ByteBuffer.wrap(underlying); + headerBody.writePayload(buf); +/* + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, underlying); + stmt.setBlob(6, dataAsBlob); +*/ + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(6,bis); + + stmt.setInt(7, mmd.getContentChunkCount()); + + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + + } + + public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + + + try + { + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + ResultSet rs = stmt.executeQuery(); + + if(rs.next()) + { + final AMQShortString exchange = new AMQShortString(rs.getString(1)); + final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); + final boolean mandatory = (rs.getShort(3) != (short)0); + final boolean immediate = (rs.getShort(4) != (short)0); + MessagePublishInfo info = new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public void setExchange(AMQShortString exchange) + { + + } + + public boolean isImmediate() + { + return immediate; + } + + public boolean isMandatory() + { + return mandatory; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + } ; + + Blob dataAsBlob = rs.getBlob(5); + + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length); + + if(localTx) + { + commitTran(context); + } + + return new MessageMetaData(info, chb, rs.getInt(6)); + + } + else + { + if(localTx) + { + abortTran(context); + } + throw new AMQException("Metadata not found for message with id " + messageId); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } + + + } + + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + + + try + { + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, index); + ResultSet rs = stmt.executeQuery(); + + if(rs.next()) + { + Blob dataAsBlob = rs.getBlob(1); + + final int size = (int) dataAsBlob.length(); + byte[] dataAsBytes = dataAsBlob.getBytes(1, size); + final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + + ContentChunk cb = new ContentChunk() + { + + public int getSize() + { + return size; + } + + public ByteBuffer getData() + { + return buf; + } + + public void reduceToFit() + { + + } + }; + + if(localTx) + { + commitTran(context); + } + + return cb; + + } + else + { + if(localTx) + { + abortTran(context); + } + throw new AMQException("Message not found for message with id " + messageId); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } + + + + } + + private void checkNotClosed() throws MessageStoreClosedException + { + if (_closed.get()) + { + throw new MessageStoreClosedException(); + } + } + + + private static final class ProcessAction + { + private final AMQQueue _queue; + private final StoreContext _context; + private final AMQMessage _message; + + public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message) + { + _queue = queue; + _context = context; + _message = message; + } + + public void process() throws AMQException + { + _queue.process(_context, _queue.createEntry(_message), false); + } + + } + + + private void deliverMessages(final StoreContext context, Map queues) + throws SQLException, AMQException + { + Map msgMap = new HashMap(); + List actions = new ArrayList(); + + Map queueRecoveries = new TreeMap(); + + final boolean inLocaltran = inTran(context); + Connection conn = null; + try + { + + if(inLocaltran) + { + conn = getConnection(context); + } + else + { + conn = newConnection(); + } + + + MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); + long maxId = 1; + + TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + + + while (rs.next()) + { + + + + AMQShortString queueName = new AMQShortString(rs.getString(1)); + + + AMQQueue queue = queues.get(queueName); + if (queue == null) + { + queue = new AMQQueue(queueName, false, null, false, _virtualHost); + _virtualHost.getQueueRegistry().registerQueue(queue); + queues.put(queueName, queue); + } + + long messageId = rs.getLong(2); + maxId = Math.max(maxId, messageId); + AMQMessage message = msgMap.get(messageId); + + if(message != null) + { + message.incrementReference(); + } + else + { + message = new AMQMessage(messageId, this, messageHandleFactory, txnContext); + msgMap.put(messageId,message); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); + } + + if (_logger.isInfoEnabled()) + { + Integer count = queueRecoveries.get(queueName); + if (count == null) + { + count = 0; + } + + queueRecoveries.put(queueName, ++count); + + } + + actions.add(new ProcessAction(queue, context, message)); + + } + + for(ProcessAction action : actions) + { + action.process(); + } + + _messageId.set(maxId + 1); + } + catch (SQLException e) + { + _logger.error("Error: " + e, e); + throw e; + } + finally + { + if (inLocaltran && conn != null) + { + conn.close(); + } + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Recovered message counts: " + queueRecoveries); + } + } + + private Connection getConnection(final StoreContext context) + { + return ((ConnectionWrapper)context.getPayload()).getConnection(); + } + + private boolean getOrCreateTransaction(StoreContext context) throws AMQException + { + + ConnectionWrapper tx = (ConnectionWrapper) context.getPayload(); + if (tx == null) + { + beginTran(context); + return true; + } + + return false; + } + + private synchronized void stateTransition(State requiredState, State newState) throws AMQException + { + if (_state != requiredState) + { + throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + + "; currently in state: " + _state); + } + + _state = newState; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java new file mode 100644 index 0000000000..7a6e0b011f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -0,0 +1,223 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; +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); + private AtomicBoolean _closed = new AtomicBoolean(false); + + 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(VirtualHost virtualHost, String base, Configuration config) throws Exception + { + configure(base, config); + } + + public void close() throws Exception + { + _closed.getAndSet(true); + if (_metaDataMap != null) + { + _metaDataMap.clear(); + _metaDataMap = null; + } + if (_contentBodyMap != null) + { + _contentBodyMap.clear(); + _contentBodyMap = null; + } + } + + public void removeMessage(StoreContext context, Long messageId) throws AMQException + { + checkNotClosed(); + if (_log.isDebugEnabled()) + { + _log.debug("Removing message with id " + messageId); + } + _metaDataMap.remove(messageId); + _contentBodyMap.remove(messageId); + } + + public void createExchange(Exchange exchange) throws AMQException + { + + } + + public void removeExchange(Exchange exchange) throws AMQException + { + + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + + public void createQueue(AMQQueue queue) throws AMQException + { + // Not required to do anything + } + + public void removeQueue(AMQShortString name) throws AMQException + { + // Not required to do anything + } + + public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + { + // Not required to do anything + } + + public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + { + // Not required to do anything + } + + public void beginTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public void commitTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public void abortTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public boolean inTran(StoreContext context) + { + return false; + } + + public List createQueues() throws AMQException + { + return null; + } + + public Long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) + throws AMQException + { + checkNotClosed(); + List bodyList = _contentBodyMap.get(messageId); + + if (bodyList == null && lastContentBody) + { + _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); + } + else + { + if (bodyList == null) + { + bodyList = new ArrayList(); + _contentBodyMap.put(messageId, bodyList); + } + + bodyList.add(index, contentBody); + } + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) + throws AMQException + { + checkNotClosed(); + _metaDataMap.put(messageId, messageMetaData); + } + + public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + { + checkNotClosed(); + return _metaDataMap.get(messageId); + } + + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + { + checkNotClosed(); + List bodyList = _contentBodyMap.get(messageId); + return bodyList.get(index); + } + + private void checkNotClosed() throws MessageStoreClosedException + { + if (_closed.get()) + { + throw new MessageStoreClosedException(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java new file mode 100644 index 0000000000..2a83d9b649 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -0,0 +1,261 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues + * and exchanges in a transactional manner. + * + *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which + * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single + * transaction. + * + *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. + * + *

      + *
      CRC Card
      Responsibilities + *
      Accept transaction boundary demarcations: Begin, Commit, Abort. + *
      Store and remove queues. + *
      Store and remove exchanges. + *
      Store and remove messages. + *
      Bind and unbind queues to exchanges. + *
      Enqueue and dequeue messages to queues. + *
      Generate message identifiers. + *
      + */ +public interface MessageStore +{ + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param base The base element identifier from which all configuration items are relative. For example, if + * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws Exception If the close fails. + */ + void close() throws Exception; + + /** + * Removes the specified message from the store in the given transactional store context. + * + * @param storeContext The transactional context to remove the message in. + * @param messageId Identifies the message to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws AMQException If the operation fails for any reason. + */ + void createExchange(Exchange exchange) throws AMQException; + + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeExchange(Exchange exchange) throws AMQException; + + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + + /** + * Removes the specified queue from the persistent store. + * + * @param name The queue to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeQueue(AMQShortString name) throws AMQException; + + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param name The name of the queue to place the message on. + * @param messageId The message to enqueue. + * + * @throws AMQException If the operation fails for any reason. + */ + void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param name The name of the queue to take the message from. + * @param messageId The message to dequeue. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + + /** + * Begins a transactional context. + * + * @param context The transactional context to begin. + * + * @throws AMQException If the operation fails for any reason. + */ + void beginTran(StoreContext context) throws AMQException; + + /** + * Commits all operations performed within a given transactional context. + * + * @param context The transactional context to commit all operations for. + * + * @throws AMQException If the operation fails for any reason. + */ + void commitTran(StoreContext context) throws AMQException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @param context The transactional context to abandon. + * + * @throws AMQException If the operation fails for any reason. + */ + void abortTran(StoreContext context) throws AMQException; + + /** + * Tests a transactional context to see if it has been begun but not yet committed or aborted. + * + * @param context The transactional context to test. + * + * @return true if the transactional context is live, false otherwise. + */ + boolean inTran(StoreContext context); + + /** + * Return a valid, currently unused message id. + * + * @return A fresh message id. + */ + Long getNewMessageId(); + + /** + * Stores a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param index The index of the data chunk. + * @param contentBody The content of the data chunk. + * @param lastContentBody Flag to indicate that this is the last such chunk for the message. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, + boolean lastContentBody) throws AMQException; + + /** + * Stores message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param messageMetaData The message meta data to store. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; + + /** + * Retrieves message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the meta-data for. + * + * @return The message meta data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; + + /** + * Retrieves a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the data chunk for. + * @param index The offset index of the data chunk within the message. + * + * @return A chunk of message data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java new file mode 100644 index 0000000000..3d1538c7eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java @@ -0,0 +1,36 @@ +package org.apache.qpid.server.store; + +import org.apache.qpid.AMQException;/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * NOTE: this class currently extends AMQException but + * we should be using AMQExceptions internally in the code base for Protocol errors hence + * the message store interface should throw a different super class which this should be + * moved to reflect + */ +public class MessageStoreClosedException extends AMQException +{ + public MessageStoreClosedException() + { + super("Message store closed"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java new file mode 100644 index 0000000000..3ee49d58cf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.log4j.Logger; + +/** + * A context that the store can use to associate with a transactional context. For example, it could store + * some kind of txn id. + * + * @author Apache Software Foundation + */ +public class StoreContext +{ + private static final Logger _logger = Logger.getLogger(StoreContext.class); + + private String _name; + private Object _payload; + + public StoreContext() + { + _name = super.toString(); + } + + public StoreContext(String name) + { + _name = name; + } + + public Object getPayload() + { + return _payload; + } + + public void setPayload(Object payload) + { + _logger.debug("public void setPayload(Object payload = " + payload + "): called"); + _payload = payload; + } + + /** + * Prints out the transactional context as a string, mainly for debugging purposes. + * + * @return The transactional context as a string. + */ + public String toString() + { + return "<_name = " + _name + ", _payload = " + _payload + ">"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java new file mode 100644 index 0000000000..23aaf56876 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -0,0 +1,114 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.util.NewThreadExecutor; +import org.apache.qpid.configuration.Configured; +import org.apache.log4j.Logger; + +public class ConnectorConfiguration +{ + private static final Logger _logger = Logger.getLogger(ConnectorConfiguration.class); + + public static final String DEFAULT_PORT = "5672"; + + public static final String SSL_PORT = "8672"; + + @Configured(path = "connector.processors", + defaultValue = "4") + public int processors; + + @Configured(path = "connector.port", + defaultValue = DEFAULT_PORT) + public int port; + + @Configured(path = "connector.bind", + defaultValue = "wildcard") + public String bindAddress; + + @Configured(path = "connector.socketReceiveBuffer", + defaultValue = "32767") + public int socketReceiveBufferSize; + + @Configured(path = "connector.socketWriteBuffer", + defaultValue = "32767") + public int socketWriteBuferSize; + + @Configured(path = "connector.tcpNoDelay", + defaultValue = "true") + public boolean tcpNoDelay; + + @Configured(path = "advanced.filterchain[@enableExecutorPool]", + defaultValue = "false") + public boolean enableExecutorPool; + + @Configured(path = "advanced.enablePooledAllocator", + defaultValue = "false") + public boolean enablePooledAllocator; + + @Configured(path = "advanced.enableDirectBuffers", + defaultValue = "false") + public boolean enableDirectBuffers; + + @Configured(path = "connector.ssl.enabled", + defaultValue = "false") + public boolean enableSSL; + + @Configured(path = "connector.ssl.sslOnly", + defaultValue = "true") + public boolean sslOnly; + + @Configured(path = "connector.ssl.port", + defaultValue = SSL_PORT) + public int sslPort; + + @Configured(path = "connector.ssl.keystorePath", + defaultValue = "none") + public String keystorePath; + + @Configured(path = "connector.ssl.keystorePassword", + defaultValue = "none") + public String keystorePassword; + + @Configured(path = "connector.ssl.certType", + defaultValue = "SunX509") + public String certType; + + @Configured(path = "connector.qpidnio", + defaultValue = "false") + public boolean _multiThreadNIO; + + + public IoAcceptor createAcceptor() + { + if (_multiThreadNIO) + { + _logger.warn("Using Qpid Multithreaded IO Processing"); + return new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(processors, new NewThreadExecutor()); + } + else + { + _logger.warn("Using Mina IO Processing"); + return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java new file mode 100644 index 0000000000..bdd27f2d1c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -0,0 +1,705 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoFilterAdapter; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoSession; +import org.apache.mina.util.BlockingQueue; +import org.apache.mina.util.ByteBufferUtil; +import org.apache.mina.util.IdentityHashSet; +import org.apache.mina.util.Queue; +import org.apache.mina.util.Stack; + +/** + * 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); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java new file mode 100644 index 0000000000..988f589339 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.store.StoreContext; + +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(StoreContext context) 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(StoreContext context) + { + // No-op can't be done here has this is before the message has been attempted to be delivered. + /*try + { + _msg.checkDeliveredToConsumer(); + } + catch (NoConsumersException e) + { + _returns.add(e); + }*/ + } + + public void rollback(StoreContext context) + { + // NO OP + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java new file mode 100644 index 0000000000..2307b94566 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -0,0 +1,267 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.ack.TxAck; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +import java.util.LinkedList; +import java.util.List; + +/** A transactional context that only supports local transactions. */ +public class LocalTransactionalContext implements TransactionalContext +{ + private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); + + private final TxnBuffer _txnBuffer = new TxnBuffer(); + + private final List _postCommitDeliveryList = new LinkedList(); + + /** + * 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 final StoreContext _storeContext; + + private boolean _inTran = false; + + /** Are there messages to deliver. NOT Has the message been delivered */ + private boolean _messageDelivered = false; + + private static class DeliveryDetails + { + public QueueEntry entry; + + private boolean deliverFirst; + + public DeliveryDetails(QueueEntry entry, boolean deliverFirst) + { + this.entry = entry; + this.deliverFirst = deliverFirst; + } + } + + public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, + List returnMessages) + { + _messageStore = messageStore; + _storeContext = storeContext; + _returnMessages = returnMessages; + // _txnBuffer.enlist(new StoreMessageOperation(messageStore)); + } + + public StoreContext getStoreContext() + { + return _storeContext; + } + + public void rollback() throws AMQException + { + _txnBuffer.rollback(_storeContext); + // Hack to deal with uncommitted non-transactional writes + if (_messageStore.inTran(_storeContext)) + { + _messageStore.abortTran(_storeContext); + _inTran = false; + } + + _postCommitDeliveryList.clear(); + } + + public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException + { + // A publication will result in the enlisting of several + // TxnOps. The first is an op that will store the message. + // Following that (and ordering is important), an op will + // be added for every queue onto which the message is + // enqueued. Finally a cleanup op will be added to decrement + // the reference associated with the routing. + // message.incrementReference(); + _postCommitDeliveryList.add(new DeliveryDetails(entry, deliverFirst)); + _messageDelivered = true; + _txnBuffer.enlist(new CleanupMessageOperation(entry.getMessage(), _returnMessages)); + /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); + if (_log.isDebugEnabled()) + { + _log.debug("Incrementing ref count on message and enlisting cleanup operation - id " + + message.getMessageId()); + } + message.incrementReference(); + _messageDelivered = true; + + */ + } + + private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); + } + } + + public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + // check that the tag exists to give early failure + if (!multiple || (deliveryTag > 0)) + { + checkAck(deliveryTag, unacknowledgedMessageMap); + } + // we use a single txn op for all acks and update this op + // as new acks come in. If this is the first ack in the txn + // we will need to create and enlist the op. + if (_ackOp == null) + { + + _ackOp = new TxAck(unacknowledgedMessageMap); + + _txnBuffer.enlist(_ackOp); + } + // update the op to include this ack request + if (multiple && (deliveryTag == 0)) + { + // if have signalled to ack all, that refers only + // to all at this time + _ackOp.update(lastDeliveryTag, multiple); + } + else + { + _ackOp.update(deliveryTag, multiple); + } + if(!_inTran && _ackOp.checkPersistent()) + { + beginTranIfNecessary(); + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + // Not required in this transactional context + } + + public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + // Not required in this transactional context + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + if (_log.isDebugEnabled()) + { + _log.debug("Starting transaction on message store: " + this); + } + + _messageStore.beginTran(_storeContext); + _inTran = true; + } + } + + public void commit() throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Committing transactional context: " + this); + } + + if (_ackOp != null) + { + + _messageDelivered = true; + _ackOp.consolidate(); + // already enlisted, after commit will reset regardless of outcome + _ackOp = null; + } + + if (_messageDelivered && _inTran) + { + _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); + } + // fixme fail commit here ... QPID-440 + try + { + _txnBuffer.commit(_storeContext); + } + finally + { + _messageDelivered = false; + _inTran = _messageStore.inTran(_storeContext); + } + + try + { + postCommitDelivery(_returnMessages); + } + catch (AMQException e) + { + // OK so what do we do now...? + _log.error("Failed to deliver messages following txn commit: " + e, e); + } + } + + private void postCommitDelivery(List returnMessages) throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Performing post commit delivery"); + } + + try + { + for (DeliveryDetails dd : _postCommitDeliveryList) + { + dd.entry.process(_storeContext, dd.deliverFirst); + + try + { + dd.entry.checkDeliveredToConsumer(); + } + catch (NoConsumersException nce) + { + returnMessages.add(nce); + } + } + } + finally + { + _postCommitDeliveryList.clear(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java new file mode 100644 index 0000000000..cac3489f4c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -0,0 +1,233 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +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.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** @author Apache Software Foundation */ +public class NonTransactionalContext implements TransactionalContext +{ + private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); + + /** Channel is useful for logging */ + private final AMQChannel _channel; + + /** Where to put undeliverable messages */ + private final List _returnMessages; + + private final MessageStore _messageStore; + + private final StoreContext _storeContext; + + /** Whether we are in a transaction */ + private boolean _inTran; + + public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, + List returnMessages, Set browsedAcks) + { + this(messageStore,storeContext,channel,returnMessages); + } + + public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, + List returnMessages) + { + _channel = channel; + _storeContext = storeContext; + _returnMessages = returnMessages; + _messageStore = messageStore; + + } + + + public StoreContext getStoreContext() + { + return _storeContext; + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(_storeContext); + _inTran = true; + } + } + + public void commit() throws AMQException + { + // Does not apply to this context + } + + public void rollback() throws AMQException + { + // Does not apply to this context + } + + public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException + { + try + { + entry.process(_storeContext, deliverFirst); + //following check implements the functionality + //required by the 'immediate' flag: + entry.checkDeliveredToConsumer(); + } + catch (NoConsumersException e) + { + _returnMessages.add(e); + } + } + + public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, + boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) + throws AMQException + { + + final boolean debug = _log.isDebugEnabled(); + + if (multiple) + { + if (deliveryTag == 0) + { + + //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, + // tells the server to acknowledge all outstanding mesages. + _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + + unacknowledgedMessageMap.size()); + unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + if (debug) + { + _log.debug("Discarding message: " + message.getMessage().getMessageId()); + } + if(message.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } + //Message has been ack so discard it. This will dequeue and decrement the reference. + message.discard(_storeContext); + + return false; + } + + public void visitComplete() + { + unacknowledgedMessageMap.clear(); + } + }); + } + else + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + } + + LinkedList acked = new LinkedList(); + unacknowledgedMessageMap.drainTo(acked, deliveryTag); + for (UnacknowledgedMessage msg : acked) + { + if (debug) + { + _log.debug("Discarding message: " + msg.getMessage().getMessageId()); + } + if(msg.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(_storeContext); + } + } + } + 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()); + } + + if (debug) + { + _log.debug("Discarding message: " + msg.getMessage().getMessageId()); + } + if(msg.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(_storeContext); + + if (debug) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + + msg.getMessage().getMessageId()); + } + } + + if(_inTran) + { + _messageStore.commitTran(_storeContext); + _inTran = false; + } + + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + if (persistent) + { + _messageStore.commitTran(_storeContext); + _inTran = false; + } + } + + public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + _channel.processReturns(protocolSession); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java new file mode 100644 index 0000000000..0e4d6c2030 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** + * A transactional operation to store messages in an underlying persistent store. When this operation + * commits it will do everything to ensure that all messages are safely committed to persistent + * storage. + */ +public class StoreMessageOperation implements TxnOp +{ + private final MessageStore _messsageStore; + + public StoreMessageOperation(MessageStore messageStore) + { + _messsageStore = messageStore; + } + + public void prepare(StoreContext context) throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit(StoreContext context) throws AMQException + { + _messsageStore.commitTran(context); + } + + public void rollback(StoreContext context) throws AMQException + { + _messsageStore.abortTran(context); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java new file mode 100644 index 0000000000..6016ecc1a5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -0,0 +1,170 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; + +/** + * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. + * Different levels of transactional support for the delivery of messages may be provided by different implementations + * of this interface. + * + *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. + * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} + * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. + * + *

      + *
      CRC Card
      Responsibilities + *
      Explicitly accept a transaction start notification. + *
      Commit all pending operations in a transaction. + *
      Rollback all pending operations in a transaction. + *
      Deliver a message to a queue as part of a transaction. + *
      Redeliver a message to a queue as part of a transaction. + *
      Mark a message as acknowledged as part of a transaction. + *
      Accept notification that a message has been completely received as part of a transaction. + *
      Accept notification that a message has been fully processed as part of a transaction. + *
      Associate a message store context with this transaction context. + *
      + * + * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional + * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them + * somewhere else, a seperate interface for example. + * + * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides + * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any + * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean + * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be + * conceptually neater. + * + * For example: + *

      + * public interface Transactional
      + * {
      + *    public void commit();
      + *    public void rollback();
      + * }
      + *
      + * public interface TransactionalQueue extends Transactional, SizeableQueue
      + * {}
      + *
      + * public class Queues
      + * {
      + *    ...
      + *    // For transactional messaging, take a transactional view onto the queue.
      + *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      + *
      + *    // For non-transactional messaging, take a non-transactional view onto the queue.
      + *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      + * }
      + * 
      + */ +public interface TransactionalContext +{ + /** + * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} + * should automatically begin the next transaction in the chain. + * + * @throws AMQException If the transaction cannot be started for any reason. + */ + void beginTranIfNecessary() throws AMQException; + + /** + * Makes all pending operations on the transaction permanent and visible. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ + void commit() throws AMQException; + + /** + * Erases all pending operations on the transaction. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ + void rollback() throws AMQException; + + /** + * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a + * redelivery, and should be placed on the front of the queue. + * + *

      This is an 'enqueue' operation. + * + * @param entry The message to deliver, and the queue to deliver to. + * @param deliverFirst true to place the message on the front of the queue for redelivery, false + * for normal FIFO message ordering. + * + * @throws AMQException If the message cannot be delivered for any reason. + */ + void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException; + + /** + * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by + * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' + * flag is set, in which case an acknowledgement up to the latest delivered message should be done. + * + *

      This is a 'dequeue' operation. + * + * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement + * up to the latest message. + * @param lastDeliveryTag The latest message delivered. + * @param multiple true if all message ids up the acknowledged one or latest delivered, are + * to be acknowledged, false otherwise. + * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message + * from. + * + * @throws AMQException If the message cannot be acknowledged for any reason. + */ + void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + + /** + * Notifies the transactional context that a message has been fully received. The actual message that was received + * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, + * flushing its data to disk. + * + * @param persistent true if the received message is persistent, false otherwise. + * + * @throws AMQException If the fully received event cannot be processed for any reason. + */ + void messageFullyReceived(boolean persistent) throws AMQException; + + /** + * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual + * message that was delivered is not specified. This event may be used to trigger a process related to the + * outcome of the delivery of the message, for example, cleaning up failed deliveries. + * + * @param protocolSession The protocol session of the deliverable message. + * + * @throws AMQException If the message processed event cannot be handled for any reason. + */ + void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; + + /** + * Gets the message store context associated with this transactional context. + * + * @return The message store context associated with this transactional context. + */ + StoreContext getStoreContext(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java new file mode 100644 index 0000000000..46a68b6a23 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -0,0 +1,109 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; + +/** Holds a list of TxnOp instance representing transactional operations. */ +public class TxnBuffer +{ + private final List _ops = new ArrayList(); + private static final Logger _log = Logger.getLogger(TxnBuffer.class); + + public TxnBuffer() + { + } + + public void commit(StoreContext context) throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); + } + + if (prepare(context)) + { + for (TxnOp op : _ops) + { + op.commit(context); + } + } + _ops.clear(); + } + + private boolean prepare(StoreContext context) throws AMQException + { + for (int i = 0; i < _ops.size(); i++) + { + TxnOp op = _ops.get(i); + try + { + op.prepare(context); + } + catch (AMQException e) + { + undoPrepare(i); + throw e; + } + catch (RuntimeException e) + { + undoPrepare(i); + throw e; + } + } + return true; + } + + private void undoPrepare(int lastPrepared) + { + //compensate previously prepared ops + for (int j = 0; j < lastPrepared; j++) + { + _ops.get(j).undoPrepare(); + } + } + + + + public void rollback(StoreContext context) throws AMQException + { + for (TxnOp op : _ops) + { + op.rollback(context); + } + _ops.clear(); + } + + public void enlist(TxnOp op) + { + _ops.add(op); + } + + public void cancel(TxnOp op) + { + _ops.remove(op); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java new file mode 100644 index 0000000000..919c078cf0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; + +/** + * This provides the abstraction of an individual operation within a + * transaction. It is used by the TxnBuffer class. + */ +public interface TxnOp +{ + /** + * Do the part of the operation that updates persistent state + */ + public void prepare(StoreContext context) throws AMQException; + /** + * Complete the operation started by prepare. Can now update in + * memory state or make netork transfers. + */ + public void commit(StoreContext context) throws AMQException; + /** + * This is not the same as rollback. Unfortunately the use of an + * in memory reference count as a locking mechanism and a test for + * whether a message should be deleted means that as things are, + * handling an acknowledgement unavoidably alters both memory and + * persistent state on prepare. This is needed to 'compensate' or + * undo the in-memory change if the peristent update of later ops + * fails. + */ + public void undoPrepare(); + /** + * Rolls back the operation. + */ + public void rollback(StoreContext context) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java new file mode 100644 index 0000000000..e730e2f3c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java @@ -0,0 +1,131 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +public class CircularBuffer implements Iterable +{ + + private static final Logger _logger = Logger.getLogger(CircularBuffer.class); + + 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) + { + _logger.info(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); + _logger.info(buffer); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java new file mode 100644 index 0000000000..cf5e71a6e2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue +{ + public int size() + { + if (isEmpty()) + { + return 0; + } + else + { + return 1; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java new file mode 100644 index 0000000000..eda97e0ed2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +/** + * Dynamic proxy that records invocations in a fixed size circular buffer, + * dumping details on hitting an exception. + *

      + * Useful in debugging. + *

      + */ +public class LoggingProxy implements InvocationHandler +{ + private final Object _target; + private final CircularBuffer _log; + + public LoggingProxy(Object target, int size) + { + _target = target; + _log = new CircularBuffer(size); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + try + { + entered(method, args); + Object result = method.invoke(_target, args); + returned(method, result); + return result; + } + catch(InvocationTargetException e) + { + dump(); + throw e.getTargetException(); + } + } + + void dump() + { + _log.dump(); + } + + CircularBuffer getBuffer() + { + return _log; + } + + private synchronized void entered(Method method, Object[] args) + { + if (args == null) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); + } + } + + private synchronized void returned(Method method, Object result) + { + if (method.getReturnType() == Void.TYPE) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); + } + } + + public Object getProxy(Class... c) + { + return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); + } + + public int getBufferSize() { + return _log.size(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java new file mode 100644 index 0000000000..0acfa84f31 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -0,0 +1,131 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Properties; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.MapConfiguration; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +public class NullApplicationRegistry extends ApplicationRegistry +{ + private ManagedObjectRegistry _managedObjectRegistry; + + private AuthenticationManager _authenticationManager; + + private VirtualHostRegistry _virtualHostRegistry; + + private ACLPlugin _accessManager; + + private PrincipalDatabaseManager _databaseManager; + + private PluginManager _pluginManager; + + + public NullApplicationRegistry() + { + super(new MapConfiguration(new HashMap())); + } + + public void initialise() throws Exception + { + _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); + + Properties users = new Properties(); + + users.put("guest", "guest"); + + _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); + + _accessManager = new AllowAll(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + + _managedObjectRegistry = new NoopManagedObjectRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(); + VirtualHost dummyHost = new VirtualHost("test", getConfiguration()); + _virtualHostRegistry.registerVirtualHost(dummyHost); + _virtualHostRegistry.setDefaultVirtualHostName("test"); + _pluginManager = new PluginManager(""); + _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes + + } + + public Configuration getConfiguration() + { + return _configuration; + } + + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public Collection getVirtualHostNames() + { + String[] hosts = {"test"}; + return Arrays.asList(hosts); + } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public ACLPlugin getAccessManager() + { + return _accessManager; + } + + public PluginManager getPluginManager() + { + return _pluginManager; + } +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java new file mode 100644 index 0000000000..85d804457e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; + +/** + * The management interface exposed to allow management of an Exchange. + * @version 0.1 + */ +public interface ManagedVirtualHost +{ + static final String TYPE = "VirtualHost"; + + /** + * Returns the name of the managed virtualHost. + * @return the name of the exchange. + * @throws java.io.IOException + */ + @MBeanAttribute(name="Name", description= TYPE + " Name") + String getName() throws IOException; + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java new file mode 100644 index 0000000000..3ff9b8c356 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -0,0 +1,308 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.AMQException; + +import java.util.Timer; +import java.util.TimerTask; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + + private final String _name; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private ACLPlugin _accessManager; + + private final Timer _houseKeepingTimer = new Timer("Queue-housekeeping", true); + + private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, "VirtualHost"); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + + } // End of MBean class + + /** + * Used for testing only + * @param name + * @param store + * @throws Exception + */ + public VirtualHost(String name, MessageStore store) throws Exception + { + this(name, new PropertiesConfiguration(), store); + } + + /** + * Normal Constructor + * @param name + * @param hostConfig + * @throws Exception + */ + public VirtualHost(String name, Configuration hostConfig) throws Exception + { + this(name, hostConfig, null); + } + + public VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + { + _name = name; + + _virtualHostMBean = new VirtualHostMBean(); + // This isn't needed to be registered + //_virtualHostMBean.register(); + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + _exchangeRegistry = new DefaultExchangeRegistry(this); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + _exchangeRegistry.initialise(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + + _accessManager = ACLManager.loadACLManager(name, hostConfig); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + initialiseHouseKeeping(hostConfig); + } + + private void initialiseHouseKeeping(final Configuration hostConfig) + { + + long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); + + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ + if(period != 0L) + { + class RemoveExpiredMessagesTask extends TimerTask + { + public void run() + { + for(AMQQueue q : _queueRegistry.getQueues()) + { + + try + { + q.removeExpiredIfNoSubscribers(); + } + catch (AMQException e) + { + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e); + throw new RuntimeException(e); + } + } + } + } + + _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), + period/2, + period); + } + } + + private void initialiseMessageStore(Configuration config) throws Exception + { + String messageStoreClass = config.getString("store.class"); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(this, "store", config); + } + + + public T getConfiguredObject(Class instanceType, Configuration config) + { + T instance; + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + } + Configurator.configure(instance); + + return instance; + } + + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public ACLPlugin getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + if (_houseKeepingTimer != null) + { + _houseKeepingTimer.cancel(); + } + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java new file mode 100644 index 0000000000..27917fac8a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -0,0 +1,70 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class VirtualHostRegistry +{ + private final Map _registry = new ConcurrentHashMap(); + + + private String _defaultVirtualHostName; + + public synchronized void registerVirtualHost(VirtualHost host) throws Exception + { + if(_registry.containsKey(host.getName())) + { + throw new Exception("Virtual Host with name " + host.getName() + " already registered."); + } + _registry.put(host.getName(),host); + } + + public VirtualHost getVirtualHost(String name) + { + if(name == null || name.trim().length() == 0 ) + { + name = getDefaultVirtualHostName(); + } + + return _registry.get(name); + } + + private String getDefaultVirtualHostName() + { + return _defaultVirtualHostName; + } + + public void setDefaultVirtualHostName(String defaultVirtualHostName) + { + _defaultVirtualHostName = defaultVirtualHostName; + } + + + public Collection getVirtualHosts() + { + return new ArrayList(_registry.values()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java new file mode 100644 index 0000000000..edc900f401 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -0,0 +1,652 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.commands.Clear; +import org.apache.qpid.tools.messagestore.commands.Command; +import org.apache.qpid.tools.messagestore.commands.Copy; +import org.apache.qpid.tools.messagestore.commands.Dump; +import org.apache.qpid.tools.messagestore.commands.Help; +import org.apache.qpid.tools.messagestore.commands.List; +import org.apache.qpid.tools.messagestore.commands.Load; +import org.apache.qpid.tools.messagestore.commands.Quit; +import org.apache.qpid.tools.messagestore.commands.Select; +import org.apache.qpid.tools.messagestore.commands.Show; +import org.apache.qpid.tools.messagestore.commands.Move; +import org.apache.qpid.tools.messagestore.commands.Purge; +import org.apache.qpid.tools.utils.CommandParser; +import org.apache.qpid.tools.utils.Console; +import org.apache.qpid.tools.utils.SimpleCommandParser; +import org.apache.qpid.tools.utils.SimpleConsole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * MessageStoreTool. + */ +public class MessageStoreTool +{ + /** Text outputted at the start of each console.*/ + private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; + + /** I/O Wrapper. */ + protected Console _console; + + /** Batch mode flag. */ + protected boolean _batchMode; + + /** Internal State object. */ + private State _state = new State(); + + private HashMap _commands = new HashMap(); + + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); + + /** Loaded configuration file. */ + private Configuration _config; + + /** Control used for main run loop. */ + private boolean _running = true; + private boolean _initialised = false; + + //---------------------------------------------------------------------------------------------------/ + + public static void main(String[] args) throws Configuration.InitException + { + + MessageStoreTool tool = new MessageStoreTool(args); + + tool.start(); + } + + + public MessageStoreTool(String[] args) throws Configuration.InitException + { + this(args, System.in, System.out); + } + + public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException + { + BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); + BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); + + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); + _batchMode = false; + + _console = new SimpleConsole(consoleWriter, consoleReader); + + _config = new Configuration(); + + setOptions(); + _config.processCommandline(args); + } + + + private void setOptions() + { + 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 By " + + "default looks for a file named " + + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) + .withLongOpt("config") + .create("c"); + + _config.setOption(help); + _config.setOption(version); + _config.setOption(configFile); + } + + public State getState() + { + return _state; + } + + public Map getCommands() + { + return _commands; + } + + public void setConfigurationFile(String configfile) throws Configuration.InitException + { + _config.loadConfig(new File(configfile)); + setup(); + } + + public Console getConsole() + { + return _console; + } + + public void setConsole(Console console) + { + _console = console; + } + + /** + * Simple ShutdownHook to cleanly shutdown the databases + */ + class ShutdownHook implements Runnable + { + MessageStoreTool _tool; + + ShutdownHook(MessageStoreTool messageStoreTool) + { + _tool = messageStoreTool; + } + + public void run() + { + _tool.quit(); + } + } + + public void quit() + { + _running = false; + + if (_initialised) + { + ApplicationRegistry.remove(1); + } + + _console.println("...exiting"); + + _console.close(); + } + + public void setBatchMode(boolean batchmode) + { + _batchMode = batchmode; + } + + /** + * Main loop + */ + protected void start() + { + setup(); + + if (!_initialised) + { + System.exit(1); + } + + _console.println(""); + + _console.println(BOILER_PLATE); + + runCLI(); + } + + private void setup() + { + loadDefaultVirtualHosts(); + + loadCommands(); + + _state.clearAll(); + } + + private void loadCommands() + { + _commands.clear(); + //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands + _commands.put("close", new Clear(this)); + _commands.put("copy", new Copy(this)); + _commands.put("dump", new Dump(this)); + _commands.put("help", new Help(this)); + _commands.put("list", new List(this)); + _commands.put("load", new Load(this)); + _commands.put("move", new Move(this)); + _commands.put("purge", new Purge(this)); + _commands.put("quit", new Quit(this)); + _commands.put("select", new Select(this)); + _commands.put("show", new Show(this)); + } + + private void loadDefaultVirtualHosts() + { + final File configFile = _config.getConfigFile(); + + loadVirtualHosts(configFile); + } + + private void loadVirtualHosts(File configFile) + { + + if (!configFile.exists()) + { + _devlog.error("Config file not found:" + configFile.getAbsolutePath()); + return; + } + else + { + _devlog.debug("using config file :" + configFile.getAbsolutePath()); + } + + try + { + ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); + + ApplicationRegistry.remove(1); + + ApplicationRegistry.initialise(registry); + + checkMessageStores(); + _initialised = true; + } + catch (ConfigurationException e) + { + _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); + e.printStackTrace(); + } + catch (Exception e) + { + _console.println("Unable to load configuration due to: " + e.getMessage()); + e.printStackTrace(); + } + + + } + + private void checkMessageStores() + { + Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); + + boolean warning = false; + for (VirtualHost vhost : vhosts) + { + if (vhost.getMessageStore() instanceof MemoryMessageStore) + { + _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " + + "Changes will not persist."); + warning = true; + } + } + + if (warning) + { + _console.println(""); + _console.println("Please ensure you are using the correct config file currently using '" + + _config.getConfigFile().getAbsolutePath() + "'"); + _console.println("New config file can be specifed by 'load ' or -c on the commandline."); + _console.println(""); + } + } + + private void runCLI() + { + while (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + String[] args = _console.readCommand(); + + while (args != null) + { + exec(args); + + if (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + args = _console.readCommand(); + } + } + } + } + + private void printPrompt() + { + _console.print(prompt()); + } + + + /** + * Execute a script (batch mode). + * + * @param script The file script + */ + protected void runScripts(String script) + { + //Store Current State + boolean oldBatch = _batchMode; + CommandParser oldParser = _console.getCommandParser(); + setBatchMode(true); + + try + { + _devlog.debug("Running script '" + script + "'"); + + _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); + + start(); + } + catch (java.io.FileNotFoundException e) + { + _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); + } + + //Restore previous state + _console.setCommandParser(oldParser); + setBatchMode(oldBatch); + } + + public String prompt() + { + String state = _state.toString(); + if (state != null && state.length() != 0) + { + return state + ":bdb$ "; + } + else + { + return "bdb$ "; + } + } + + /** + * Execute the command. + * + * @param args [command, arg0, arg1...]. + */ + protected void exec(String[] args) + { + // Comment lines start with a # + if (args.length == 0 || args[0].startsWith("#")) + { + return; + } + + final String command = args[0]; + + Command cmd = _commands.get(command); + + if (cmd == null) + { + _console.println("Command not understood: " + command); + } + else + { + cmd.execute(args); + } + } + + + /** + * Displays usage info. + */ + protected static void help() + { + System.out.println(BOILER_PLATE); + System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); + System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); + } + + + /** + * This class is used to store the current state of the tool. + * + * This is then interrogated by the various commands to augment their behaviour. + * + * + */ + public class State + { + private VirtualHost _vhost = null; + private AMQQueue _queue = null; + private Exchange _exchange = null; + private java.util.List _msgids = null; + + public State() + { + } + + public void setQueue(AMQQueue queue) + { + _queue = queue; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void setVhost(VirtualHost vhost) + { + _vhost = vhost; + } + + public VirtualHost getVhost() + { + return _vhost; + } + + public Exchange getExchange() + { + return _exchange; + } + + public void setExchange(Exchange exchange) + { + _exchange = exchange; + } + + public String toString() + { + StringBuilder status = new StringBuilder(); + + if (_vhost != null) + { + status.append(_vhost.getName()); + + if (_exchange != null) + { + status.append("["); + status.append(_exchange.getName()); + status.append("]"); + + if (_queue != null) + { + status.append("->'"); + status.append(_queue.getName()); + status.append("'"); + + if (_msgids != null) + { + status.append(printMessages()); + } + } + } + } + + return status.toString(); + } + + + public String printMessages() + { + StringBuilder sb = new StringBuilder(); + + Long previous = null; + + Long start = null; + for (Long id : _msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(id); + start = null; + } + else + { + sb.append(","); + sb.append(previous); + } + } + } + + previous = id; + } + + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(_msgids.get(_msgids.size() - 1)); + } + else + { + sb.append(","); + sb.append(previous); + } + + // surround list in () + sb.replace(0, 1, "("); + sb.append(")"); + return sb.toString(); + } + + public void clearAll() + { + _vhost = null; + clearExchange(); + } + + public void clearExchange() + { + _exchange = null; + clearQueue(); + } + + public void clearQueue() + { + _queue = null; + clearMessages(); + } + + public void clearMessages() + { + _msgids = null; + } + + /** + * A common location to provide parsing of the message id string + * utilised by a number of the commands. + * The String is comma separated list of ids that can be individual ids + * or a range (4-10) + * + * @param msgString string of msg ids to parse 1,2,4-10 + */ + public void setMessages(String msgString) + { + StringTokenizer tok = new StringTokenizer(msgString, ","); + + if (tok.hasMoreTokens()) + { + _msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + _msgids.add(l); + } + } + } + else + { + _msgids.add(Long.parseLong(next)); + } + } + + } + + public void setMessages(java.util.List msgids) + { + _msgids = msgids; + } + + public java.util.List getMessages() + { + return _msgids; + } + }//Class State + +}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java new file mode 100644 index 0000000000..5444197cb4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +public abstract class AbstractCommand implements Command +{ + protected Console _console; + protected MessageStoreTool _tool; + + public AbstractCommand(MessageStoreTool tool) + { + _console = tool.getConsole(); + _tool = tool; + } + + public void setOutput(Console out) + { + _console = out; + } + + protected void commandError(String message, String[] args) + { + _console.print(getCommand() + " : " + message); + + if (args != null) + { + for (int i = 1; i < args.length; i++) + { + _console.print(args[i]); + } + } + _console.println(""); + _console.println(help()); + } + + + public abstract String help(); + + public abstract String usage(); + + public abstract String getCommand(); + + + public abstract void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java new file mode 100644 index 0000000000..b0006b3fe6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Clear extends AbstractCommand +{ + public Clear(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Clears any selection."; + } + + public String usage() + { + return "clear [ all | virtualhost | exchange | queue | msgs ]"; + } + + public String getCommand() + { + return "clear"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 1) + { + doClose("all"); + } + else + { + doClose(args[1]); + } + } + + private void doClose(String type) + { + if (type.equals("virtualhost") + || type.equals("all")) + { + _tool.getState().clearAll(); + } + + if (type.equals("exchange")) + { + _tool.getState().clearExchange(); + } + + if (type.equals("queue")) + { + _tool.getState().clearQueue(); + } + + if (type.equals("msgs")) + { + _tool.getState().clearMessages(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java new file mode 100644 index 0000000000..bfa775a34a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.utils.Console; + +public interface Command +{ + public void setOutput(Console out); + + public String help(); + + public abstract String usage(); + + String getCommand(); + + public void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java new file mode 100644 index 0000000000..a5b3a87616 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Copy extends Move +{ + public Copy(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Copy messages between queues.";/*\n" + + "The currently selected message set will be copied to the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; */ + } + + public String usage() + { + return "copy to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "copy"; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java new file mode 100644 index 0000000000..218d5f04ed --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.commons.codec.binary.Hex; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class Dump extends Show +{ + private static final int LINE_SIZE = 8; + private static final String DEFAULT_ENCODING = "utf-8"; + private static final boolean SPACE_BYTES = true; + private static final String BYTE_SPACER = " "; + private static final String NON_PRINTING_ASCII_CHAR = "?"; + + protected boolean _content = true; + + public Dump(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Dump selected message content. Default: show=content"; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; + } + + public String getCommand() + { + return "dump"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _content = arg.contains("content") || arg.contains("all"); + } + } + + parseArgs(args); + } + + performShow(); + } + + + protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + List display = new LinkedList(); + + List hex = new LinkedList(); + List ascii = new LinkedList(); + display.add(hex); + display.add(ascii); + + for (QueueEntry entry : messages) + { + AMQMessage msg = entry.getMessage(); + if (!includeMsg(msg, msgids)) + { + continue; + } + + //Add divider between messages + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + // Show general message information + hex.add(Show.Columns.ID.name()); + ascii.add(msg.getMessageId().toString()); + + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + if (showRouting) + { + addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); + } + if (showHeaders) + { + addShowInformation(hex, ascii, msg, "Headers", false, true, false); + } + if (showMessageHeaders) + { + addShowInformation(hex, ascii, msg, null, false, false, true); + } + + // Add Content Body seciont + hex.add("Content Body"); + ascii.add(""); + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + Iterator bodies = msg.getContentBodyIterator(); + if (bodies.hasNext()) + { + + hex.add("Hex"); + hex.add(Console.ROW_DIVIDER); + + + ascii.add("ASCII"); + ascii.add(Console.ROW_DIVIDER); + + while (bodies.hasNext()) + { + ContentChunk chunk = (ContentChunk) bodies.next(); + + //Duplicate so we don't destroy original data :) + ByteBuffer hexBuffer = chunk.getData().duplicate(); + + ByteBuffer charBuffer = hexBuffer.duplicate(); + + Hex hexencoder = new Hex(); + + while (hexBuffer.hasRemaining()) + { + byte[] line = new byte[LINE_SIZE]; + + int bufsize = hexBuffer.remaining(); + if (bufsize < LINE_SIZE) + { + hexBuffer.get(line, 0, bufsize); + } + else + { + bufsize = line.length; + hexBuffer.get(line); + } + + byte[] encoded = hexencoder.encode(line); + + try + { + String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); + String hexLine = ""; + + int strKength = encStr.length(); + for (int c = 0; c < strKength; c++) + { + hexLine += encStr.charAt(c); + + if (c % 2 == 1 && SPACE_BYTES) + { + hexLine += BYTE_SPACER; + } + } + + hex.add(hexLine); + } + catch (UnsupportedEncodingException e) + { + _console.println(e.getMessage()); + return null; + } + } + + while (charBuffer.hasRemaining()) + { + String asciiLine = ""; + + for (int pos = 0; pos < LINE_SIZE; pos++) + { + if (charBuffer.hasRemaining()) + { + byte ch = charBuffer.get(); + + if (isPrintable(ch)) + { + asciiLine += (char) ch; + } + else + { + asciiLine += NON_PRINTING_ASCII_CHAR; + } + + if (SPACE_BYTES) + { + asciiLine += BYTE_SPACER; + } + } + else + { + break; + } + } + + ascii.add(asciiLine); + } + } + } + else + { + List result = new LinkedList(); + + display.add(result); + result.add("No ContentBodies"); + } + } + + // if hex is empty then we have no data to display + if (hex.size() == 0) + { + return null; + } + + return display; + } + + private void addShowInformation(List column1, List column2, AMQMessage msg, + String title, boolean routing, boolean headers, boolean messageHeaders) + { + List single = new LinkedList(); + single.add(new QueueEntry(null,msg)); + + List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); + + //Reformat data + if (title != null) + { + column1.add(title); + column2.add(""); + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + // look at all columns in the routing Data + for (List item : routingData) + { + // the item should be: + // Title + // *divider + // value + // otherwise we can't reason about the correct value + if (item.size() == 3) + { + //Filter out the columns we are not interested in. + + String columnName = item.get(0).toString(); + + if (!(columnName.equals(Show.Columns.ID.name()) + || columnName.equals(Show.Columns.Size.name()))) + { + column1.add(columnName); + column2.add(item.get(2).toString()); + } + } + } + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + private boolean isPrintable(byte c) + { + return c > 31 && c < 127; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java new file mode 100644 index 0000000000..0f9546541b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.Map; + +public class Help extends AbstractCommand +{ + public Help(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Provides detailed help on commands."; + } + + public String getCommand() + { + return "help"; + } + + public String usage() + { + return "help []"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + Command command = _tool.getCommands().get(args[1]); + if (command != null) + { + _console.println(command.help()); + _console.println("Usage:" + command.usage()); + } + else + { + commandError("Command not found: ", args); + } + } + else + { + java.util.List data = new LinkedList(); + + java.util.List commandName = new LinkedList(); + java.util.List commandDescription = new LinkedList(); + + data.add(commandName); + data.add(commandDescription); + + //Set up Headers + commandName.add("Command"); + commandDescription.add("Description"); + + commandName.add(Console.ROW_DIVIDER); + commandDescription.add(Console.ROW_DIVIDER); + + //Add current Commands with descriptions + Map commands = _tool.getCommands(); + + for (Command command : commands.values()) + { + commandName.add(command.getCommand()); + commandDescription.add(command.help()); + } + + _console.printMap("Available Commands", data); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java new file mode 100644 index 0000000000..df8b59ec19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -0,0 +1,314 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.Collection; +import java.util.LinkedList; + +public class List extends AbstractCommand +{ + + public List(MessageStoreTool tool) + { + super(tool); + } + + public void setOutput(Console out) + { + _console = out; + } + + public String help() + { + return "list available items."; + } + + public String usage() + { + return "list queues [] | exchanges | bindings [] | all"; + } + + public String getCommand() + { + return "list"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + if ((args[1].equals("exchanges")) + || (args[1].equals("queues")) + || (args[1].equals("bindings")) + || (args[1].equals("all"))) + { + if (args.length == 2) + { + doList(args[1]); + } + else if (args.length == 3) + { + doList(args[1], args[2]); + } + } + else + { + commandError("Unknown options. ", args); + } + } + else if (args.length < 2) + { + doList("all"); + } + else + { + doList(args[1]); + } + } + + private void doList(String... listItem) + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + listVirtualHosts(); + return; + } + + VirtualHost vhost = _tool.getState().getVhost(); + + java.util.List data = null; + + if (listItem[0].equals("queues")) + { + if (listItem.length > 1) + { + data = listQueues(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + data = listQueues(vhost, exchange); + } + } + + if (listItem[0].equals("exchanges")) + { + data = listExchanges(vhost); + } + + if (listItem[0].equals("bindings")) + { + + if (listItem.length > 1) + { + data = listBindings(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + + data = listBindings(vhost, exchange); + } + } + + if (data != null) + { + if (data.size() == 1) + { + _console.println("No '" + listItem[0] + "' to display,"); + } + else + { + _console.displayList(true, data.toArray(new String[0])); + } + } + + + if (listItem[0].equals("all")) + { + + boolean displayed = false; + Exchange exchange = _tool.getState().getExchange(); + + //Do the display here for each one so that they are pretty printed + data = listQueues(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (exchange == null) + { + data = listExchanges(vhost); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + } + + data = listBindings(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (!displayed) + { + _console.println("Nothing to list"); + } + } + } + + private void listVirtualHosts() + { + Collection vhosts = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHosts(); + + String[] data = new String[vhosts.size() + 1]; + + data[0] = "Available VirtualHosts"; + + int index = 1; + for (VirtualHost vhost : vhosts) + { + data[index] = vhost.getName(); + index++; + } + + _console.displayList(true, data); + } + + private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) + { + return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listBindings(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueueNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Current Bindings"); + + for (AMQShortString queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.toString()); + } + } + else + { + data.add(queue.toString()); + } + } + + return data; + } + + private java.util.List listExchanges(VirtualHost vhost) + { + Collection queues = vhost.getExchangeRegistry().getExchangeNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Exchanges"); + + for (AMQShortString queue : queues) + { + data.add(queue.toString()); + } + + return data; + } + + private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) + { + return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listQueues(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueues(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Queues"); + + for (AMQQueue queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.getName().toString()); + } + } + else + { + data.add(queue.getName().toString()); + } + } + + if (exchange != null) + { + if (queues.size() == 1) + { + return null; + } + } + + return data; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java new file mode 100644 index 0000000000..244a311c30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Load extends AbstractCommand +{ + public Load(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Loads specified broker configuration file."; + } + + public String usage() + { + return "load "; + } + + public String getCommand() + { + return "load"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 2) + { + _console.print("load " + args[1] + ": additional options not understood:"); + for (int i = 2; i < args.length; i++) + { + _console.print(args[i] + " "); + } + _console.println(""); + } + else if (args.length < 2) + { + _console.println("Enter Configuration file."); + String input = _console.readln(); + if (input != null) + { + doLoad(input); + } + else + { + _console.println("Did not recognise config file."); + } + } + else + { + doLoad(args[1]); + } + } + + private void doLoad(String configfile) + { + _console.println("Loading Configuration:" + configfile); + + try + { + _tool.setConfigurationFile(configfile); + } + catch (Configuration.InitException e) + { + _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java new file mode 100644 index 0000000000..7e21253fab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.List; + +public class Move extends AbstractCommand +{ + + /** + * Since the Coopy command is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + protected StoreContext _storeContext = new StoreContext(); + + public Move(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Move messages between queues.";/*\n" + + "The currently selected message set will be moved to the specifed queue.\n" + + "Alternatively the values can be provided on the command line.";*/ + } + + public String usage() + { + return "move to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "move"; + } + + public void execute(String... args) + { + AMQQueue toQueue = null; + AMQQueue fromQueue = _tool.getState().getQueue(); + java.util.List msgids = _tool.getState().getMessages(); + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("to=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("from=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("msgids=")) + { + String msgidStr = arg.substring(arg.indexOf("=") + 1); + + // Record the current message selection + java.util.List currentIDs = _tool.getState().getMessages(); + + // Use the ToolState class to perform the messasge parsing + _tool.getState().setMessages(msgidStr); + msgids = _tool.getState().getMessages(); + + // Reset the original selection of messages + _tool.getState().setMessages(currentIDs); + } + } + } + + if (!checkRequirements(fromQueue, toQueue, msgids)) + { + return; + } + + processIDs(fromQueue, toQueue, msgids); + } + + private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + Long previous = null; + Long start = null; + + if (msgids == null) + { + msgids = allMessageIDs(fromQueue); + } + + if (msgids == null || msgids.size() == 0) + { + _console.println("No Messages to move."); + return; + } + + for (long id : msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, id, toQueue); + start = null; + } + else + { + //move a single id + doCommand(fromQueue, id, id, toQueue); + } + } + } + + previous = id; + } + + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, previous, toQueue); + } + } + + private List allMessageIDs(AMQQueue fromQueue) + { + List ids = new LinkedList(); + + if (fromQueue != null) + { + List messages = fromQueue.getMessagesOnTheQueue(); + if (messages != null) + { + for (QueueEntry msg : messages) + { + ids.add(msg.getMessage().getMessageId()); + } + } + } + + return ids; + } + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) + { + if (toQueue == null) + { + _console.println("Destination queue not specifed."); + _console.println(usage()); + return false; + } + + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) + { + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java new file mode 100644 index 0000000000..f187e26593 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Purge extends Move +{ + public Purge(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Purge messages from a queue.\n" + + "The currently selected message set will be purged from the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "purge from= [msgids=]"; + } + + public String getCommand() + { + return "purge"; + } + + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.removeMessagesFromQueue(start, end, _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java new file mode 100644 index 0000000000..a81bc07c38 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Quit extends AbstractCommand +{ + public Quit(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Quit the tool."; + } + + public String usage() + { + return "quit"; + } + + public String getCommand() + { + return "quit"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals("quit"); + + _tool.quit(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java new file mode 100644 index 0000000000..fd7d4c3f13 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.StringTokenizer; + +public class Select extends AbstractCommand +{ + + public Select(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Perform a selection."; + } + + public String usage() + { + return "select virtualhost |exchange |queue | msg id="; + } + + public String getCommand() + { + return "select"; + } + + public void execute(String... args) + { + assert args.length > 2; + assert args[0].equals("select"); + + if (args.length < 3) + { + if (args[1].equals("show")) + { + doSelect(args[1], null); + } + else + { + _console.print("select : unknown command:"); + _console.println(help()); + } + } + else + { + if (args[1].equals("virtualhost") + || args[1].equals("vhost") + || args[1].equals("exchange") + || args[1].equals("queue") + || args[1].equals("msg") + ) + { + doSelect(args[1], args[2]); + } + else + { + _console.println(help()); + } + } + } + + private void doSelect(String type, String item) + { + if (type.equals("virtualhost")) + { + + VirtualHost vhost = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHost(item); + + if (vhost == null) + { + _console.println("Virtualhost '" + item + "' not found."); + } + else + { + _tool.getState().setVhost(vhost); + } + } + + if (type.equals("exchange")) + { + + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + + Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); + + if (exchange == null) + { + _console.println("Exchange '" + item + "' not found."); + } + else + { + _tool.getState().setExchange(exchange); + } + + if (_tool.getState().getQueue() != null) + { + if (!exchange.isBound(_tool.getState().getQueue())) + { + _tool.getState().setQueue(null); + } + } + } + + if (type.equals("queue")) + { + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); + + if (queue == null) + { + _console.println("Queue '" + item + "' not found."); + } + else + { + _tool.getState().setQueue(queue); + + if (_tool.getState().getExchange() == null) + { + for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) + { + Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); + if (exchange.isBound(queue)) + { + _tool.getState().setExchange(exchange); + break; + } + } + } + + //remove the message selection + _tool.getState().setMessages((java.util.List) null); + } + } + + if (type.equals("msg")) + { + if (item.startsWith("id=")) + { + StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); + + java.util.List msgids = null; + + if (tok.hasMoreTokens()) + { + msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + msgids.add(l); + } + } + } + else + { + msgids.add(Long.parseLong(next)); + } + } + + _tool.getState().setMessages(msgids); + } + + } + + if (type.equals("show")) + { + _console.println(_tool.getState().toString()); + if (_tool.getState().getMessages() != null) + { + _console.print("Msgs:"); + for (Long l : _tool.getState().getMessages()) + { + _console.print(" " + l); + } + _console.println(""); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java new file mode 100644 index 0000000000..a6dccf0f36 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -0,0 +1,515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +public class Show extends AbstractCommand +{ + protected boolean _amqHeaders = false; + protected boolean _routing = false; + protected boolean _msgHeaders = false; + + public Show(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Shows the messages headers."; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; + } + + public String getCommand() + { + return "show"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 2) + { + parseArgs("all"); + } + else + { + parseArgs(args); + } + + performShow(); + } + + protected void parseArgs(String... args) + { + List msgids = null; + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); + _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); + _routing = arg.contains("routing") || arg.contains("all"); + } + + if (arg.startsWith("id=")) + { + _tool.getState().setMessages(msgids); + } + }//for args + }// if args > 2 + } + + protected void performShow() + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); + return; + } + + AMQQueue _queue = _tool.getState().getQueue(); + + List msgids = _tool.getState().getMessages(); + + if (_queue != null) + { + List messages = _queue.getMessagesOnTheQueue(); + if (messages == null || messages.size() == 0) + { + _console.println("No messages on queue"); + return; + } + + List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); + if (data != null) + { + _console.printMap(null, data); + } + else + { + String message = "No data to display."; + if (msgids != null) + { + message += " Is message selection correct? " + _tool.getState().printMessages(); + } + _console.println(message); + } + + } + else + { + _console.println("No Queue specified to show."); + } + } + + /** + * Create the list data for display from the messages. + * + * @param msgids The list of message ids to display + * @param messages A list of messages to format and display. + * @param showHeaders should the header info be shown + * @param showRouting show the routing info be shown + * @param showMessageHeaders show the msg headers be shown + * @return the formated data lists for printing + */ + protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + // Currenly exposed message properties +// //Printing the content Body +// msg.getContentBodyIterator(); +// //Print the Headers +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); +// +// //Print out all the property names +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); +// +// msg.getMessageId(); +// msg.getSize(); +// msg.getArrivalTime(); + +// msg.getDeliveredSubscription(); +// msg.getDeliveredToConsumer(); +// msg.getMessageHandle(); +// msg.getMessageId(); +// msg.getMessagePublishInfo(); +// msg.getPublisher(); + +// msg.getStoreContext(); +// msg.isAllContentReceived(); +// msg.isPersistent(); +// msg.isRedelivered(); +// msg.isRejectedBy(); +// msg.isTaken(); + + //Header setup + + List data = new LinkedList(); + + List id = new LinkedList(); + data.add(id); + id.add(Columns.ID.name()); + id.add(Console.ROW_DIVIDER); + + List exchange = new LinkedList(); + List routingkey = new LinkedList(); + List immediate = new LinkedList(); + List mandatory = new LinkedList(); + if (showRouting) + { + data.add(exchange); + exchange.add(Columns.Exchange.name()); + exchange.add(Console.ROW_DIVIDER); + + data.add(routingkey); + routingkey.add(Columns.RoutingKey.name()); + routingkey.add(Console.ROW_DIVIDER); + + data.add(immediate); + immediate.add(Columns.isImmediate.name()); + immediate.add(Console.ROW_DIVIDER); + + data.add(mandatory); + mandatory.add(Columns.isMandatory.name()); + mandatory.add(Console.ROW_DIVIDER); + } + + List size = new LinkedList(); + List appid = new LinkedList(); + List clusterid = new LinkedList(); + List contenttype = new LinkedList(); + List correlationid = new LinkedList(); + List deliverymode = new LinkedList(); + List encoding = new LinkedList(); + List arrival = new LinkedList(); + List expiration = new LinkedList(); + List priority = new LinkedList(); + List propertyflag = new LinkedList(); + List replyto = new LinkedList(); + List timestamp = new LinkedList(); + List type = new LinkedList(); + List userid = new LinkedList(); + List ispersitent = new LinkedList(); + List isredelivered = new LinkedList(); + List isdelivered = new LinkedList(); + + data.add(size); + size.add(Columns.Size.name()); + size.add(Console.ROW_DIVIDER); + + if (showHeaders) + { + data.add(ispersitent); + ispersitent.add(Columns.isPersistent.name()); + ispersitent.add(Console.ROW_DIVIDER); + + data.add(isredelivered); + isredelivered.add(Columns.isRedelivered.name()); + isredelivered.add(Console.ROW_DIVIDER); + + data.add(isdelivered); + isdelivered.add(Columns.isDelivered.name()); + isdelivered.add(Console.ROW_DIVIDER); + + data.add(appid); + appid.add(Columns.App_ID.name()); + appid.add(Console.ROW_DIVIDER); + + data.add(clusterid); + clusterid.add(Columns.Cluster_ID.name()); + clusterid.add(Console.ROW_DIVIDER); + + data.add(contenttype); + contenttype.add(Columns.Content_Type.name()); + contenttype.add(Console.ROW_DIVIDER); + + data.add(correlationid); + correlationid.add(Columns.Correlation_ID.name()); + correlationid.add(Console.ROW_DIVIDER); + + data.add(deliverymode); + deliverymode.add(Columns.Delivery_Mode.name()); + deliverymode.add(Console.ROW_DIVIDER); + + data.add(encoding); + encoding.add(Columns.Encoding.name()); + encoding.add(Console.ROW_DIVIDER); + + data.add(arrival); + expiration.add(Columns.Arrival.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(expiration); + expiration.add(Columns.Expiration.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(priority); + priority.add(Columns.Priority.name()); + priority.add(Console.ROW_DIVIDER); + + data.add(propertyflag); + propertyflag.add(Columns.Property_Flag.name()); + propertyflag.add(Console.ROW_DIVIDER); + + data.add(replyto); + replyto.add(Columns.ReplyTo.name()); + replyto.add(Console.ROW_DIVIDER); + + data.add(timestamp); + timestamp.add(Columns.Timestamp.name()); + timestamp.add(Console.ROW_DIVIDER); + + data.add(type); + type.add(Columns.Type.name()); + type.add(Console.ROW_DIVIDER); + + data.add(userid); + userid.add(Columns.UserID.name()); + userid.add(Console.ROW_DIVIDER); + } + + List msgHeaders = new LinkedList(); + if (showMessageHeaders) + { + data.add(msgHeaders); + msgHeaders.add(Columns.MsgHeaders.name()); + msgHeaders.add(Console.ROW_DIVIDER); + } + + //Add create the table of data + for (QueueEntry entry : messages) + { + AMQMessage msg = entry.getMessage(); + if (!includeMsg(msg, msgids)) + { + continue; + } + + id.add(msg.getMessageId().toString()); + + size.add("" + msg.getSize()); + + arrival.add("" + msg.getArrivalTime()); + + try + { + ispersitent.add(msg.isPersistent() ? "true" : "false"); + } + catch (AMQException e) + { + ispersitent.add("n/a"); + } + + isredelivered.add(msg.isRedelivered() ? "true" : "false"); + + isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + +// msg.getMessageHandle(); + + BasicContentHeaderProperties headers = null; + + try + { + headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + } + catch (AMQException e) + { + //ignore +// commandError("Unable to read properties for message: " + e.getMessage(), null); + } + + if (headers != null) + { + String appidS = headers.getAppIdAsString(); + appid.add(appidS == null ? "null" : appidS); + + String clusterS = headers.getClusterIdAsString(); + clusterid.add(clusterS == null ? "null" : clusterS); + + String contentS = headers.getContentTypeAsString(); + contenttype.add(contentS == null ? "null" : contentS); + + String correlationS = headers.getCorrelationIdAsString(); + correlationid.add(correlationS == null ? "null" : correlationS); + + deliverymode.add("" + headers.getDeliveryMode()); + + AMQShortString encodeSS = headers.getEncoding(); + encoding.add(encodeSS == null ? "null" : encodeSS.toString()); + + expiration.add("" + headers.getExpiration()); + + FieldTable headerFT = headers.getHeaders(); + msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); + + priority.add("" + headers.getPriority()); + propertyflag.add("" + headers.getPropertyFlags()); + + AMQShortString replytoSS = headers.getReplyTo(); + replyto.add(replytoSS == null ? "null" : replytoSS.toString()); + + timestamp.add("" + headers.getTimestamp()); + + AMQShortString typeSS = headers.getType(); + type.add(typeSS == null ? "null" : typeSS.toString()); + + AMQShortString useridSS = headers.getUserId(); + userid.add(useridSS == null ? "null" : useridSS.toString()); + + MessagePublishInfo info = null; + try + { + info = msg.getMessagePublishInfo(); + } + catch (AMQException e) + { + //ignore + } + + if (info != null) + { + AMQShortString exchangeSS = info.getExchange(); + exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); + + AMQShortString routingkeySS = info.getRoutingKey(); + routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); + + immediate.add(info.isImmediate() ? "true" : "false"); + mandatory.add(info.isMandatory() ? "true" : "false"); + } + +// msg.getPublisher(); -- only used in clustering +// msg.getStoreContext(); +// msg.isAllContentReceived(); + + }// if headers!=null + +// need to access internal map and do lookups. +// msg.isTaken(); +// msg.getDeliveredSubscription(); +// msg.isRejectedBy(); + + } + + // if id only had the header and the divider in it then we have no data to display + if (id.size() == 2) + { + return null; + } + return data; + } + + protected boolean includeMsg(AMQMessage msg, List msgids) + { + if (msgids == null) + { + return true; + } + + Long msgid = msg.getMessageId(); + + boolean found = false; + + if (msgids != null) + { + //check msgid is in msgids + for (Long l : msgids) + { + if (l.equals(msgid)) + { + found = true; + break; + } + } + } + return found; + } + + public enum Columns + { + ID, + Size, + Exchange, + RoutingKey, + isImmediate, + isMandatory, + isPersistent, + isRedelivered, + isDelivered, + App_ID, + Cluster_ID, + Content_Type, + Correlation_ID, + Delivery_Mode, + Encoding, + Arrival, + Expiration, + Priority, + Property_Flag, + ReplyTo, + Timestamp, + Type, + UserID, + MsgHeaders + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java new file mode 100644 index 0000000000..c27c52eb8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java new file mode 100644 index 0000000000..986fea32cc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +public interface CommandParser +{ + /** + * If there is more than one command received on the last parse request. + * + * Subsequent calls to parse will utilise this input rather than reading new data from the input source + * @return boolean + */ + boolean more(); + + /** + * True if the currently parsed command has been requested as a background operation + * + * @return boolean + */ + boolean isBackground(); + + /** + * Parses user commands, and groups tokens in the + * String[] format that all Java main's love. + * + * If more than one command is provided in one input line then the more() method will return true. + * A subsequent call to parse() will continue to parse that input line before reading new input. + * + * @return input split in args[] format; null if eof. + * @throws java.io.IOException if there is a problem reading from the input stream + */ + String[] parse() throws java.io.IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java new file mode 100644 index 0000000000..cf457d1ea5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.util.List; + +public interface Console +{ + public enum CellFormat + { + CENTRED, LEFT, RIGHT + } + + public static String ROW_DIVIDER = "*divider"; + + public void print(String... message); + + public void println(String... message); + + public String readln(); + + /** + * Reads and parses the command line. + * + * + * @return The next command or null + */ + public String[] readCommand(); + + public CommandParser getCommandParser(); + + public void setCommandParser(CommandParser parser); + + /** + * + * Prints the list of String nicely. + * + * +-------------+ + * | Heading | + * +-------------+ + * | Item 1 | + * | Item 2 | + * | Item 3 | + * +-------------+ + * + * @param hasTitle should list[0] be used as a heading + * @param list The list of Strings to display + */ + public void displayList(boolean hasTitle, String... list); + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * +----------------------------+ (*divider) + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + void printMap(String title, List entries); + + + public void close(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java new file mode 100644 index 0000000000..09444ccdd7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.StringTokenizer; + +public class SimpleCommandParser implements CommandParser +{ + private static final String COMMAND_SEPERATOR = ";"; + + /** Input source of commands */ + protected BufferedReader _reader; + + /** The next list of commands from the command line */ + private StringBuilder _nextCommand = null; + + public SimpleCommandParser(BufferedReader reader) + { + _reader = reader; + } + + public boolean more() + { + return _nextCommand != null; + } + + public boolean isBackground() + { + return false; + } + + public String[] parse() throws IOException + { + String[] commands = null; + + String input = null; + + if (_nextCommand == null) + { + input = _reader.readLine(); + } + else + { + input = _nextCommand.toString(); + _nextCommand = null; + } + + if (input == null) + { + return null; + } + + StringTokenizer tok = new StringTokenizer(input, " "); + + int tokenCount = tok.countTokens(); + int index = 0; + + if (tokenCount > 0) + { + commands = new String[tokenCount]; + boolean commandComplete = false; + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + + if (next.equals(COMMAND_SEPERATOR)) + { + commandComplete = true; + _nextCommand = new StringBuilder(); + continue; + } + + if (commandComplete) + { + _nextCommand.append(next); + _nextCommand.append(" "); + } + else + { + commands[index] = next; + index++; + } + } + + } + + //Reduce the String[] if not all the tokens were used in this command. + // i.e. there is more than one command on the line. + if (index != tokenCount) + { + String[] shortCommands = new String[index]; + System.arraycopy(commands, 0, shortCommands, 0, index); + return shortCommands; + } + else + { + return commands; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java new file mode 100644 index 0000000000..ec080a4611 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +public class SimpleConsole implements Console +{ + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); + + /** Console Writer. */ + protected static BufferedWriter _consoleWriter; + + /** Console Reader. */ + protected static BufferedReader _consoleReader; + + /** Parser for command-line input. */ + protected CommandParser _parser; + + public SimpleConsole(BufferedWriter writer, BufferedReader reader) + { + _consoleWriter = writer; + _consoleReader = reader; + _parser = new SimpleCommandParser(_consoleReader); + } + + public void print(String... message) + { + try + { + for (String s : message) + { + _consoleWriter.write(s); + } + _consoleWriter.flush(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); + } + + } + + public void println(String... message) + { + print(message); + print(System.getProperty("line.separator")); + } + + + public String readln() + { + try + { + return _consoleReader.readLine(); + } + catch (IOException e) + { + _devlog.debug("Unable to read input due to:" + e.getMessage()); + return null; + } + } + + public String[] readCommand() + { + try + { + return _parser.parse(); + } + catch (IOException e) + { + _devlog.error("Error reading command:" + e.getMessage()); + return new String[0]; + } + } + + public CommandParser getCommandParser() + { + return _parser; + } + + public void setCommandParser(CommandParser parser) + { + _parser = parser; + } + + public void displayList(boolean hasTitle, String... list) + { + java.util.List data = new LinkedList(); + + java.util.List values = new LinkedList(); + + data.add(values); + + for (String value : list) + { + values.add(value); + } + + if (hasTitle) + { + values.add(1, "*divider"); + } + + printMap(null, data); + } + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + public void printMap(String title, java.util.List entries) + { + try + { + int columns = entries.size(); + + int[] columnWidth = new int[columns]; + + // calculate row count + int rowMax = 0; + + //the longest item + int itemMax = 0; + + for (int i = 0; i < columns; i++) + { + int columnIRowMax = entries.get(i).size(); + + if (columnIRowMax > rowMax) + { + rowMax = columnIRowMax; + } + for (Object values : entries.get(i)) + { + if (values.toString().equals(Console.ROW_DIVIDER)) + { + continue; + } + + int itemLength = values.toString().length(); + + //note for single width + if (itemLength > itemMax) + { + itemMax = itemLength; + } + + //note for mulit width + if (itemLength > columnWidth[i]) + { + columnWidth[i] = itemLength; + } + + } + } + + int tableWidth = 0; + + + for (int i = 0; i < columns; i++) + { + // plus 2 for the space padding + columnWidth[i] += 2; + } + for (int size : columnWidth) + { + tableWidth += size; + } + tableWidth += (columns - 1); + + if (title != null) + { + if (title.length() > tableWidth) + { + tableWidth = title.length(); + } + + printCellRow("+", "-", tableWidth); + + printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); + _consoleWriter.newLine(); + + } + + //put top line | or bottom of title + printCellRow("+", "-", tableWidth); + + //print the table data + int row = 0; + + for (; row < rowMax; row++) + { + for (int i = 0; i < columns; i++) + { + java.util.List columnData = entries.get(i); + + String value; + // does this column have a value for this row + if (columnData.size() > row) + { + value = " " + columnData.get(row).toString() + " "; + } + else + { + value = " "; + } + + if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) + { + printCellRow("+", "-", tableWidth); + //move on to the next row + break; + } + else + { + printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); + } + + // if it is the last row then do a new line. + if (i == columns - 1) + { + _consoleWriter.newLine(); + } + } + } + + printCellRow("+", "-", tableWidth); + + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write."); + } + } + + public void close() + { + + try + { + _consoleReader.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); + } + + try + { + + _consoleWriter.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); + } + + } + + private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException + { + int pad = cellWidth - cell.length(); + + if (column == 0) + { + _consoleWriter.write(edge); + } + + switch (format) + { + case CENTRED: + printPad(" ", pad / 2); + break; + case RIGHT: + printPad(" ", pad); + break; + } + + _consoleWriter.write(cell); + + + switch (format) + { + case CENTRED: + // if pad isn't even put the extra one on the right + if (pad % 2 == 0) + { + printPad(" ", pad / 2); + } + else + { + printPad(" ", (pad / 2) + 1); + } + break; + case LEFT: + printPad(" ", pad); + break; + } + + + _consoleWriter.write(edge); + + } + + private void printCellRow(String edge, String mid, int cellWidth) throws IOException + { + _consoleWriter.write(edge); + + printPad(mid, cellWidth); + + _consoleWriter.write(edge); + _consoleWriter.newLine(); + } + + private void printPad(String padChar, int count) throws IOException + { + for (int i = 0; i < count; i++) + { + _consoleWriter.write(padChar); + } + } + + +} -- cgit v1.2.1 From 470ebf87ec336e81277c550669839161f2630b5f Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 24 Apr 2008 01:54:20 +0000 Subject: QPID-832 merge M2.x git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651133 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java | 2 +- .../java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java | 2 +- .../java/org/apache/qpid/server/security/access/plugins/AllowAll.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 1a9dc6673a..636aa7eb03 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -67,7 +67,7 @@ public class DefaultExchangeFactory implements ExchangeFactory if (exchType == null) { - throw new AMQUnknownExchangeType("Unknown exchange type: " + type); + throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null); } Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); return e; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index 9a98bc9659..97d25f650d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -101,7 +101,7 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener Date: Thu, 24 Apr 2008 14:35:01 +0000 Subject: QPID-832: fixed DerbyMessageStore to compile on Java 1.5 (hopefully) git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651276 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/store/DerbyMessageStore.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 4664fd5e14..bd980c696c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -638,8 +638,9 @@ public class DerbyMessageStore implements MessageStore blobArgs.setBytes(0, args.getDataAsBytes()); stmt.setBlob(4, blobArgs); */ - ByteArrayInputStream bis = new ByteArrayInputStream(args.getDataAsBytes()); - stmt.setBinaryStream(4, bis); + byte[] bytes = args.getDataAsBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + stmt.setBinaryStream(4, bis, bytes.length); } else { @@ -1043,7 +1044,7 @@ public class DerbyMessageStore implements MessageStore stmt.setBlob(3, dataAsBlob); */ ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); - stmt.setBinaryStream(3, bis); + stmt.setBinaryStream(3, bis, chunkData.length); stmt.executeUpdate(); connWrapper.requiresCommit(); @@ -1093,7 +1094,7 @@ public class DerbyMessageStore implements MessageStore stmt.setBlob(6, dataAsBlob); */ ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(6,bis); + stmt.setBinaryStream(6,bis,underlying.length); stmt.setInt(7, mmd.getContentChunkCount()); -- cgit v1.2.1 From e32debe1df7d0a837e30cd937fb7a18fc5cfa203 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 24 Apr 2008 17:49:03 +0000 Subject: QPID-832 : Fix eol-style git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651325 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/FanoutExchange.java | 480 ++++----- .../qpid/server/handler/AccessRequestHandler.java | 130 +-- .../qpid/server/handler/BasicGetMethodHandler.java | 202 ++-- .../handler/BasicRecoverSyncMethodHandler.java | 150 +-- .../qpid/server/handler/QueuePurgeHandler.java | 242 ++--- .../server/handler/ServerMethodDispatcherImpl.java | 1132 ++++++++++---------- .../handler/ServerMethodDispatcherImpl_0_9.java | 328 +++--- .../handler/ServerMethodDispatcherImpl_8_0.java | 172 +-- .../server/handler/UnexpectedMethodException.java | 66 +- .../server/output/ProtocolOutputConverter.java | 114 +- .../output/ProtocolOutputConverterRegistry.java | 122 +-- .../amqp0_8/ProtocolOutputConverterImpl.java | 570 +++++----- .../amqp0_9/ProtocolOutputConverterImpl.java | 794 +++++++------- .../protocol/AMQNoMethodHandlerException.java | 92 +- .../protocol/UnknnownMessageTypeException.java | 92 +- .../qpid/server/queue/NotificationCheck.java | 276 ++--- .../server/queue/QueueNotificationListener.java | 54 +- .../server/virtualhost/ManagedVirtualHost.java | 88 +- .../server/virtualhost/VirtualHostRegistry.java | 140 +-- 19 files changed, 2622 insertions(+), 2622 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index e7c887f306..f1b383eac9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -1,240 +1,240 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArraySet; - -public class FanoutExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(FanoutExchange.class); - - /** - * Maps from queue name to queue instances - */ - private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Fanout Exchange") - private final class FanoutExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException - { - super(); - _exchangeType = "fanout"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (AMQQueue queue : _queues) - { - String queueName = queue.getName().toString(); - - Object[] bindingItemValues = {queueName, new String[]{queueName}}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, FanoutExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new FanoutExchange.FanoutExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } - } - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return FanoutExchange.class; - } - - public FanoutExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - FanoutExchange exch = new FanoutExchange(); - exch.initialise(host, name, durable, ticket, autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_NAME; - } - }; - - public Map> getBindings() - { - return null; - } - - public AMQShortString getType() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (_queues.contains(queue)) - { - _logger.debug("Queue " + queue + " is already registered"); - } - else - { - _queues.add(queue); - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); - } - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (!_queues.remove(queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); - } - } - - public void route(AMQMessage payload) throws AMQException - { - final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); - final AMQShortString routingKey = publishInfo.getRoutingKey(); - if ((_queues == null) || _queues.isEmpty()) - { - String msg = "No queues bound to " + this; - if (publishInfo.isMandatory() || publishInfo.isImmediate()) - { - throw new NoRouteException(msg, payload); - } - else - { - _logger.warn(msg); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + _queues); - } - - payload.enqueue(new ArrayList(_queues)); - - } - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return _queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - - return (_queues != null) && !_queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - - return _queues.contains(queue); - } - - public boolean hasBindings() - { - return !_queues.isEmpty(); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class FanoutExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Fanout Exchange") + private final class FanoutExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") + public FanoutExchangeMBean() throws JMException + { + super(); + _exchangeType = "fanout"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (AMQQueue queue : _queues) + { + String queueName = queue.getName().toString(); + + Object[] bindingItemValues = {queueName, new String[]{queueName}}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(new AMQShortString(binding), null, FanoutExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new FanoutExchange.FanoutExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return FanoutExchange.class; + } + + public FanoutExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + FanoutExchange exch = new FanoutExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_NAME; + } + }; + + public Map> getBindings() + { + return null; + } + + public AMQShortString getType() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (_queues.contains(queue)) + { + _logger.debug("Queue " + queue + " is already registered"); + } + else + { + _queues.add(queue); + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); + } + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (!_queues.remove(queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); + } + } + + public void route(AMQMessage payload) throws AMQException + { + final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); + final AMQShortString routingKey = publishInfo.getRoutingKey(); + if ((_queues == null) || _queues.isEmpty()) + { + String msg = "No queues bound to " + this; + if (publishInfo.isMandatory() || publishInfo.isImmediate()) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn(msg); + } + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + _queues); + } + + payload.enqueue(new ArrayList(_queues)); + + } + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return _queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + + return (_queues != null) && !_queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + + return _queues.contains(queue); + } + + public boolean hasBindings() + { + return !_queues.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java index dd712a404c..133c97a146 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -1,65 +1,65 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.AMQException; - -/** - * @author Apache Software Foundation - * - * - */ -public class AccessRequestHandler implements StateAwareMethodListener -{ - private static final AccessRequestHandler _instance = new AccessRequestHandler(); - - - public static AccessRequestHandler getInstance() - { - return _instance; - } - - private AccessRequestHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - - // We don't implement access control class, but to keep clients happy that expect it - // always use the "0" ticket. - AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); - - session.writeFrame(response.generateFrame(channelId)); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.AMQException; + +/** + * @author Apache Software Foundation + * + * + */ +public class AccessRequestHandler implements StateAwareMethodListener +{ + private static final AccessRequestHandler _instance = new AccessRequestHandler(); + + + public static AccessRequestHandler getInstance() + { + return _instance; + } + + private AccessRequestHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + // We don't implement access control class, but to keep clients happy that expect it + // always use the "0" ticket. + AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index f8f9127809..3731116cba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -1,101 +1,101 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicGetBody; -import org.apache.qpid.framing.BasicGetEmptyBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicGetMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); - - private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); - - public static BasicGetMethodHandler getInstance() - { - return _instance; - } - - private BasicGetMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - VirtualHost vHost = session.getVirtualHost(); - - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - else - { - AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); - - if (queue == null) - { - _log.info("No queue for '" + body.getQueue() + "'"); - if(body.getQueue()!=null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, - "No such queue, '" + body.getQueue()+ "'"); - } - else - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "No queue name provided, no default queue defined."); - } - } - else - { - - //Perform ACLs - vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); - - if (!queue.performGet(session, channel, !body.getNoAck())) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - // TODO - set clusterId - BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); - - - session.writeFrame(responseBody.generateFrame(channelId)); - } - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + VirtualHost vHost = session.getVirtualHost(); + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); + + if (queue == null) + { + _log.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue()+ "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined."); + } + } + else + { + + //Perform ACLs + vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); + + if (!queue.performGet(session, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + // TODO - set clusterId + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java index 3e2cab2e53..bca35be535 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java @@ -1,75 +1,75 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; - -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.BasicRecoverSyncBody; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.AMQException; - -public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); - - private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); - - public static BasicRecoverSyncMethodHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); - AMQChannel channel = session.getChannel(channelId); - - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.resend(body.getRequeue()); - - // Qpid 0-8 hacks a synchronous -ok onto recover. - // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant - if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) - { - MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); - AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); - session.writeFrame(recoverOk.generateFrame(channelId)); - - } - - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.framing.BasicRecoverBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.BasicRecoverSyncBody; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); + + private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); + + public static BasicRecoverSyncMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index cce49f13c7..a854c97f60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -1,121 +1,121 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.QueuePurgeBody; -import org.apache.qpid.framing.QueuePurgeOkBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.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.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.security.access.Permission; - -public class QueuePurgeHandler implements StateAwareMethodListener -{ - private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); - - public static QueuePurgeHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueuePurgeHandler() - { - this(true); - } - - public QueuePurgeHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - } - - public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - AMQChannel channel = session.getChannel(channelId); - - - AMQQueue queue; - if(body.getQueue() == null) - { - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); - } - } - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - } - else - { - - //Perform ACLs - virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue); - - long purged = queue.clearQueue(channel.getStoreContext()); - - - if(!body.getNowait()) - { - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.QueuePurgeBody; +import org.apache.qpid.framing.QueuePurgeOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.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.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + AMQChannel channel = session.getChannel(channelId); + + + AMQQueue queue; + if(body.getQueue() == null) + { + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); + } + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue); + + long purged = queue.clearQueue(channel.getStoreContext()); + + + if(!body.getNowait()) + { + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java index 9475b83c8f..d24e4f6ffa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java @@ -1,566 +1,566 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.Map; -import java.util.HashMap; - -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.framing.*; -import org.apache.qpid.AMQException; - -public class ServerMethodDispatcherImpl implements MethodDispatcher -{ - private final AMQStateManager _stateManager; - - private static interface DispatcherFactory - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); - } - - private static final Map _dispatcherFactories = - new HashMap(); - - - static - { - _dispatcherFactories.put(ProtocolVersion.v8_0, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_8_0(stateManager); - } - }); - - _dispatcherFactories.put(ProtocolVersion.v0_9, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_0_9(stateManager); - } - }); - - } - - - private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); - private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); - private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); - private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); - private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); - private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); - private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); - private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); - private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); - private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); - private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); - private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); - private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); - private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); - private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); - private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); - private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); - private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); - private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); - private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); - private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); - private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); - private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); - private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); - private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); - private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); - private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); - private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); - private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); - - - - public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) - { - return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); - } - - - public ServerMethodDispatcherImpl(AMQStateManager stateManager) - { - _stateManager = stateManager; - } - - - protected AMQStateManager getStateManager() - { - return _stateManager; - } - - - - public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException - { - _accessRequestHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException - { - _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException - { - _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException - { - _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException - { - _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException - { - _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException - { - _basicQosHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException - { - _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException - { - _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException - { - _channelOpenHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException - { - _channelCloseHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException - { - _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException - { - _channelFlowHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException - { - _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException - { - _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException - { - _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException - { - _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException - { - _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException - { - _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException - { - _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException - { - _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException - { - _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException - { - _queueBindHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException - { - _queueDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException - { - _queueDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException - { - _queuePurgeHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException - { - _txCommitHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException - { - _txRollbackHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException - { - _txSelectHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.Map; +import java.util.HashMap; + +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.framing.*; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl implements MethodDispatcher +{ + private final AMQStateManager _stateManager; + + private static interface DispatcherFactory + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); + } + + private static final Map _dispatcherFactories = + new HashMap(); + + + static + { + _dispatcherFactories.put(ProtocolVersion.v8_0, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_8_0(stateManager); + } + }); + + _dispatcherFactories.put(ProtocolVersion.v0_9, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_0_9(stateManager); + } + }); + + } + + + private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); + private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); + private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); + private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); + private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); + private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); + private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); + private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); + private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); + private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); + private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); + private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); + private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); + private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); + private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); + private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); + private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); + private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); + private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); + private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); + private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); + private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); + private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); + private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); + private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); + private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); + private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); + private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); + private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); + + + + public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) + { + return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); + } + + + public ServerMethodDispatcherImpl(AMQStateManager stateManager) + { + _stateManager = stateManager; + } + + + protected AMQStateManager getStateManager() + { + return _stateManager; + } + + + + public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException + { + _accessRequestHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException + { + _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException + { + _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException + { + _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException + { + _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException + { + _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException + { + _basicQosHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException + { + _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException + { + _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException + { + _channelOpenHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException + { + _channelCloseHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException + { + _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException + { + _channelFlowHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException + { + _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException + { + _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException + { + _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException + { + _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException + { + _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException + { + _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException + { + _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException + { + _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException + { + _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException + { + _queueBindHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException + { + _queueDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException + { + _queueDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException + { + _queuePurgeHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException + { + _txCommitHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException + { + _txRollbackHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException + { + _txSelectHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java index 8b1dca77ba..382a85347b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java @@ -1,164 +1,164 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.amqp_0_9.MethodDispatcher_0_9; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - - - -public class ServerMethodDispatcherImpl_0_9 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_0_9 - -{ - - private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = - BasicRecoverSyncMethodHandler.getInstance(); - private static final QueueUnbindHandler _queueUnbindHandler = - QueueUnbindHandler.getInstance(); - - - public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException - { - _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); - return true; - } - - public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException - { - _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); - return true; - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_0_9.MethodDispatcher_0_9; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + + + +public class ServerMethodDispatcherImpl_0_9 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_0_9 + +{ + + private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = + BasicRecoverSyncMethodHandler.getInstance(); + private static final QueueUnbindHandler _queueUnbindHandler = + QueueUnbindHandler.getInstance(); + + + public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException + { + _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); + return true; + } + + public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException + { + _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java index d599ca3d4e..22f64cf7d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java @@ -1,86 +1,86 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - -public class ServerMethodDispatcherImpl_8_0 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_8_0 -{ - public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException - { - return false; - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_8_0.MethodDispatcher_8_0; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl_8_0 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_8_0 +{ + public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException + { + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java index fb18519fe1..0abb3cdd7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java @@ -1,33 +1,33 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - - -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.AMQException; - -public class UnexpectedMethodException extends AMQException -{ - public UnexpectedMethodException(AMQMethodBody body) - { - super("Unexpected method recevied: " + body.getClass().getName()); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.AMQMethodBody; +import org.apache.qpid.AMQException; + +public class UnexpectedMethodException extends AMQException +{ + public UnexpectedMethodException(AMQMethodBody body) + { + super("Unexpected method recevied: " + body.getClass().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java index e01c5aabbf..576d577b40 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -1,57 +1,57 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.AMQException; - -public interface ProtocolOutputConverter -{ - void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); - - interface Factory - { - ProtocolOutputConverter newInstance(AMQProtocolSession session); - } - - void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException; - - void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; - - byte getProtocolMinorVersion(); - - byte getProtocolMajorVersion(); - - void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException; - - void writeFrame(AMQDataBlock block); -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public interface ProtocolOutputConverter +{ + void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); + + interface Factory + { + ProtocolOutputConverter newInstance(AMQProtocolSession session); + } + + void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException; + + void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + + byte getProtocolMinorVersion(); + + byte getProtocolMajorVersion(); + + void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException; + + void writeFrame(AMQDataBlock block); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java index 36e7e88fd6..02fb1429c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -1,61 +1,61 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.ProtocolVersion; - -import java.util.Map; -import java.util.HashMap; - -public class ProtocolOutputConverterRegistry -{ - - private static final Map _registry = - new HashMap(); - - - static - { - register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); - register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); - - } - - private static void register(ProtocolVersion version, Factory converter) - { - - _registry.put(version,converter); - } - - - public static ProtocolOutputConverter getConverter(AMQProtocolSession session) - { - return _registry.get(session.getProtocolVersion()).newInstance(session); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.ProtocolVersion; + +import java.util.Map; +import java.util.HashMap; + +public class ProtocolOutputConverterRegistry +{ + + private static final Map _registry = + new HashMap(); + + + static + { + register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); + register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); + + } + + private static void register(ProtocolVersion version, Factory converter) + { + + _registry.put(version,converter); + } + + + public static ProtocolOutputConverter getConverter(AMQProtocolSession session) + { + return _registry.get(session.getProtocolVersion()).newInstance(session); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index d7a879180a..d4cb7c878f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -1,285 +1,285 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output.amqp0_8; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.AMQException; - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final Long messageId = message.getMessageId(); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext,messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); - - AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicDeliverBody deliverBody = - methodRegistry.createBasicDeliverBody(consumerTag, - deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey()); - AMQFrame deliverFrame = deliverBody.generateFrame(channelId); - - - return deliverFrame; - } - - private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicGetOkBody getOkBody = - methodRegistry.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicReturnBody basicReturnBody = - methodRegistry.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final Long messageId = message.getMessageId(); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext,messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, messageId, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicDeliverBody deliverBody = + methodRegistry.createBasicDeliverBody(consumerTag, + deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey()); + AMQFrame deliverFrame = deliverBody.generateFrame(channelId); + + + return deliverFrame; + } + + private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicGetOkBody getOkBody = + methodRegistry.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicReturnBody basicReturnBody = + methodRegistry.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index 48d2ca9bc9..f87d3bcae1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -1,397 +1,397 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.output.amqp0_9; - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); - private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); - - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final Long messageId = message.getMessageId(); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - - if(bodyCount == 0) - { - SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, - contentHeaderBody); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); - - CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext,messageId, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - - } - - private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) - { - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - contentHeaderBody); - return contentHeader; - } - - - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); - - AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, messageId, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - - } - - - private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) - throws AMQException - { - - - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - - final AMQBody returnBlock = new AMQBody() - { - - - - private final boolean _isRedelivered = messageHandle.isRedelivered(); - private final AMQShortString _exchangeName = pb.getExchange(); - private final AMQShortString _routingKey = pb.getRoutingKey(); - - - public AMQBody _underlyingBody; - - public AMQBody createAMQBody() - { - return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, - deliveryTag, - _isRedelivered, - _exchangeName, - _routingKey); - - - - - - } - - public byte getFrameType() - { - return AMQMethodBody.TYPE; - } - - public int getSize() - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - return _underlyingBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - _underlyingBody.writePayload(buffer); - } - - public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) - throws AMQException - { - throw new AMQException("This block should never be dispatched!"); - } - }; - return returnBlock; - } - - private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - - BasicGetOkBody getOkBody = - METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - - BasicReturnBody basicReturnBody = - METHOD_REGISTRY.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - - BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } - - - public static final class CompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final AMQBody _contentBody; - private final int _channel; - - - public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - _contentBody = contentBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); - } - } - - public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final int _channel; - - - public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); - } - } - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.output.amqp0_9; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); + + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final Long messageId = message.getMessageId(); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + + if(bodyCount == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); + + CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext,messageId, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + final long messageId = message.getMessageId(); + + AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, messageId, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + + private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) + throws AMQException + { + + + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + final AMQBody returnBlock = new AMQBody() + { + + + + private final boolean _isRedelivered = messageHandle.isRedelivered(); + private final AMQShortString _exchangeName = pb.getExchange(); + private final AMQShortString _routingKey = pb.getRoutingKey(); + + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + _isRedelivered, + _exchangeName, + _routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java index a7599a3e0d..92f951ce39 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -1,46 +1,46 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to handle an AMQP method. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a - * Runtime. - */ -public class AMQNoMethodHandlerException extends AMQException -{ - public AMQNoMethodHandlerException(AMQMethodEvent evt) - { - super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to handle an AMQP method. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a + * Runtime. + */ +public class AMQNoMethodHandlerException extends AMQException +{ + public AMQNoMethodHandlerException(AMQMethodEvent evt) + { + super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java index 6e72aa062f..bb2db8d506 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -1,46 +1,46 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; - -/** - * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to cast a frame to its expected type. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would - * be better just to leave that as a ClassCastException. However, check the framing layer catches this error - * first. - */ -public class UnknnownMessageTypeException extends AMQException -{ - public UnknnownMessageTypeException(AMQDataBlock message) - { - super("Unknown message type: " + message.getClass().getName() + ": " + message); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; + +/** + * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to cast a frame to its expected type. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would + * be better just to leave that as a ClassCastException. However, check the framing layer catches this error + * first. + */ +public class UnknnownMessageTypeException extends AMQException +{ + public UnknnownMessageTypeException(AMQDataBlock message) + { + super("Unknown message type: " + message.getClass().getName() + ": " + message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 6f9efd3200..65115e4103 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -1,138 +1,138 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -public enum NotificationCheck -{ - - MESSAGE_COUNT_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - int msgCount; - final long maximumMessageCount = queue.getMaximumMessageCount(); - if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) - { - listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); - return true; - } - return false; - } - }, - MESSAGE_SIZE_ALERT(true) - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - final long maximumMessageSize = queue.getMaximumMessageSize(); - if(maximumMessageSize != 0) - { - // Check for threshold message size - long messageSize; - try - { - messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - messageSize = 0; - } - - - if (messageSize >= maximumMessageSize) - { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); - return true; - } - } - return false; - } - - }, - QUEUE_DEPTH_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - // Check for threshold queue depth in bytes - final long maximumQueueDepth = queue.getMaximumQueueDepth(); - - if(maximumQueueDepth != 0) - { - final long queueDepth = queue.getQueueDepth(); - - if (queueDepth >= maximumQueueDepth) - { - listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); - return true; - } - } - return false; - } - - }, - MESSAGE_AGE_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - - final long maxMessageAge = queue.getMaximumMessageAge(); - if(maxMessageAge != 0) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - maxMessageAge; - final long firstArrivalTime = queue.getOldestMessageArrivalTime(); - - if(firstArrivalTime < thresholdTime) - { - long oldestAge = currentTime - firstArrivalTime; - listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); - - return true; - } - } - return false; - - } - - } - ; - - private final boolean _messageSpecific; - - NotificationCheck() - { - this(false); - } - - NotificationCheck(boolean messageSpecific) - { - _messageSpecific = messageSpecific; - } - - public boolean isMessageSpecific() - { - return _messageSpecific; - } - - abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 enum NotificationCheck +{ + + MESSAGE_COUNT_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + int msgCount; + final long maximumMessageCount = queue.getMaximumMessageCount(); + if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) + { + listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); + return true; + } + return false; + } + }, + MESSAGE_SIZE_ALERT(true) + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + final long maximumMessageSize = queue.getMaximumMessageSize(); + if(maximumMessageSize != 0) + { + // Check for threshold message size + long messageSize; + try + { + messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + messageSize = 0; + } + + + if (messageSize >= maximumMessageSize) + { + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + return true; + } + } + return false; + } + + }, + QUEUE_DEPTH_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + // Check for threshold queue depth in bytes + final long maximumQueueDepth = queue.getMaximumQueueDepth(); + + if(maximumQueueDepth != 0) + { + final long queueDepth = queue.getQueueDepth(); + + if (queueDepth >= maximumQueueDepth) + { + listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); + return true; + } + } + return false; + } + + }, + MESSAGE_AGE_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + + final long maxMessageAge = queue.getMaximumMessageAge(); + if(maxMessageAge != 0) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - maxMessageAge; + final long firstArrivalTime = queue.getOldestMessageArrivalTime(); + + if(firstArrivalTime < thresholdTime) + { + long oldestAge = currentTime - firstArrivalTime; + listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); + + return true; + } + } + return false; + + } + + } + ; + + private final boolean _messageSpecific; + + NotificationCheck() + { + this(false); + } + + NotificationCheck(boolean messageSpecific) + { + _messageSpecific = messageSpecific; + } + + public boolean isMessageSpecific() + { + return _messageSpecific; + } + + abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java index 959ca03c80..f1e7c98387 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -1,27 +1,27 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - - -public interface QueueNotificationListener -{ - void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 QueueNotificationListener +{ + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 85d804457e..70a76dd8c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -1,44 +1,44 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; - -/** - * The management interface exposed to allow management of an Exchange. - * @version 0.1 - */ -public interface ManagedVirtualHost -{ - static final String TYPE = "VirtualHost"; - - /** - * Returns the name of the managed virtualHost. - * @return the name of the exchange. - * @throws java.io.IOException - */ - @MBeanAttribute(name="Name", description= TYPE + " Name") - String getName() throws IOException; - - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; + +/** + * The management interface exposed to allow management of an Exchange. + * @version 0.1 + */ +public interface ManagedVirtualHost +{ + static final String TYPE = "VirtualHost"; + + /** + * Returns the name of the managed virtualHost. + * @return the name of the exchange. + * @throws java.io.IOException + */ + @MBeanAttribute(name="Name", description= TYPE + " Name") + String getName() throws IOException; + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 27917fac8a..9b1619c609 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -1,70 +1,70 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -public class VirtualHostRegistry -{ - private final Map _registry = new ConcurrentHashMap(); - - - private String _defaultVirtualHostName; - - public synchronized void registerVirtualHost(VirtualHost host) throws Exception - { - if(_registry.containsKey(host.getName())) - { - throw new Exception("Virtual Host with name " + host.getName() + " already registered."); - } - _registry.put(host.getName(),host); - } - - public VirtualHost getVirtualHost(String name) - { - if(name == null || name.trim().length() == 0 ) - { - name = getDefaultVirtualHostName(); - } - - return _registry.get(name); - } - - private String getDefaultVirtualHostName() - { - return _defaultVirtualHostName; - } - - public void setDefaultVirtualHostName(String defaultVirtualHostName) - { - _defaultVirtualHostName = defaultVirtualHostName; - } - - - public Collection getVirtualHosts() - { - return new ArrayList(_registry.values()); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class VirtualHostRegistry +{ + private final Map _registry = new ConcurrentHashMap(); + + + private String _defaultVirtualHostName; + + public synchronized void registerVirtualHost(VirtualHost host) throws Exception + { + if(_registry.containsKey(host.getName())) + { + throw new Exception("Virtual Host with name " + host.getName() + " already registered."); + } + _registry.put(host.getName(),host); + } + + public VirtualHost getVirtualHost(String name) + { + if(name == null || name.trim().length() == 0 ) + { + name = getDefaultVirtualHostName(); + } + + return _registry.get(name); + } + + private String getDefaultVirtualHostName() + { + return _defaultVirtualHostName; + } + + public void setDefaultVirtualHostName(String defaultVirtualHostName) + { + _defaultVirtualHostName = defaultVirtualHostName; + } + + + public Collection getVirtualHosts() + { + return new ArrayList(_registry.values()); + } +} -- cgit v1.2.1 From 15c43931e982f9c811574dffbdf8d1c191012a9c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 May 2008 10:24:26 +0000 Subject: QPID-887 : Renamed QueueHouseKeeping threads so they can be identified in thread dump. Named Queue-housekeeping- git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@653415 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHost.java | 69 +++++++++++----------- 1 file changed, 36 insertions(+), 33 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 3ff9b8c356..90dc7432b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -71,8 +71,8 @@ public class VirtualHost implements Accessable private ACLPlugin _accessManager; - private final Timer _houseKeepingTimer = new Timer("Queue-housekeeping", true); - + private Timer _houseKeepingTimer; + private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public void setAccessableName(String name) @@ -172,43 +172,46 @@ public class VirtualHost implements Accessable _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); + + _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + initialiseHouseKeeping(hostConfig); } private void initialiseHouseKeeping(final Configuration hostConfig) { - - long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); - - /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if(period != 0L) - { - class RemoveExpiredMessagesTask extends TimerTask - { - public void run() - { - for(AMQQueue q : _queueRegistry.getQueues()) - { - - try - { - q.removeExpiredIfNoSubscribers(); - } - catch (AMQException e) - { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e); - throw new RuntimeException(e); - } - } - } - } - - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period/2, - period); - } + + long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); + + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ + if (period != 0L) + { + class RemoveExpiredMessagesTask extends TimerTask + { + public void run() + { + for (AMQQueue q : _queueRegistry.getQueues()) + { + + try + { + q.removeExpiredIfNoSubscribers(); + } + catch (AMQException e) + { + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + throw new RuntimeException(e); + } + } + } + } + + _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), + period / 2, + period); + } } - + private void initialiseMessageStore(Configuration config) throws Exception { String messageStoreClass = config.getString("store.class"); -- cgit v1.2.1 From cc2b691a89b4250cccdce08009602570110570a7 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 6 May 2008 09:26:37 +0000 Subject: Merged revisions 652388-652389,652399,652567-652568,653416 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2.x ........ r652388 | ritchiem | 2008-04-30 15:40:18 +0100 (Wed, 30 Apr 2008) | 2 lines QPID-889 : Removed _reapingStoreContext from CSDM replaced with local StoreContext()s so they are not reused by different threads. ........ r652389 | ritchiem | 2008-04-30 15:40:45 +0100 (Wed, 30 Apr 2008) | 1 line QPID-887 : Renamed QueueHouseKeeping threads so they can be identified in thread dump. Named Queue-housekeeping- ........ r652399 | ritchiem | 2008-04-30 16:32:42 +0100 (Wed, 30 Apr 2008) | 1 line QPID-888,QPID-886 : Fixed all management uses of _lock.lock / _lock.unlock so that they correctly call unlock from a finally block in the CSDM. There are two issues that cover that. QPID-888 - Fix the management ones and QPID-886 to fix the use in removeExpired. ........ r652567 | aidan | 2008-05-01 17:32:20 +0100 (Thu, 01 May 2008) | 1 line QPID-994 Dont wait for attain state as connection is closed by we get CloseOk ........ r652568 | aidan | 2008-05-01 17:35:09 +0100 (Thu, 01 May 2008) | 1 line QPID-1001 dont set the expiration time if TTL is 0 ........ r653416 | aidan | 2008-05-05 11:24:50 +0100 (Mon, 05 May 2008) | 1 line QPID-1019 prevent messages being dequeued unecessarily, from rgodfrey ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@653720 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 2 +- .../qpid/server/ack/UnacknowledgedMessage.java | 23 ++- .../queue/ConcurrentSelectorDeliveryManager.java | 178 +++++++++++++-------- 3 files changed, 129 insertions(+), 74 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 74169a19bb..1314b2b715 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -469,7 +469,7 @@ public class AMQChannel synchronized (_unacknowledgedMessageMap.getLock()) { - _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(entry, consumerTag, deliveryTag)); + _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(entry, consumerTag, deliveryTag,_unacknowledgedMessageMap)); checkSuspension(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java index df7cecc940..0112d3b388 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -34,13 +34,18 @@ public class UnacknowledgedMessage public final long deliveryTag; private boolean _queueDeleted; + private final UnacknowledgedMessageMap _unacknowledgeMessageMap; - public UnacknowledgedMessage(QueueEntry entry, AMQShortString consumerTag, long deliveryTag) + public UnacknowledgedMessage(QueueEntry entry, + AMQShortString consumerTag, + long deliveryTag, + final UnacknowledgedMessageMap unacknowledgedMessageMap) { this.entry = entry; this.consumerTag = consumerTag; this.deliveryTag = deliveryTag; + _unacknowledgeMessageMap = unacknowledgedMessageMap; } public String toString() @@ -60,12 +65,20 @@ public class UnacknowledgedMessage public void discard(StoreContext storeContext) throws AMQException { - if (entry.getQueue() != null) + synchronized(_unacknowledgeMessageMap) { - entry.getQueue().dequeue(storeContext, entry); + if(_unacknowledgeMessageMap.contains(deliveryTag)) + { + + if (entry.getQueue() != null) + { + entry.getQueue().dequeue(storeContext, entry); + } + //if the queue is null then the message is waiting to be acked, but has been removed. + entry.getMessage().decrementReference(storeContext); + } } - //if the queue is null then the message is waiting to be acked, but has been removed. - entry.getMessage().decrementReference(storeContext); + } public AMQMessage getMessage() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index 7dfcae95c3..cf607548f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -87,10 +87,6 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager private final Object _queueHeadLock = new Object(); private String _processingThreadName = ""; - - /** Used by any reaping thread to purge messages */ - private StoreContext _reapingStoreContext = new StoreContext(); - ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) { @@ -218,22 +214,32 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void removeExpired() throws AMQException { _lock.lock(); - - - for(Iterator iter = _messages.iterator(); iter.hasNext();) + try { - QueueEntry entry = iter.next(); - if(entry.expired()) + // New Context to for dealing with the MessageStore. + StoreContext context = new StoreContext(); + + for(Iterator iter = _messages.iterator(); iter.hasNext();) { - // fixme: Currently we have to update the total byte size here for the data in the queue - _totalMessageSize.addAndGet(-entry.getSize()); - _queue.dequeue(_reapingStoreContext,entry); - iter.remove(); - } - } + QueueEntry entry = iter.next(); + if(entry.expired()) + { + // fixme: Currently we have to update the total byte size here for the data in the queue + _totalMessageSize.addAndGet(-entry.getSize()); + // Remove the message from the queue in the MessageStore + _queue.dequeue(context,entry); - _lock.unlock(); + // This queue nolonger needs a reference to this message + entry.getMessage().decrementReference(context); + iter.remove(); + } + } + } + finally + { + _lock.unlock(); + } } /** @return the state of the async processor. */ @@ -249,14 +255,20 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager */ public List getMessages() { - _lock.lock(); - List list = new ArrayList(); + List list = new ArrayList(); - for (QueueEntry entry : _messages) + _lock.lock(); + try { - list.add(entry); + for (QueueEntry entry : _messages) + { + list.add(entry); + } + } + finally + { + _lock.unlock(); } - _lock.unlock(); return list; } @@ -278,24 +290,28 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager long maxMessageCount = toMessageId - fromMessageId + 1; - _lock.lock(); - List foundMessagesList = new ArrayList(); - - for (QueueEntry entry : _messages) + _lock.lock(); + try { - long msgId = entry.getMessage().getMessageId(); - if (msgId >= fromMessageId && msgId <= toMessageId) + for (QueueEntry entry : _messages) { - foundMessagesList.add(entry); - } - // break if the no of messages are found - if (foundMessagesList.size() == maxMessageCount) - { - break; + long msgId = entry.getMessage().getMessageId(); + if (msgId >= fromMessageId && msgId <= toMessageId) + { + foundMessagesList.add(entry); + } + // break if the no of messages are found + if (foundMessagesList.size() == maxMessageCount) + { + break; + } } } - _lock.unlock(); + finally + { + _lock.unlock(); + } return foundMessagesList; } @@ -445,45 +461,62 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _lock.lock(); - QueueEntry entry = _messages.poll(); - - if (entry != null) + try { - queue.dequeue(storeContext, entry); + QueueEntry entry = _messages.poll(); - _totalMessageSize.addAndGet(-entry.getSize()); + if (entry != null) + { + queue.dequeue(storeContext, entry); - //If this causes ref count to hit zero then data will be purged so message.getSize() will NPE. - entry.getMessage().decrementReference(storeContext); + _totalMessageSize.addAndGet(-entry.getSize()); - } + //If this causes ref count to hit zero then data will be purged so message.getSize() will NPE. + entry.getMessage().decrementReference(storeContext); - _lock.unlock(); + } + } + finally + { + _lock.unlock(); + } } public long clearAllMessages(StoreContext storeContext) throws AMQException { long count = 0; - _lock.lock(); - synchronized (_queueHeadLock) + _lock.lock(); + try { - QueueEntry entry = getNextMessage(); - while (entry != null) + synchronized (_queueHeadLock) { - //and remove it - _messages.poll(); + QueueEntry entry = getNextMessage(); - _queue.dequeue(storeContext, entry); + // todo: note: why do we need this? Why not reuse the passed 'storeContext' + //Create a new StoreContext for decrementing the References + StoreContext context = new StoreContext(); + + while (entry != null) + { + //and remove it + _messages.poll(); - entry.getMessage().decrementReference(_reapingStoreContext); + // todo: NOTE: Why is this a different context to the new local 'context'? + _queue.dequeue(storeContext, entry); - entry = getNextMessage(); - count++; + entry.getMessage().decrementReference(context); + + entry = getNextMessage(); + count++; + } + _totalMessageSize.set(0L); } - _totalMessageSize.set(0L); } - _lock.unlock(); + finally + { + _lock.unlock(); + } return count; } @@ -518,10 +551,13 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { _totalMessageSize.addAndGet(-entry.getSize()); + // New Store Context for removing expired messages + StoreContext storeContext = new StoreContext(); + // Use the reapingStoreContext as any sub(if we have one) may be in a tx. - _queue.dequeue(_reapingStoreContext, entry); + _queue.dequeue(storeContext, entry); - message.decrementReference(_reapingStoreContext); + message.decrementReference(storeContext); if (_log.isInfoEnabled()) { @@ -760,24 +796,30 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void enqueueMovedMessages(StoreContext storeContext, List movedMessageList) { _lock.lock(); - for (QueueEntry entry : movedMessageList) - { - addMessageToQueue(entry, false); - } - - // enqueue on the pre delivery queues - for (Subscription sub : _subscriptions.getSubscriptions()) + try { for (QueueEntry entry : movedMessageList) { - // Only give the message to those that want them. - if (sub.hasInterest(entry)) + addMessageToQueue(entry, false); + } + + // enqueue on the pre delivery queues + for (Subscription sub : _subscriptions.getSubscriptions()) + { + for (QueueEntry entry : movedMessageList) { - sub.enqueueForPreDelivery(entry, true); + // Only give the message to those that want them. + if (sub.hasInterest(entry)) + { + sub.enqueueForPreDelivery(entry, true); + } } } } - _lock.unlock(); + finally + { + _lock.unlock(); + } } /** -- cgit v1.2.1 From a6cb2c7292734b59868687bb8928582f0aa296ec Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 16 May 2008 15:08:55 +0000 Subject: QPID-1060 : Release ref to transient meta data; cache message size git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@657097 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQMessage.java | 33 ++++++++++++++-------- .../qpid/server/queue/NotificationCheck.java | 11 +------- 2 files changed, 22 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index f501bc27d1..a76b13ce74 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -89,6 +89,11 @@ public class AMQMessage private static final boolean SYNCED_CLOCKS = ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false); + private static final long UNKNOWN_SIZE = Long.MIN_VALUE; + + private long _size = UNKNOWN_SIZE; + + public String debugIdentity() { @@ -255,7 +260,6 @@ public class AMQMessage _txnContext = txnContext; _immediate = info.isImmediate(); _transientMessageData.setMessagePublishInfo(info); - } /** @@ -276,6 +280,7 @@ public class AMQMessage _messageHandle = factory.createMessageHandle(messageId, store, true); _txnContext = txnConext; _transientMessageData = null; + } /** @@ -352,6 +357,7 @@ public class AMQMessage public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException { _transientMessageData.setContentHeaderBody(contentHeaderBody); + _size = _transientMessageData.getContentHeaderBody().bodySize; } public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) @@ -376,6 +382,8 @@ public class AMQMessage { deliver(storeContext); } + + } public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException @@ -670,6 +678,7 @@ public class AMQMessage // Remove refence for routing process . Reference count should now == delivered queue count decrementReference(storeContext); + _transientMessageData = null; } } @@ -681,19 +690,19 @@ public class AMQMessage public long getSize() { - try + if(_size == UNKNOWN_SIZE) { - long size = getContentHeaderBody().bodySize; - - return size; - } - catch (AMQException e) - { - _log.error(e.toString(), e); - - return 0; + try + { + _size = getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + _log.warn("Unable to retrieve message meta data for message:" + this, e); + return 0; + } } - + return _size; } public void restoreTransientMessageData() throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 65115e4103..12d6c5998a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -47,16 +47,7 @@ public enum NotificationCheck if(maximumMessageSize != 0) { // Check for threshold message size - long messageSize; - try - { - messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - messageSize = 0; - } - + long messageSize = (msg == null) ? 0 : msg.getSize(); if (messageSize >= maximumMessageSize) { -- cgit v1.2.1 From db54dfbaa9bd04f23745cf93b3ee4a56d0817cf7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 19 May 2008 16:54:06 +0000 Subject: QPID-1066 : Removed isInfo wrapping. Added test that is missing from trunk from M2.x QueueDepthSelectorTest. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@657859 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/ConcurrentSelectorDeliveryManager.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index cf607548f8..0e8cff0f2a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -751,13 +751,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser()) { - if (_log.isInfoEnabled()) - { - //fixme - we should do the clean up as the message remains on the _message queue - // this is resulting in the next consumer receiving the message and then attempting to purge it - // - cleanMainQueue(sub); - } + cleanMainQueue(sub); } } -- cgit v1.2.1 From a16002f9be0a06da956eb548d70a3fcd1adeab89 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 19 Jun 2008 09:01:59 +0000 Subject: QPID-950 : Broker refactoring, copied / merged from branch git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@669431 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 8 +- .../java/org/apache/qpid/server/AMQChannel.java | 575 +++---- .../src/main/java/org/apache/qpid/server/Main.java | 6 + .../qpid/server/RequiredDeliveryException.java | 15 +- .../java/org/apache/qpid/server/ack/TxAck.java | 56 +- .../qpid/server/ack/UnacknowledgedMessage.java | 104 -- .../qpid/server/ack/UnacknowledgedMessageMap.java | 24 +- .../server/ack/UnacknowledgedMessageMapImpl.java | 63 +- .../configuration/VirtualHostConfiguration.java | 21 +- .../qpid/server/exchange/AbstractExchange.java | 4 +- .../server/exchange/DefaultExchangeFactory.java | 6 +- .../server/exchange/DefaultExchangeRegistry.java | 5 +- .../qpid/server/exchange/DestNameExchange.java | 260 --- .../qpid/server/exchange/DestWildExchange.java | 579 ------- .../qpid/server/exchange/DirectExchange.java | 245 +++ .../org/apache/qpid/server/exchange/Exchange.java | 7 +- .../qpid/server/exchange/FanoutExchange.java | 32 +- .../qpid/server/exchange/HeadersExchange.java | 26 +- .../org/apache/qpid/server/exchange/Index.java | 2 +- .../apache/qpid/server/exchange/MessageRouter.java | 3 +- .../qpid/server/exchange/NoRouteException.java | 5 +- .../apache/qpid/server/exchange/TopicExchange.java | 651 ++++++++ .../qpid/server/exchange/headers/HeaderKey.java | 40 + .../exchange/headers/HeaderKeyDictionary.java | 50 + .../exchange/headers/HeaderMatcherResult.java | 25 + .../exchange/headers/HeadersMatcherDFAState.java | 339 ++++ .../server/exchange/headers/HeadersParser.java | 439 +++++ .../exchange/topic/TopicMatcherDFAState.java | 295 ++++ .../server/exchange/topic/TopicMatcherResult.java | 25 + .../qpid/server/exchange/topic/TopicParser.java | 613 +++++++ .../qpid/server/exchange/topic/TopicWord.java | 54 + .../server/exchange/topic/TopicWordDictionary.java | 63 + .../qpid/server/filter/ArithmeticExpression.java | 6 +- .../qpid/server/filter/BinaryExpression.java | 16 +- .../qpid/server/filter/BooleanExpression.java | 7 +- .../qpid/server/filter/ComparisonExpression.java | 141 +- .../qpid/server/filter/ConstantExpression.java | 16 +- .../org/apache/qpid/server/filter/Expression.java | 5 +- .../apache/qpid/server/filter/FilterManager.java | 10 +- .../qpid/server/filter/FilterManagerFactory.java | 14 +- .../qpid/server/filter/JMSSelectorFilter.java | 31 +- .../apache/qpid/server/filter/LogicExpression.java | 126 +- .../apache/qpid/server/filter/MessageFilter.java | 5 +- .../qpid/server/filter/NoConsumerFilter.java | 4 +- .../qpid/server/filter/PropertyExpression.java | 332 ++-- .../qpid/server/filter/SimpleFilterManager.java | 15 +- .../apache/qpid/server/filter/UnaryExpression.java | 322 ++-- .../apache/qpid/server/filter/XPathExpression.java | 7 +- .../qpid/server/filter/XQueryExpression.java | 5 +- .../qpid/server/filter/XalanXPathEvaluator.java | 3 +- .../server/flow/AbstractFlowCreditManager.java | 62 + .../qpid/server/flow/BytesOnlyCreditManager.java | 77 + .../apache/qpid/server/flow/FlowCreditManager.java | 44 + .../qpid/server/flow/LimitlessCreditManager.java | 44 + .../server/flow/MessageAndBytesCreditManager.java | 79 + .../qpid/server/flow/MessageOnlyCreditManager.java | 76 + .../qpid/server/flow/Pre0_10CreditManager.java | 185 +++ .../qpid/server/handler/AccessRequestHandler.java | 105 +- .../server/handler/BasicCancelMethodHandler.java | 4 +- .../server/handler/BasicConsumeMethodHandler.java | 5 +- .../qpid/server/handler/BasicGetMethodHandler.java | 288 ++-- .../server/handler/BasicPublishMethodHandler.java | 2 +- .../qpid/server/handler/BasicQosHandler.java | 6 +- .../handler/BasicRecoverSyncMethodHandler.java | 129 +- .../server/handler/BasicRejectMethodHandler.java | 27 +- .../qpid/server/handler/ExchangeBoundHandler.java | 4 +- .../server/handler/ExchangeDeclareHandler.java | 2 +- .../qpid/server/handler/QueueBindHandler.java | 2 +- .../qpid/server/handler/QueueDeclareHandler.java | 9 +- .../qpid/server/handler/QueueDeleteHandler.java | 10 +- .../qpid/server/handler/QueuePurgeHandler.java | 240 ++- .../qpid/server/handler/QueueUnbindHandler.java | 25 +- .../server/handler/ServerMethodDispatcherImpl.java | 1132 ++++++------- .../handler/ServerMethodDispatcherImpl_0_9.java | 328 ++-- .../handler/ServerMethodDispatcherImpl_8_0.java | 172 +- .../qpid/server/handler/TxCommitHandler.java | 4 +- .../server/handler/UnexpectedMethodException.java | 66 +- .../server/output/ProtocolOutputConverter.java | 114 +- .../output/ProtocolOutputConverterRegistry.java | 122 +- .../amqp0_8/ProtocolOutputConverterImpl.java | 569 ++++--- .../amqp0_9/ProtocolOutputConverterImpl.java | 767 +++++---- .../server/protocol/AMQMinaProtocolSession.java | 23 +- .../protocol/AMQNoMethodHandlerException.java | 92 +- .../server/protocol/AMQPFastProtocolHandler.java | 4 + .../qpid/server/protocol/AMQProtocolSession.java | 25 +- .../protocol/UnknnownMessageTypeException.java | 92 +- .../org/apache/qpid/server/queue/AMQMessage.java | 465 ++---- .../apache/qpid/server/queue/AMQMessageHandle.java | 32 +- .../apache/qpid/server/queue/AMQPriorityQueue.java | 67 + .../org/apache/qpid/server/queue/AMQQueue.java | 1005 ++---------- .../apache/qpid/server/queue/AMQQueueFactory.java | 52 + .../apache/qpid/server/queue/AMQQueueMBean.java | 4 +- .../queue/ConcurrentSelectorDeliveryManager.java | 1097 ------------- .../apache/qpid/server/queue/DeliveryManager.java | 102 -- .../apache/qpid/server/queue/ExchangeBindings.java | 4 +- .../org/apache/qpid/server/queue/Filterable.java | 33 + .../qpid/server/queue/InMemoryMessageHandle.java | 71 +- .../apache/qpid/server/queue/IncomingMessage.java | 336 ++++ .../org/apache/qpid/server/queue/ManagedQueue.java | 2 +- .../qpid/server/queue/MessageHandleFactory.java | 4 +- .../qpid/server/queue/NotificationCheck.java | 267 ++-- .../qpid/server/queue/PriorityQueueList.java | 164 ++ .../org/apache/qpid/server/queue/QueueEntry.java | 245 +-- .../apache/qpid/server/queue/QueueEntryImpl.java | 392 +++++ .../qpid/server/queue/QueueEntryIterator.java | 30 + .../apache/qpid/server/queue/QueueEntryList.java | 34 + .../qpid/server/queue/QueueEntryListFactory.java | 26 + .../server/queue/QueueNotificationListener.java | 54 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 1671 ++++++++++++++++++++ .../qpid/server/queue/SimpleQueueEntryList.java | 178 +++ .../org/apache/qpid/server/queue/Subscription.java | 63 - .../qpid/server/queue/SubscriptionFactory.java | 43 - .../apache/qpid/server/queue/SubscriptionImpl.java | 680 -------- .../qpid/server/queue/SubscriptionManager.java | 34 - .../apache/qpid/server/queue/SubscriptionSet.java | 274 ---- .../server/queue/WeakReferenceMessageHandle.java | 66 +- .../server/queue/WeightedSubscriptionManager.java | 26 - .../qpid/server/registry/ApplicationRegistry.java | 6 +- .../ConfigurationFileApplicationRegistry.java | 7 +- .../qpid/server/security/access/Permission.java | 74 +- .../server/security/access/plugins/AllowAll.java | 4 - .../qpid/server/store/DerbyMessageStore.java | 192 +-- .../qpid/server/store/MemoryMessageStore.java | 8 +- .../org/apache/qpid/server/store/MessageStore.java | 17 +- .../org/apache/qpid/server/store/StoreContext.java | 7 +- .../server/subscription/ClientDeliveryMethod.java | 29 + .../server/subscription/RecordDeliveryMethod.java | 28 + .../qpid/server/subscription/Subscription.java | 94 ++ .../server/subscription/SubscriptionFactory.java | 59 + .../subscription/SubscriptionFactoryImpl.java | 103 ++ .../qpid/server/subscription/SubscriptionImpl.java | 605 +++++++ .../qpid/server/subscription/SubscriptionList.java | 247 +++ .../server/transport/ConnectorConfiguration.java | 4 + .../qpid/server/txn/CleanupMessageOperation.java | 77 - .../qpid/server/txn/LocalTransactionalContext.java | 140 +- .../qpid/server/txn/NonTransactionalContext.java | 73 +- .../qpid/server/txn/TransactionalContext.java | 23 +- .../server/virtualhost/ManagedVirtualHost.java | 88 +- .../qpid/server/virtualhost/VirtualHost.java | 23 +- .../server/virtualhost/VirtualHostRegistry.java | 140 +- .../qpid/tools/messagestore/MessageStoreTool.java | 2 +- .../qpid/tools/messagestore/commands/Copy.java | 2 +- .../qpid/tools/messagestore/commands/Dump.java | 3 +- .../qpid/tools/messagestore/commands/Move.java | 2 +- .../qpid/tools/messagestore/commands/Purge.java | 3 +- .../qpid/tools/messagestore/commands/Select.java | 2 +- .../qpid/tools/messagestore/commands/Show.java | 2 +- 147 files changed, 11629 insertions(+), 8596 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 9335723bc5..88d5360f3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -56,8 +56,9 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -175,7 +176,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr ownerShortString = new AMQShortString(owner); } - queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); + queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost(), + null); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); @@ -220,7 +222,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.removeQueue(new AMQShortString(queueName)); + _messageStore.removeQueue(queue); } catch (AMQException ex) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1314b2b715..847c8b8459 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -21,7 +21,6 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; @@ -30,14 +29,23 @@ import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -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.configuration.Configurator; -import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.NoRouteException; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; @@ -45,13 +53,13 @@ import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; import java.util.Collection; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class AMQChannel { @@ -61,13 +69,8 @@ public class AMQChannel private final int _channelId; - // private boolean _transactional; - - private long _prefetch_HighWaterMark; - private long _prefetch_LowWaterMark; - - private long _prefetchSize; + private final Pre0_10CreditManager _creditManager = new Pre0_10CreditManager(0l,0l); /** * The delivery tag is unique per channel. This is pre-incremented before putting into the deliver frame so that @@ -86,10 +89,11 @@ public class AMQChannel * 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; + private IncomingMessage _currentMessage; + + /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */ + private final Map _tag2SubscriptionMap = new HashMap(); - /** Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */ - private final Map _consumerTag2QueueMap = new ConcurrentHashMap(); private final MessageStore _messageStore; @@ -97,7 +101,7 @@ public class AMQChannel private final AtomicBoolean _suspended = new AtomicBoolean(false); - private TransactionalContext _txnContext, _nonTransactedContext; + private TransactionalContext _txnContext; /** * A context used by the message store enabling it to track context for a given channel even across thread @@ -109,8 +113,6 @@ public class AMQChannel private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); - private Set _browsedAcks = new HashSet(); - // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; private boolean _closing; @@ -118,7 +120,7 @@ public class AMQChannel @Configured(path = "advanced.enableJMSXUserID", defaultValue = "false") public boolean ENABLE_JMSXUserID; - + public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -129,8 +131,8 @@ public class AMQChannel _session = session; _channelId = channelId; _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); - _prefetch_HighWaterMark = DEFAULT_PREFETCH; - _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; + + _messageStore = messageStore; // by default the session is non-transactional @@ -140,7 +142,7 @@ public class AMQChannel /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { - _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages); + _txnContext = new LocalTransactionalContext(this); } public boolean isTransactional() @@ -156,55 +158,15 @@ public class AMQChannel return _channelId; } - public long getPrefetchCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - public long getPrefetchSize() - { - return _prefetchSize; - } - - public void setPrefetchSize(long prefetchSize) - { - _prefetchSize = prefetchSize; - } - - public long getPrefetchLowMarkCount() - { - return _prefetch_LowWaterMark; - } - - public void setPrefetchLowMarkCount(long prefetchCount) - { - _prefetch_LowWaterMark = prefetchCount; - } - - public long getPrefetchHighMarkCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchHighMarkCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher, final Exchange e) throws AMQException + public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException { - _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext); - _currentMessage.setPublisher(publisher); + _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session); + _currentMessage.setMessageStore(_messageStore); _currentMessage.setExchange(e); } - public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession) + public void publishContentHeader(ContentHeaderBody contentHeaderBody) throws AMQException { if (_currentMessage == null) @@ -215,7 +177,7 @@ public class AMQChannel { if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + "Content header received on channel " + _channelId); + _log.debug("Content header received on channel " + _channelId); } if (ENABLE_JMSXUserID) @@ -225,25 +187,48 @@ public class AMQChannel //fixme: fudge for QPID-677 properties.getHeaders().keySet(); - properties.setUserId(protocolSession.getAuthorizedID().getName()); + properties.setUserId(_session.getAuthorizedID().getName()); } _currentMessage.setContentHeaderBody(contentHeaderBody); + _currentMessage.setExpiration(); routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory); - // check and deliver if header says body length is zero - if (contentHeaderBody.bodySize == 0) + _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + + deliverCurrentMessageIfComplete(); + + } + } + + private void deliverCurrentMessageIfComplete() + throws AMQException + { + // check and deliver if header says body length is zero + if (_currentMessage.allContentReceived()) + { + try { - _txnContext.messageProcessed(protocolSession); + _currentMessage.deliverToQueues(); + } + catch (NoRouteException e) + { + _returnMessages.add(e); + } + finally + { + // callback to allow the context to do any post message processing + // primary use is to allow message return processing in the non-tx case + _txnContext.messageProcessed(_session); _currentMessage = null; } } + } - public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException + public void publishContentBody(ContentBody contentBody) throws AMQException { if (_currentMessage == null) { @@ -260,15 +245,11 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received - if (_currentMessage.addContentBodyFrame(_storeContext, - protocolSession.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody))) - { - // callback to allow the context to do any post message processing - // primary use is to allow message return processing in the non-tx case - _txnContext.messageProcessed(protocolSession); - _currentMessage = null; - } + _currentMessage.addContentBodyFrame( + _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( + contentBody)); + + deliverCurrentMessageIfComplete(); } catch (AMQException e) { @@ -287,6 +268,7 @@ public class AMQChannel } catch (NoRouteException e) { + //_currentMessage.incrementReference(); _returnMessages.add(e); } } @@ -307,18 +289,17 @@ public class AMQChannel * * @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 - * @param noLocal Flag stopping own messages being receivied. - * @param exclusive Flag requesting exclusive access to the queue * @param acks Are acks enabled for this subscriber * @param filters Filters to apply to this subscriber * + * @param noLocal Flag stopping own messages being receivied. + * @param exclusive Flag requesting exclusive access to the queue * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests * * @throws ConsumerTagNotUniqueException if the tag is not unique * @throws AMQException if something goes wrong */ - public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks, + public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks, FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException { if (tag == null) @@ -326,77 +307,65 @@ public class AMQChannel tag = new AMQShortString("sgen_" + getNextConsumerTag()); } - if (_consumerTag2QueueMap.containsKey(tag)) + if (_tag2SubscriptionMap.containsKey(tag)) { throw new ConsumerTagNotUniqueException(); } + Subscription subscription = + SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager); + + + // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. // We add before we register as the Async Delivery process may AutoClose the subscriber // so calling _cT2QM.remove before we have done put which was after the register succeeded. // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. - _consumerTag2QueueMap.put(tag, queue); + + _tag2SubscriptionMap.put(tag, subscription); try { - queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive); + queue.registerSubscription(subscription, exclusive); } catch (AMQException e) { - _consumerTag2QueueMap.remove(tag); + _tag2SubscriptionMap.remove(tag); throw e; } - return tag; } /** * Unsubscribe a consumer from a queue. - * @param session * @param consumerTag * @return true if the consumerTag had a mapped queue that could be unregistered. * @throws AMQException */ - public boolean unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException + public boolean unsubscribeConsumer(AMQShortString consumerTag) throws AMQException { - if (_log.isDebugEnabled()) - { - _log.debug("Unacked Map Dump size:" + _unacknowledgedMessageMap.size()); - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - _log.debug(message); - - return true; - } - public void visitComplete() - { - } - }); - } - - AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); - if (q != null) + Subscription sub = _tag2SubscriptionMap.remove(consumerTag); + if (sub != null) { - q.unregisterProtocolSession(session, _channelId, consumerTag); + sub.getQueue().unregisterSubscription(sub); return true; } + else + { + _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); + } return false; } /** * Called from the protocol session to close this channel and clean up. T * - * @param session The session to close - * * @throws AMQException if there is an error during closure */ - public void close(AMQProtocolSession session) throws AMQException + public void close() throws AMQException { _txnContext.rollback(); - unsubscribeAllConsumers(session); + unsubscribeAllConsumers(); try { requeue(); @@ -414,11 +383,11 @@ public class AMQChannel _closing = closing; } - private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException + private void unsubscribeAllConsumers() throws AMQException { if (_log.isInfoEnabled()) { - if (!_consumerTag2QueueMap.isEmpty()) + if (!_tag2SubscriptionMap.isEmpty()) { _log.info("Unsubscribing all consumers on channel " + toString()); } @@ -428,17 +397,19 @@ public class AMQChannel } } - for (Map.Entry me : _consumerTag2QueueMap.entrySet()) + for (Map.Entry me : _tag2SubscriptionMap.entrySet()) { if (_log.isInfoEnabled()) { _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); } - me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); + Subscription sub = me.getValue(); + + sub.getQueue().unregisterSubscription(sub); } - _consumerTag2QueueMap.clear(); + _tag2SubscriptionMap.clear(); } /** @@ -447,9 +418,9 @@ public class AMQChannel * @param entry the record of the message on the queue that was delivered * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the * delivery tag) - * @param consumerTag The tag for the consumer that is to acknowledge this message. + * @param subscription The consumer that is to acknowledge this message. */ - public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, AMQShortString consumerTag) + public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription) { if (_log.isDebugEnabled()) { @@ -462,16 +433,13 @@ public class AMQChannel if (_log.isDebugEnabled()) { _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag - + ") with a queue(" + entry.getQueue() + ") for " + consumerTag); + + ") with a queue(" + entry.getQueue() + ") for " + subscription); } } } - synchronized (_unacknowledgedMessageMap.getLock()) - { - _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(entry, consumerTag, deliveryTag,_unacknowledgedMessageMap)); - checkSuspension(); - } + _unacknowledgedMessageMap.add(deliveryTag, entry); + } private final String id = "(" + System.identityHashCode(this) + ")"; @@ -490,7 +458,7 @@ public class AMQChannel 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(); + Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); // Deliver these messages out of the transaction as their delivery was never // part of the transaction only the receive. @@ -505,13 +473,9 @@ public class AMQChannel if (!(_txnContext instanceof NonTransactionalContext)) { - // if (_nonTransactedContext == null) - { - _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - deliveryContext = _nonTransactedContext; + deliveryContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); } else { @@ -519,22 +483,23 @@ public class AMQChannel } } - for (UnacknowledgedMessage unacked : messagesToBeDelivered) + for (QueueEntry unacked : messagesToBeDelivered) { if (!unacked.isQueueDeleted()) { - // Ensure message is released for redelivery - unacked.entry.release(); - // Mark message redelivered unacked.getMessage().setRedelivered(true); + // Ensure message is released for redelivery + unacked.release(); + // Deliver Message - deliveryContext.deliver(unacked.entry, false); + deliveryContext.requeue(unacked); - // Should we allow access To the DM to directy deliver the message? - // As we don't need to check for Consumers or worry about incrementing the message count? - // unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false); + } + else + { + unacked.discard(_storeContext); } } @@ -549,32 +514,29 @@ public class AMQChannel */ public void requeue(long deliveryTag) throws AMQException { - UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag); + QueueEntry unacked = _unacknowledgedMessageMap.remove(deliveryTag); if (unacked != null) { + // Mark message redelivered + unacked.getMessage().setRedelivered(true); // Ensure message is released for redelivery if (!unacked.isQueueDeleted()) { - unacked.entry.release(); + unacked.release(); } - // Mark message redelivered - unacked.getMessage().setRedelivered(true); // Deliver these messages out of the transaction as their delivery was never // part of the transaction only the receive. TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - // if (_nonTransactedContext == null) - { - _nonTransactedContext = + + deliveryContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - deliveryContext = _nonTransactedContext; } else { @@ -584,7 +546,7 @@ public class AMQChannel if (!unacked.isQueueDeleted()) { // Redeliver the messages to the front of the queue - deliveryContext.deliver(unacked.entry, true); + deliveryContext.requeue(unacked); // Deliver increments the message count but we have already deliverted this once so don't increment it again // this was because deliver did an increment changed this. } @@ -592,11 +554,8 @@ public class AMQChannel { _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - // _log.error("Requested requeue of message:" + deliveryTag + - // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue()); - // - // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false); - // + + unacked.discard(_storeContext); } } else @@ -604,25 +563,6 @@ public class AMQChannel _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); - if (_log.isDebugEnabled()) - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - int count = 0; - - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - _log.debug( - (count++) + ": (" + message.getMessage().debugIdentity() + ")" + "[" + message.deliveryTag + "]"); - - return false; // Continue - } - - public void visitComplete() - { - } - }); - } } } @@ -636,8 +576,10 @@ public class AMQChannel */ public void resend(final boolean requeue) throws AMQException { - final List msgToRequeue = new LinkedList(); - final List msgToResend = new LinkedList(); + + + final Map msgToRequeue = new LinkedHashMap(); + final Map msgToResend = new LinkedHashMap(); if (_log.isDebugEnabled()) { @@ -647,23 +589,25 @@ public class AMQChannel // Process the Unacked-Map. // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - public boolean callback(UnacknowledgedMessage message) throws AMQException + public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException { - AMQShortString consumerTag = message.consumerTag; + AMQMessage msg = message.getMessage(); msg.setRedelivered(true); - if (consumerTag != null) + final Subscription subscription = message.getDeliveredSubscription(); + if (subscription != null) { // Consumer exists - if (_consumerTag2QueueMap.containsKey(consumerTag)) + if (!subscription.isClosed()) { - msgToResend.add(message); + msgToResend.put(deliveryTag, message); } else // consumer has gone { - msgToRequeue.add(message); + msgToRequeue.put(deliveryTag, message); } } else @@ -675,7 +619,7 @@ public class AMQChannel { if (requeue) { - msgToRequeue.add(message); + msgToRequeue.put(deliveryTag, message); } else { @@ -684,7 +628,8 @@ public class AMQChannel } else { - _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + message.discard(_storeContext); + _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } } @@ -697,6 +642,8 @@ public class AMQChannel } }); + _unacknowledgedMessageMap.clear(); + // Process Messages to Resend if (_log.isDebugEnabled()) { @@ -710,9 +657,15 @@ public class AMQChannel } } - for (UnacknowledgedMessage message : msgToResend) + for (Map.Entry entry : msgToResend.entrySet()) { + QueueEntry message = entry.getValue(); + long deliveryTag = entry.getKey(); + + + AMQMessage msg = message.getMessage(); + AMQQueue queue = message.getQueue(); // Our Java Client will always suspend the channel when resending! // If the client has requested the messages be resent then it is @@ -727,46 +680,20 @@ public class AMQChannel // else // { // release to allow it to be delivered - message.entry.release(); // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. msg.setRedelivered(true); - Subscription sub = message.entry.getDeliveredSubscription(); + Subscription sub = message.getDeliveredSubscription(); if (sub != null) { - // Get the lock so we can tell if the sub scription has closed. - // will stop delivery to this subscription until the lock is released. - // note: this approach would allow the use of a single queue if the - // PreDeliveryQueue would allow head additions. - // In the Java Qpid client we are suspended whilst doing this so it is all rather Mute.. - // needs guidance from AMQP WG Model SIG - synchronized (sub.getSendLock()) + + if(!queue.resend(message, sub)) { - if (sub.isClosed()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Subscription(" + System.identityHashCode(sub) - + ") closed during resend so requeuing message"); - } - // move this message to requeue - msgToRequeue.add(message); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:" - + System.identityHashCode(sub)); - } - - sub.addToResendQueue(message.entry); - _unacknowledgedMessageMap.remove(message.deliveryTag); - } - } // sync(sub.getSendLock) + msgToRequeue.put(deliveryTag, message); + } } else { @@ -777,7 +704,7 @@ public class AMQChannel + ")to prevent loss"); } // move this message to requeue - msgToRequeue.add(message); + msgToRequeue.put(deliveryTag, message); } } // for all messages // } else !isSuspend @@ -795,13 +722,9 @@ public class AMQChannel TransactionalContext deliveryContext; if (!(_txnContext instanceof NonTransactionalContext)) { - if (_nonTransactedContext == null) - { - _nonTransactedContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - deliveryContext = _nonTransactedContext; + deliveryContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); } else { @@ -809,14 +732,17 @@ public class AMQChannel } // Process Messages to Requeue at the front of the queue - for (UnacknowledgedMessage message : msgToRequeue) + for (Map.Entry entry : msgToRequeue.entrySet()) { - message.entry.release(); - message.entry.setRedelivered(true); + QueueEntry message = entry.getValue(); + long deliveryTag = entry.getKey(); + + message.release(); + message.setRedelivered(true); - deliveryContext.deliver(message.entry, true); + deliveryContext.requeue(message); - _unacknowledgedMessageMap.remove(message.deliveryTag); + _unacknowledgedMessageMap.remove(deliveryTag); } } @@ -827,38 +753,47 @@ public class AMQChannel * * @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 + /* public void queueDeleted(final AMQQueue queue) { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + try { - public boolean callback(UnacknowledgedMessage message) throws AMQException + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - if (message.getQueue() == queue) + public boolean callback(UnacknowledgedMessage message) { - try + if (message.getQueue() == queue) { - message.discard(_storeContext); - message.setQueueDeleted(true); + try + { + message.discard(_storeContext); + message.setQueueDeleted(true); + } + catch (AMQException e) + { + _log.error( + "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); + throw new RuntimeException(e); + } } - catch (AMQException e) - { - _log.error( - "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); - } + + return false; } - return false; - } + public void visitComplete() + { + } + }); + } + catch (AMQException e) + { + _log.error("Unexpected Error while handling deletion of queue", e); + throw new RuntimeException(e); + } - public void visitComplete() - { - } - }); } - +*/ /** * Acknowledge one or more messages. * @@ -870,23 +805,7 @@ public class AMQChannel */ public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { - synchronized (_unacknowledgedMessageMap.getLock()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Unacked (PreAck) Size:" + _unacknowledgedMessageMap.size()); - } - - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); - - if (_log.isDebugEnabled()) - { - _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size()); - } - - } - - checkSuspension(); + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); } /** @@ -899,43 +818,22 @@ public class AMQChannel return _unacknowledgedMessageMap; } - private void checkSuspension() - { - boolean suspend; - - suspend = - ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark)) - || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes())); - - setSuspended(suspend); - } public void setSuspended(boolean suspended) { - boolean isSuspended = _suspended.get(); - if (isSuspended && !suspended) - { - // Continue being suspended if we are above the _prefetch_LowWaterMark - suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; - } boolean wasSuspended = _suspended.getAndSet(suspended); if (wasSuspended != suspended) { if (wasSuspended) { - _log.debug("Unsuspending channel " + this); // may need to deliver queued messages - for (AMQQueue q : _consumerTag2QueueMap.values()) + for (Subscription s : _tag2SubscriptionMap.values()) { - q.deliverAsync(); + s.getQueue().deliverAsync(s); } } - else - { - _log.debug("Suspending channel " + this); - } } } @@ -961,12 +859,7 @@ public class AMQChannel public String toString() { - StringBuilder sb = new StringBuilder(30); - sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(isTransactional()); - sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); - sb.append("/").append(_prefetch_HighWaterMark); - - return sb.toString(); + return "["+_session.toString()+":"+_channelId+"]"; } public void setDefaultQueue(AMQQueue queue) @@ -984,14 +877,14 @@ public class AMQChannel return _storeContext; } - public void processReturns(AMQProtocolSession session) throws AMQException + public void processReturns() throws AMQException { if (!_returnMessages.isEmpty()) { for (RequiredDeliveryException bouncedMessage : _returnMessages) { AMQMessage message = bouncedMessage.getAMQMessage(); - session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), + _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), new AMQShortString(bouncedMessage.getMessage())); message.decrementReference(_storeContext); @@ -1001,40 +894,68 @@ public class AMQChannel } } - public boolean wouldSuspend(AMQMessage msg) + + public TransactionalContext getTransactionalContext() { - if (isSuspended()) - { - return true; - } - else - { - boolean willSuspend = - ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark)); - if (!willSuspend) - { - final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes(); + return _txnContext; + } - willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < (msg.getSize() + unackedSize)); - } + public boolean isClosing() + { + return _closing; + } - if (willSuspend) - { - setSuspended(true); - } + public AMQProtocolSession getProtocolSession() + { + return _session; + } - return willSuspend; - } + public FlowCreditManager getCreditManager() + { + return _creditManager; + } + public void setCredit(final long prefetchSize, final int prefetchCount) + { + _creditManager.setCreditLimits(prefetchSize, prefetchCount); } - public TransactionalContext getTransactionalContext() + public List getReturnMessages() { - return _txnContext; + return _returnMessages; } - public boolean isClosing() + public MessageStore getMessageStore() { - return _closing; + return _messageStore; + } + + private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod() + { + + public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) + throws AMQException + { + getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag()); + } + }; + + public ClientDeliveryMethod getClientDeliveryMethod() + { + return _clientDeliveryMethod; + } + + private final RecordDeliveryMethod _recordDeliveryMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) + { + addUnacknowledgedMessage(entry, deliveryTag, sub); + } + }; + + public RecordDeliveryMethod getRecordDeliveryMethod() + { + return _recordDeliveryMethod; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index d8a8cfb6d1..41d7f6c067 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -279,6 +279,12 @@ public class Main ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); } + + if(connectorConfig.useBiasedWrites) + { + System.setProperty("org.apache.qpid.use_write_biased_pool","true"); + } + int port = connectorConfig.port; String portStr = commandLine.getOptionValue("p"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index d61bb8916a..3f1947d65a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -39,19 +39,30 @@ import org.apache.qpid.server.queue.AMQMessage; */ public abstract class RequiredDeliveryException extends AMQException { - private final AMQMessage _amqMessage; + private AMQMessage _amqMessage; public RequiredDeliveryException(String message, AMQMessage payload) { super(message); + setMessage(payload); + } + + + public RequiredDeliveryException(String message) + { + super(message); + } + + public void setMessage(final AMQMessage payload) + { + // Increment the reference as this message is in the routing phase // and so will have the ref decremented as routing fails. // we need to keep this message around so we can return it in the // handler. So increment here. _amqMessage = payload.takeReference(); - // payload.incrementReference(); } public AMQMessage getAMQMessage() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index 6ad704a5d8..caf34f13bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -22,11 +22,14 @@ package org.apache.qpid.server.ack; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.HashMap; import java.util.ArrayList; import org.apache.qpid.AMQException; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TxnOp; +import org.apache.qpid.server.queue.QueueEntry; /** * A TxnOp implementation for handling accumulated acks @@ -34,7 +37,7 @@ import org.apache.qpid.server.txn.TxnOp; public class TxAck implements TxnOp { private final UnacknowledgedMessageMap _map; - private final List _unacked = new ArrayList(); + private final Map _unacked = new HashMap(); private List _individual; private long _deliveryTag; private boolean _multiple; @@ -46,11 +49,12 @@ public class TxAck implements TxnOp public void update(long deliveryTag, boolean multiple) { + _unacked.clear(); if (!multiple) { if(_individual == null) { - _individual = new ArrayList(); + _individual = new ArrayList(); } //have acked a single message that is not part of //the previously acked region so record @@ -64,36 +68,29 @@ public class TxAck implements TxnOp _deliveryTag = deliveryTag; _multiple = true; } - _unacked.clear(); } public void consolidate() { if(_unacked.isEmpty()) { - consolidate(_unacked); - } - - } - - private void consolidate(List unacked) - { - //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 - if(_individual != null) - { - for (Long tag : _individual) + //lookup all the unacked messages that have been acked in this transaction + if (_multiple) { - if(_deliveryTag < tag) + //get all the unacked messages for the accumulated + //multiple acks + _map.collect(_deliveryTag, true, _unacked); + } + if(_individual != null) + { + //get any unacked messages for individual acks outside the + //range covered by multiple acks + for (long tag : _individual) { - _map.collect(tag, false, unacked); + if(_deliveryTag < tag) + { + _map.collect(tag, false, _unacked); + } } } } @@ -101,12 +98,10 @@ public class TxAck implements TxnOp public boolean checkPersistent() throws AMQException { - - consolidate(); //if any of the messages in unacked are persistent the txn //buffer must be marked as persistent: - for (UnacknowledgedMessage msg : _unacked) + for (QueueEntry msg : _unacked.values()) { if (msg.getMessage().isPersistent()) { @@ -119,8 +114,9 @@ public class TxAck implements TxnOp public void prepare(StoreContext storeContext) throws AMQException { //make persistent changes, i.e. dequeue and decrementReference - for (UnacknowledgedMessage msg : _unacked) + for (QueueEntry msg : _unacked.values()) { + msg.restoreCredit(); //Message has been ack so discard it. This will dequeue and decrement the reference. msg.discard(storeContext); @@ -133,7 +129,7 @@ public class TxAck implements TxnOp //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) + for (QueueEntry msg : _unacked.values()) { msg.getMessage().takeReference(); } @@ -142,7 +138,7 @@ public class TxAck implements TxnOp public void commit(StoreContext storeContext) { //remove the unacked messages from the channels map - _map.remove(_unacked); + _map.remove(_unacked); } public void rollback(StoreContext storeContext) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java deleted file mode 100644 index 0112d3b388..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; - -public class UnacknowledgedMessage -{ - public final QueueEntry entry; - public final AMQShortString consumerTag; - public final long deliveryTag; - - private boolean _queueDeleted; - private final UnacknowledgedMessageMap _unacknowledgeMessageMap; - - - public UnacknowledgedMessage(QueueEntry entry, - AMQShortString consumerTag, - long deliveryTag, - final UnacknowledgedMessageMap unacknowledgedMessageMap) - { - this.entry = entry; - this.consumerTag = consumerTag; - this.deliveryTag = deliveryTag; - _unacknowledgeMessageMap = unacknowledgedMessageMap; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("Q:"); - sb.append(entry.getQueue()); - sb.append(" M:"); - sb.append(entry.getMessage()); - sb.append(" CT:"); - sb.append(consumerTag); - sb.append(" DT:"); - sb.append(deliveryTag); - - return sb.toString(); - } - - public void discard(StoreContext storeContext) throws AMQException - { - synchronized(_unacknowledgeMessageMap) - { - if(_unacknowledgeMessageMap.contains(deliveryTag)) - { - - if (entry.getQueue() != null) - { - entry.getQueue().dequeue(storeContext, entry); - } - //if the queue is null then the message is waiting to be acked, but has been removed. - entry.getMessage().decrementReference(storeContext); - } - } - - } - - public AMQMessage getMessage() - { - return entry.getMessage(); - } - - public AMQQueue getQueue() - { - return entry.getQueue(); - } - - public void setQueueDeleted(boolean queueDeleted) - { - _queueDeleted = queueDeleted; - } - - public boolean isQueueDeleted() - { - return _queueDeleted; - } -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index 5b0f3cf5eb..8e5b631f96 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -23,41 +23,41 @@ package org.apache.qpid.server.ack; import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.Map; import org.apache.qpid.AMQException; import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.queue.QueueEntry; public interface UnacknowledgedMessageMap { public interface Visitor { /** - * @param message the message being iterated over - * @return true to stop iteration, false to continue + * @param deliveryTag + *@param message the message being iterated over @return true to stop iteration, false to continue * @throws AMQException */ - boolean callback(UnacknowledgedMessage message) throws AMQException; + boolean callback(final long deliveryTag, QueueEntry message) throws AMQException; void visitComplete(); } void visit(Visitor visitor) throws AMQException; - Object getLock(); + void add(long deliveryTag, QueueEntry message); - void add(long deliveryTag, UnacknowledgedMessage message); - - void collect(Long deliveryTag, boolean multiple, List msgs); + void collect(long deliveryTag, boolean multiple, Map msgs); boolean contains(long deliveryTag) throws AMQException; - void remove(List msgs); + void remove(Map msgs); - UnacknowledgedMessage remove(long deliveryTag); + QueueEntry remove(long deliveryTag); - void drainTo(Collection destination, long deliveryTag) throws AMQException; + void drainTo(Collection destination, long deliveryTag) throws AMQException; - Collection cancelAllMessages(); + Collection cancelAllMessages(); void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; @@ -65,7 +65,7 @@ public interface UnacknowledgedMessageMap void clear(); - UnacknowledgedMessage get(long deliveryTag); + QueueEntry get(long deliveryTag); /** * Get the set of delivery tags that are outstanding. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 5204f13e81..79208ab426 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -28,6 +28,10 @@ import java.util.Map; import java.util.Set; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.txn.TransactionalContext; public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap @@ -36,7 +40,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap private long _unackedSize; - private Map _map; + private Map _map; private long _lastDeliveryTag; @@ -45,10 +49,10 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap public UnacknowledgedMessageMapImpl(int prefetchLimit) { _prefetchLimit = prefetchLimit; - _map = new LinkedHashMap(prefetchLimit); + _map = new LinkedHashMap(prefetchLimit); } - public void collect(Long deliveryTag, boolean multiple, List msgs) + public void collect(long deliveryTag, boolean multiple, Map msgs) { if (multiple) { @@ -56,7 +60,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } else { - msgs.add(get(deliveryTag)); + msgs.put(deliveryTag, get(deliveryTag)); } } @@ -69,26 +73,27 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void remove(List msgs) + public void remove(Map msgs) { synchronized (_lock) { - for (UnacknowledgedMessage msg : msgs) + for (Long deliveryTag : msgs.keySet()) { - remove(msg.deliveryTag); + remove(deliveryTag); } } } - public UnacknowledgedMessage remove(long deliveryTag) + public QueueEntry remove(long deliveryTag) { synchronized (_lock) { - UnacknowledgedMessage message = _map.remove(deliveryTag); + QueueEntry message = _map.remove(deliveryTag); if(message != null) { _unackedSize -= message.getMessage().getSize(); + message.restoreCredit(); } return message; @@ -99,21 +104,16 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { synchronized (_lock) { - Collection currentEntries = _map.values(); - for (UnacknowledgedMessage msg : currentEntries) + Set> currentEntries = _map.entrySet(); + for (Map.Entry entry : currentEntries) { - visitor.callback(msg); + visitor.callback(entry.getKey().longValue(), entry.getValue()); } visitor.visitComplete(); } } - public Object getLock() - { - return _lock; - } - - public void add(long deliveryTag, UnacknowledgedMessage message) + public void add(long deliveryTag, QueueEntry message) { synchronized (_lock) { @@ -123,12 +123,12 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public Collection cancelAllMessages() + public Collection cancelAllMessages() { synchronized (_lock) { - Collection currentEntries = _map.values(); - _map = new LinkedHashMap(_prefetchLimit); + Collection currentEntries = _map.values(); + _map = new LinkedHashMap(_prefetchLimit); _unackedSize = 0l; return currentEntries; } @@ -160,14 +160,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void drainTo(Collection destination, long deliveryTag) throws AMQException + public void drainTo(Collection destination, long deliveryTag) throws AMQException { synchronized (_lock) { - Iterator> it = _map.entrySet().iterator(); + Iterator> it = _map.entrySet().iterator(); while (it.hasNext()) { - Map.Entry unacked = it.next(); + Map.Entry unacked = it.next(); if (unacked.getKey() > deliveryTag) { @@ -175,10 +175,13 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); } - it.remove(); + _unackedSize -= unacked.getValue().getMessage().getSize(); + unacked.getValue().restoreCredit(); + + destination.add(unacked.getValue()); if (unacked.getKey() == deliveryTag) { @@ -188,7 +191,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public UnacknowledgedMessage get(long key) + public QueueEntry get(long key) { synchronized (_lock) { @@ -204,14 +207,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - private void collect(Long key, List msgs) + private void collect(long key, Map msgs) { synchronized (_lock) { - for (Map.Entry entry : _map.entrySet()) + for (Map.Entry entry : _map.entrySet()) { - msgs.add(entry.getValue()); - if (entry.getKey().equals(key)) + msgs.put(entry.getKey(),entry.getValue()); + if (entry.getKey() == key) { break; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 8573902af4..bd3e5b1f72 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -30,11 +30,13 @@ import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -176,11 +178,22 @@ public class VirtualHostConfiguration boolean durable = queueConfiguration.getBoolean("durable" ,false); boolean autodelete = queueConfiguration.getBoolean("autodelete", false); String owner = queueConfiguration.getString("owner", null); + FieldTable arguments = null; + Integer priorities = queueConfiguration.getInteger("priorities", null); + if(priorities != null && priorities.intValue() > 1) + { + if(arguments == null) + { + arguments = new FieldTable(); + } + arguments.put(new AMQShortString("x-qpid-priorities"), priorities); + } + - queue = new AMQQueue(queueName, + queue = AMQQueueFactory.createAMQQueueImpl(queueName, durable, owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, - autodelete /* Therefore autodelete makes no sence */, virtualHost); + autodelete /* Therefore autodelete makes no sence */, virtualHost, arguments); if (queue.isDurable()) { @@ -221,7 +234,7 @@ public class VirtualHostConfiguration AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - queue.bind(routingKey, null, exchange); + queue.bind(exchange, routingKey, null); _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); @@ -229,7 +242,7 @@ public class VirtualHostConfiguration if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) { - queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange()); + queue.bind(virtualHost.getExchangeRegistry().getDefaultExchange(), queue.getName(), null); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 9ebb893362..8d24626b73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -191,9 +191,7 @@ public abstract class AbstractExchange implements Exchange, Managable { _exchangeMbean.unregister(); } - } - - abstract public Map> getBindings(); + } public String toString() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 636aa7eb03..9d4c090971 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -43,8 +43,8 @@ public class DefaultExchangeFactory implements ExchangeFactory public DefaultExchangeFactory(VirtualHost host) { _host = host; - registerExchangeType(DestNameExchange.TYPE); - registerExchangeType(DestWildExchange.TYPE); + registerExchangeType(DirectExchange.TYPE); + registerExchangeType(TopicExchange.TYPE); registerExchangeType(HeadersExchange.TYPE); registerExchangeType(FanoutExchange.TYPE); } @@ -67,7 +67,7 @@ public class DefaultExchangeFactory implements ExchangeFactory if (exchType == null) { - throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null); + throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); } Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); return e; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 98abf7977a..0ab8208d88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -25,6 +25,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -121,9 +122,9 @@ public class DefaultExchangeRegistry implements ExchangeRegistry * @param payload * @throws AMQException if something goes wrong delivering data */ - public void routeContent(AMQMessage payload) throws AMQException + public void routeContent(IncomingMessage payload) throws AMQException { - final AMQShortString exchange = payload.getMessagePublishInfo().getExchange(); + final AMQShortString exchange = payload.getExchange(); final Exchange exch = getExchange(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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java deleted file mode 100644 index 12347c0278..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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(); - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return DestNameExchange.class; - } - - public DestNameExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - DestNameExchange exch = new DestNameExchange(); - exch.initialise(host,name,durable,ticket,autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.DIRECT_EXCHANGE_NAME; - } - }; - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DestNameExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DestNameExchangeMBean() throws JMException - { - super(); - _exchangeType = "direct"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - Map> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : bindings.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, DestNameExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - }// End of MBean class - - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestNameExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } - } - - public AMQShortString getType() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "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 MessagePublishInfo info = payload.getMessagePublishInfo(); - final AMQShortString routingKey = info.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : info.getRoutingKey(); - final List queues = (routingKey == null) ? null : _index.get(routingKey); - if (queues == null || queues.isEmpty()) - { - String msg = "Routing key " + routingKey + " is not known to " + this; - if (info.isMandatory() || info.isImmediate()) - { - throw new NoRouteException(msg, payload); - } - else - { - _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); - _logger.warn(msg); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + queues); - } - - payload.enqueue(queues); - - - } - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey,queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - final List queues = _index.get(routingKey); - return queues != null && queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - final List queues = _index.get(routingKey); - return queues != null && !queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - Map> bindings = _index.getBindingsMap(); - for (List queues : bindings.values()) - { - if (queues.contains(queue)) - { - return true; - } - } - return false; - } - - public boolean hasBindings() - { - return !_index.getBindingsMap().isEmpty(); - } - - public Map> getBindings() - { - return _index.getBindingsMap(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java deleted file mode 100644 index 6fa3686152..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortStringTokenizer; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -public class DestWildExchange extends AbstractExchange -{ - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return DestWildExchange.class; - } - - public DestWildExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - DestWildExchange exch = new DestWildExchange(); - exch.initialise(host, name, durable, ticket, autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.TOPIC_EXCHANGE_NAME; - } - }; - - - private static final Logger _logger = Logger.getLogger(DestWildExchange.class); - - private final ConcurrentHashMap> _bindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _simpleBindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _wildCardBindingKey2queues = - new ConcurrentHashMap>(); - - private static final byte TOPIC_SEPARATOR = (byte)'.'; - private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); - private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); - private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); - private ConcurrentHashMap _bindingKey2Tokenized = - new ConcurrentHashMap(); - private static final byte HASH_BYTE = (byte)'#'; - private static final byte STAR_BYTE = (byte)'*'; - - /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class DestWildExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public DestWildExchangeMBean() throws JMException - { - super(); - _exchangeType = "topic"; - init(); - } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Map.Entry> entry : _bindingKey2queues.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = getMatchedQueues(key); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(new AMQShortString(binding), null, DestWildExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); - - // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition - List queueList = _bindingKey2queues.putIfAbsent(rKey, 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 = _bindingKey2queues.get(rKey); - } - - - - if (!queueList.contains(queue)) - { - queueList.add(queue); - - - if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) - { - AMQShortString routingKey = normalize(rKey); - List queueList2 = _wildCardBindingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList()); - - if(queueList2 == null) - { - queueList2 = _wildCardBindingKey2queues.get(routingKey); - AMQShortStringTokenizer keyTok = routingKey.tokenize(TOPIC_SEPARATOR); - - ArrayList keyTokList = new ArrayList(keyTok.countTokens()); - - while (keyTok.hasMoreTokens()) - { - keyTokList.add(keyTok.nextToken()); - } - - _bindingKey2Tokenized.put(routingKey, keyTokList.toArray(new AMQShortString[keyTokList.size()])); - } - queueList2.add(queue); - - } - else - { - List queueList2 = _simpleBindingKey2queues.putIfAbsent(rKey, new CopyOnWriteArrayList()); - if(queueList2 == null) - { - queueList2 = _simpleBindingKey2queues.get(rKey); - } - queueList2.add(queue); - - } - - - - - } - else if (_logger.isDebugEnabled()) - { - _logger.debug("Queue " + queue + " is already registered with routing key " + rKey); - } - - - - } - - private AMQShortString normalize(AMQShortString routingKey) - { - if(routingKey == null) - { - routingKey = AMQShortString.EMPTY_STRING; - } - - AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); - - List subscriptionList = new ArrayList(); - - while (routingTokens.hasMoreTokens()) - { - subscriptionList.add(routingTokens.nextToken()); - } - - int size = subscriptionList.size(); - - for (int index = 0; index < size; index++) - { - // if there are more levels - if ((index + 1) < size) - { - if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) - { - if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) - { - // we don't need #.# delete this one - subscriptionList.remove(index); - size--; - // redo this normalisation - index--; - } - - if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) - { - // we don't want #.* swap to *.# - // remove it and put it in at index + 1 - subscriptionList.add(index + 1, subscriptionList.remove(index)); - } - } - } // if we have more levels - } - - - - AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); - - return normalizedString; - } - - public void route(AMQMessage payload) throws AMQException - { - MessagePublishInfo info = payload.getMessagePublishInfo(); - - final AMQShortString routingKey = info.getRoutingKey(); - - List queues = getMatchedQueues(routingKey); - // if we have no registered queues we have nothing to do - // TODO: add support for the immediate flag - if ((queues == null) || queues.isEmpty()) - { - if (info.isMandatory() || info.isImmediate()) - { - String msg = "Topic " + routingKey + " is not known to " + this; - throw new NoRouteException(msg, payload); - } - else - { - _logger.warn("No queues found for routing key " + routingKey); - _logger.warn("Routing map contains: " + _bindingKey2queues); - - return; - } - } - - payload.enqueue(queues); - - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - List queues = _bindingKey2queues.get(normalize(routingKey)); - - return (queues != null) && queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - List queues = _bindingKey2queues.get(normalize(routingKey)); - - return (queues != null) && !queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - for (List queues : _bindingKey2queues.values()) - { - if (queues.contains(queue)) - { - return true; - } - } - - return false; - } - - public boolean hasBindings() - { - return !_bindingKey2queues.isEmpty(); - } - - public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - List queues = _bindingKey2queues.get(rKey); - if (queues == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with routing key " + rKey + ". No queue was registered with that _routing key"); - - } - - boolean removedQ = queues.remove(queue); - if (!removedQ) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with routing key " + rKey); - } - - - if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) - { - AMQShortString bindingKey = normalize(rKey); - List queues2 = _wildCardBindingKey2queues.get(bindingKey); - queues2.remove(queue); - if(queues2.isEmpty()) - { - _wildCardBindingKey2queues.remove(bindingKey); - _bindingKey2Tokenized.remove(bindingKey); - } - - } - else - { - List queues2 = _simpleBindingKey2queues.get(rKey); - queues2.remove(queue); - if(queues2.isEmpty()) - { - _simpleBindingKey2queues.remove(rKey); - } - - } - - - - - if (queues.isEmpty()) - { - _bindingKey2queues.remove(rKey); - } - } - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestWildExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); - } - } - - public Map> getBindings() - { - return _bindingKey2queues; - } - - private List getMatchedQueues(AMQShortString routingKey) - { - - List list = null; - - if(!_wildCardBindingKey2queues.isEmpty()) - { - - - AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); - - final int routingTokensCount = routingTokens.countTokens(); - - - AMQShortString[] routingkeyTokens = new AMQShortString[routingTokensCount]; - - if(routingTokensCount == 1) - { - routingkeyTokens[0] =routingKey; - } - else - { - - - int token = 0; - while (routingTokens.hasMoreTokens()) - { - - AMQShortString next = routingTokens.nextToken(); - - routingkeyTokens[token++] = next; - } - } - for (AMQShortString bindingKey : _wildCardBindingKey2queues.keySet()) - { - - AMQShortString[] bindingKeyTokens = _bindingKey2Tokenized.get(bindingKey); - - - boolean matching = true; - boolean done = false; - - int depthPlusRoutingSkip = 0; - int depthPlusQueueSkip = 0; - - final int bindingKeyTokensCount = bindingKeyTokens.length; - - while (matching && !done) - { - - if ((bindingKeyTokensCount == depthPlusQueueSkip) || (routingTokensCount == depthPlusRoutingSkip)) - { - done = true; - - // if it was the routing key that ran out of digits - if (routingTokensCount == depthPlusRoutingSkip) - { - if (bindingKeyTokensCount > depthPlusQueueSkip) - { // a hash and it is the last entry - matching = - bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN) - && (bindingKeyTokensCount == (depthPlusQueueSkip + 1)); - } - } - else if (routingTokensCount > depthPlusRoutingSkip) - { - // There is still more routing key to check - matching = false; - } - - continue; - } - - // if the values on the two topics don't match - if (!bindingKeyTokens[depthPlusQueueSkip].equals(routingkeyTokens[depthPlusRoutingSkip])) - { - if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_STAR_TOKEN)) - { - depthPlusQueueSkip++; - depthPlusRoutingSkip++; - - continue; - } - else if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN)) - { - // Is this a # at the end - if (bindingKeyTokensCount == (depthPlusQueueSkip + 1)) - { - done = true; - - continue; - } - - // otherwise # in the middle - while (routingTokensCount > depthPlusRoutingSkip) - { - if (routingkeyTokens[depthPlusRoutingSkip].equals(bindingKeyTokens[depthPlusQueueSkip + 1])) - { - depthPlusQueueSkip += 2; - depthPlusRoutingSkip++; - - break; - } - - depthPlusRoutingSkip++; - } - - continue; - } - - matching = false; - } - - depthPlusQueueSkip++; - depthPlusRoutingSkip++; - } - - if (matching) - { - if(list == null) - { - list = new ArrayList(_wildCardBindingKey2queues.get(bindingKey)); - } - else - { - list.addAll(_wildCardBindingKey2queues.get(bindingKey)); - } - } - } - - } - if(!_simpleBindingKey2queues.isEmpty()) - { - List queues = _simpleBindingKey2queues.get(routingKey); - if(list == null) - { - if(queues == null) - { - list = Collections.EMPTY_LIST; - } - else - { - list = new ArrayList(queues); - } - } - else if(queues != null) - { - list.addAll(queues); - } - - } - - return list; - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java new file mode 100644 index 0000000000..5dcc2cf143 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -0,0 +1,245 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class DirectExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(DirectExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final Index _index = new Index(); + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DirectExchange.class; + } + + public DirectExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + DirectExchange exch = new DirectExchange(); + exch.initialise(host,name,durable,ticket,autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_NAME; + } + }; + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Direct Exchange") + private final class DirectExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DirectExchangeMBean() throws JMException + { + super(); + _exchangeType = "direct"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + Map> bindings = _index.getBindingsMap(); + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (Map.Entry> entry : bindings.entrySet()) + { + AMQShortString key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = entry.getValue(); + for (AMQQueue q : queues) + { + queueList.add(q.getName().toString()); + } + + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(DirectExchange.this, new AMQShortString(binding), null); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + }// End of MBean class + + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DirectExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public AMQShortString getType() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + + if (!_index.remove(routingKey, queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that _routing key"); + } + } + + public void route(IncomingMessage payload) throws AMQException + { + + final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); + + final List queues = (routingKey == null) ? null : _index.get(routingKey); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + queues); + } + + payload.enqueue(queues); + + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey,queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + final List queues = _index.get(routingKey); + return queues != null && queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + final List queues = _index.get(routingKey); + return queues != null && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + Map> bindings = _index.getBindingsMap(); + for (List queues : bindings.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() + { + return !_index.getBindingsMap().isEmpty(); + } + + public Map> getBindings() + { + return _index.getBindingsMap(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 37cd85a8f8..06209c5458 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -23,7 +23,8 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQMessage; + +import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -53,7 +54,7 @@ public interface Exchange void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - void route(AMQMessage message) throws AMQException; + void route(IncomingMessage message) throws AMQException; /** @@ -92,6 +93,6 @@ public interface Exchange */ boolean hasBindings(); - Map> getBindings(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index f1b383eac9..e9fd4d548b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -26,10 +26,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -95,7 +94,7 @@ public class FanoutExchange extends AbstractExchange try { - queue.bind(new AMQShortString(binding), null, FanoutExchange.this); + queue.bind(FanoutExchange.this, new AMQShortString(binding), null); } catch (AMQException ex) { @@ -183,32 +182,17 @@ public class FanoutExchange extends AbstractExchange } } - public void route(AMQMessage payload) throws AMQException + public void route(IncomingMessage payload) throws AMQException { - final MessagePublishInfo publishInfo = payload.getMessagePublishInfo(); - final AMQShortString routingKey = publishInfo.getRoutingKey(); - if ((_queues == null) || _queues.isEmpty()) + + + if (_logger.isDebugEnabled()) { - String msg = "No queues bound to " + this; - if (publishInfo.isMandatory() || publishInfo.isImmediate()) - { - throw new NoRouteException(msg, payload); - } - else - { - _logger.warn(msg); - } + _logger.debug("Publishing message to queue " + _queues); } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + _queues); - } - payload.enqueue(new ArrayList(_queues)); + payload.enqueue(new ArrayList(_queues)); - } } public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 68ad88c4cb..d1bea3410b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -31,7 +31,7 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -50,6 +50,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -240,7 +241,7 @@ public class HeadersExchange extends AbstractExchange } } - public void route(AMQMessage payload) throws AMQException + public void route(IncomingMessage payload) throws AMQException { FieldTable headers = getHeaders(payload.getContentHeaderBody()); if (_logger.isDebugEnabled()) @@ -248,8 +249,10 @@ public class HeadersExchange extends AbstractExchange _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); } boolean routed = false; + Collection queues = new ArrayList(); for (Registration e : _bindings) { + if (e.binding.matches(headers)) { if (_logger.isDebugEnabled()) @@ -257,25 +260,12 @@ public class HeadersExchange extends AbstractExchange _logger.debug("Exchange " + getName() + ": delivering message with headers " + headers + " to " + e.queue.getName()); } - payload.enqueue(e.queue); - routed = true; - } - } - if (!routed) - { - - String msg = "Exchange " + getName() + ": message not routable."; + queues.add(e.queue); - if (payload.getMessagePublishInfo().isMandatory() || payload.getMessagePublishInfo().isImmediate()) - { - throw new NoRouteException(msg, payload); - } - else - { - _logger.warn(msg); + routed = true; } - } + payload.enqueue(queues); } public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index eacdad8a8e..4f1f550e94 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -32,7 +32,7 @@ import org.apache.qpid.server.queue.AMQQueue; /** * An index of queues against routing key. Allows multiple queues to be stored - * against the same key. Used in the DestNameExchange. + * against the same key. Used in the DirectExchange. */ class Index { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java index 7508e80f7f..db9beb6da7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; /** * Separated out from the ExchangeRegistry interface to allow components @@ -36,5 +37,5 @@ public interface MessageRouter * * @throws org.apache.qpid.AMQException if something goes wrong delivering data */ - void routeContent(AMQMessage message) throws AMQException; + void routeContent(IncomingMessage message) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index 1d6ab3842d..d18ad7ab14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; /** * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message @@ -36,9 +37,9 @@ import org.apache.qpid.server.queue.AMQMessage; */ public class NoRouteException extends RequiredDeliveryException { - public NoRouteException(String msg, AMQMessage message) + public NoRouteException(String msg, AMQMessage amqMessage) { - super(msg, message); + super(msg, amqMessage); } public AMQConstant getReplyCode() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java new file mode 100644 index 0000000000..d07501a188 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -0,0 +1,651 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.common.AMQPFilterTypes; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortStringTokenizer; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.topic.TopicParser; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; +import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.filter.JMSSelectorFilter; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicInteger; +import java.lang.ref.WeakReference; + +public class TopicExchange extends AbstractExchange +{ + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return TopicExchange.class; + } + + public TopicExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + TopicExchange exch = new TopicExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_NAME; + } + }; + + + private static final Logger _logger = Logger.getLogger(TopicExchange.class); + +/* + private final ConcurrentHashMap> _bindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _simpleBindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _wildCardBindingKey2queues = + new ConcurrentHashMap>(); +*/ + // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); + private static final byte TOPIC_SEPARATOR = (byte)'.'; + private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); + private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); + private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); + + private static final byte HASH_BYTE = (byte)'#'; + private static final byte STAR_BYTE = (byte)'*'; + + private final TopicParser _parser = new TopicParser(); + + private final Map _topicExchangeResults = + new ConcurrentHashMap(); + + private final Map _bindings = new HashMap(); + + private final Map>> _selectorCache = new WeakHashMap>>(); + + public static class Binding + { + private final AMQShortString _bindingKey; + private final AMQQueue _queue; + + public Binding(AMQShortString bindingKey, AMQQueue queue) + { + _bindingKey = bindingKey; + _queue = queue; + } + + public AMQShortString getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public int hashCode() + { + return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 + _queue.hashCode(); + } + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(o instanceof Binding) + { + Binding other = (Binding) o; + return (_queue == other._queue) + && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); + } + return false; + } + } + + + + private final class TopicExchangeResult implements TopicMatcherResult + { + private final Map _unfilteredQueues = new ConcurrentHashMap(); + private final ConcurrentHashMap,Integer>> _filteredQueues = new ConcurrentHashMap, Integer>>(); + + public void addUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == null) + { + _unfilteredQueues.put(queue, 1); + } + else + { + _unfilteredQueues.put(queue, instances + 1); + } + } + + public void removeUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == 1) + { + _unfilteredQueues.remove(queue); + } + else + { + _unfilteredQueues.put(queue,instances - 1); + } + + } + + + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map,Integer> filters = _filteredQueues.get(queue); + if(filters == null) + { + filters = new ConcurrentHashMap,Integer>(); + _filteredQueues.put(queue, filters); + } + Integer instances = filters.get(filter); + if(instances == null) + { + filters.put(filter,1); + } + else + { + filters.put(filter, instances + 1); + } + + } + + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map,Integer> filters = _filteredQueues.get(queue); + if(filters != null) + { + Integer instances = filters.get(filter); + if(instances == 1) + { + filters.remove(filter); + if(filters.isEmpty()) + { + _filteredQueues.remove(queue); + } + } + else if(instances != null) + { + filters.put(filter, instances - 1); + } + + } + + } + + public void replaceQueueFilter(AMQQueue queue, + MessageFilter oldFilter, + MessageFilter newFilter) + { + Map,Integer> filters = _filteredQueues.get(queue); + Map,Integer> newFilters = new ConcurrentHashMap,Integer>(filters); + Integer oldFilterInstances = filters.get(oldFilter); + if(oldFilterInstances == 1) + { + newFilters.remove(oldFilter); + } + else + { + newFilters.put(oldFilter, oldFilterInstances-1); + } + Integer newFilterInstances = filters.get(newFilter); + if(newFilterInstances == null) + { + newFilters.put(newFilter, 1); + } + else + { + newFilters.put(newFilter, newFilterInstances+1); + } + _filteredQueues.put(queue,newFilters); + } + + public Collection processMessage(IncomingMessage msg, Collection queues) + { + if(queues == null) + { + if(_filteredQueues.isEmpty()) + { + return new ArrayList(_unfilteredQueues.keySet()); + } + else + { + queues = new HashSet(); + } + } + else if(!(queues instanceof Set)) + { + queues = new HashSet(queues); + } + + queues.addAll(_unfilteredQueues.keySet()); + if(!_filteredQueues.isEmpty()) + { + for(Map.Entry, Integer>> entry : _filteredQueues.entrySet()) + { + if(!queues.contains(entry.getKey())) + { + for(MessageFilter filter : entry.getValue().keySet()) + { + if(filter.matches(msg)) + { + queues.add(entry.getKey()); + } + } + } + } + } + return queues; + } + + } + + + /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ + @MBeanDescription("Management Bean for Topic Exchange") + private final class TopicExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public TopicExchangeMBean() throws JMException + { + super(); + _exchangeType = "topic"; + init(); + } + + /** returns exchange bindings in tabular form */ + public TabularData bindings() throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + Map> bindingData = new HashMap>(); + for (Binding binding : _bindings.keySet()) + { + String key = binding.getBindingKey().toString(); + List queueNames = bindingData.get(key); + if(queueNames == null) + { + queueNames = new ArrayList(); + bindingData.put(key, queueNames); + } + queueNames.add(binding.getQueue().getName().toString()); + + } + for(Map.Entry> entry : bindingData.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; + CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingCompositeData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(TopicExchange.this, new AMQShortString(binding), null); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + public AMQShortString getType() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); + + + AMQShortString routingKey; + + if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) + { + routingKey = normalize(rKey); + } + else + { + routingKey = rKey; + } + + Binding binding = new Binding(rKey, queue); + + if(_bindings.containsKey(binding)) + { + FieldTable oldArgs = _bindings.get(binding); + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + + if(argumentsContainSelector(args)) + { + if(argumentsContainSelector(oldArgs)) + { + result.replaceQueueFilter(queue,createSelectorFilter(oldArgs), createSelectorFilter(args)); + } + else + { + result.addFilteredQueue(queue,createSelectorFilter(args)); + result.removeUnfilteredQueue(queue); + } + } + else + { + if(argumentsContainSelector(oldArgs)) + { + result.addUnfilteredQueue(queue); + result.removeFilteredQueue(queue, createSelectorFilter(oldArgs)); + } + else + { + // TODO - fix control flow + return; + } + } + + } + else + { + + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + if(result == null) + { + result = new TopicExchangeResult(); + if(argumentsContainSelector(args)) + { + result.addFilteredQueue(queue, createSelectorFilter(args)); + } + else + { + result.addUnfilteredQueue(queue); + } + _parser.addBinding(routingKey, result); + _topicExchangeResults.put(routingKey,result); + } + else + { + if(argumentsContainSelector(args)) + { + result.addFilteredQueue(queue, createSelectorFilter(args)); + } + else + { + result.addUnfilteredQueue(queue); + } + } + _bindings.put(binding, args); + } + + + } + + private JMSSelectorFilter createSelectorFilter(final FieldTable args) + throws AMQException + { + + final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); + WeakReference> selectorRef = _selectorCache.get(selectorString); + JMSSelectorFilter selector = null; + + if(selectorRef == null || (selector = selectorRef.get())==null) + { + selector = new JMSSelectorFilter(selectorString); + _selectorCache.put(selectorString, new WeakReference>(selector)); + } + return selector; + } + + private static boolean argumentsContainSelector(final FieldTable args) + { + return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0; + } + + private AMQShortString normalize(AMQShortString routingKey) + { + if(routingKey == null) + { + routingKey = AMQShortString.EMPTY_STRING; + } + + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + List subscriptionList = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + subscriptionList.add(routingTokens.nextToken()); + } + + int size = subscriptionList.size(); + + for (int index = 0; index < size; index++) + { + // if there are more levels + if ((index + 1) < size) + { + if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) + { + if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) + { + // we don't need #.# delete this one + subscriptionList.remove(index); + size--; + // redo this normalisation + index--; + } + + if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + subscriptionList.add(index + 1, subscriptionList.remove(index)); + } + } + } // if we have more levels + } + + + + AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); + + return normalizedString; + } + + public void route(IncomingMessage payload) throws AMQException + { + + final AMQShortString routingKey = payload.getRoutingKey(); + + Collection queues = getMatchedQueues(payload, routingKey); + + if(queues == null || queues.isEmpty()) + { + _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); + } + + payload.enqueue(queues); + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + Binding binding = new Binding(routingKey, queue); + + return _bindings.containsKey(binding); + } + + public boolean isBound(AMQShortString routingKey) + { + for(Binding b : _bindings.keySet()) + { + if(b.getBindingKey().equals(routingKey)) + { + return true; + } + } + + return false; + } + + public boolean isBound(AMQQueue queue) + { + for(Binding b : _bindings.keySet()) + { + if(b.getQueue().equals(queue)) + { + return true; + } + } + + return false; + } + + public boolean hasBindings() + { + return !_bindings.isEmpty(); + } + + public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + Binding binding = new Binding(rKey, queue); + + + if (!_bindings.containsKey(binding)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName() + + " with routing key " + rKey + "."); + } + + FieldTable bindingArgs = _bindings.remove(binding); + AMQShortString bindingKey = normalize(rKey); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + if(argumentsContainSelector(bindingArgs)) + { + result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs)); + } + else + { + result.removeUnfilteredQueue(queue); + } + + } + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new TopicExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the topic exchenge mbean", ex); + throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); + } + } + + private Collection getMatchedQueues(IncomingMessage message, AMQShortString routingKey) + { + + Collection results = _parser.parse(routingKey); + if(results.isEmpty()) + { + return Collections.EMPTY_SET; + } + else + { + Collection queues = results.size() == 1 ? null : new HashSet(); + for(TopicMatcherResult result : results) + { + + queues = ((TopicExchangeResult)result).processMessage(message, queues); + } + return queues; + } + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java new file mode 100644 index 0000000000..8fdb91cbef --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java @@ -0,0 +1,40 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQShortString; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderKey +{ + public static final HeaderKey UNKNOWN = new HeaderKey(new AMQShortString("<< UNKNOWN >>")); + private AMQShortString _key; + + public HeaderKey(final AMQShortString key) + { + _key = key; + } + + public String toString() + { + return _key.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java new file mode 100644 index 0000000000..7be99a88c9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java @@ -0,0 +1,50 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.Map; +import java.util.HashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderKeyDictionary +{ + + private final Map _dictionary = new HashMap(); + + + public HeaderKey get(final AMQShortString key) + { + HeaderKey headerKey = _dictionary.get(key); + return headerKey == null ? HeaderKey.UNKNOWN : headerKey; + } + + public HeaderKey getOrCreate(final AMQShortString key) + { + HeaderKey headerKey = _dictionary.get(key); + if(headerKey == null) + { + headerKey = new HeaderKey(key); + _dictionary.put(key, headerKey); + } + return headerKey; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java new file mode 100644 index 0000000000..518064bb29 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java @@ -0,0 +1,25 @@ +package org.apache.qpid.server.exchange.headers; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderMatcherResult +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java new file mode 100644 index 0000000000..9da93d483a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java @@ -0,0 +1,339 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.topic.TopicMatcherDFAState; +import org.apache.qpid.server.exchange.topic.TopicWord; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; + +import java.util.*; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeadersMatcherDFAState +{ + + + private final Collection _results; + private final Map> _nextStateMap; + private final HeaderKeyDictionary _dictionary; + + public HeadersMatcherDFAState(Map> nextStateMap, + Collection results, + HeaderKeyDictionary dictionary) + { + _nextStateMap = nextStateMap; + _results = results; + _dictionary = dictionary; + } + + + public Collection match(final FieldTable table) + { + return match(table.iterator()); + } + + + + public Collection match(Iterator> fieldTableIterator) + { + + if(_nextStateMap.isEmpty()) + { + return _results; + } + + while(fieldTableIterator.hasNext()) + { + + Map.Entry fieldTableEntry = fieldTableIterator.next(); + HeaderKey key = _dictionary.get(fieldTableEntry.getKey()); + if(key != HeaderKey.UNKNOWN) + { + Map valueToStateMap = _nextStateMap.get(key); + + if(valueToStateMap != null) + { + HeadersMatcherDFAState nextState = valueToStateMap.get(fieldTableEntry.getValue()); + + if(nextState == null) + { + nextState = valueToStateMap.get(null); + } + if(nextState != null && nextState != this) + { + return nextState.match(fieldTableIterator); + } + } + + } + } + + return _results; + + } + + + HeadersMatcherDFAState mergeStateMachines(HeadersMatcherDFAState otherStateMachine) + { + + assert(otherStateMachine._dictionary == _dictionary); + + Map, HeadersMatcherDFAState> newStateMap= new HashMap, HeadersMatcherDFAState>(); + + Collection results; + + if(_results.isEmpty()) + { + results = otherStateMachine._results; + } + else if(otherStateMachine._results.isEmpty()) + { + results = _results; + } + else + { + results = new HashSet(_results); + results.addAll(otherStateMachine._results); + } + + + final Map> newNextStateMap = new HashMap>(); + + HeadersMatcherDFAState newState = new HeadersMatcherDFAState(newNextStateMap, results, _dictionary); + + + Set oldStates = new HashSet(); + oldStates.add(this); + oldStates.add(otherStateMachine); + + newStateMap.put(oldStates, newState); + + mergeStateMachines(oldStates, newNextStateMap, newStateMap); + + return newState; + + + } + + private void mergeStateMachines(final Set oldStates, + final Map> newNextStateMap, + final Map, HeadersMatcherDFAState> newStateMap) + { + Map>> nfaMap = new HashMap>>(); + + Set distinctKeys = new HashSet(); + + for(HeadersMatcherDFAState state : oldStates) + { + Map> map = state._nextStateMap; + + for(Map.Entry> entry : map.entrySet()) + { + Map> valueToStatesMap = nfaMap.get(entry.getKey()); + + if(valueToStatesMap == null) + { + valueToStatesMap = new HashMap>(); + nfaMap.put(entry.getKey(), valueToStatesMap); + } + + for(Map.Entry valueToStateEntry : entry.getValue().entrySet()) + { + Set states = valueToStatesMap.get(valueToStateEntry.getKey()); + if(states == null) + { + states = new HashSet(); + valueToStatesMap.put(valueToStateEntry.getKey(),states); + } + states.add(valueToStateEntry.getValue()); + } + + distinctKeys.add(entry.getKey()); + } + } + + Map> anyValueStates = new HashMap>(); + + for(HeaderKey distinctKey : distinctKeys) + { + Map> valueToStateMap = nfaMap.get(distinctKey); + if(valueToStateMap != null) + { + Set statesForKeyDefault = valueToStateMap.get(null); + if(statesForKeyDefault != null) + { + anyValueStates.put(distinctKey, statesForKeyDefault); + } + } + } + + // add the defaults for "null" to all other specified values of a given header key + + for( Map.Entry>> entry : nfaMap.entrySet()) + { + Map> valueToStatesMap = entry.getValue(); + for(Map.Entry> valueToStates : valueToStatesMap.entrySet()) + { + if(valueToStates.getKey() != null) + { + + + Set defaults = anyValueStates.get(entry.getKey()); + if(defaults != null) + { + valueToStates.getValue().addAll(defaults); + } + } + } + } + + // if a given header key is not mentioned in the map of a machine; then that machine would stay at the same state + // for that key. + for(HeaderKey distinctKey : distinctKeys) + { + Map> valueToStatesMap = nfaMap.get(distinctKey); + for(HeadersMatcherDFAState oldState : oldStates) + { + if(!oldState._nextStateMap.containsKey(distinctKey)) + { + for(Set endStates : valueToStatesMap.values()) + { + endStates.add(oldState); + } + } + } + } + + + + + for(Map.Entry>> transitionClass : nfaMap.entrySet()) + { + Map valueToDFAState = newNextStateMap.get(transitionClass.getKey()); + if(valueToDFAState == null) + { + valueToDFAState = new HashMap(); + newNextStateMap.put(transitionClass.getKey(), valueToDFAState); + } + + for(Map.Entry> transition : transitionClass.getValue().entrySet()) + { + Set destinations = transition.getValue(); + + + HeadersMatcherDFAState nextState = newStateMap.get(destinations); + + if(nextState == null) + { + + if(destinations.size() == 1) + { + nextState = destinations.iterator().next(); + newStateMap.put(destinations, nextState); + } + else + { + Collection results; + + Set> resultSets = new HashSet>(); + for(HeadersMatcherDFAState destination : destinations) + { + resultSets.add(destination._results); + } + resultSets.remove(Collections.EMPTY_SET); + if(resultSets.size() == 0) + { + results = Collections.EMPTY_SET; + } + else if(resultSets.size() == 1) + { + results = resultSets.iterator().next(); + } + else + { + results = new HashSet(); + for(Collection oldResult : resultSets) + { + results.addAll(oldResult); + } + } + + final Map> nextStateMap = new HashMap>(); + + nextState = new HeadersMatcherDFAState(nextStateMap, results, _dictionary); + newStateMap.put(destinations, nextState); + + mergeStateMachines( + destinations, + nextStateMap, + newStateMap); + + + } + + + } + valueToDFAState.put(transition.getKey(),nextState); + } + } + + + + final ArrayList removeKeyList = new ArrayList(); + + for(Map.Entry> entry : _nextStateMap.entrySet()) + { + final ArrayList removeValueList = new ArrayList(); + + for(Map.Entry valueToDFAState : entry.getValue().entrySet()) + { + if(valueToDFAState.getValue() == this) + { + HeadersMatcherDFAState defaultState = entry.getValue().get(null); + if(defaultState == null || defaultState == this) + { + removeValueList.add(valueToDFAState.getKey()); + } + } + } + + for(AMQTypedValue removeValue : removeValueList) + { + entry.getValue().remove(removeValue); + } + + if(entry.getValue().isEmpty()) + { + removeKeyList.add(entry.getKey()); + } + + } + + for(HeaderKey removeKey : removeKeyList) + { + _nextStateMap.remove(removeKey); + } + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java new file mode 100644 index 0000000000..85e74122c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java @@ -0,0 +1,439 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.*; + +import java.util.*; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeadersParser +{ + + private final HeaderKeyDictionary _dictionary = new HeaderKeyDictionary(); + private static final AMQShortString MATCHING_TYPE_KEY = new AMQShortString("x-match"); + private static final String ANY_MATCHING = "any"; + private static final AMQShortString RESERVED_KEY_PREFIX = new AMQShortString("x-"); + + + HeadersMatcherDFAState createStateMachine(FieldTable bindingArguments, HeaderMatcherResult result) + { + String matchingType = bindingArguments.getString(MATCHING_TYPE_KEY); + boolean matchAny = matchingType.equalsIgnoreCase(ANY_MATCHING); + if(matchAny) + { + return createStateMachineForAnyMatch(bindingArguments, result); + } + else + { + return createStateMachineForAllMatch(bindingArguments, result); + } + + + } + + + private HeadersMatcherDFAState createStateMachineForAnyMatch(final FieldTable bindingArguments, + final HeaderMatcherResult result) + { + + // DFAs for "any" matches have only two states, "not-matched" and "matched"... they start in the former + // and upon meeting any of the criteria they move to the latter + + //noinspection unchecked + final HeadersMatcherDFAState successState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); + + Map> nextStateMap = + new HashMap>(); + + Set seenKeys = new HashSet(); + + Iterator> tableIterator = bindingArguments.iterator(); + + while(tableIterator.hasNext()) + { + final Map.Entry entry = tableIterator.next(); + final AMQShortString key = entry.getKey(); + final AMQTypedValue value = entry.getValue(); + + + if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) + { + final AMQType type = value.getType(); + + final HeaderKey headerKey = _dictionary.getOrCreate(key); + final Map valueMap; + + if(type == AMQType.VOID || + ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) + { + valueMap = Collections.singletonMap(null,successState); + + } + else + { + valueMap = Collections.singletonMap(value,successState); + } + nextStateMap.put(headerKey,valueMap); + + } + + } + + if(seenKeys.size() == 0) + { + return successState; + } + else + { + return new HeadersMatcherDFAState(nextStateMap,Collections.EMPTY_SET,_dictionary); + } + + + } + + + private HeadersMatcherDFAState createStateMachineForAllMatch(final FieldTable bindingArguments, + final HeaderMatcherResult result) + { + // DFAs for "all" matches have a "success" state, a "fail" state, and states for every subset of + // matches which are possible, starting with the empty subset. For example if we have a binding + // { x-match="all" + // a=1 + // b=1 + // c=1 + // d=1 } + // Then we would have the following states + // (1) Seen none of a, b, c, or d + // (2) Seen a=1 ; none of b,c, or d + // (3) Seen b=1 ; none of a,c, or d + // (4) Seen c=1 ; none of a,b, or d + // (5) Seen d=1 ; none of a,b, or c + // (6) Seen a=1,b=1 ; none of c,d + // (7) Seen a=1,c=1 ; none of b,d + // (8) Seen a=1,d=1 ; none of b,c + // (9) Seen b=1,c=1 ; none of a,d + //(10) Seen b=1,d=1 ; none of c,d + //(11) Seen c=1,d=1 ; none of a,b + //(12) Seen a=1,b=1,c=1 ; not d + //(13) Seen a=1,b=1,d=1 ; not c + //(14) Seen a=1,c=1,d=1 ; not b + //(15) Seen b=1,c=1,d=1 ; not a + //(16) success + //(17) fail + // + // All states but (16) can transition to (17); additionally: + // (1) can transition to (2),(3),(4),(5) + // (2) can transition to (6),(7),(8) + // (3) can transition to (6),(9),(10) + // (4) can transition to (7),(9),(11) + // (5) can transition to (8),(10),(11) + // (6) can transition to (12),(13) + // (7) can transition to (12),(14) + // (8) can transition to (13),(14) + // (9) can transition to (12),(15) + //(10) can transition to (13),(15) + //(11) can transition to (14),(15) + //(12)-(15) can transition to (16) + + Set seenKeys = new HashSet(); + List requiredTerms = new ArrayList(bindingArguments.size()); + + Iterator> tableIterator = bindingArguments.iterator(); + + + + while(tableIterator.hasNext()) + { + final Map.Entry entry = tableIterator.next(); + final AMQShortString key = entry.getKey(); + final AMQTypedValue value = entry.getValue(); + + + if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) + { + final AMQType type = value.getType(); + + if(type == AMQType.VOID || + ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) + { + requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),null)); + } + else + { + requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),value)); + } + } + + } + + final HeadersMatcherDFAState successState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); + + final HeadersMatcherDFAState failState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.EMPTY_SET,_dictionary); + + Map, HeadersMatcherDFAState> notSeenTermsToStateMap = + new HashMap, HeadersMatcherDFAState>(); + + notSeenTermsToStateMap.put(Collections.EMPTY_SET, successState); + + + final int numberOfTerms = requiredTerms.size(); + + for(int numMissingTerms = 1; numMissingTerms <= numberOfTerms; numMissingTerms++) + { + int[] pos = new int[numMissingTerms]; + for(int i = 0; i < numMissingTerms; i++) + { + pos[i] = i; + } + + final int maxTermValue = (numberOfTerms - (numMissingTerms - 1)); + + while(pos[0] < maxTermValue) + { + + Set stateSet = new HashSet(); + for(int posIndex = 0; posIndex < pos.length; posIndex++) + { + stateSet.add(requiredTerms.get(pos[posIndex])); + } + + final Map> nextStateMap = + new HashMap>(); + + + for(int posIndex = 0; posIndex < pos.length; posIndex++) + { + KeyValuePair nextTerm = requiredTerms.get(pos[posIndex]); + HashSet nextStateSet = + new HashSet(stateSet); + nextStateSet.remove(nextTerm); + + Map valueToStateMap = + new HashMap(); + nextStateMap.put(nextTerm._key, valueToStateMap); + + valueToStateMap.put( nextTerm._value,notSeenTermsToStateMap.get(nextStateSet)); + if(nextTerm._value != null) + { + valueToStateMap.put(null, failState); + } + + + } + + + HeadersMatcherDFAState newState = new HeadersMatcherDFAState(nextStateMap, Collections.EMPTY_SET, _dictionary); + + notSeenTermsToStateMap.put(stateSet, newState); + + int i = numMissingTerms; + while(i-- != 0) + { + if(++pos[i] <= numberOfTerms -(numMissingTerms-i)) + { + int k = pos[i]; + for(int j = i+1; j < numMissingTerms; j++) + { + pos[j] = ++k; + } + break; + } + } + } + + + + + } + + + return notSeenTermsToStateMap.get(new HashSet(requiredTerms)); + + + + } + + public static void main(String[] args) throws AMQFrameDecodingException + { + + FieldTable bindingTable = new FieldTable(); + + bindingTable.setString(new AMQShortString("x-match"),"all"); + bindingTable.setInteger("a",1); + bindingTable.setVoid(new AMQShortString("b")); + bindingTable.setString("c",""); + bindingTable.setInteger("d",4); + bindingTable.setInteger("e",1); + + + + FieldTable bindingTable2 = new FieldTable(); + bindingTable2.setString(new AMQShortString("x-match"),"all"); + bindingTable2.setInteger("a",1); + bindingTable2.setVoid(new AMQShortString("b")); + bindingTable2.setString("c",""); + bindingTable2.setInteger("d",4); + bindingTable2.setInteger("e",1); + bindingTable2.setInteger("f",1); + + + FieldTable table = new FieldTable(); + table.setInteger("a",1); + table.setInteger("b",2); + table.setString("c",""); + table.setInteger("d",4); + table.setInteger("e",1); + table.setInteger("f",1); + table.setInteger("h",1); + table.setInteger("i",1); + table.setInteger("j",1); + table.setInteger("k",1); + table.setInteger("l",1); + + org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.allocate( (int) table.getEncodedSize()); + EncodingUtils.writeFieldTableBytes(buffer, table); + buffer.flip(); + + FieldTable table2 = EncodingUtils.readFieldTable(buffer); + + + + FieldTable bindingTable3 = new FieldTable(); + bindingTable3.setString(new AMQShortString("x-match"),"any"); + bindingTable3.setInteger("a",1); + bindingTable3.setInteger("b",3); + + + FieldTable bindingTable4 = new FieldTable(); + bindingTable4.setString(new AMQShortString("x-match"),"any"); + bindingTable4.setVoid(new AMQShortString("a")); + + + FieldTable bindingTable5 = new FieldTable(); + bindingTable5.setString(new AMQShortString("x-match"),"all"); + bindingTable5.setString(new AMQShortString("h"),"hello"); + + for(int i = 0; i < 100; i++) + { + printMatches(new FieldTable[] {bindingTable5} , table2); + } + + + + } + + + + private static void printMatches(final FieldTable[] bindingKeys, final FieldTable routingKey) + { + HeadersMatcherDFAState sm = null; + Map resultMap = new HashMap(); + + HeadersParser parser = new HeadersParser(); + + for(int i = 0; i < bindingKeys.length; i++) + { + HeaderMatcherResult r = new HeaderMatcherResult(); + resultMap.put(r, bindingKeys[i].toString()); + + + if(i==0) + { + sm = parser.createStateMachine(bindingKeys[i], r); + } + else + { + sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeys[i], r)); + } + } + + Collection results = null; + long beforeTime = System.currentTimeMillis(); + for(int i = 0; i < 1000000; i++) + { + routingKey.size(); + + assert sm != null; + results = sm.match(routingKey); + + } + long elapsed = System.currentTimeMillis() - beforeTime; + System.out.println("1000000 Iterations took: " + elapsed); + Collection resultStrings = new ArrayList(); + + assert results != null; + for(HeaderMatcherResult result : results) + { + resultStrings.add(resultMap.get(result)); + } + + final ArrayList nonMatches = new ArrayList(); + for(FieldTable key : bindingKeys) + { + nonMatches.add(key.toString()); + } + nonMatches.removeAll(resultStrings); + System.out.println("\""+routingKey+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); + + + } + + + public final static class KeyValuePair + { + public final HeaderKey _key; + public final AMQTypedValue _value; + private final int _hashCode; + + public KeyValuePair(final HeaderKey key, final AMQTypedValue value) + { + _key = key; + _value = value; + int hash = (1 + 31 * _key.hashCode()); + if(_value != null) + { + hash+=_value.hashCode(); + } + _hashCode = hash; + } + + public int hashCode() + { + return _hashCode; + } + + public boolean equals(Object o) + { + KeyValuePair other = (KeyValuePair)o; + return (_key == other._key) && (_value == null ? other._value == null : _value.equals(other._value)); + } + + + public String toString() + { + return "{" + _key + " -> " + _value + "}"; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java new file mode 100644 index 0000000000..36076cf75b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java @@ -0,0 +1,295 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicMatcherDFAState +{ + private static final AtomicInteger stateId = new AtomicInteger(); + + private final int _id = stateId.incrementAndGet(); + + private final Collection _results; + private final Map _nextStateMap; + private static final byte TOPIC_DELIMITTER = (byte)'.'; + + + public TopicMatcherDFAState(Map nextStateMap, + Collection results ) + { + _nextStateMap = nextStateMap; + _results = results; + } + + + public TopicMatcherDFAState nextState(TopicWord word) + { + final TopicMatcherDFAState nextState = _nextStateMap.get(word); + return nextState == null ? _nextStateMap.get(TopicWord.ANY_WORD) : nextState; + } + + public Collection terminate() + { + return _results; + } + + + public Collection parse(TopicWordDictionary dictionary, AMQShortString routingKey) + { + return parse(dictionary, routingKey.tokenize(TOPIC_DELIMITTER)); + } + + private Collection parse(final TopicWordDictionary dictionary, + final AMQShortStringTokenizer tokens) + { + if(!tokens.hasMoreTokens()) + { + return _results; + } + TopicWord word = dictionary.getWord(tokens.nextToken()); + TopicMatcherDFAState nextState = _nextStateMap.get(word); + if(nextState == null && word != TopicWord.ANY_WORD) + { + nextState = _nextStateMap.get(TopicWord.ANY_WORD); + } + if(nextState == null) + { + return Collections.EMPTY_SET; + } + // Shortcut if we are at a looping terminal state + if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD)) + { + return _results; + } + + return nextState.parse(dictionary, tokens); + + } + + + public TopicMatcherDFAState mergeStateMachines(TopicMatcherDFAState otherStateMachine) + { + Map, TopicMatcherDFAState> newStateMap= new HashMap, TopicMatcherDFAState>(); + + Collection results; + + if(_results.isEmpty()) + { + results = otherStateMachine._results; + } + else if(otherStateMachine._results.isEmpty()) + { + results = _results; + } + else + { + results = new HashSet(_results); + results.addAll(otherStateMachine._results); + } + + + final Map newNextStateMap = new HashMap(); + + TopicMatcherDFAState newState = new TopicMatcherDFAState(newNextStateMap, results); + + + Set oldStates = new HashSet(); + oldStates.add(this); + oldStates.add(otherStateMachine); + + newStateMap.put(oldStates, newState); + + mergeStateMachines(oldStates, newNextStateMap, newStateMap); + + return newState; + + } + + private static void mergeStateMachines( + final Set oldStates, + final Map newNextStateMap, + final Map, TopicMatcherDFAState> newStateMap) + { + Map> nfaMap = new HashMap>(); + + for(TopicMatcherDFAState state : oldStates) + { + Map map = state._nextStateMap; + for(Map.Entry entry : map.entrySet()) + { + Set states = nfaMap.get(entry.getKey()); + if(states == null) + { + states = new HashSet(); + nfaMap.put(entry.getKey(), states); + } + states.add(entry.getValue()); + } + } + + Set anyWordStates = nfaMap.get(TopicWord.ANY_WORD); + + for(Map.Entry> transition : nfaMap.entrySet()) + { + Set destinations = transition.getValue(); + + if(anyWordStates != null) + { + destinations.addAll(anyWordStates); + } + + TopicMatcherDFAState nextState = newStateMap.get(destinations); + if(nextState == null) + { + + if(destinations.size() == 1) + { + nextState = destinations.iterator().next(); + newStateMap.put(destinations, nextState); + } + else + { + Collection results; + + Set> resultSets = new HashSet>(); + for(TopicMatcherDFAState destination : destinations) + { + resultSets.add(destination._results); + } + resultSets.remove(Collections.EMPTY_SET); + if(resultSets.size() == 0) + { + results = Collections.EMPTY_SET; + } + else if(resultSets.size() == 1) + { + results = resultSets.iterator().next(); + } + else + { + results = new HashSet(); + for(Collection oldResult : resultSets) + { + results.addAll(oldResult); + } + } + + final Map nextStateMap = new HashMap(); + + nextState = new TopicMatcherDFAState(nextStateMap, results); + newStateMap.put(destinations, nextState); + + mergeStateMachines( + destinations, + nextStateMap, + newStateMap); + + + } + + + } + newNextStateMap.put(transition.getKey(),nextState); + } + + // Remove redundant transitions where defined tokenWord has same action as ANY_WORD + TopicMatcherDFAState anyWordState = newNextStateMap.get(TopicWord.ANY_WORD); + if(anyWordState != null) + { + List removeList = new ArrayList(); + for(Map.Entry entry : newNextStateMap.entrySet()) + { + if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) + { + removeList.add(entry.getKey()); + } + } + for(TopicWord removeKey : removeList) + { + newNextStateMap.remove(removeKey); + } + } + + + + } + + + public String toString() + { + StringBuilder transitions = new StringBuilder(); + for(Map.Entry entry : _nextStateMap.entrySet()) + { + transitions.append("[ "); + transitions.append(entry.getKey()); + transitions.append("\t ->\t "); + transitions.append(entry.getValue()._id); + transitions.append(" ]\n"); + } + + + return "[ State " + _id + " ]\n" + transitions + "\n"; + + } + + public String reachableStates() + { + StringBuilder result = new StringBuilder("Start state: " + _id + "\n"); + + SortedSet reachableStates = + new TreeSet(new Comparator() + { + public int compare(final TopicMatcherDFAState o1, final TopicMatcherDFAState o2) + { + return o1._id - o2._id; + } + }); + reachableStates.add(this); + + int count; + + do + { + count = reachableStates.size(); + Collection originalStates = new ArrayList(reachableStates); + for(TopicMatcherDFAState state : originalStates) + { + reachableStates.addAll(state._nextStateMap.values()); + } + } + while(reachableStates.size() != count); + + + + for(TopicMatcherDFAState state : reachableStates) + { + result.append(state.toString()); + } + + return result.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java new file mode 100644 index 0000000000..71d30adfac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java @@ -0,0 +1,25 @@ +package org.apache.qpid.server.exchange.topic; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface TopicMatcherResult +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java new file mode 100644 index 0000000000..3e9facf412 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java @@ -0,0 +1,613 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.io.IOException; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicParser +{ + private static final byte TOPIC_DELIMITER = (byte)'.'; + + private final TopicWordDictionary _dictionary = new TopicWordDictionary(); + private final AtomicReference _stateMachine = new AtomicReference(); + + private static class Position + { + private final TopicWord _word; + private final boolean _selfTransition; + private final int _position; + private final boolean _endState; + private boolean _followedByAnyLoop; + + + public Position(final int position, final TopicWord word, final boolean selfTransition, final boolean endState) + { + _position = position; + _word = word; + _selfTransition = selfTransition; + _endState = endState; + } + + + } + + private static final Position ERROR_POSITION = new Position(Integer.MAX_VALUE,null, true, false); + + private static class SimpleState + { + Set _positions; + Map _nextState; + } + + + public void addBinding(AMQShortString bindingKey, TopicMatcherResult result) + { + + TopicMatcherDFAState startingStateMachine; + TopicMatcherDFAState newStateMachine; + + do + { + startingStateMachine = _stateMachine.get(); + if(startingStateMachine == null) + { + newStateMachine = createStateMachine(bindingKey, result); + } + else + { + newStateMachine = startingStateMachine.mergeStateMachines(createStateMachine(bindingKey, result)); + } + + } + while(!_stateMachine.compareAndSet(startingStateMachine,newStateMachine)); + + } + + public Collection parse(AMQShortString routingKey) + { + TopicMatcherDFAState stateMachine = _stateMachine.get(); + if(stateMachine == null) + { + return Collections.EMPTY_SET; + } + else + { + return stateMachine.parse(_dictionary,routingKey); + } + } + + + TopicMatcherDFAState createStateMachine(AMQShortString bindingKey, TopicMatcherResult result) + { + List wordList = createTopicWordList(bindingKey); + int wildCards = 0; + for(TopicWord word : wordList) + { + if(word == TopicWord.WILDCARD_WORD) + { + wildCards++; + } + } + if(wildCards == 0) + { + TopicMatcherDFAState[] states = new TopicMatcherDFAState[wordList.size()+1]; + states[states.length-1] = new TopicMatcherDFAState(Collections.EMPTY_MAP, Collections.singleton(result)); + for(int i = states.length-2; i >= 0; i--) + { + states[i] = new TopicMatcherDFAState(Collections.singletonMap(wordList.get(i),states[i+1]),Collections.EMPTY_SET); + + } + return states[0]; + } + else if(wildCards == wordList.size()) + { + Map stateMap = new HashMap(); + TopicMatcherDFAState state = new TopicMatcherDFAState(stateMap, Collections.singleton(result)); + stateMap.put(TopicWord.ANY_WORD, state); + return state; + } + + + int positionCount = wordList.size() - wildCards; + + Position[] positions = new Position[positionCount+1]; + + int lastWord; + + if(wordList.get(wordList.size()-1)== TopicWord.WILDCARD_WORD) + { + lastWord = wordList.size()-1; + positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, true, true); + } + else + { + lastWord = wordList.size(); + positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, false, true); + } + + + int pos = 0; + int wordPos = 0; + + + while(wordPos < lastWord) + { + TopicWord word = wordList.get(wordPos++); + + if(word == TopicWord.WILDCARD_WORD) + { + int nextWordPos = wordPos++; + word = wordList.get(nextWordPos); + + positions[pos] = new Position(pos++,word,true,false); + } + else + { + positions[pos] = new Position(pos++,word,false,false); + } + + } + + + for(int p = 0; p,SimpleState> stateMap = new HashMap,SimpleState>(); + + + SimpleState state = new SimpleState(); + state._positions = Collections.singleton( positions[0] ); + stateMap.put(state._positions, state); + + calculateNextStates(state, stateMap, positions); + + SimpleState[] simpleStates = stateMap.values().toArray(new SimpleState[stateMap.size()]); + HashMap[] dfaStateMaps = new HashMap[simpleStates.length]; + Map simple2DFAMap = new HashMap(); + + for(int i = 0; i < simpleStates.length; i++) + { + + Collection results; + boolean endState = false; + + for(Position p : simpleStates[i]._positions) + { + if(p._endState) + { + endState = true; + break; + } + } + + if(endState) + { + results = Collections.singleton(result); + } + else + { + results = Collections.EMPTY_SET; + } + + dfaStateMaps[i] = new HashMap(); + simple2DFAMap.put(simpleStates[i], new TopicMatcherDFAState(dfaStateMaps[i],results)); + + } + for(int i = 0; i < simpleStates.length; i++) + { + SimpleState simpleState = simpleStates[i]; + + Map nextSimpleStateMap = simpleState._nextState; + for(Map.Entry stateMapEntry : nextSimpleStateMap.entrySet()) + { + dfaStateMaps[i].put(stateMapEntry.getKey(), simple2DFAMap.get(stateMapEntry.getValue())); + } + + } + + return simple2DFAMap.get(state); + + } + + + + private void calculateNextStates(final SimpleState state, + final Map, SimpleState> stateMap, + final Position[] positions) + { + Map> transitions = new HashMap>(); + + for(Position pos : state._positions) + { + if(pos._selfTransition) + { + Set dest = transitions.get(TopicWord.ANY_WORD); + if(dest == null) + { + dest = new HashSet(); + transitions.put(TopicWord.ANY_WORD,dest); + } + dest.add(pos); + } + + final int nextPos = pos._position + 1; + Position nextPosition = nextPos == positions.length ? ERROR_POSITION : positions[nextPos]; + + Set dest = transitions.get(pos._word); + if(dest == null) + { + dest = new HashSet(); + transitions.put(pos._word,dest); + } + dest.add(nextPosition); + + } + + Set anyWordTransitions = transitions.get(TopicWord.ANY_WORD); + if(anyWordTransitions != null) + { + for(Set dest : transitions.values()) + { + dest.addAll(anyWordTransitions); + } + } + + state._nextState = new HashMap(); + + for(Map.Entry> dest : transitions.entrySet()) + { + + if(dest.getValue().size()>1) + { + dest.getValue().remove(ERROR_POSITION); + } + Position loopingTerminal = null; + for(Position destPos : dest.getValue()) + { + if(destPos._selfTransition && destPos._endState) + { + loopingTerminal = destPos; + break; + } + } + + if(loopingTerminal!=null) + { + dest.setValue(Collections.singleton(loopingTerminal)); + } + else + { + Position anyLoop = null; + for(Position destPos : dest.getValue()) + { + if(destPos._followedByAnyLoop) + { + if(anyLoop == null || anyLoop._position removals = new ArrayList(); + for(Position destPos : dest.getValue()) + { + if(destPos._position < anyLoop._position) + { + removals.add(destPos); + } + } + dest.getValue().removeAll(removals); + } + } + + SimpleState stateForEntry = stateMap.get(dest.getValue()); + if(stateForEntry == null) + { + stateForEntry = new SimpleState(); + stateForEntry._positions = dest.getValue(); + stateMap.put(dest.getValue(),stateForEntry); + calculateNextStates(stateForEntry, + stateMap, + positions); + } + state._nextState.put(dest.getKey(),stateForEntry); + + + + } + + // remove redundant transitions + SimpleState anyWordState = state._nextState.get(TopicWord.ANY_WORD); + if(anyWordState != null) + { + List removeList = new ArrayList(); + for(Map.Entry entry : state._nextState.entrySet()) + { + if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) + { + removeList.add(entry.getKey()); + } + } + for(TopicWord removeKey : removeList) + { + state._nextState.remove(removeKey); + } + } + + + } + + private List createTopicWordList(final AMQShortString bindingKey) + { + AMQShortStringTokenizer tokens = bindingKey.tokenize(TOPIC_DELIMITER); + TopicWord previousWord = null; + + List wordList = new ArrayList(); + + while(tokens.hasMoreTokens()) + { + TopicWord nextWord = _dictionary.getOrCreateWord(tokens.nextToken()); + if(previousWord == TopicWord.WILDCARD_WORD) + { + + if(nextWord == TopicWord.WILDCARD_WORD) + { + // consecutive wildcards can be merged + // i.e. subsequent wildcards can be discarded + continue; + } + else if(nextWord == TopicWord.ANY_WORD) + { + // wildcard and anyword can be reordered to always put anyword first + wordList.set(wordList.size()-1,TopicWord.ANY_WORD); + nextWord = TopicWord.WILDCARD_WORD; + } + } + wordList.add(nextWord); + previousWord = nextWord; + + } + return wordList; + } + + + public static void main(String[] args) + { + + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.*.q.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches(new String[]{ + "#.a.#", + "#.b.#", + "#.c.#", + "#.d.#", + "#.e.#", + "#.f.#", + "#.g.#", + "#.h.#", + "#.i.#", + "#.j.#", + "#.k.#", + "#.l.#", + "#.m.#", + "#.n.#", + "#.o.#", + "#.p.#", + "#.q.#" + + }, "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); +/* + printMatches(new String[]{ + "#.a.#", + "#.b.#", + "#.c.#", + "#.d.#", + "#.e.#", + "#.f.#", + "#.g.#", + "#.h.#", + "#.i.#", + "#.j.#", + "#.k.#", + "#.l.#", + "#.m.#", + "#.n.#", + "#.o.#", + "#.p.#", + "#.q.#", + "#.r.#", + "#.s.#", + "#.t.#", + "#.u.#", + "#.v.#", + "#.w.#", + "#.x.#", + "#.y.#", + "#.z.#" + + + },"a.b"); + + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches("a.#.b.#","a.b.b.b.b.b.b.b.c"); + +*/ + + printMatches("",""); + printMatches("a","a"); + printMatches("a",""); + printMatches("","a"); + printMatches("a.b","a.b"); + printMatches("a","a.b"); + printMatches("a.b","a"); + printMatches("*","a"); + printMatches("*.b","a.b"); + printMatches("*.*","a.b"); + printMatches("a.*","a.b"); + printMatches("a.*.#","a.b"); + printMatches("a.#.b","a.b"); + + printMatches("#.b","a"); + printMatches("#.b","a.b"); + printMatches("#.a.b","a.b"); + + + printMatches("#",""); + printMatches("#","a"); + printMatches("#","a.b"); + printMatches("#.#","a.b"); + printMatches("#.*","a.b"); + + printMatches("#.a.b","a.b"); + printMatches("a.b.#","a.b"); + printMatches("a.#","a.b"); + printMatches("#.*.#","a.b"); + printMatches("#.*.b.#","a.b"); + printMatches("#.a.*.#","a.b"); + printMatches("#.a.#.b.#","a.b"); + printMatches("#.*.#.*.#","a.b"); + printMatches("*.#.*.#","a.b"); + printMatches("#.*.#.*","a.b"); + + + printMatches(new String[]{"a.#.b.#","a.*.#.b.#"},"a.b.b.b.b.b.b.b.c"); + + + printMatches(new String[]{"a.b", "a.c"},"a.b"); + printMatches(new String[]{"a.#", "a.c", "#.b"},"a.b"); + printMatches(new String[]{"a.#", "a.c", "#.b", "#", "*.*"},"a.b"); + + printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.e"); + printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.f.g"); + + + + + } + + private static void printMatches(final String[] bindingKeys, final String routingKey) + { + TopicMatcherDFAState sm = null; + Map resultMap = new HashMap(); + + TopicParser parser = new TopicParser(); + + long start = System.currentTimeMillis(); + for(int i = 0; i < bindingKeys.length; i++) + { + System.out.println((System.currentTimeMillis() - start) + ":\t" + bindingKeys[i]); + TopicMatcherResult r = new TopicMatcherResult(){}; + resultMap.put(r, bindingKeys[i]); + AMQShortString bindingKeyShortString = new AMQShortString(bindingKeys[i]); + + System.err.println("====================================================="); + System.err.println("Adding binding key: " + bindingKeyShortString); + System.err.println("-----------------------------------------------------"); + + + if(i==0) + { + sm = parser.createStateMachine(bindingKeyShortString, r); + } + else + { + sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeyShortString, r)); + } + System.err.println(sm.reachableStates()); + System.err.println("====================================================="); + try + { + System.in.read(); + } + catch (IOException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + AMQShortString routingKeyShortString = new AMQShortString(routingKey); + + Collection results = sm.parse(parser._dictionary, routingKeyShortString); + Collection resultStrings = new ArrayList(); + + for(TopicMatcherResult result : results) + { + resultStrings.add(resultMap.get(result)); + } + + final ArrayList nonMatches = new ArrayList(Arrays.asList(bindingKeys)); + nonMatches.removeAll(resultStrings); + System.out.println("\""+routingKeyShortString+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); + + + } + + private static void printMatches(String bindingKey, String routingKey) + { + printMatches(new String[] { bindingKey }, routingKey); + } + + + private static boolean matches(String bindingKey, String routingKey) + { + AMQShortString bindingKeyShortString = new AMQShortString(bindingKey); + AMQShortString routingKeyShortString = new AMQShortString(routingKey); + TopicParser parser = new TopicParser(); + + final TopicMatcherResult result = new TopicMatcherResult(){}; + + TopicMatcherDFAState sm = parser.createStateMachine(bindingKeyShortString, result); + return !sm.parse(parser._dictionary,routingKeyShortString).isEmpty(); + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java new file mode 100644 index 0000000000..f14d70f8a1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java @@ -0,0 +1,54 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public final class TopicWord +{ + public static final TopicWord ANY_WORD = new TopicWord("*"); + public static final TopicWord WILDCARD_WORD = new TopicWord("#"); + private String _word; + + public TopicWord() + { + + } + + public TopicWord(String s) + { + _word = s; + } + + public TopicWord(final AMQShortString name) + { + _word = name.toString(); + } + + public String toString() + { + return _word; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java new file mode 100644 index 0000000000..65a0cd3107 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java @@ -0,0 +1,63 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.concurrent.ConcurrentHashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicWordDictionary +{ + private final ConcurrentHashMap _dictionary = + new ConcurrentHashMap(); + + + + public TopicWordDictionary() + { + _dictionary.put(new AMQShortString("*"), TopicWord.ANY_WORD); + _dictionary.put(new AMQShortString("#"), TopicWord.WILDCARD_WORD); + } + + + + + public TopicWord getOrCreateWord(AMQShortString name) + { + TopicWord word = _dictionary.putIfAbsent(name, new TopicWord(name)); + if(word == null) + { + word = _dictionary.get(name); + } + return word; + } + + + public TopicWord getWord(AMQShortString name) + { + TopicWord word = _dictionary.get(name); + if(word == null) + { + word = TopicWord.ANY_WORD; + } + return word; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index fb5220f4da..a964bce306 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -21,12 +21,12 @@ package org.apache.qpid.server.filter; // import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class ArithmeticExpression extends BinaryExpression +public abstract class ArithmeticExpression extends BinaryExpression { protected static final int INTEGER = 1; @@ -248,7 +248,7 @@ public abstract class ArithmeticExpression extends BinaryExpression } } - public Object evaluate(AMQMessage message) throws AMQException + public Object evaluate(Filterable message) throws E { Object lvalue = left.evaluate(message); if (lvalue == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java index 024257bea9..7308de80d6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -23,23 +23,23 @@ package org.apache.qpid.server.filter; /** * An expression which performs an operation on two expression values. */ -public abstract class BinaryExpression implements Expression +public abstract class BinaryExpression implements Expression { - protected Expression left; - protected Expression right; + protected Expression left; + protected Expression right; - public BinaryExpression(Expression left, Expression right) + public BinaryExpression(Expression left, Expression right) { this.left = left; this.right = right; } - public Expression getLeft() + public Expression getLeft() { return left; } - public Expression getRight() + public Expression getRight() { return right; } @@ -90,7 +90,7 @@ public abstract class BinaryExpression implements Expression /** * @param expression */ - public void setRight(Expression expression) + public void setRight(Expression expression) { right = expression; } @@ -98,7 +98,7 @@ public abstract class BinaryExpression implements Expression /** * @param expression */ - public void setLeft(Expression expression) + public void setLeft(Expression expression) { left = expression; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index e28ff79820..9beb9798d0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -22,19 +22,20 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * A BooleanExpression is an expression that always * produces a Boolean result. */ -public interface BooleanExpression extends Expression +public interface BooleanExpression extends Expression { /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException + * @throws E */ - public boolean matches(AMQMessage message) throws AMQException; + public boolean matches(Filterable message) throws E; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 44281a3aae..921005c462 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -28,21 +28,21 @@ import java.util.List; import java.util.regex.Pattern; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) { return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); } - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) { return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); } @@ -73,7 +73,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B REGEXP_CONTROL_CHARS.add(new Character('!')); } - static class LikeExpression extends UnaryExpression implements BooleanExpression + static class LikeExpression extends UnaryExpression implements BooleanExpression { Pattern likePattern; @@ -81,7 +81,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B /** * @param right */ - public LikeExpression(Expression right, String like, int escape) + public LikeExpression(Expression right, String like, int escape) { super(right); @@ -138,7 +138,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B /** * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) */ - public Object evaluate(AMQMessage message) throws AMQException + public Object evaluate(Filterable message) throws E { Object rv = this.getRight().evaluate(message); @@ -148,11 +148,6 @@ public abstract class ComparisonExpression extends BinaryExpression implements B return null; } - if(rv instanceof AMQShortString) - { - rv = rv.toString(); - } - if (!(rv instanceof String)) { return @@ -163,7 +158,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; } - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws E { Object object = evaluate(message); @@ -241,45 +236,9 @@ public abstract class ComparisonExpression extends BinaryExpression implements B return doCreateEqual(left, right); } - private static BooleanExpression doCreateEqual(Expression left, Expression right) + private static BooleanExpression doCreateEqual(Expression left, Expression right) { - return new ComparisonExpression(left, right) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - Object lv = left.evaluate(message); - Object rv = right.evaluate(message); - - // Iff one of the values is null - if ((lv == null) ^ (rv == null)) - { - return Boolean.FALSE; - } - - if ((lv == rv) || lv.equals(rv)) - { - return Boolean.TRUE; - } - - if ((lv instanceof Comparable) && (rv instanceof Comparable)) - { - return compare((Comparable) lv, (Comparable) rv); - } - - return Boolean.FALSE; - } - - protected boolean asBoolean(int answer) - { - return answer == 0; - } - - public String getExpressionSymbol() - { - return "="; - } - }; + return new EqualExpression(left, right); } public static BooleanExpression createGreaterThan(final Expression left, final Expression right) @@ -429,7 +388,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B super(left, right); } - public Object evaluate(AMQMessage message) throws AMQException + public Object evaluate(Filterable message) throws E { Comparable lv = (Comparable) left.evaluate(message); if (lv == null) @@ -454,40 +413,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B // try to convert up to allow the comparison. if (lc != rc) { - if(lc == AMQShortString.class) - { - if(rc == String.class) - { - rv = new AMQShortString((String) rv); - - if(right instanceof ConstantExpression) - { - ((ConstantExpression)right).setValue(rv); - } - } - else - { - return Boolean.FALSE; - } - } - else if(lc == String.class) - { - if(rc == AMQShortString.class) - { - lv = new AMQShortString((String) lv); - - if(left instanceof ConstantExpression) - { - ((ConstantExpression)left).setValue(lv); - } - } - else - { - return Boolean.FALSE; - } - - } - else if (lc == Byte.class) + if (lc == Byte.class) { if (rc == Short.class) { @@ -624,11 +550,52 @@ public abstract class ComparisonExpression extends BinaryExpression implements B protected abstract boolean asBoolean(int answer); - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws E { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } + private static class EqualExpression extends ComparisonExpression + { + public EqualExpression(final Expression left, final Expression right) + { + super(left, right); + } + + public Object evaluate(Filterable message) throws E + { + Object lv = left.evaluate(message); + Object rv = right.evaluate(message); + + // Iff one of the values is null + if ((lv == null) ^ (rv == null)) + { + return Boolean.FALSE; + } + + if ((lv == rv) || lv.equals(rv)) + { + return Boolean.TRUE; + } + + if ((lv instanceof Comparable) && (rv instanceof Comparable)) + { + return compare((Comparable) lv, (Comparable) rv); + } + + return Boolean.FALSE; + } + + protected boolean asBoolean(int answer) + { + return answer == 0; + } + + public String getExpressionSymbol() + { + return "="; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 73c4c66ad7..3ed2286f2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -26,23 +26,23 @@ package org.apache.qpid.server.filter; import java.math.BigDecimal; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * Represents a constant expression */ -public class ConstantExpression implements Expression +public class ConstantExpression implements Expression { - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression { public BooleanConstantExpression(Object value) { super(value); } - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws E { Object object = evaluate(message); @@ -121,7 +121,7 @@ public class ConstantExpression implements Expression this.value = value; } - public Object evaluate(AMQMessage message) throws AMQException + public Object evaluate(Filterable message) throws E { return value; } @@ -131,12 +131,6 @@ public class ConstantExpression implements Expression return value; } - public void setValue(final Object value) - { - this.value = value; - } - - /** * @see java.lang.Object#toString() */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index 5f646c15db..f2ebe41d26 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -22,16 +22,17 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * Represents an expression */ -public interface Expression +public interface Expression { /** * @return the value of this expression */ - public Object evaluate(AMQMessage message) throws AMQException; + public Object evaluate(Filterable message) throws E; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java index c82de9fa15..dd3c126ee5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -24,14 +24,16 @@ package org.apache.qpid.server.filter; // import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; +import org.apache.qpid.AMQException; -public interface FilterManager +public interface FilterManager { - void add(MessageFilter filter); + void add(MessageFilter filter); - void remove(MessageFilter filter); + void remove(MessageFilter filter); - boolean allAllow(AMQMessage msg); + boolean allAllow(Filterable msg); boolean hasFilters(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index 311f0680ec..a7f49d0566 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -39,7 +39,7 @@ public class FilterManagerFactory if (filters != null) { - manager = new SimpleFilterManager(); + if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) { @@ -47,23 +47,13 @@ public class FilterManagerFactory if (selector != null && !selector.equals("")) { + manager = new SimpleFilterManager(); manager.add(new JMSSelectorFilter(selector)); } } - if (filters.containsKey(AMQPFilterTypes.NO_CONSUME.getValue())) - { - manager.add(new NoConsumerFilter()); - } - - - //If we added no filters don't bear the overhead of having an filter manager - if (!manager.hasFilters()) - { - manager = null; - } } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 48b6602bda..96c9353872 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -23,45 +23,30 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.filter.jms.selector.SelectorParser; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; - -public class JMSSelectorFilter implements MessageFilter +public class JMSSelectorFilter implements MessageFilter { private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); private String _selector; - private BooleanExpression _matcher; + private BooleanExpression _matcher; public JMSSelectorFilter(String selector) throws AMQException { _selector = selector; - _logger.info("Created JMSSelectorFilter with selector:" + _selector); - - _matcher = new SelectorParser().parse(selector); - - } - public boolean matches(AMQMessage message) + public boolean matches(Filterable message) throws E { - try - { - boolean match = _matcher.matches(message); - if(_logger.isDebugEnabled()) - { - _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); - } - return match; - } - catch (AMQException e) + boolean match = _matcher.matches(message); + if(_logger.isDebugEnabled()) { - //fixme this needs to be sorted.. it shouldn't happen - e.printStackTrace(); + _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); } - return false; + return match; } public String getSelector() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index c8cbdb2125..094363ed9a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -22,71 +22,22 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - - Boolean lv = (Boolean) left.evaluate(message); - // Can we do an OR shortcut?? - if ((lv != null) && lv.booleanValue()) - { - return Boolean.TRUE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "OR"; - } - }; + return new OrExpression(lvalue, rvalue); } - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AMQMessage message) throws AMQException - { - - Boolean lv = (Boolean) left.evaluate(message); - - // Can we do an AND shortcut?? - if (lv == null) - { - return null; - } - - if (!lv.booleanValue()) - { - return Boolean.FALSE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "AND"; - } - }; + return new AndExpression(lvalue, rvalue); } /** @@ -98,13 +49,74 @@ public abstract class LogicExpression extends BinaryExpression implements Boolea super(left, right); } - public abstract Object evaluate(AMQMessage message) throws AMQException; + public abstract Object evaluate(Filterable message) throws E; - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws E { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } + private static class OrExpression extends LogicExpression + { + public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + { + super(lvalue, rvalue); + } + + public Object evaluate(Filterable message) throws E + { + + Boolean lv = (Boolean) left.evaluate(message); + // Can we do an OR shortcut?? + if ((lv != null) && lv.booleanValue()) + { + return Boolean.TRUE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "OR"; + } + } + + private static class AndExpression extends LogicExpression + { + public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + { + super(lvalue, rvalue); + } + + public Object evaluate(Filterable message) throws E + { + + Boolean lv = (Boolean) left.evaluate(message); + + // Can we do an AND shortcut?? + if (lv == null) + { + return null; + } + + if (!lv.booleanValue()) + { + return Boolean.FALSE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "AND"; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index e6bfe974d5..58fc55f8e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -22,8 +22,9 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; -public interface MessageFilter +public interface MessageFilter { - boolean matches(AMQMessage message) throws AMQException; + boolean matches(Filterable message) throws E; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java index 47ca930d12..f1b3b2511d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -22,7 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; public class NoConsumerFilter implements MessageFilter { @@ -34,7 +34,7 @@ public class NoConsumerFilter implements MessageFilter _logger.info("Created NoConsumerFilter"); } - public boolean matches(AMQMessage message) + public boolean matches(Filterable message) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index e5e9acf9bb..b30c70dac3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -30,12 +30,12 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * Represents a property expression */ -public class PropertyExpression implements Expression +public class PropertyExpression implements Expression { // Constants - defined the same as JMS private static final int NON_PERSISTENT = 1; @@ -44,223 +44,60 @@ public class PropertyExpression implements Expression private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - private static final HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); + private static final HashMap> JMS_PROPERTY_EXPRESSIONS = new HashMap>(); - static { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() { - public Object evaluate(AMQMessage message) + public Object evaluate(Filterable message) { //TODO return null; } }); - JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - - return (replyTo == null) ? null : replyTo; - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - - return (type == null) ? null : type; - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; - if (_logger.isDebugEnabled()) - { - _logger.debug("JMSDeliveryMode is :" + mode); - } - - return mode; - } - catch (AMQException e) - { - _logger.warn(e); - } - - return NON_PERSISTENT; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression() - { - public Object evaluate(AMQMessage message) - { - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return (int) _properties.getPriority(); - } - catch (AMQException e) - { - _logger.warn(e); - } - - return DEFAULT_PRIORITY; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); - - return (messageId == null) ? null : messageId; - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getTimestamp(); - } - catch (AMQException e) - { - _logger.warn(e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression() - { - public Object evaluate(AMQMessage message) - { - - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - - return (correlationId == null) ? null : correlationId; - } - catch (AMQException e) - { - _logger.warn(e); + JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new ReplyToExpression()); - return null; - } + JMS_PROPERTY_EXPRESSIONS.put("JMSType", new TypeExpression()); - } - }); + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new DeliveryModeExpression()); - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression() - { - public Object evaluate(AMQMessage message) - { + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression()); - try - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression()); - return _properties.getExpiration(); - } - catch (AMQException e) - { - _logger.warn(e); + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression()); - return null; - } + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new CorrelationIdExpression()); - } - }); + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() { - public Object evaluate(AMQMessage message) + public Object evaluate(Filterable message) throws E { return message.isRedelivered(); } }); - } - private final AMQShortString name; - private final Expression jmsPropertyExpression; + private final String name; + private final Expression jmsPropertyExpression; + + public boolean outerTest() + { + return false; + } public PropertyExpression(String name) { - this.name = new AMQShortString(name); - jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); + this.name = name; + + + + jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); } - public Object evaluate(AMQMessage message) throws AMQException + public Object evaluate(Filterable message) throws E { if (jmsPropertyExpression != null) @@ -283,7 +120,7 @@ public class PropertyExpression implements Expression } } - public AMQShortString getName() + public String getName() { return name; } @@ -293,7 +130,7 @@ public class PropertyExpression implements Expression */ public String toString() { - return name.toString(); + return name; } /** @@ -319,4 +156,113 @@ public class PropertyExpression implements Expression } + private static class ReplyToExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString replyTo = _properties.getReplyTo(); + + return (replyTo == null) ? null : replyTo.toString(); + + } + + } + + private static class TypeExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString type = _properties.getType(); + + return (type == null) ? null : type.toString(); + + } + } + + private static class DeliveryModeExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; + if (_logger.isDebugEnabled()) + { + _logger.debug("JMSDeliveryMode is :" + mode); + } + + return mode; + } + } + + private static class PriorityExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return (int) _properties.getPriority(); + } + } + + private static class MessageIDExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString messageId = _properties.getMessageId(); + + return (messageId == null) ? null : messageId; + + } + } + + private static class TimestampExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getTimestamp(); + } + } + + private static class CorrelationIdExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString correlationId = _properties.getCorrelationId(); + + return (correlationId == null) ? null : correlationId.toString(); + } + } + + private static class ExpirationExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getExpiration(); + + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index 62a45f5420..cb738e1489 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -25,32 +25,33 @@ import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; -public class SimpleFilterManager implements FilterManager +public class SimpleFilterManager implements FilterManager { private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - private final ConcurrentLinkedQueue _filters; + private final ConcurrentLinkedQueue> _filters; public SimpleFilterManager() { _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue(); + _filters = new ConcurrentLinkedQueue>(); } - public void add(MessageFilter filter) + public void add(MessageFilter filter) { _filters.add(filter); } - public void remove(MessageFilter filter) + public void remove(MessageFilter filter) { _filters.remove(filter); } - public boolean allAllow(AMQMessage msg) + public boolean allAllow(Filterable msg) { - for (MessageFilter filter : _filters) + for (MessageFilter filter : _filters) { try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 83b4ed5358..799a38af5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -30,45 +30,23 @@ import java.util.Iterator; import java.util.List; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class UnaryExpression implements Expression +public abstract class UnaryExpression implements Expression { private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression right; + protected Expression right; - public static Expression createNegate(Expression left) + public static Expression createNegate(Expression left) { - return new UnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue instanceof Number) - { - return negate((Number) rvalue); - } - - return null; - } - - public String getExpressionSymbol() - { - return "-"; - } - }; + return new NegativeExpression(left); } - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { // Use a HashSet if there are many elements. @@ -88,81 +66,17 @@ public abstract class UnaryExpression implements Expression final Collection inList = t; - return new BooleanUnaryExpression(right) - { - public Object evaluate(AMQMessage message) throws AMQException - { - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue.getClass() != String.class) - { - return null; - } - - if (((inList != null) && inList.contains(rvalue)) ^ not) - { - return Boolean.TRUE; - } - else - { - return Boolean.FALSE; - } - - } - - public String toString() - { - StringBuffer answer = new StringBuffer(); - answer.append(right); - answer.append(" "); - answer.append(getExpressionSymbol()); - answer.append(" ( "); - - int count = 0; - for (Iterator i = inList.iterator(); i.hasNext();) - { - Object o = (Object) i.next(); - if (count != 0) - { - answer.append(", "); - } - - answer.append(o); - count++; - } - - answer.append(" )"); - - return answer.toString(); - } - - public String getExpressionSymbol() - { - if (not) - { - return "NOT IN"; - } - else - { - return "IN"; - } - } - }; + return new InExpression(right, inList, not); } - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { - public BooleanUnaryExpression(Expression left) + public BooleanUnaryExpression(Expression left) { super(left); } - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws E { Object object = evaluate(message); @@ -171,26 +85,9 @@ public abstract class UnaryExpression implements Expression } ; - public static BooleanExpression createNOT(BooleanExpression left) + public static BooleanExpression createNOT(BooleanExpression left) { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) - { - return null; - } - - return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - - public String getExpressionSymbol() - { - return "NOT"; - } - }; + return new NotExpression(left); } public static BooleanExpression createXPath(final String xpath) @@ -203,36 +100,9 @@ public abstract class UnaryExpression implements Expression return new XQueryExpression(xpath); } - public static BooleanExpression createBooleanCast(Expression left) + public static BooleanExpression createBooleanCast(Expression left) { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AMQMessage message) throws AMQException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (!rvalue.getClass().equals(Boolean.class)) - { - return Boolean.FALSE; - } - - return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; - } - - public String toString() - { - return right.toString(); - } - - public String getExpressionSymbol() - { - return ""; - } - }; + return new BooleanCastExpression(left); } private static Number negate(Number left) @@ -281,7 +151,7 @@ public abstract class UnaryExpression implements Expression this.right = left; } - public Expression getRight() + public Expression getRight() { return right; } @@ -334,4 +204,166 @@ public abstract class UnaryExpression implements Expression */ public abstract String getExpressionSymbol(); + private static class NegativeExpression extends UnaryExpression + { + public NegativeExpression(final Expression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue instanceof Number) + { + return negate((Number) rvalue); + } + + return null; + } + + public String getExpressionSymbol() + { + return "-"; + } + } + + private static class InExpression extends BooleanUnaryExpression + { + private final Collection _inList; + private final boolean _not; + + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) + { + super(right); + _inList = inList; + _not = not; + } + + public Object evaluate(Filterable message) throws E + { + + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue.getClass() != String.class) + { + return null; + } + + if (((_inList != null) && _inList.contains(rvalue)) ^ _not) + { + return Boolean.TRUE; + } + else + { + return Boolean.FALSE; + } + + } + + public String toString() + { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count = 0; + for (Iterator i = _inList.iterator(); i.hasNext();) + { + Object o = (Object) i.next(); + if (count != 0) + { + answer.append(", "); + } + + answer.append(o); + count++; + } + + answer.append(" )"); + + return answer.toString(); + } + + public String getExpressionSymbol() + { + if (_not) + { + return "NOT IN"; + } + else + { + return "IN"; + } + } + } + + private static class NotExpression extends BooleanUnaryExpression + { + public NotExpression(final BooleanExpression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Boolean lvalue = (Boolean) right.evaluate(message); + if (lvalue == null) + { + return null; + } + + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + public String getExpressionSymbol() + { + return "NOT"; + } + } + + private static class BooleanCastExpression extends BooleanUnaryExpression + { + public BooleanCastExpression(final Expression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (!rvalue.getClass().equals(Boolean.class)) + { + return Boolean.FALSE; + } + + return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + public String toString() + { + return right.toString(); + } + + public String getExpressionSymbol() + { + return ""; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index f5454afae5..1311178fb1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -70,7 +71,7 @@ public final class XPathExpression implements BooleanExpression { private final XPathEvaluator evaluator; static public interface XPathEvaluator { - public boolean evaluate(AMQMessage message) throws AMQException; + public boolean evaluate(Filterable message) throws AMQException; } XPathExpression(String xpath) { @@ -92,7 +93,7 @@ public final class XPathExpression implements BooleanExpression { } } - public Object evaluate(AMQMessage message) throws AMQException { + public Object evaluate(Filterable message) throws AMQException { // try { //FIXME this is flow to disk work // if( message.isDropped() ) @@ -117,7 +118,7 @@ public final class XPathExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index f5debb607a..c13f81cd08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -19,6 +19,7 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; // // Based on like named file from r450141 of the Apache ActiveMQ project @@ -35,7 +36,7 @@ public final class XQueryExpression implements BooleanExpression { this.xpath = xpath; } - public Object evaluate(AMQMessage message) throws AMQException { + public Object evaluate(Filterable message) throws AMQException { return Boolean.FALSE; } @@ -48,7 +49,7 @@ public final class XQueryExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(AMQMessage message) throws AMQException + public boolean matches(Filterable message) throws AMQException { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index 35d770fd5d..cc67776682 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -29,6 +29,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; import org.apache.xpath.CachedXPathAPI; import org.w3c.dom.Document; import org.w3c.dom.traversal.NodeIterator; @@ -42,7 +43,7 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { this.xpath = xpath; } - public boolean evaluate(AMQMessage m) throws AMQException + public boolean evaluate(Filterable m) throws AMQException { // TODO - we would have to check the content type and then evaluate the content // here... is this really a feature we wish to implement? - RobG diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java new file mode 100644 index 0000000000..895db7b15b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java @@ -0,0 +1,62 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.flow; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; +import java.util.HashSet; + +public abstract class AbstractFlowCreditManager implements FlowCreditManager +{ + protected final AtomicBoolean _suspended = new AtomicBoolean(false); + private final Set _listeners = new HashSet(); + + public final void addStateListener(FlowCreditManagerListener listener) + { + _listeners.add(listener); + } + + public final boolean removeListener(FlowCreditManagerListener listener) + { + return _listeners.remove(listener); + } + + private void notifyListeners(final boolean suspended) + { + for(FlowCreditManagerListener listener : _listeners) + { + listener.creditStateChanged(!suspended); + } + } + + protected final void setSuspended(final boolean suspended) + { + if(_suspended.compareAndSet(!suspended, suspended)) + { + notifyListeners(suspended); + } + } + + protected final void notifyIncreaseBytesCredit() + { + notifyListeners(false); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java new file mode 100644 index 0000000000..96a1071135 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -0,0 +1,77 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; +import java.util.HashSet; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class BytesOnlyCreditManager extends AbstractFlowCreditManager +{ + private final AtomicLong _bytesCredit; + + public BytesOnlyCreditManager(long initialCredit) + { + _bytesCredit = new AtomicLong(initialCredit); + } + + public void addCredit(long messageCredit, long bytesCredit) + { + _bytesCredit.addAndGet(bytesCredit); + setSuspended(false); + } + + public void removeAllCredit() + { + _bytesCredit.set(0L); + } + + public boolean hasCredit() + { + return _bytesCredit.get() > 0L; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + final long msgSize = msg.getSize(); + if(hasCredit()) + { + if(_bytesCredit.addAndGet(-msgSize) >= 0) + { + return true; + } + else + { + _bytesCredit.addAndGet(msgSize); + setSuspended(true); + return false; + } + } + else + { + return false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java new file mode 100644 index 0000000000..a249a6e63a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java @@ -0,0 +1,44 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface FlowCreditManager +{ + + public static interface FlowCreditManagerListener + { + void creditStateChanged(boolean hasCredit); + } + + void addStateListener(FlowCreditManagerListener listener); + + boolean removeListener(FlowCreditManagerListener listener); + + public void addCredit(long messageCredit, long bytesCredit); + + public void removeAllCredit(); + + public boolean hasCredit(); + + public boolean useCreditForMessage(AMQMessage msg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java new file mode 100644 index 0000000000..d63431c3eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java @@ -0,0 +1,44 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + public void addCredit(long messageCredit, long bytesCredit) + { + } + + public void removeAllCredit() + { + } + + public boolean hasCredit() + { + return true; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java new file mode 100644 index 0000000000..9c377481de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -0,0 +1,79 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class MessageAndBytesCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + private long _messageCredit; + private long _bytesCredit; + + MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) + { + _messageCredit = messageCredit; + _bytesCredit = bytesCredit; + } + + public synchronized void addCredit(long messageCredit, long bytesCredit) + { + _messageCredit += messageCredit; + _bytesCredit += bytesCredit; + setSuspended(hasCredit()); + } + + public synchronized void removeAllCredit() + { + _messageCredit = 0L; + _bytesCredit = 0L; + setSuspended(true); + } + + public synchronized boolean hasCredit() + { + return (_messageCredit > 0L) && ( _bytesCredit > 0L ); + } + + public synchronized boolean useCreditForMessage(AMQMessage msg) + { + if(_messageCredit == 0L) + { + setSuspended(true); + return false; + } + else + { + final long msgSize = msg.getSize(); + if(msgSize > _bytesCredit) + { + setSuspended(true); + return false; + } + _messageCredit--; + _bytesCredit -= msgSize; + setSuspended(false); + return true; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java new file mode 100644 index 0000000000..c1b3a09006 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java @@ -0,0 +1,76 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class MessageOnlyCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + private final AtomicLong _messageCredit; + + public MessageOnlyCreditManager(final long initialCredit) + { + _messageCredit = new AtomicLong(initialCredit); + } + + public void addCredit(long messageCredit, long bytesCredit) + { + setSuspended(false); + _messageCredit.addAndGet(messageCredit); + } + + public void removeAllCredit() + { + setSuspended(true); + _messageCredit.set(0L); + } + + public boolean hasCredit() + { + return _messageCredit.get() > 0L; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + if(hasCredit()) + { + if(_messageCredit.addAndGet(-1L) >= 0) + { + setSuspended(false); + return true; + } + else + { + _messageCredit.addAndGet(1L); + setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java new file mode 100644 index 0000000000..be0300f2c1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java @@ -0,0 +1,185 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + + private volatile long _bytesCreditLimit; + private volatile long _messageCreditLimit; + + private volatile long _bytesCredit; + private volatile long _messageCredit; + + public Pre0_10CreditManager(long bytesCreditLimit, long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + _bytesCredit = bytesCreditLimit; + _messageCredit = messageCreditLimit; + } + + + public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit) + { + long bytesCreditChange = bytesCreditLimit - _bytesCreditLimit; + long messageCreditChange = messageCreditLimit - _messageCreditLimit; + + + + if(bytesCreditChange != 0L) + { + if(bytesCreditLimit == 0L) + { + _bytesCredit = 0; + } + else + { + _bytesCredit += bytesCreditChange; + } + } + + + if(messageCreditChange != 0L) + { + if(messageCreditLimit == 0L) + { + _messageCredit = 0; + } + else + { + _messageCredit += messageCreditChange; + } + } + + + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + + setSuspended(!hasCredit()); + + } + + + public synchronized void addCredit(final long messageCredit, final long bytesCredit) + { + final long messageCreditLimit = _messageCreditLimit; + boolean notifyIncrease = true; + if(messageCreditLimit != 0L) + { + notifyIncrease = (_messageCredit != 0); + long newCredit = _messageCredit + messageCredit; + _messageCredit = newCredit > messageCreditLimit ? messageCreditLimit : newCredit; + } + + + final long bytesCreditLimit = _bytesCreditLimit; + if(bytesCreditLimit != 0L) + { + long newCredit = _bytesCredit + bytesCredit; + _bytesCredit = newCredit > bytesCreditLimit ? bytesCreditLimit : newCredit; + if(notifyIncrease && bytesCredit>0) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + public synchronized void removeAllCredit() + { + _bytesCredit = 0L; + _messageCredit = 0L; + setSuspended(!hasCredit()); + } + + public synchronized boolean hasCredit() + { + return (_bytesCreditLimit == 0L || _bytesCredit > 0) + && (_messageCreditLimit == 0L || _messageCredit > 0); + } + + public synchronized boolean useCreditForMessage(final AMQMessage msg) + { + if(_messageCreditLimit != 0L) + { + if(_messageCredit != 0L) + { + if(_bytesCreditLimit == 0L) + { + _messageCredit--; + + return true; + } + else + { + if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + { + _messageCredit--; + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + } + else + { + setSuspended(true); + return false; + } + } + else + { + if(_bytesCreditLimit == 0L) + { + + return true; + } + else + { + if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + { + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java index 133c97a146..c13a69b793 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -1,65 +1,40 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.AMQException; - -/** - * @author Apache Software Foundation - * - * - */ -public class AccessRequestHandler implements StateAwareMethodListener -{ - private static final AccessRequestHandler _instance = new AccessRequestHandler(); - - - public static AccessRequestHandler getInstance() - { - return _instance; - } - - private AccessRequestHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - - // We don't implement access control class, but to keep clients happy that expect it - // always use the "0" ticket. - AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); - - session.writeFrame(response.generateFrame(channelId)); - } -} +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +/** + * @author Apache Software Foundation + * + * + */ +public class AccessRequestHandler implements StateAwareMethodListener +{ + private static final AccessRequestHandler _instance = new AccessRequestHandler(); + + + public static AccessRequestHandler getInstance() + { + return _instance; + } + + private AccessRequestHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + // We don't implement access control class, but to keep clients happy that expect it + // always use the "0" ticket. + AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java index bda1c16cf6..29054f55c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -21,11 +21,9 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.BasicCancelBody; import org.apache.qpid.framing.BasicCancelOkBody; import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; @@ -65,7 +63,7 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); - - private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); - - public static BasicGetMethodHandler getInstance() - { - return _instance; - } - - private BasicGetMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - VirtualHost vHost = session.getVirtualHost(); - - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - else - { - AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); - - if (queue == null) - { - _log.info("No queue for '" + body.getQueue() + "'"); - if(body.getQueue()!=null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, - "No such queue, '" + body.getQueue()+ "'"); - } - else - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "No queue name provided, no default queue defined."); - } - } - else - { - - //Perform ACLs - vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); - - if (!queue.performGet(session, channel, !body.getNoAck())) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - // TODO - set clusterId - BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); - - - session.writeFrame(responseBody.generateFrame(channelId)); - } - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.MessageOnlyCreditManager; +import org.apache.qpid.server.subscription.SubscriptionImpl; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.SimpleAMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + VirtualHost vHost = session.getVirtualHost(); + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); + if (queue == null) + { + _log.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue()+ "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined."); + } + } + else + { + + //Perform ACLs + vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue); + + if (!performGet(queue,session, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + // TODO - set clusterId + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } + } + + public static boolean performGet(final AMQQueue queue, + final AMQProtocolSession session, + final AMQChannel channel, + final boolean acks) + throws AMQException + { + + final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); + + final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod() + { + + int _msg; + + public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) + throws AMQException + { + singleMessageCredit.useCreditForMessage(entry.getMessage()); + session.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(), + deliveryTag, queue.getMessageCount()); + + } + }; + final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, null); + } + }; + + Subscription sub; + if(acks) + { + sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod); + } + else + { + sub = new GetNoAckSubscription(channel, + session, + null, + null, + false, + singleMessageCredit, + getDeliveryMethod, + getRecordMethod); + } + + queue.registerSubscription(sub,false); + queue.flushSubscription(sub); + queue.unregisterSubscription(sub); + return(!singleMessageCredit.hasCredit()); + + + } + + public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription + { + public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + public boolean wouldSuspend(QueueEntry msg) + { + return !getCreditManager().useCreditForMessage(msg.getMessage()); + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index 0f99a21ee5..e8e42454de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -91,7 +91,7 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener throw body.getChannelNotFoundException(channelId); } - channel.setPrefetchCount(body.getPrefetchCount()); - channel.setPrefetchSize(body.getPrefetchSize()); + channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount()); + MethodRegistry methodRegistry = session.getMethodRegistry(); AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java index bca35be535..15484273c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java @@ -1,75 +1,54 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; - -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.BasicRecoverSyncBody; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.AMQException; - -public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); - - private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); - - public static BasicRecoverSyncMethodHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); - AMQChannel channel = session.getChannel(channelId); - - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.resend(body.getRequeue()); - - // Qpid 0-8 hacks a synchronous -ok onto recover. - // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant - if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) - { - MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); - AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); - session.writeFrame(recoverOk.generateFrame(channelId)); - - } - - } -} +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.BasicRecoverSyncBody; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); + + private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); + + public static BasicRecoverSyncMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index 069cc6ea2c..f3cab10ed7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -22,9 +22,8 @@ package org.apache.qpid.server.handler; import org.apache.qpid.AMQException; import org.apache.qpid.framing.BasicRejectBody; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; @@ -49,16 +48,6 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener if (!exch.isBound(routingKey, body.getArguments(), queue)) { - queue.bind(routingKey, body.getArguments(), exch); + queue.bind(exch, routingKey, body.getArguments()); } } catch (AMQInvalidRoutingKeyException rke) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 7df864f189..379ec7a7d6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -34,9 +34,10 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.store.MessageStore; @@ -123,7 +124,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener -{ - private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); - - public static QueuePurgeHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueuePurgeHandler() - { - this(true); - } - - public QueuePurgeHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - } - - public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - AMQChannel channel = session.getChannel(channelId); - - - AMQQueue queue; - if(body.getQueue() == null) - { - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); - } - } - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - } - else - { - - //Perform ACLs - virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue); - - long purged = queue.clearQueue(channel.getStoreContext()); - - - if(!body.getNowait()) - { - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.QueuePurgeBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +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.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + AMQChannel channel = session.getChannel(channelId); + + + AMQQueue queue; + if(body.getQueue() == null) + { + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); + } + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + + //Perform ACLs + virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue); + + long purged = queue.clearQueue(channel.getStoreContext()); + + + if(!body.getNowait()) + { + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index 6b2924031a..d73e33d6c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -1,24 +1,3 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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; @@ -63,7 +42,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener _dispatcherFactories = - new HashMap(); - - - static - { - _dispatcherFactories.put(ProtocolVersion.v8_0, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_8_0(stateManager); - } - }); - - _dispatcherFactories.put(ProtocolVersion.v0_9, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_0_9(stateManager); - } - }); - - } - - - private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); - private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); - private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); - private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); - private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); - private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); - private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); - private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); - private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); - private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); - private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); - private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); - private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); - private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); - private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); - private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); - private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); - private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); - private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); - private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); - private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); - private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); - private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); - private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); - private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); - private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); - private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); - private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); - private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); - - - - public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) - { - return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); - } - - - public ServerMethodDispatcherImpl(AMQStateManager stateManager) - { - _stateManager = stateManager; - } - - - protected AMQStateManager getStateManager() - { - return _stateManager; - } - - - - public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException - { - _accessRequestHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException - { - _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException - { - _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException - { - _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException - { - _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException - { - _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException - { - _basicQosHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException - { - _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException - { - _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException - { - _channelOpenHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException - { - _channelCloseHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException - { - _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException - { - _channelFlowHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException - { - _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException - { - _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException - { - _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException - { - _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException - { - _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException - { - _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException - { - _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException - { - _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException - { - _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException - { - _queueBindHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException - { - _queueDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException - { - _queueDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException - { - _queuePurgeHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException - { - _txCommitHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException - { - _txRollbackHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException - { - _txSelectHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.Map; +import java.util.HashMap; + +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.framing.*; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl implements MethodDispatcher +{ + private final AMQStateManager _stateManager; + + private static interface DispatcherFactory + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); + } + + private static final Map _dispatcherFactories = + new HashMap(); + + + static + { + _dispatcherFactories.put(ProtocolVersion.v8_0, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_8_0(stateManager); + } + }); + + _dispatcherFactories.put(ProtocolVersion.v0_9, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_0_9(stateManager); + } + }); + + } + + + private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); + private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); + private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); + private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); + private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); + private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); + private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); + private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); + private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); + private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); + private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); + private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); + private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); + private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); + private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); + private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); + private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); + private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); + private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); + private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); + private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); + private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); + private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); + private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); + private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); + private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); + private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); + private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); + private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); + + + + public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) + { + return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); + } + + + public ServerMethodDispatcherImpl(AMQStateManager stateManager) + { + _stateManager = stateManager; + } + + + protected AMQStateManager getStateManager() + { + return _stateManager; + } + + + + public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException + { + _accessRequestHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException + { + _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException + { + _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException + { + _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException + { + _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException + { + _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException + { + _basicQosHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException + { + _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException + { + _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException + { + _channelOpenHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException + { + _channelCloseHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException + { + _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException + { + _channelFlowHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException + { + _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException + { + _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException + { + _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException + { + _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException + { + _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException + { + _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException + { + _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException + { + _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException + { + _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException + { + _queueBindHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException + { + _queueDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException + { + _queueDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException + { + _queuePurgeHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException + { + _txCommitHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException + { + _txRollbackHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException + { + _txSelectHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java index 382a85347b..8b1dca77ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java @@ -1,164 +1,164 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.amqp_0_9.MethodDispatcher_0_9; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - - - -public class ServerMethodDispatcherImpl_0_9 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_0_9 - -{ - - private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = - BasicRecoverSyncMethodHandler.getInstance(); - private static final QueueUnbindHandler _queueUnbindHandler = - QueueUnbindHandler.getInstance(); - - - public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException - { - _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); - return true; - } - - public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException - { - _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); - return true; - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_0_9.MethodDispatcher_0_9; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + + + +public class ServerMethodDispatcherImpl_0_9 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_0_9 + +{ + + private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = + BasicRecoverSyncMethodHandler.getInstance(); + private static final QueueUnbindHandler _queueUnbindHandler = + QueueUnbindHandler.getInstance(); + + + public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException + { + _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); + return true; + } + + public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException + { + _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java index 22f64cf7d3..d599ca3d4e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java @@ -1,86 +1,86 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - -public class ServerMethodDispatcherImpl_8_0 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_8_0 -{ - public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException - { - return false; - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_8_0.MethodDispatcher_8_0; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl_8_0 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_8_0 +{ + public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException + { + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java index 79cc722e0e..9b23d88838 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -23,10 +23,8 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.TxCommitBody; -import org.apache.qpid.framing.TxCommitOkBody; import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQStateManager; @@ -70,7 +68,7 @@ public class TxCommitHandler implements StateAwareMethodListener AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); session.writeFrame(responseBody.generateFrame(channelId)); - channel.processReturns(session); + channel.processReturns(); } catch (AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java index 0abb3cdd7d..fb18519fe1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java @@ -1,33 +1,33 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - - -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.AMQException; - -public class UnexpectedMethodException extends AMQException -{ - public UnexpectedMethodException(AMQMethodBody body) - { - super("Unexpected method recevied: " + body.getClass().getName()); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.AMQMethodBody; +import org.apache.qpid.AMQException; + +public class UnexpectedMethodException extends AMQException +{ + public UnexpectedMethodException(AMQMethodBody body) + { + super("Unexpected method recevied: " + body.getClass().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java index 576d577b40..e01c5aabbf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -1,57 +1,57 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.AMQException; - -public interface ProtocolOutputConverter -{ - void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); - - interface Factory - { - ProtocolOutputConverter newInstance(AMQProtocolSession session); - } - - void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException; - - void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; - - byte getProtocolMinorVersion(); - - byte getProtocolMajorVersion(); - - void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException; - - void writeFrame(AMQDataBlock block); -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public interface ProtocolOutputConverter +{ + void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); + + interface Factory + { + ProtocolOutputConverter newInstance(AMQProtocolSession session); + } + + void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException; + + void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + + byte getProtocolMinorVersion(); + + byte getProtocolMajorVersion(); + + void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException; + + void writeFrame(AMQDataBlock block); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java index 02fb1429c0..36e7e88fd6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -1,61 +1,61 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.ProtocolVersion; - -import java.util.Map; -import java.util.HashMap; - -public class ProtocolOutputConverterRegistry -{ - - private static final Map _registry = - new HashMap(); - - - static - { - register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); - register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); - - } - - private static void register(ProtocolVersion version, Factory converter) - { - - _registry.put(version,converter); - } - - - public static ProtocolOutputConverter getConverter(AMQProtocolSession session) - { - return _registry.get(session.getProtocolVersion()).newInstance(session); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.ProtocolVersion; + +import java.util.Map; +import java.util.HashMap; + +public class ProtocolOutputConverterRegistry +{ + + private static final Map _registry = + new HashMap(); + + + static + { + register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); + register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); + + } + + private static void register(ProtocolVersion version, Factory converter) + { + + _registry.put(version,converter); + } + + + public static ProtocolOutputConverter getConverter(AMQProtocolSession session) + { + return _registry.get(session.getProtocolVersion()).newInstance(session); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index d4cb7c878f..2b55d294b5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -1,285 +1,284 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output.amqp0_8; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.AMQException; - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final Long messageId = message.getMessageId(); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext,messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); - - AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, messageId, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicDeliverBody deliverBody = - methodRegistry.createBasicDeliverBody(consumerTag, - deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey()); - AMQFrame deliverFrame = deliverBody.generateFrame(channelId); - - - return deliverFrame; - } - - private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicGetOkBody getOkBody = - methodRegistry.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicReturnBody basicReturnBody = - methodRegistry.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + + final int bodyCount = messageHandle.getBodyCount(storeContext); + + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicDeliverBody deliverBody = + methodRegistry.createBasicDeliverBody(consumerTag, + deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey()); + AMQFrame deliverFrame = deliverBody.generateFrame(channelId); + + + return deliverFrame; + } + + private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicGetOkBody getOkBody = + methodRegistry.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicReturnBody basicReturnBody = + methodRegistry.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index f87d3bcae1..c76c262edd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -1,397 +1,370 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.output.amqp0_9; - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); - private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); - - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final Long messageId = message.getMessageId(); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - - if(bodyCount == 0) - { - SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, - contentHeaderBody); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); - - CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext,messageId, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - - } - - private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) - { - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - contentHeaderBody); - return contentHeader; - } - - - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - final long messageId = message.getMessageId(); - - AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - final int bodyCount = messageHandle.getBodyCount(storeContext,messageId); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, messageId, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - - } - - - private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) - throws AMQException - { - - - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - - final AMQBody returnBlock = new AMQBody() - { - - - - private final boolean _isRedelivered = messageHandle.isRedelivered(); - private final AMQShortString _exchangeName = pb.getExchange(); - private final AMQShortString _routingKey = pb.getRoutingKey(); - - - public AMQBody _underlyingBody; - - public AMQBody createAMQBody() - { - return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, - deliveryTag, - _isRedelivered, - _exchangeName, - _routingKey); - - - - - - } - - public byte getFrameType() - { - return AMQMethodBody.TYPE; - } - - public int getSize() - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - return _underlyingBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - _underlyingBody.writePayload(buffer); - } - - public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) - throws AMQException - { - throw new AMQException("This block should never be dispatched!"); - } - }; - return returnBlock; - } - - private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - - BasicGetOkBody getOkBody = - METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - - BasicReturnBody basicReturnBody = - METHOD_REGISTRY.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - - BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } - - - public static final class CompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final AMQBody _contentBody; - private final int _channel; - - - public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - _contentBody = contentBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); - } - } - - public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final int _channel; - - - public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); - } - } - -} +package org.apache.qpid.server.output.amqp0_9; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); + + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + + final int bodyCount = messageHandle.getBodyCount(storeContext); + + if(bodyCount == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); + + CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + + private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + final boolean isRedelivered = messageHandle.isRedelivered(); + final AMQShortString exchangeName = pb.getExchange(); + final AMQShortString routingKey = pb.getRoutingKey(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 4267642b14..bdb16d0fcb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -113,6 +113,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private ProtocolOutputConverter _protocolOutputConverter; private Principal _authorizedID; private MethodDispatcher _dispatcher; + private ProtocolSessionIdentifier _sessionIdentifier; public ManagedObject getManagedObject() { @@ -198,7 +199,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } private void frameReceived(AMQFrame frame) throws AMQException - { + { int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); @@ -373,7 +374,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable AMQChannel channel = getAndAssertChannel(channelId); - channel.publishContentHeader(body, this); + channel.publishContentHeader(body); } @@ -381,7 +382,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { AMQChannel channel = getAndAssertChannel(channelId); - channel.publishContentBody(body, this); + channel.publishContentBody(body); } public void heartbeatBodyReceived(int channelId, HeartbeatBody body) @@ -443,7 +444,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public boolean channelAwaitingClosure(int channelId) { - return _closingChannelsList.contains(channelId); + return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId); } public void addChannel(AMQChannel channel) throws AMQException @@ -536,7 +537,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { try { - channel.close(this); + channel.close(); markChannelAwaitingCloseOk(channelId); } finally @@ -602,7 +603,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { for (AMQChannel channel : _channelMap.values()) { - channel.close(this); + channel.close(); } _channelMap.clear(); @@ -633,7 +634,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public String toString() { - return "AMQProtocolSession(" + _minaProtocolSession.getRemoteAddress() + ")"; + return _minaProtocolSession.getRemoteAddress() + "("+(getAuthorizedID() == null ? "?" : getAuthorizedID().getName()+")"); } public String dump() @@ -702,6 +703,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); } } + _sessionIdentifier = new ProtocolSessionIdentifier(this); } private void setProtocolVersion(ProtocolVersion pv) @@ -739,7 +741,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public Object getClientIdentifier() { - return _minaProtocolSession.getRemoteAddress(); + return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null; } public VirtualHost getVirtualHost() @@ -789,6 +791,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable return _dispatcher; } + public ProtocolSessionIdentifier getSessionIdentifier() + { + return _sessionIdentifier; + } + public String getClientVersion() { return (_clientVersion == null) ? null : _clientVersion.toString(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java index 92f951ce39..a7599a3e0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -1,46 +1,46 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to handle an AMQP method. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a - * Runtime. - */ -public class AMQNoMethodHandlerException extends AMQException -{ - public AMQNoMethodHandlerException(AMQMethodEvent evt) - { - super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to handle an AMQP method. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a + * Runtime. + */ +public class AMQNoMethodHandlerException extends AMQException +{ + public AMQNoMethodHandlerException(AMQMethodEvent evt) + { + super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index ad1c507c04..d8dbf97e49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -265,6 +265,10 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter */ public void messageSent(IoSession protocolSession, Object object) throws Exception { + if (_logger.isDebugEnabled()) + { + _logger.debug("Message sent: " + object); + } } protected boolean isSSLClient(ConnectorConfiguration connectionConfig, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index c9316f7405..c3400029da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.protocol; import javax.security.sasl.SaslServer; import org.apache.qpid.AMQException; +import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; @@ -35,7 +36,27 @@ import java.security.Principal; public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { - + public static final class ProtocolSessionIdentifier + { + private final Object _sessionIdentifier; + private final Object _sessionInstance; + + ProtocolSessionIdentifier(AMQProtocolSession session) + { + _sessionIdentifier = session.getClientIdentifier(); + _sessionInstance = session.getClientProperties() == null ? null : session.getClientProperties().getObject(ClientProperties.instance.toAMQShortString()); + } + + public Object getSessionIdentifier() + { + return _sessionIdentifier; + } + + public Object getSessionInstance() + { + return _sessionInstance; + } + } public static interface Task { @@ -175,5 +196,7 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public MethodRegistry getMethodRegistry(); public MethodDispatcher getMethodDispatcher(); + + public ProtocolSessionIdentifier getSessionIdentifier(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java index bb2db8d506..6e72aa062f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -1,46 +1,46 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; - -/** - * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to cast a frame to its expected type. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would - * be better just to leave that as a ClassCastException. However, check the framing layer catches this error - * first. - */ -public class UnknnownMessageTypeException extends AMQException -{ - public UnknnownMessageTypeException(AMQDataBlock message) - { - super("Unknown message type: " + message.getClass().getName() + ": " + message); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; + +/** + * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to cast a frame to its expected type. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would + * be better just to leave that as a ClassCastException. However, check the framing layer catches this error + * first. + */ +public class UnknnownMessageTypeException extends AMQException +{ + public UnknnownMessageTypeException(AMQDataBlock message) + { + super("Unknown message type: " + message.getClass().getName() + ": " + message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index a76b13ce74..0e5e7aa68c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -25,131 +25,55 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.exchange.Exchange; -import java.util.HashMap; -import java.util.HashSet; + import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * A deliverable message. */ -public class AMQMessage +public class AMQMessage implements Filterable { /** Used for debugging purposes. */ private static final Logger _log = Logger.getLogger(AMQMessage.class); - /** Used in clustering. @todo What for? */ - private Set _tokens; - - /** Only use in clustering. @todo What for? */ - private AMQProtocolSession _publisher; - - private final Long _messageId; - private final AtomicInteger _referenceCount = new AtomicInteger(1); - private AMQMessageHandle _messageHandle; + private final AMQMessageHandle _messageHandle; /** Holds the transactional context in which this message is being processed. */ - private TransactionalContext _txnContext; + private StoreContext _storeContext; + + /** Flag to indicate that this message requires 'immediate' delivery. */ + + private static final byte IMMEDIATE = 0x01; /** * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality * for messages published with the 'immediate' flag. */ - private boolean _deliveredToConsumer; - /** Flag to indicate that this message requires 'immediate' delivery. */ - private boolean _immediate; + private static final byte DELIVERED_TO_CONSUMER = 0x02; - private TransientMessageData _transientMessageData = new TransientMessageData(); + private byte _flags = 0; private long _expiration; + private final long _size; + private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; + private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - private Exchange _exchange; - private static final boolean SYNCED_CLOCKS = - ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false); - - private static final long UNKNOWN_SIZE = Long.MIN_VALUE; - - private long _size = UNKNOWN_SIZE; - - - - public String debugIdentity() - { - return "(HC:" + System.identityHashCode(this) + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; - } - - public void setExpiration() - { - long expiration = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration(); - long timestamp = - ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp(); - - if (SYNCED_CLOCKS) - { - _expiration = expiration; - } - else - { - // Update TTL to be in broker time. - if (expiration != 0L) - { - if (timestamp != 0L) - { - // todo perhaps use arrival time - long diff = (System.currentTimeMillis() - timestamp); - - if ((diff > 1000L) || (diff < 1000L)) - { - _expiration = expiration + diff; - } - } - } - } - - } - - public boolean isReferenced() - { - return _referenceCount.get() > 0; - } - - public void setExchange(final Exchange exchange) - { - _exchange = exchange; - } - - public void route() throws AMQException - { - _exchange.route(this); - } - - public void enqueue(final List queues) - { - _transientMessageData.setDestinationQueues(queues); - } /** * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory @@ -172,7 +96,7 @@ public class AMQMessage { try { - return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); + return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); } catch (AMQException e) { @@ -189,7 +113,7 @@ public class AMQMessage AMQBody cb = getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - _messageId, ++_index)); + ++_index)); return new AMQFrame(_channel, cb); } @@ -212,9 +136,14 @@ public class AMQMessage } } + public void clearStoreContext() + { + _storeContext = new StoreContext(); + } + public StoreContext getStoreContext() { - return _txnContext.getStoreContext(); + return _storeContext; } private class BodyContentIterator implements Iterator @@ -226,7 +155,7 @@ public class AMQMessage { try { - return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1); + return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); } catch (AMQException e) { @@ -240,7 +169,7 @@ public class AMQMessage { try { - return _messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index); + return _messageHandle.getContentChunk(getStoreContext(), ++_index); } catch (AMQException e) { @@ -254,13 +183,7 @@ public class AMQMessage } } - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext) - { - _messageId = messageId; - _txnContext = txnContext; - _immediate = info.isImmediate(); - _transientMessageData.setMessagePublishInfo(info); - } + /** * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal @@ -276,141 +199,85 @@ public class AMQMessage public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) throws AMQException { - _messageId = messageId; _messageHandle = factory.createMessageHandle(messageId, store, true); - _txnContext = txnConext; - _transientMessageData = null; - + _storeContext = txnConext.getStoreContext(); + _size = _messageHandle.getBodySize(txnConext.getStoreContext()); } - /** - * Used in testing only. This allows the passing of the content header immediately on construction. + /** + * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal + * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to + * queues. * - * @param messageId - * @param info - * @param txnContext - * @param contentHeader + * @param messageHandle + * + * @throws AMQException */ - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader) throws AMQException + public AMQMessage( + AMQMessageHandle messageHandle, + StoreContext storeConext, + MessagePublishInfo info) + throws AMQException { - this(messageId, info, txnContext); - setContentHeaderBody(contentHeader); - } + _messageHandle = messageHandle; + _storeContext = storeConext; - /* * - * Used in testing only. This allows the passing of the content header and some body fragments on construction. - * - * @param messageId - * @param info - * @param txnContext - * @param contentHeader - * @param destinationQueues - * @param contentBodies - * - * @throws AMQException - */ /* - public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext, - ContentHeaderBody contentHeader, List destinationQueues, List contentBodies, - MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException - { - this(messageId, info, txnContext, contentHeader); - _transientMessageData.setDestinationQueues(destinationQueues); - routingComplete(messageStore, storeContext, messageHandleFactory); - for (ContentChunk cb : contentBodies) + if(info.isImmediate()) { - addContentBodyFrame(storeContext, cb); + _flags |= IMMEDIATE; } + _size = messageHandle.getBodySize(storeConext); + } - */ + + protected AMQMessage(AMQMessage msg) throws AMQException { - _messageId = msg._messageId; _messageHandle = msg._messageHandle; - _txnContext = msg._txnContext; - _deliveredToConsumer = msg._deliveredToConsumer; - _transientMessageData = msg._transientMessageData; - } + _storeContext = msg._storeContext; + _flags = msg._flags; + _size = msg._size; - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); } - public Iterator getContentBodyIterator() + + public String debugIdentity() { - return new BodyContentIterator(); + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; } - public ContentHeaderBody getContentHeaderBody() throws AMQException + public void setExpiration(final long expiration) { - if (_transientMessageData != null) - { - return _transientMessageData.getContentHeaderBody(); - } - else - { - return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId); - } + + _expiration = expiration; + } - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException + public boolean isReferenced() { - _transientMessageData.setContentHeaderBody(contentHeaderBody); - _size = _transientMessageData.getContentHeaderBody().bodySize; + return _referenceCount.get() > 0; } - public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory) - throws AMQException + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) { - 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 : _transientMessageData.getDestinationQueues()) - { - _messageHandle.enqueue(storeContext, _messageId, q); - } - - if (_transientMessageData.getContentHeaderBody().bodySize == 0) - { - deliver(storeContext); - } - - + return new BodyFrameIterator(protocolSession, channel); } - public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException + public Iterator getContentBodyIterator() { - _transientMessageData.addBodyLength(contentChunk.getSize()); - final boolean allContentReceived = isAllContentReceived(); - _messageHandle.addContentBodyFrame(storeContext, _messageId, contentChunk, allContentReceived); - if (allContentReceived) - { - deliver(storeContext); - - return true; - } - else - { - return false; - } + return new BodyContentIterator(); } - public boolean isAllContentReceived() throws AMQException + public ContentHeaderBody getContentHeaderBody() throws AMQException { - return _transientMessageData.isAllContentReceived(); + return _messageHandle.getContentHeaderBody(getStoreContext()); } + + public Long getMessageId() { - return _messageId; + return _messageHandle.getMessageId(); } /** @@ -425,13 +292,18 @@ public class AMQMessage } /** Threadsafe. Increment the reference count on the message. */ - public void incrementReference() + public boolean incrementReference() { - _referenceCount.incrementAndGet(); - // if (_log.isDebugEnabled()) - // { - // _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - // } + if(_referenceCount.incrementAndGet() <= 1) + { + _referenceCount.decrementAndGet(); + return false; + } + else + { + return true; + } + } /** @@ -445,6 +317,7 @@ public class AMQMessage */ public void decrementReference(StoreContext storeContext) throws MessageCleanupException { + int count = _referenceCount.decrementAndGet(); // note that the operation of decrementing the reference count and then removing the message does not @@ -453,25 +326,25 @@ public class AMQMessage // not relying on the all the increments having taken place before the delivery manager decrements. if (count == 0) { + // set the reference count way below 0 so that we can detect that the message has been deleted + // this is to guard against the message being spontaneously recreated (from the mgmt console) + // by copying from other queues at the same time as it is being removed. + _referenceCount.set(Integer.MIN_VALUE/2); + try { - // if (_log.isDebugEnabled()) - // { - // _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); - // } - // must check if the handle is null since there may be cases where we decide to throw away a message // and the handle has not yet been constructed if (_messageHandle != null) { - _messageHandle.removeMessage(storeContext, _messageId); + _messageHandle.removeMessage(storeContext); } } catch (AMQException e) { // to maintain consistency, we revert the count incrementReference(); - throw new MessageCleanupException(_messageId, e); + throw new MessageCleanupException(getMessageId(), e); } } else @@ -484,15 +357,6 @@ public class AMQMessage } } - public void setPublisher(AMQProtocolSession publisher) - { - _publisher = publisher; - } - - public AMQProtocolSession getPublisher() - { - return _publisher; - } /** * Called selectors to determin if the message has already been sent @@ -501,101 +365,30 @@ public class AMQMessage */ public boolean getDeliveredToConsumer() { - return _deliveredToConsumer; - } - - - public boolean checkToken(Object token) - { - - if (_tokens == null) - { - _tokens = new HashSet(); - } - - 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 - { - _transientMessageData.addDestinationQueue(queue); - } - - /** - * NOTE: Think about why you are using this method. Normal usages would want to do - * AMQQueue.dequeue(StoreContext, AMQMessage) - * This will keep the queue statistics up-to-date. - * Currently this method is only called _correctly_ from AMQQueue dequeue. - * Ideally we would have a better way for the queue to dequeue the message. - * Especially since enqueue isn't the recipriocal of this method. - * @deprecated - * @param storeContext - * @param queue - * @throws AMQException - */ - void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException - { - _messageHandle.dequeue(storeContext, _messageId, queue); + return (_flags & DELIVERED_TO_CONSUMER) != 0; } public boolean isPersistent() throws AMQException { - if (_transientMessageData != null) - { - return _transientMessageData.isPersistent(); - } - else - { - return _messageHandle.isPersistent(getStoreContext(), _messageId); - } + return _messageHandle.isPersistent(); } /** * Called to enforce the 'immediate' flag. * - * @throws NoConsumersException if the message is marked for immediate delivery but has not been marked as delivered + * @returns true if the message is marked for immediate delivery but has not been marked as delivered * to a consumer */ - public void checkDeliveredToConsumer() throws NoConsumersException + public boolean immediateAndNotDelivered() { - if (_immediate && !_deliveredToConsumer) - { - throw new NoConsumersException(this); - } + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; + } public MessagePublishInfo getMessagePublishInfo() throws AMQException { - MessagePublishInfo pb; - if (_transientMessageData != null) - { - pb = _transientMessageData.getMessagePublishInfo(); - } - else - { - pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId); - } - - return pb; + return _messageHandle.getMessagePublishInfo(getStoreContext()); } public boolean isRedelivered() @@ -641,46 +434,9 @@ public class AMQMessage */ public void setDeliveredToConsumer() { - _deliveredToConsumer = true; + _flags |= DELIVERED_TO_CONSUMER; } - private void deliver(StoreContext storeContext) throws AMQException - { - // we get a reference to the destination queues now so that we can clear the - // transient message data as quickly as possible - List destinationQueues = _transientMessageData.getDestinationQueues(); - if (_log.isDebugEnabled()) - { - _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues); - } - - try - { - // first we allow the handle to know that the message has been fully received. This is useful if it is - // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId, - _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody()); - - // 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) - { - // Increment the references to this message for each queue delivery. - incrementReference(); - // normal deliver so add this message at the end. - _txnContext.deliver(q.createEntry(this), false); - } - } - finally - { - - // Remove refence for routing process . Reference count should now == delivered queue count - decrementReference(storeContext); - _transientMessageData = null; - } - } public AMQMessageHandle getMessageHandle() @@ -690,28 +446,23 @@ public class AMQMessage public long getSize() { - if(_size == UNKNOWN_SIZE) - { - try - { - _size = getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - _log.warn("Unable to retrieve message meta data for message:" + this, e); - return 0; - } - } return _size; + + } + + public Object getPublisherClientInstance() + { + return _sessionIdentifier.getSessionInstance(); + } + + public Object getPublisherIdentifier() + { + return _sessionIdentifier.getSessionIdentifier(); } - public void restoreTransientMessageData() throws AMQException + public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) { - TransientMessageData transientMessageData = new TransientMessageData(); - transientMessageData.setMessagePublishInfo(getMessagePublishInfo()); - transientMessageData.setContentHeaderBody(getContentHeaderBody()); - transientMessageData.addBodyLength(getContentHeaderBody().getSize()); - _transientMessageData = transientMessageData; + _sessionIdentifier = sessionIdentifier; } @@ -720,7 +471,7 @@ public class AMQMessage // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + // _taken + " by :" + _takenBySubcription; - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount; + return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index ede55b3bbf..0ddd4e4d92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -29,23 +29,27 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo; /** * A pluggable way of getting message data. Implementations can provide intelligent caching for example or * even no caching at all to minimise the broker memory footprint. - * - * 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(StoreContext context, Long messageId) throws AMQException; + ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException; + + /** + * + * @return the messageId for the message associated with this handle + */ + Long getMessageId(); + /** * @return the number of body frames associated with this message */ - int getBodyCount(StoreContext context, Long messageId) throws AMQException; + int getBodyCount(StoreContext context) throws AMQException; /** * @return the size of the body */ - long getBodySize(StoreContext context, Long messageId) throws AMQException; + long getBodySize(StoreContext context) throws AMQException; /** * Get a particular content body @@ -53,27 +57,23 @@ public interface AMQMessageHandle * @return a content body * @throws IllegalArgumentException if the index is invalid */ - ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException; + ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException; - void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; + void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException; + MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; boolean isRedelivered(); void setRedelivered(boolean redelivered); - boolean isPersistent(StoreContext context, Long messageId) throws AMQException; + boolean isPersistent(); - void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, + void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) throws AMQException; - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; - - void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException; + void removeMessage(StoreContext storeContext) throws AMQException; long getArrivalTime(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java new file mode 100644 index 0000000000..ba6b392d13 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -0,0 +1,67 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.AMQException; + +public class AMQPriorityQueue extends SimpleAMQQueue +{ + protected AMQPriorityQueue(final AMQShortString name, + final boolean durable, + final AMQShortString owner, + final boolean autoDelete, + final VirtualHost virtualHost, + int priorities) + throws AMQException + { + super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); + } + + @Override + protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) + { + // check that all subscriptions are not in advance of the entry + SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator(); + while(subIter.advance() && !entry.isAcquired()) + { + final Subscription subscription = subIter.getNode().getSubscription(); + QueueEntry subnode = subscription.getLastSeenEntry(); + while((entry.compareTo(subnode) < 0) && !entry.isAcquired()) + { + if(subscription.setLastSeenEntry(subnode,entry)) + { + break; + } + else + { + subnode = subscription.getLastSeenEntry(); + } + } + + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 7c6db0b4b3..f3e4e7c28b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,1005 +20,186 @@ */ package org.apache.qpid.server.queue; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; -import javax.management.JMException; -import java.text.MessageFormat; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * 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, Comparable -{ - - /** - * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create a subscription, because an exclusive subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - public static final class ExistingExclusiveSubscription extends AMQException - { - - public ExistingExclusiveSubscription() - { - super(""); - } - } - - /** - * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create an exclusize subscription, as a subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - public static final class ExistingSubscriptionPreventsExclusive extends AMQException - { - public ExistingSubscriptionPreventsExclusive() - { - super(""); - } - } - - private static final Logger _logger = Logger.getLogger(AMQQueue.class); - - private final AMQShortString _name; - - /** null means shared */ - private final AMQShortString _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; - - private final AtomicInteger _subscriberCount = new AtomicInteger(); - - private final AtomicBoolean _isExclusive = new AtomicBoolean(); - - private final AtomicBoolean _deleted = new AtomicBoolean(false); - - private List _deleteTaskList = new CopyOnWriteArrayList(); - - /** Manages message delivery. */ - private final DeliveryManager _deliveryMgr; - - /** 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; - - private final VirtualHost _virtualHost; - - /** max allowed size(KB) of a single message */ - @Configured(path = "maximumMessageSize", defaultValue = "0") - public long _maximumMessageSize; - - /** max allowed number of messages on a queue. */ - @Configured(path = "maximumMessageCount", defaultValue = "0") - public long _maximumMessageCount; - - /** max queue depth for the queue */ - @Configured(path = "maximumQueueDepth", defaultValue = "0") - public long _maximumQueueDepth; - - /** maximum message age before alerts occur */ - @Configured(path = "maximumMessageAge", defaultValue = "0") - public long _maximumMessageAge; - - /** the minimum interval between sending out consequetive alerts of the same type */ - @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") - public long _minimumAlertRepeatGap; - - /** total messages received by the queue since startup. */ - public AtomicLong _totalMessagesReceived = new AtomicLong(); - - - private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); - - - public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException - { - this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), - new SubscriptionSet(), new SubscriptionImpl.Factory()); - } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException - { - this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, - new SubscriptionImpl.Factory()); - } - - protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers, - SubscriptionFactory subscriptionFactory) throws AMQException - { - if (name == null) - { - throw new IllegalArgumentException("Queue name must not be null"); - } - - if (virtualHost == null) - { - throw new IllegalArgumentException("Virtual Host must not be null"); - } - - _name = name; - _durable = durable; - _owner = owner; - _autoDelete = autoDelete; - _virtualHost = virtualHost; - _asyncDelivery = asyncDelivery; - - _managedObject = createMBean(); - _managedObject.register(); - - _subscribers = subscribers; - _subscriptionFactory = subscriptionFactory; - _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this); - - // This ensure that the notification checks for the configured alerts are created. - setMaximumMessageAge(_maximumMessageAge); - setMaximumMessageCount(_maximumMessageCount); - setMaximumMessageSize(_maximumMessageSize); - setMaximumQueueDepth(_maximumQueueDepth); - - } - - private AMQQueueMBean createMBean() throws AMQException - { - try - { - return new AMQQueueMBean(this); - } - catch (JMException ex) - { - throw new AMQException("AMQQueue MBean creation has failed ", ex); - } - } - - public final AMQShortString getName() - { - return _name; - } +import java.util.List; +import java.util.Set; - public boolean isShared() - { - return _owner == null; - } +public interface AMQQueue extends Managable, Comparable +{ - public boolean isDurable() - { - return _durable; - } + AMQShortString getName(); - public AMQShortString getOwner() - { - return _owner; - } + boolean isDurable(); - public boolean isAutoDelete() - { - return _autoDelete; - } + boolean isAutoDelete(); - public boolean isDeleted() - { - return _deleted.get(); - } + AMQShortString getOwner(); - /** @return no of messages(undelivered) on the queue. */ - public int getMessageCount() - { - return _deliveryMgr.getQueueMessageCount(); - } + VirtualHost getVirtualHost(); - /** @return List of messages(undelivered) on the queue. */ - public List getMessagesOnTheQueue() - { - return _deliveryMgr.getMessages(); - } - /** - * Returns messages within the given range of message Ids. - * - * @param fromMessageId - * @param toMessageId - * - * @return List of messages - */ - public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) - { - return _deliveryMgr.getMessages(fromMessageId, toMessageId); - } + void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - public long getQueueDepth() - { - return _deliveryMgr.getTotalMessageSize(); - } + void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - /** - * @param messageId - * - * @return QueueEntry with give id if exists. null if QueueEntry with given id doesn't exist. - */ - public QueueEntry getMessageOnTheQueue(long messageId) - { - List list = getMessagesOnTheQueue(messageId, messageId); - if ((list == null) || (list.size() == 0)) - { - return null; - } - return list.get(0); - } - /** - * Moves messages from this queue to another queue, and also commits the move on the message store. Delivery activity - * on the queues being moved between is suspended during the move. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param queueName The queue to move the messages to. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; - MessageStore fromStore = getVirtualHost().getMessageStore(); - MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); + void unregisterSubscription(final Subscription subscription) throws AMQException; - if (toStore != fromStore) - { - throw new RuntimeException("Can only move messages between queues on the same message store."); - } - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - toQueue.startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (QueueEntry entry : foundMessagesList) - { - AMQMessage message = entry.getMessage(); - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity - * on the queues being moved between is suspended during the move. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param queueName The queue to move the messages to. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - - MessageStore fromStore = getVirtualHost().getMessageStore(); - MessageStore toStore = toQueue.getVirtualHost().getMessageStore(); - - if (toStore != fromStore) - { - throw new RuntimeException("Can only move messages between queues on the same message store."); - } - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - toQueue.startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // Move the messages in on the message store. - for (QueueEntry entry : foundMessagesList) - { - AMQMessage message = entry.getMessage(); - toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId()); - message.takeReference(); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // Move the messages on the in-memory queues. - toQueue.enqueueMovedMessages(storeContext, foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - toQueue.stopMovingMessages(); - stopMovingMessages(); - } - } - - /** - * Removes messages from this queue, and also commits the remove on the message store. Delivery activity - * on the queues being moved between is suspended during the remove. - * - * @param fromMessageId The first message id to move. - * @param toMessageId The last message id to move. - * @param storeContext The context of the message store under which to perform the move. This is associated with - * the stores transactional context. - */ - public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) - { - MessageStore fromStore = getVirtualHost().getMessageStore(); - - try - { - // Obtain locks to prevent activity on the queues being moved between. - startMovingMessages(); - - // Get the list of messages to move. - List foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId); - - try - { - fromStore.beginTran(storeContext); - - // remove the messages in on the message store. - for (QueueEntry entry : foundMessagesList) - { - AMQMessage message = entry.getMessage(); - fromStore.dequeueMessage(storeContext, _name, message.getMessageId()); - } - - // Commit and flush the move transcations. - try - { - fromStore.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - - // remove the messages on the in-memory queues. - _deliveryMgr.removeMovedMessages(foundMessagesList); - } - // Abort the move transactions on move failures. - catch (AMQException e) - { - try - { - fromStore.abortTran(storeContext); - } - catch (AMQException ae) - { - throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae); - } - } - } - // Release locks to allow activity on the queues being moved between to continue. - finally - { - stopMovingMessages(); - } - } + int getConsumerCount(); - public void startMovingMessages() - { - _deliveryMgr.startMovingMessages(); - } + int getActiveConsumerCount(); - private void enqueueMovedMessages(StoreContext storeContext, List messageList) - { - _deliveryMgr.enqueueMovedMessages(storeContext, messageList); - _totalMessagesReceived.addAndGet(messageList.size()); - } + boolean isUnused(); - public void stopMovingMessages() - { - _deliveryMgr.stopMovingMessages(); - _deliveryMgr.processAsync(_asyncDelivery); - } + boolean isEmpty(); - /** @return MBean object associated with this Queue */ - public ManagedObject getManagedObject() - { - return _managedObject; - } + int getMessageCount(); - public long getMaximumMessageSize() - { - return _maximumMessageSize; - } + int getUndeliveredMessageCount(); - public void setMaximumMessageSize(final long maximumMessageSize) - { - _maximumMessageSize = maximumMessageSize; - if(maximumMessageSize == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT); - } - } - public int getConsumerCount() - { - return _subscribers.size(); - } + long getQueueDepth(); - public int getActiveConsumerCount() - { - return _subscribers.getWeight(); - } + long getReceivedMessageCount(); - public long getReceivedMessageCount() - { - return _totalMessagesReceived.get(); - } + long getOldestMessageArrivalTime(); - public long getMaximumMessageCount() - { - return _maximumMessageCount; - } + boolean isDeleted(); - public void setMaximumMessageCount(final long maximumMessageCount) - { - _maximumMessageCount = maximumMessageCount; - if(maximumMessageCount == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); - } + int delete() throws AMQException; - } + QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; - public long getMaximumQueueDepth() - { - return _maximumQueueDepth; - } + void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; - // Sets the queue depth, the max queue size - public void setMaximumQueueDepth(final long maximumQueueDepth) - { - _maximumQueueDepth = maximumQueueDepth; - if(maximumQueueDepth == 0L) - { - _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT); - } + void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; - } - public long getOldestMessageArrivalTime() - { - return _deliveryMgr.getOldestMessageArrival(); - } + boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - /** Removes the QueueEntry from the top of the queue. */ - public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException - { - _deliveryMgr.removeAMessageFromTop(storeContext, this); - } + - /** removes all the messages from the queue. */ - public synchronized long clearQueue(StoreContext storeContext) throws AMQException - { - return _deliveryMgr.clearAllMessages(storeContext); - } + void addQueueDeleteTask(final Task task); - public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException - { - exchange.registerQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); - } - _bindings.addBinding(routingKey, arguments, exchange); - } + List getMessagesOnTheQueue(); - public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException - { - exchange.deregisterQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); - } + List getMessagesOnTheQueue(long fromMessageId, long toMessageId); - _bindings.remove(routingKey, arguments, exchange); - } + QueueEntry getMessageOnTheQueue(long messageId); - public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException - { - if (incrementSubscriberCount() > 1) - { - if (isExclusive()) - { - decrementSubscriberCount(); - throw new ExistingExclusiveSubscription(); - } - else if (exclusive) - { - decrementSubscriberCount(); - throw new ExistingSubscriptionPreventsExclusive(); - } - } - else if (exclusive) - { - setExclusive(true); - } + void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext); - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format("Registering protocol session {0} with channel {1} and " - + "consumer tag {2} with {3}", ps, channel, consumerTag, this)); - } + void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext); - Subscription subscription = - _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this); + void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); - if (subscription.filtersMessages()) - { - if (_deliveryMgr.hasQueuedMessages()) - { - _deliveryMgr.populatePreDeliveryQueue(subscription); - } - } - _subscribers.addSubscriber(subscription); - if(exclusive) - { - _subscribers.setExclusive(true); - } - subscription.start(); - } + long getMaximumMessageSize(); - private boolean isExclusive() - { - return _isExclusive.get(); - } + void setMaximumMessageSize(long value); - private void setExclusive(boolean exclusive) - { - _isExclusive.set(exclusive); - } - private int incrementSubscriberCount() - { - return _subscriberCount.incrementAndGet(); - } + long getMaximumMessageCount(); - private int decrementSubscriberCount() - { - return _subscriberCount.decrementAndGet(); - } + void setMaximumMessageCount(long value); - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format( - "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", - ps, channel, consumerTag, this)); - } - _subscribers.setExclusive(false); - 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); - } + long getMaximumQueueDepth(); - removedSubscription.close(); - setExclusive(false); - decrementSubscriberCount(); + void setMaximumQueueDepth(long value); - // if we are eligible for auto deletion, unregister from the queue registry - if (_autoDelete && _subscribers.isEmpty()) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Auto-deleteing queue:" + this); - } - - 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 boolean isUnused() - { - return _subscribers.isEmpty(); - } + long getMaximumMessageAge(); - public boolean isEmpty() - { - return !_deliveryMgr.hasQueuedMessages(); - } + void setMaximumMessageAge(final long maximumMessageAge); - public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException - { - if (checkUnused && !_subscribers.isEmpty()) - { - _logger.info("Will not delete " + this + " as it is in use."); - return 0; - } - else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) - { - _logger.info("Will not delete " + this + " as it is not empty."); + long getMinimumAlertRepeatGap(); - return 0; - } - else - { - delete(); - return _deliveryMgr.getQueueMessageCount(); - } - } + void deleteMessageFromTop(StoreContext storeContext) throws AMQException; - public void delete() throws AMQException - { - if (!_deleted.getAndSet(true)) - { - _subscribers.queueDeleted(this); - _bindings.deregister(); - _virtualHost.getQueueRegistry().unregisterQueue(_name); - _managedObject.unregister(); - for (Task task : _deleteTaskList) - { - task.doTask(this); - } - - _deleteTaskList.clear(); - } - } + long clearQueue(StoreContext storeContext) throws AMQException; - protected void autodelete() throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format("autodeleting {0}", this)); - } - delete(); - } - /*public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException - { - // fixme not sure what this is doing. should we be passing deliverFirst through here? - // This code is not used so when it is perhaps it should - _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst); - try - { - msg.checkDeliveredToConsumer(); - updateReceivedMessageCount(msg); - } - catch (NoConsumersException e) - { - // as this message will be returned, it should be removed - // from the queue: - dequeue(storeContext, msg); - } - }*/ + void removeExpiredIfNoSubscribers() throws AMQException; - // public DeliveryManager getDeliveryManager() - // { - // return _deliveryMgr; - // } + Set getNotificationChecks(); - public void process(StoreContext storeContext, QueueEntry entry, boolean deliverFirst) throws AMQException - { - AMQMessage msg = entry.getMessage(); - _deliveryMgr.deliver(storeContext, _name, entry, deliverFirst); - try - { - msg.checkDeliveredToConsumer(); - updateReceivedMessageCount(entry); - } - catch (NoConsumersException e) - { - // as this message will be returned, it should be removed - // from the queue: - dequeue(storeContext, entry); - } - } + void flushSubscription(final Subscription sub) throws AMQException; - public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException - { - try - { - entry.getMessage().dequeue(storeContext, this); - } - catch (MessageCleanupException e) - { - // Message was dequeued, but could not then be deleted - // though it is no longer referenced. This should be very - // rare and can be detected and cleaned up on recovery or - // done through some form of manual intervention. - _logger.error(e, e); - } - catch (AMQException e) - { - throw new FailedDequeueException(_name.toString(), e); - } - } + void deliverAsync(final Subscription sub); - public void deliverAsync() - { - _deliveryMgr.processAsync(_asyncDelivery); - } + void deliverAsync(); - protected SubscriptionManager getSubscribers() - { - return _subscribers; - } - protected void updateReceivedMessageCount(QueueEntry entry) throws AMQException + /** + * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create a subscription, because an exclusive subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + static final class ExistingExclusiveSubscription extends AMQException { - AMQMessage msg = entry.getMessage(); - - if (!msg.isRedelivered()) - { - _totalMessagesReceived.incrementAndGet(); - } - try - { - _managedObject.checkForNotification(msg); - } - catch (JMException e) + public ExistingExclusiveSubscription() { - throw new AMQException("Unable to get notification from manage queue: " + e, e); + super(""); } } - public boolean equals(Object o) + /** + * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create an exclusize subscription, as a subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + static final class ExistingSubscriptionPreventsExclusive extends AMQException { - if (this == o) - { - return true; - } - - if ((o == null) || (getClass() != o.getClass())) + public ExistingSubscriptionPreventsExclusive() { - return false; + super(""); } - - 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); - } - - public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException - { - return _deliveryMgr.performGet(session, channel, acks); - } - - public QueueRegistry getQueueRegistry() - { - return _virtualHost.getQueueRegistry(); - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public static interface Task + static interface Task { public void doTask(AMQQueue queue) throws AMQException; } - - public void addQueueDeleteTask(Task task) - { - _deleteTaskList.add(task); - } - - public long getMinimumAlertRepeatGap() - { - return _minimumAlertRepeatGap; - } - - public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) - { - _minimumAlertRepeatGap = minimumAlertRepeatGap; - } - - public long getMaximumMessageAge() - { - return _maximumMessageAge; - } - - public void setMaximumMessageAge(long maximumMessageAge) - { - _maximumMessageAge = maximumMessageAge; - if(maximumMessageAge == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT); - } - } - - public void subscriberHasPendingResend(boolean hasContent, SubscriptionImpl subscription, QueueEntry entry) - { - _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, entry); - } - - public QueueEntry createEntry(AMQMessage amqMessage) - { - return new QueueEntry(this, amqMessage); - } - - public int compareTo(Object o) - { - return _name.compareTo(((AMQQueue) o).getName()); - } - - - public void removeExpiredIfNoSubscribers() throws AMQException - { - synchronized(_subscribers.getChangeLock()) - { - if(_subscribers.isEmpty()) - { - _deliveryMgr.removeExpired(); - } - } - } - - public final Set getNotificationChecks() - { - return _notificationChecks; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java new file mode 100644 index 0000000000..431b76754f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.AMQException; + + +public class AMQQueueFactory +{ + private static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + + public static AMQQueue createAMQQueueImpl(AMQShortString name, + boolean durable, + AMQShortString owner, + boolean autoDelete, + VirtualHost virtualHost, final FieldTable arguments) + throws AMQException + { + + final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + + if(priorities > 1) + { + return new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); + } + else + { + return new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 348a136f9d..2ed6be77c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -292,7 +292,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que } /** - * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop + * @see AMQQueue#deleteMessageFromTop */ public void deleteMessageFromTop() throws JMException { @@ -307,7 +307,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que } /** - * @see org.apache.qpid.server.queue.AMQQueue#clearQueue + * @see AMQQueue#clearQueue */ public void clearQueue() throws JMException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java deleted file mode 100644 index 0e8cff0f2a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.configuration.Configured; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; -import org.apache.qpid.util.MessageQueue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; - - -/** Manages delivery of messages on behalf of a queue */ -public class ConcurrentSelectorDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class); - - @Configured(path = "advanced.compressBufferOnQueue", - defaultValue = "false") - public boolean compressBufferOnQueue; - /** Holds any queued messages */ - private final MessageQueue _messages = new ConcurrentLinkedMessageQueueAtomicSize(); - - /** Ensures that only one asynchronous task is running for this manager at any time. */ - private final AtomicBoolean _processing = new AtomicBoolean(); - /** The subscriptions on the queue to whom messages are delivered */ - private final SubscriptionManager _subscriptions; - - /** - * A reference to the queue we are delivering messages for. We need this to be able to pass the code that handles - * acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - /** - * Flag used while moving messages from this queue to another. For moving messages the async delivery should also - * stop. This flat should be set to true to stop async delivery and set to false to enable async delivery again. - */ - private AtomicBoolean _movingMessages = new AtomicBoolean(); - - /** - * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced - * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be - * delivered via the async thread.

      Lock is used to control access to hasQueuedMessages() and over the addition - * of messages to the queue. - */ - private ReentrantLock _lock = new ReentrantLock(); - private AtomicLong _totalMessageSize = new AtomicLong(); - private AtomicInteger _extraMessages = new AtomicInteger(); - private Set _hasContent = Collections.synchronizedSet(new HashSet()); - private final Object _queueHeadLock = new Object(); - private String _processingThreadName = ""; - - ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - - //Set values from configuration - Configurator.configure(this); - - if (compressBufferOnQueue) - { - _log.warn("Compressing Buffers on queue."); - } - - _subscriptions = subscriptions; - _queue = queue; - } - - - private boolean addMessageToQueue(QueueEntry entry, boolean deliverFirst) - { - AMQMessage msg = entry.getMessage(); - // Shrink the ContentBodies to their actual size to save memory. - if (compressBufferOnQueue) - { - Iterator it = msg.getContentBodyIterator(); - while (it.hasNext()) - { - ContentChunk cb = it.next(); - cb.reduceToFit(); - } - } - - if (deliverFirst) - { - synchronized (_queueHeadLock) - { - _messages.pushHead(entry); - } - } - else - { - _messages.offer(entry); - } - - _totalMessageSize.addAndGet(msg.getSize()); - - return true; - } - - - public boolean hasQueuedMessages() - { - _lock.lock(); - try - { - return !(_messages.isEmpty() && _hasContent.isEmpty()); - } - finally - { - _lock.unlock(); - } - } - - public int getQueueMessageCount() - { - return getMessageCount(); - } - - /** - * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine - * size. The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. - * - * @return int the number of messages in the delivery queue. - */ - private int getMessageCount() - { - return _messages.size() + _extraMessages.get(); - } - - - public long getTotalMessageSize() - { - return _totalMessageSize.get(); - } - - public long getOldestMessageArrival() - { - QueueEntry entry = _messages.peek(); - return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); - } - - public void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry entry) - { - _lock.lock(); - try - { - if (hasContent) - { - _log.debug("Queue has adding subscriber content"); - _hasContent.add(subscription); - _totalMessageSize.addAndGet(entry.getSize()); - _extraMessages.addAndGet(1); - } - else - { - _log.debug("Queue has removing subscriber content"); - if (entry == null) - { - _hasContent.remove(subscription); - } - else - { - _totalMessageSize.addAndGet(-entry.getSize()); - _extraMessages.addAndGet(-1); - } - } - } - finally - { - _lock.unlock(); - } - } - - /** - * NOTE : This method should only be called when there are no active subscribers - */ - public void removeExpired() throws AMQException - { - _lock.lock(); - try - { - // New Context to for dealing with the MessageStore. - StoreContext context = new StoreContext(); - - for(Iterator iter = _messages.iterator(); iter.hasNext();) - { - QueueEntry entry = iter.next(); - if(entry.expired()) - { - // fixme: Currently we have to update the total byte size here for the data in the queue - _totalMessageSize.addAndGet(-entry.getSize()); - - // Remove the message from the queue in the MessageStore - _queue.dequeue(context,entry); - - // This queue nolonger needs a reference to this message - entry.getMessage().decrementReference(context); - iter.remove(); - } - } - } - finally - { - _lock.unlock(); - } - } - - /** @return the state of the async processor. */ - public boolean isProcessingAsync() - { - return _processing.get(); - } - - /** - * Returns all the messages in the Queue - * - * @return List of messages - */ - public List getMessages() - { - List list = new ArrayList(); - - _lock.lock(); - try - { - for (QueueEntry entry : _messages) - { - list.add(entry); - } - } - finally - { - _lock.unlock(); - } - - return list; - } - - /** - * Returns messages within the range of given messageIds - * - * @param fromMessageId - * @param toMessageId - * - * @return - */ - public List getMessages(long fromMessageId, long toMessageId) - { - if (fromMessageId <= 0 || toMessageId <= 0) - { - return null; - } - - long maxMessageCount = toMessageId - fromMessageId + 1; - - List foundMessagesList = new ArrayList(); - _lock.lock(); - try - { - for (QueueEntry entry : _messages) - { - long msgId = entry.getMessage().getMessageId(); - if (msgId >= fromMessageId && msgId <= toMessageId) - { - foundMessagesList.add(entry); - } - // break if the no of messages are found - if (foundMessagesList.size() == maxMessageCount) - { - break; - } - } - } - finally - { - _lock.unlock(); - } - - return foundMessagesList; - } - - public void populatePreDeliveryQueue(Subscription subscription) - { - if (_log.isDebugEnabled()) - { - _log.debug("Populating PreDeliveryQueue for Subscription(" + System.identityHashCode(subscription) + ")"); - } - - Iterator currentQueue = _messages.iterator(); - - while (currentQueue.hasNext()) - { - QueueEntry entry = currentQueue.next(); - - if (subscription.hasInterest(entry)) - { - subscription.enqueueForPreDelivery(entry, false); - } - - } - } - - public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException - { - QueueEntry entry = getNextMessage(); - if (entry == null) - { - return false; - } - else - { - - try - { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!acks) - { - if (_log.isDebugEnabled()) - { - _log.debug("No ack mode so dequeuing message immediately: " + entry.getMessage().getMessageId()); - } - _queue.dequeue(channel.getStoreContext(), entry); - } - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (acks) - { - channel.addUnacknowledgedMessage(entry, deliveryTag, null); - } - - protocolSession.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(), - deliveryTag, _queue.getMessageCount()); - - } - _totalMessageSize.addAndGet(-entry.getSize()); - - if (!acks) - { - entry.getMessage().decrementReference(channel.getStoreContext()); - } - } - finally - { - entry.setDeliveredToConsumer(); - } - return true; - - } - } - - /** - * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, so that - * the asyn delivery is also stopped. - */ - public void startMovingMessages() - { - _movingMessages.set(true); - } - - /** - * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, so that - * the async delivery can start again. - */ - public void stopMovingMessages() - { - _movingMessages.set(false); - if (_lock.isHeldByCurrentThread()) - { - _lock.unlock(); - } - } - - /** - * Messages will be removed from this queue and all preDeliveryQueues - * - * @param messageList - */ - public void removeMovedMessages(List messageList) - { - // Remove from the - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - if (hasSubscribers) - { - for (Subscription sub : _subscriptions.getSubscriptions()) - { - if (!sub.isSuspended() && sub.filtersMessages()) - { - Queue preDeliveryQueue = sub.getPreDeliveryQueue(); - for (QueueEntry entry : messageList) - { - preDeliveryQueue.remove(entry); - } - } - } - } - - for (QueueEntry entry : messageList) - { - if (_messages.remove(entry)) - { - _totalMessageSize.getAndAdd(-entry.getSize()); - } - } - } - - /** - * Now with implementation of predelivery queues, this method will mark the message on the top as taken. - * - * @param storeContext - * - * @throws AMQException - */ - public void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException - { - _lock.lock(); - - try - { - QueueEntry entry = _messages.poll(); - - if (entry != null) - { - queue.dequeue(storeContext, entry); - - _totalMessageSize.addAndGet(-entry.getSize()); - - //If this causes ref count to hit zero then data will be purged so message.getSize() will NPE. - entry.getMessage().decrementReference(storeContext); - - } - } - finally - { - _lock.unlock(); - } - } - - public long clearAllMessages(StoreContext storeContext) throws AMQException - { - long count = 0; - - _lock.lock(); - try - { - synchronized (_queueHeadLock) - { - QueueEntry entry = getNextMessage(); - - // todo: note: why do we need this? Why not reuse the passed 'storeContext' - //Create a new StoreContext for decrementing the References - StoreContext context = new StoreContext(); - - while (entry != null) - { - //and remove it - _messages.poll(); - - // todo: NOTE: Why is this a different context to the new local 'context'? - _queue.dequeue(storeContext, entry); - - entry.getMessage().decrementReference(context); - - entry = getNextMessage(); - count++; - } - _totalMessageSize.set(0L); - } - } - finally - { - _lock.unlock(); - } - return count; - } - - /** - * This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. - * - * @return the next message or null - * - * @throws org.apache.qpid.AMQException - */ - private QueueEntry getNextMessage() throws AMQException - { - return getNextMessage(_messages, null, false); - } - - private QueueEntry getNextMessage(Queue messages, Subscription sub, boolean purgeOnly) throws AMQException - { - QueueEntry entry = messages.peek(); - - //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) - while (purgeMessage(entry, sub, purgeOnly)) - { - AMQMessage message = entry.getMessage(); - - //remove the already taken message or expired - QueueEntry removed = messages.poll(); - - assert removed == entry; - - // if the message expired then the _totalMessageSize needs adjusting - if (message.expired(_queue) && !entry.taken(sub)) - { - _totalMessageSize.addAndGet(-entry.getSize()); - - // New Store Context for removing expired messages - StoreContext storeContext = new StoreContext(); - - // Use the reapingStoreContext as any sub(if we have one) may be in a tx. - _queue.dequeue(storeContext, entry); - - message.decrementReference(storeContext); - - if (_log.isInfoEnabled()) - { - _log.info(debugIdentity() + " Doing clean up of the main _message queue."); - } - } - - //else the clean up is not required as the message has already been taken for this queue therefore - // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated. - - if (_log.isDebugEnabled()) - { - _log.debug("Removed taken message:" + message.debugIdentity()); - } - - // try the next message - entry = messages.peek(); - } - - return entry; - } - - /** - * This method will return true if the message is to be purged from the queue. - * - * - * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue) - * - * @param message - * @param sub - * - * @return - * - * @throws AMQException - */ - private boolean purgeMessage(QueueEntry message, Subscription sub) throws AMQException - { - return purgeMessage(message, sub, false); - } - - /** - * This method will return true if the message is to be purged from the queue. - * \ - * SIDE-EFFECT: The msg will be taken by the Subscription(sub) for the current Queue(_queue) when purgeOnly is false - * - * @param message - * @param sub - * @param purgeOnly When set to false the message will be taken by the given Subscription. - * - * @return if the msg should be purged - * - * @throws AMQException - */ - private boolean purgeMessage(QueueEntry message, Subscription sub, boolean purgeOnly) throws AMQException - { - //Original.. complicated while loop control -// (message != null -// && ( -// ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) -// || sub == null) -// && message.taken(_queue, sub)); - - boolean purge = false; - - // if the message is null then don't purge as we have no messagse. - if (message != null) - { - // Check that the message hasn't expired. - if (message.expired()) - { - return true; - } - - // if we have a subscriber perform message checks - if (sub != null) - { - // if we have a queue browser(we don't purge) so check mark the message as taken - purge = ((!sub.isBrowser() || message.isTaken())); - } - else - { - // if there is no subscription we are doing - // a get or purging so mark message as taken. - message.isTaken(); - // and then ensure that it gets purged - purge = true; - } - } - - if (purgeOnly) - { - // If we are simply purging the queue don't take the message - // just purge up to the next non-taken msg. - return purge && message.isTaken(); - } - else - { - // if we are purging then ensure we mark this message taken for the current subscriber - // the current subscriber may be null in the case of a get or a purge but this is ok. - return purge && message.taken(sub); - } - } - - public void sendNextMessage(Subscription sub, AMQQueue queue) - { - - Queue messageQueue = sub.getNextQueue(_messages); - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Async sendNextMessage for sub (" + System.identityHashCode(sub) + - ") from queue (" + System.identityHashCode(messageQueue) + - ") AMQQueue (" + System.identityHashCode(queue) + ")"); - } - - if (messageQueue == null) - { - // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector - if (_log.isInfoEnabled()) - { - _log.info(debugIdentity() + sub + ": asked to send messages but has none on given queue:" + queue); - } - return; - } - - QueueEntry entry = null; - QueueEntry removed = null; - try - { - synchronized (_queueHeadLock) - { - entry = getNextMessage(messageQueue, sub, false); - - // message will be null if we have no messages in the messageQueue. - if (entry == null) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")"); - } - return; - } - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Async Delivery Message :" + entry + "(" + System.identityHashCode(entry) + - ") by :" + System.identityHashCode(this) + - ") to :" + System.identityHashCode(sub)); - } - - - if (messageQueue == _messages) - { - _totalMessageSize.addAndGet(-entry.getSize()); - } - - sub.send(entry, _queue); - - //remove sent message from our queue. - removed = messageQueue.poll(); - //If we don't remove the message from _messages - // Otherwise the Async send will never end - } - - if (removed != entry) - { - _log.error("Just send message:" + entry.getMessage().debugIdentity() + " BUT removed this from queue:" + removed); - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.getMessage().debugIdentity() + "d:" + entry + - ") by :" + System.identityHashCode(this) + - ") to :" + System.identityHashCode(sub)); - } - - - if (messageQueue == sub.getResendQueue()) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "All messages sent from resendQueue for " + sub); - } - if (messageQueue.isEmpty()) - { - subscriberHasPendingResend(false, sub, null); - //better to use the above method as this keeps all the tracking in one location. - // _hasContent.remove(sub); - } - - _extraMessages.decrementAndGet(); - } - else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser()) - { - cleanMainQueue(sub); - } - - } - catch (AMQException e) - { - if (entry != null) - { - entry.release(); - } - else - { - _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e); - } - _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); - } - } - - private void cleanMainQueue(Subscription sub) - { - try - { - getNextMessage(_messages, sub, true); - } - catch (AMQException e) - { - _log.warn("Problem during main queue purge:" + e.getMessage()); - } - } - - /** - * enqueues the messages in the list on the queue and all required predelivery queues - * - * @param storeContext - * @param movedMessageList - */ - public void enqueueMovedMessages(StoreContext storeContext, List movedMessageList) - { - _lock.lock(); - try - { - for (QueueEntry entry : movedMessageList) - { - addMessageToQueue(entry, false); - } - - // enqueue on the pre delivery queues - for (Subscription sub : _subscriptions.getSubscriptions()) - { - for (QueueEntry entry : movedMessageList) - { - // Only give the message to those that want them. - if (sub.hasInterest(entry)) - { - sub.enqueueForPreDelivery(entry, true); - } - } - } - } - finally - { - _lock.unlock(); - } - } - - /** - * Only one thread should ever execute this method concurrently, but it can do so while other threads invoke - * deliver(). - */ - private void processQueue() - { - //record thread name - if (_log.isDebugEnabled()) - { - _processingThreadName = Thread.currentThread().getName(); - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Running process Queue." + currentStatus()); - } - - // Continue to process delivery while we haveSubscribers and messages - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - - while (hasSubscribers && hasQueuedMessages() && !_movingMessages.get()) - { - hasSubscribers = false; - - for (Subscription sub : _subscriptions.getSubscriptions()) - { - synchronized (sub.getSendLock()) - { - if (!sub.isSuspended()) - { - sendNextMessage(sub, _queue); - - hasSubscribers = true; - } - } - } - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Done process Queue." + currentStatus()); - } - - } - - public void deliver(StoreContext context, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws AMQException - { - - final boolean debugEnabled = _log.isDebugEnabled(); - if (debugEnabled) - { - _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + entry); - } - - //Check if we have someone to deliver the message to. - _lock.lock(); - try - { - Subscription s = _subscriptions.nextSubscriber(entry); - - if (s == null || (!s.filtersMessages() && hasQueuedMessages())) //no-one can take the message right now or we're queueing - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Testing Message(" + entry + ") for Queued Delivery:" + currentStatus()); - } - if (!entry.getMessage().getMessagePublishInfo().isImmediate()) - { - addMessageToQueue(entry, deliverFirst); - - //release lock now message is on queue. - _lock.unlock(); - - //Pre Deliver to all subscriptions - if (debugEnabled) - { - _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() + - " subscribers to give the message to:" + currentStatus()); - } - for (Subscription sub : _subscriptions.getSubscriptions()) - { - - // Only give the message to those that want them. - if (sub.hasInterest(entry)) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(entry) + - ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")"); - } - sub.enqueueForPreDelivery(entry, deliverFirst); - } - } - - //if we have a non-filtering subscriber but queued messages && we're not Async && we have other Active subs then something is wrong! - if ((s != null && hasQueuedMessages()) && !isProcessingAsync() && _subscriptions.hasActiveSubscribers()) - { - _queue.deliverAsync(); - } - - } - } - else - { - - if (s.filtersMessages()) - { - if (s.getPreDeliveryQueue().size() > 0) - { - _log.error("Direct delivery from PDQ with queued msgs:" + s.getPreDeliveryQueue().size()); - } - } - else if (_messages.size() > 0) - { - _log.error("Direct delivery from MainQueue queued msgs:" + _messages.size()); - } - - //release lock now - _lock.unlock(); - synchronized (s.getSendLock()) - { - if (!s.isSuspended()) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + "Delivering Message:" + entry.getMessage().debugIdentity() + " to(" + - System.identityHashCode(s) + ") :" + s); - } - - if (entry.taken(s)) - { - //Message has been delivered so don't redeliver. - // This can currently occur because of the recursive call below - // During unit tests the send can occur - // client then rejects - // this reject then releases the message by the time the - // if(!msg.isTaken()) call is made below - // the message has been released so that thread loops to send the message again - // of course by the time it gets back to here. the thread that released the - // message is now ready to send it. Here is a sample trace for reference -//1192627162613:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false] -//1192627162613:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null} -//1192627162613:Thread[pool-917-thread-4,5,main]:28398657 Sent :dt:214 msg:(HC:5529738 ID:145 Ref:1) -//1192627162613:Thread[pool-917-thread-2,5,main]:Reject message by:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false] -//1192627162613:Thread[pool-917-thread-2,5,main]:Releasing Message:(HC:5529738 ID:145 Ref:1) -//1192627162613:Thread[pool-917-thread-2,5,main]:Msg:Release:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:This:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]} -//1192627162613:Thread[pool-917-thread-2,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false] -//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:suspended: Message((HC:5529738 ID:145 Ref:1)) has not been taken so recursing!: Subscriber:28398657 -//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false] -//1192627162629:Thread[pool-917-thread-2,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null} -//1192627162629:Thread[pool-917-thread-2,5,main]:25386607 Sent :dt:172 msg:(HC:5529738 ID:145 Ref:1) -//1192627162629:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=true} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]} - // Note: In the last request to take the message from thread 4,5 the message has been - // taken by the previous call done by thread 2,5 - - - return; - } - //Deliver the message - s.send(entry, _queue); - } - else - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " + - "suspended between nextSubscriber and send for message:" + entry.getMessage().debugIdentity()); - } - } - } - - // - // Why do we do this? What was the reasoning? We should have a better approach - // than recursion and rejecting if someone else sends it before we do. - // - if (!entry.isTaken()) - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Message(" + entry.getMessage().debugIdentity() + ") has not been taken so recursing!:" + - " Subscriber:" + System.identityHashCode(s)); - } - - deliver(context, name, entry, deliverFirst); - } - else - { - if (debugEnabled) - { - _log.debug(debugIdentity() + " Message(" + entry.toString() + - ") has been taken so disregarding deliver request to Subscriber:" + - System.identityHashCode(s)); - } - } - } - - } - finally - { - //ensure lock is released - if (_lock.isHeldByCurrentThread()) - { - _lock.unlock(); - } - } - } - - private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")"; - - private String debugIdentity() - { - return id; - } - - final Runner _asyncDelivery = new Runner(); - - private class Runner implements Runnable - { - public void run() - { - String startName = Thread.currentThread().getName(); - Thread.currentThread().setName("CSDM-AsyncDelivery:" + startName); - boolean running = true; - while (running && !_movingMessages.get()) - { - processQueue(); - - //Check that messages have not been added since we did our last peek(); - // Synchronize with the thread that adds to the queue. - // If the queue is still empty then we can exit - synchronized (_asyncDelivery) - { - if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) - { - running = false; - _processing.set(false); - } - } - } - Thread.currentThread().setName(startName); - } - } - - public void processAsync(Executor executor) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Processing Async." + currentStatus()); - } - - synchronized (_asyncDelivery) - { - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Executing Async process."); - } - executor.execute(_asyncDelivery); - } - } - } - } - - private String currentStatus() - { - return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains(H:M)") + - "(" + ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize() + - ":" + (_messages.size() - ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize()) + ") " + - " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") + - "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + (_processing.get() ? " true : Processing Thread: " + _processingThreadName : " false"); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java deleted file mode 100644 index 1568f58e2e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; -import java.util.concurrent.Executor; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; - -interface DeliveryManager -{ - /** - * Determines whether there are queued messages. Sets _queueing to false if there are no queued messages. This needs - * to be atomic. - * - * @return true if there are queued messages - */ - boolean hasQueuedMessages(); - - /** - * This method should not be used to determin if there are messages in the queue. - * - * @return int The number of messages in the queue - * - * @use hasQueuedMessages() for all controls relating to having messages on the queue. - */ - int getQueueMessageCount(); - - /** - * Requests that the delivery manager start processing the queue asynchronously if there is work that can be done - * (i.e. there are messages queued up and subscribers that can receive them.

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

      - * - * @param executor the executor on which the delivery should take place - */ - void processAsync(Executor executor); - - /** - * Handles message delivery. The delivery manager is always in one of two modes; it is either queueing messages for - * asynchronous delivery or delivering directly. - * - * @param storeContext - * @param name the name of the entity on whose behalf we are delivering the message - * @param entry the message to deliver - * @param deliverFirst - * - * @throws org.apache.qpid.server.queue.FailedDequeueException - * if the message could not be dequeued - */ - void deliver(StoreContext storeContext, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws FailedDequeueException, AMQException; - - void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException; - - long clearAllMessages(StoreContext storeContext) throws AMQException; - - void startMovingMessages(); - - void enqueueMovedMessages(StoreContext context, List messageList); - - void stopMovingMessages(); - - void removeMovedMessages(List messageListToRemove); - - List getMessages(); - - List getMessages(long fromMessageId, long toMessageId); - - void populatePreDeliveryQueue(Subscription subscription); - - boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException; - - long getTotalMessageSize(); - - long getOldestMessageArrival(); - - void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry msg); - - void removeExpired() throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index e6377b33da..d2e5a02508 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -109,9 +109,9 @@ class ExchangeBindings } - public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); + return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java new file mode 100644 index 0000000000..d38932bb61 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.AMQException; + +public interface Filterable +{ + ContentHeaderBody getContentHeaderBody() throws E; + + boolean isPersistent() throws E; + + boolean isRedelivered(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 0b40f01f1a..35ad5be4e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -22,11 +22,10 @@ package org.apache.qpid.server.queue; import java.util.LinkedList; import java.util.List; +import java.util.Collections; import java.util.ArrayList; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ContentChunk; @@ -41,32 +40,40 @@ public class InMemoryMessageHandle implements AMQMessageHandle private MessagePublishInfo _messagePublishInfo; - private List _contentBodies = new ArrayList(); + private List _contentBodies; private boolean _redelivered; private long _arrivalTime; - public InMemoryMessageHandle() + private final Long _messageId; + + public InMemoryMessageHandle(final Long messageId) { + _messageId = messageId; } - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException { return _contentHeaderBody; } - public int getBodyCount(StoreContext context, Long messageId) + public Long getMessageId() + { + return _messageId; + } + + public int getBodyCount(StoreContext context) { return _contentBodies.size(); } - public long getBodySize(StoreContext context, Long messageId) throws AMQException + public long getBodySize(StoreContext context) throws AMQException { - return getContentHeaderBody(context, messageId).bodySize; + return getContentHeaderBody(context).bodySize; } - public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -76,13 +83,28 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _contentBodies.get(index); } - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException { - _contentBodies.add(contentBody); + if(_contentBodies == null) + { + if(isLastContentBody) + { + _contentBodies = Collections.singletonList(contentBody); + } + else + { + _contentBodies = new ArrayList(); + _contentBodies.add(contentBody); + } + } + else + { + _contentBodies.add(contentBody); + } } - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException { return _messagePublishInfo; } @@ -98,12 +120,9 @@ public class InMemoryMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(StoreContext context, Long messageId) throws AMQException + public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(context, messageId); - return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + return false; } /** @@ -112,26 +131,20 @@ public class InMemoryMessageHandle implements AMQMessageHandle * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo, + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) throws AMQException { _messagePublishInfo = messagePublishInfo; _contentHeaderBody = contentHeaderBody; + if(contentHeaderBody.bodySize == 0) + { + _contentBodies = Collections.EMPTY_LIST; + } _arrivalTime = System.currentTimeMillis(); } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - // NO OP - } - - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - // NO OP - } - - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + public void removeMessage(StoreContext storeContext) throws AMQException { // NO OP } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java new file mode 100644 index 0000000000..9d769d7582 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -0,0 +1,336 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.exchange.NoRouteException; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import java.util.Collection; + +public class IncomingMessage implements Filterable +{ + + /** Used for debugging purposes. */ + private static final Logger _logger = Logger.getLogger(IncomingMessage.class); + + private static final boolean SYNCHED_CLOCKS = + ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false); + + private final MessagePublishInfo _messagePublishInfo; + private ContentHeaderBody _contentHeaderBody; + private AMQMessageHandle _messageHandle; + private final Long _messageId; + private final TransactionalContext _txnContext; + + + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + /** + * This is stored during routing, to know the queues to which this message should immediately be + * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done + * by the message handle. + */ + private Collection _destinationQueues; + + private AMQProtocolSession _publisher; + private MessageStore _messageStore; + private long _expiration; + + private Exchange _exchange; + + + public IncomingMessage(final Long messageId, + final MessagePublishInfo info, + final TransactionalContext txnContext, + final AMQProtocolSession publisher) + { + _messageId = messageId; + _messagePublishInfo = info; + _txnContext = txnContext; + _publisher = publisher; + + } + + public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException + { + _contentHeaderBody = contentHeaderBody; + } + + public void setExpiration() + { + long expiration = + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getExpiration(); + long timestamp = + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getTimestamp(); + + if (SYNCHED_CLOCKS) + { + _expiration = expiration; + } + else + { + // Update TTL to be in broker time. + if (expiration != 0L) + { + if (timestamp != 0L) + { + // todo perhaps use arrival time + long diff = (System.currentTimeMillis() - timestamp); + + if ((diff > 1000L) || (diff < 1000L)) + { + _expiration = expiration + diff; + } + } + } + } + + } + + public void routingComplete(final MessageStore store, + final 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 + + if(_destinationQueues != null) + { + for (AMQQueue q : _destinationQueues) + { + if(q.isDurable()) + { + + _messageStore.enqueueMessage(_txnContext.getStoreContext(), q, _messageId); + } + } + } + + } + + + + + } + + public AMQMessage deliverToQueues() + throws AMQException + { + + // we get a reference to the destination queues now so that we can clear the + // transient message data as quickly as possible + Collection destinationQueues = _destinationQueues; + if (_logger.isDebugEnabled()) + { + _logger.debug("Delivering message " + _messageId + " to " + destinationQueues); + } + + AMQMessage message = null; + + try + { + // first we allow the handle to know that the message has been fully received. This is useful if it is + // maintaining any calculated values based on content chunks + _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), + _messagePublishInfo, getContentHeaderBody()); + + + message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); + + message.setExpiration(_expiration); + message.setClientIdentifier(_publisher.getSessionIdentifier()); + + + + + if ((destinationQueues == null) || destinationQueues.isEmpty()) + { + + if (isMandatory() || isImmediate()) + { + throw new NoRouteException("No Route for message", message); + + } + else + { + _logger.warn("MESSAGE DISCARDED: No routes for message - " + message); + } + } + else + { + // TODO + + int offset; + final int queueCount = destinationQueues.size(); + if(queueCount == 1) + { + offset = 0; + } + else + { + offset = ((int)(message.getMessageId().longValue())) % queueCount; + if(offset < 0) + { + offset = -offset; + } + } + + int i = 0; + for (AMQQueue q : destinationQueues) + { + if(++i > offset) + { + // Increment the references to this message for each queue delivery. + message.incrementReference(); + // normal deliver so add this message at the end. + _txnContext.deliver(q, message); + } + } + i = 0; + if(offset != 0) + { + for (AMQQueue q : destinationQueues) + { + if(i++ < offset) + { + // Increment the references to this message for each queue delivery. + message.incrementReference(); + // normal deliver so add this message at the end. + _txnContext.deliver(q, message); + } + } + } + + } + + // we then allow the transactional context to do something with the message content + // now that it has all been received, before we attempt delivery + _txnContext.messageFullyReceived(isPersistent()); + message.clearStoreContext(); + return message; + } + finally + { + // Remove refence for routing process . Reference count should now == delivered queue count + if(message != null) message.decrementReference(_txnContext.getStoreContext()); + } + + } + + public void addContentBodyFrame(final ContentChunk contentChunk) + throws AMQException + { + + _bodyLengthReceived += contentChunk.getSize(); + + _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); + + } + + public boolean allContentReceived() + { + return (_bodyLengthReceived == getContentHeaderBody().bodySize); + } + + public AMQShortString getExchange() throws AMQException + { + return _messagePublishInfo.getExchange(); + } + + public AMQShortString getRoutingKey() throws AMQException + { + return _messagePublishInfo.getRoutingKey(); + } + + public boolean isMandatory() throws AMQException + { + return _messagePublishInfo.isMandatory(); + } + + + public boolean isImmediate() throws AMQException + { + return _messagePublishInfo.isImmediate(); + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + + public boolean isPersistent() + { + //todo remove literal values to a constant file such as AMQConstants in common + return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2; + } + + public boolean isRedelivered() + { + return false; + } + + public void setMessageStore(final MessageStore messageStore) + { + _messageStore = messageStore; + } + + public Long getMessageId() + { + return _messageId; + } + + public void setExchange(final Exchange e) + { + _exchange = e; + } + + public void route() throws AMQException + { + _exchange.route(this); + } + + public void enqueue(final Collection queues) + { + _destinationQueues = queues; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 061ab56024..2bc94995e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -126,7 +126,7 @@ public interface ManagedQueue * @param age maximum age of message. * @throws IOException */ - @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on thr broker") + @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on the broker") void setMaximumMessageAge(Long age) throws IOException; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java index 94ab935115..0b214ca336 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -36,11 +36,11 @@ public class MessageHandleFactory // just hardcoded for now if (persistent) { - return new WeakReferenceMessageHandle(store); + return new WeakReferenceMessageHandle(messageId, store); } else { - return new InMemoryMessageHandle(); + return new InMemoryMessageHandle(messageId); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 12d6c5998a..6f9efd3200 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -1,129 +1,138 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -public enum NotificationCheck -{ - - MESSAGE_COUNT_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - int msgCount; - final long maximumMessageCount = queue.getMaximumMessageCount(); - if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) - { - listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); - return true; - } - return false; - } - }, - MESSAGE_SIZE_ALERT(true) - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - final long maximumMessageSize = queue.getMaximumMessageSize(); - if(maximumMessageSize != 0) - { - // Check for threshold message size - long messageSize = (msg == null) ? 0 : msg.getSize(); - - if (messageSize >= maximumMessageSize) - { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); - return true; - } - } - return false; - } - - }, - QUEUE_DEPTH_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - // Check for threshold queue depth in bytes - final long maximumQueueDepth = queue.getMaximumQueueDepth(); - - if(maximumQueueDepth != 0) - { - final long queueDepth = queue.getQueueDepth(); - - if (queueDepth >= maximumQueueDepth) - { - listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); - return true; - } - } - return false; - } - - }, - MESSAGE_AGE_ALERT - { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) - { - - final long maxMessageAge = queue.getMaximumMessageAge(); - if(maxMessageAge != 0) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - maxMessageAge; - final long firstArrivalTime = queue.getOldestMessageArrivalTime(); - - if(firstArrivalTime < thresholdTime) - { - long oldestAge = currentTime - firstArrivalTime; - listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); - - return true; - } - } - return false; - - } - - } - ; - - private final boolean _messageSpecific; - - NotificationCheck() - { - this(false); - } - - NotificationCheck(boolean messageSpecific) - { - _messageSpecific = messageSpecific; - } - - public boolean isMessageSpecific() - { - return _messageSpecific; - } - - abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 enum NotificationCheck +{ + + MESSAGE_COUNT_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + int msgCount; + final long maximumMessageCount = queue.getMaximumMessageCount(); + if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) + { + listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); + return true; + } + return false; + } + }, + MESSAGE_SIZE_ALERT(true) + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + final long maximumMessageSize = queue.getMaximumMessageSize(); + if(maximumMessageSize != 0) + { + // Check for threshold message size + long messageSize; + try + { + messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + messageSize = 0; + } + + + if (messageSize >= maximumMessageSize) + { + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + return true; + } + } + return false; + } + + }, + QUEUE_DEPTH_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + // Check for threshold queue depth in bytes + final long maximumQueueDepth = queue.getMaximumQueueDepth(); + + if(maximumQueueDepth != 0) + { + final long queueDepth = queue.getQueueDepth(); + + if (queueDepth >= maximumQueueDepth) + { + listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); + return true; + } + } + return false; + } + + }, + MESSAGE_AGE_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + + final long maxMessageAge = queue.getMaximumMessageAge(); + if(maxMessageAge != 0) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - maxMessageAge; + final long firstArrivalTime = queue.getOldestMessageArrivalTime(); + + if(firstArrivalTime < thresholdTime) + { + long oldestAge = currentTime - firstArrivalTime; + listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); + + return true; + } + } + return false; + + } + + } + ; + + private final boolean _messageSpecific; + + NotificationCheck() + { + this(false); + } + + NotificationCheck(boolean messageSpecific) + { + _messageSpecific = messageSpecific; + } + + public boolean isMessageSpecific() + { + return _messageSpecific; + } + + abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java new file mode 100644 index 0000000000..e6628832cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -0,0 +1,164 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* 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.CommonContentHeaderProperties; +import org.apache.qpid.AMQException; + +public class PriorityQueueList implements QueueEntryList +{ + private final AMQQueue _queue; + private final QueueEntryList[] _priorityLists; + private final int _priorities; + private final int _priorityOffset; + + public PriorityQueueList(AMQQueue queue, int priorities) + { + _queue = queue; + _priorityLists = new QueueEntryList[priorities]; + _priorities = priorities; + _priorityOffset = 5-((priorities + 1)/2); + for(int i = 0; i < priorities; i++) + { + _priorityLists[i] = new SimpleQueueEntryList(queue); + } + } + + public AMQQueue getQueue() + { + return _queue; + } + + public QueueEntry add(AMQMessage message) + { + try + { + int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; + if(index >= _priorities) + { + index = _priorities-1; + } + else if(index < 0) + { + index = 0; + } + return _priorityLists[index].add(message); + } + catch (AMQException e) + { + // TODO - fix AMQ Exception + throw new RuntimeException(e); + } + + } + + public QueueEntry next(QueueEntry node) + { + QueueEntryImpl nodeImpl = (QueueEntryImpl)node; + QueueEntry next = nodeImpl.getNext(); + + if(next == null) + { + QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); + int index; + for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--); + + while(next == null && index != 0) + { + index--; + next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext(); + } + + } + return next; + } + + private final class PriorityQueueEntryListIterator implements QueueEntryIterator + { + private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; + private QueueEntry _lastNode; + + PriorityQueueEntryListIterator() + { + for(int i = 0; i < _priorityLists.length; i++) + { + _iterators[i] = _priorityLists[i].iterator(); + } + _lastNode = _iterators[_iterators.length - 1].getNode(); + } + + + public boolean atTail() + { + for(int i = 0; i < _iterators.length; i++) + { + if(!_iterators[i].atTail()) + { + return false; + } + } + return true; + } + + public QueueEntry getNode() + { + return _lastNode; + } + + public boolean advance() + { + for(int i = _iterators.length-1; i >= 0; i--) + { + if(_iterators[i].advance()) + { + _lastNode = _iterators[i].getNode(); + return true; + } + } + return false; + } + } + + public QueueEntryIterator iterator() + { + return new PriorityQueueEntryListIterator(); + } + + public QueueEntry getHead() + { + return _priorityLists[_priorities-1].getHead(); + } + + static class Factory implements QueueEntryListFactory + { + private final int _priorities; + + Factory(int priorities) + { + _priorities = priorities; + } + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new PriorityQueueList(queue, _priorities); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 8553db3e09..dd967a7cb1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -1,173 +1,186 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.server.store.StoreContext; -import org.apache.log4j.Logger; - -import java.util.Set; -import java.util.HashSet; -import java.util.concurrent.atomic.AtomicReference; - +import org.apache.qpid.server.subscription.Subscription; -public class QueueEntry +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface QueueEntry extends Comparable { - /** - * Used for debugging purposes. - */ - private static final Logger _log = Logger.getLogger(QueueEntry.class); - - private final AMQQueue _queue; - private final AMQMessage _message; - private Set _rejectedBy = null; - private AtomicReference _owner = new AtomicReference(); - - - public QueueEntry(AMQQueue queue, AMQMessage message) + public static enum State { - _queue = queue; - _message = message; + AVAILABLE, + ACQUIRED, + EXPIRED, + DEQUEUED, + DELETED } - - public AMQQueue getQueue() + public static interface StateChangeListener { - return _queue; + public void stateChanged(QueueEntry entry, State oldSate, State newState); } - public AMQMessage getMessage() + public abstract class EntryState { - return _message; - } + private EntryState() + { + } - public long getSize() - { - return getMessage().getSize(); + public abstract State getState(); } - public boolean getDeliveredToConsumer() - { - return getMessage().getDeliveredToConsumer(); - } - public boolean expired() throws AMQException + public final class AvailableState extends EntryState { - return getMessage().expired(_queue); - } - public boolean isTaken() - { - return _owner.get() != null; + public State getState() + { + return State.AVAILABLE; + } } - public boolean taken(Subscription sub) - { - return !(_owner.compareAndSet(null, sub == null ? this : sub)); - } - public void setDeliveredToConsumer() + public final class DequeuedState extends EntryState { - getMessage().setDeliveredToConsumer(); - } - public void release() - { - _owner.set(null); + public State getState() + { + return State.DEQUEUED; + } } - public String debugIdentity() - { - return getMessage().debugIdentity(); - } - public void process(StoreContext storeContext, boolean deliverFirst) throws AMQException + public final class DeletedState extends EntryState { - _queue.process(storeContext, this, deliverFirst); - } - public void checkDeliveredToConsumer() throws NoConsumersException - { - _message.checkDeliveredToConsumer(); + public State getState() + { + return State.DELETED; + } } - public void setRedelivered(boolean b) + public final class ExpiredState extends EntryState { - getMessage().setRedelivered(b); - } - public Subscription getDeliveredSubscription() - { - synchronized (this) + public State getState() { - Object owner = _owner.get(); - if (owner instanceof Subscription) - { - return (Subscription) owner; - } - else - { - return null; - } + return State.EXPIRED; } } - public void reject() + + public final class NonSubscriptionAcquiredState extends EntryState { - reject(getDeliveredSubscription()); + public State getState() + { + return State.ACQUIRED; + } } - public void reject(Subscription subscription) + public final class SubscriptionAcquiredState extends EntryState { - if (subscription != null) - { - if (_rejectedBy == null) - { - _rejectedBy = new HashSet(); - } + private final Subscription _subscription; - _rejectedBy.add(subscription); - } - else + public SubscriptionAcquiredState(Subscription subscription) { - _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + _subscription = subscription; } - } - public boolean isRejectedBy(Subscription subscription) - { - boolean rejected = _rejectedBy != null; - if (rejected) // We have subscriptions that rejected this message + public State getState() { - return _rejectedBy.contains(subscription); + return State.ACQUIRED; } - else // This messasge hasn't been rejected yet. + + public Subscription getSubscription() { - return rejected; + return _subscription; } } + final static EntryState AVAILABLE_STATE = new AvailableState(); + final static EntryState DELETED_STATE = new DeletedState(); + final static EntryState DEQUEUED_STATE = new DequeuedState(); + final static EntryState EXPIRED_STATE = new ExpiredState(); + final static EntryState NON_SUBSCRIPTION_ACQUIRED_STATE = new NonSubscriptionAcquiredState(); + + + + + AMQQueue getQueue(); + + AMQMessage getMessage(); + + long getSize(); + + boolean getDeliveredToConsumer(); + + boolean expired() throws AMQException; + + boolean isAcquired(); + + boolean acquire(); + boolean acquire(Subscription sub); + + boolean delete(); + boolean isDeleted(); + + boolean acquiredBySubscription(); + + void setDeliveredToSubscription(); + + void release(); + + String debugIdentity(); + + boolean immediateAndNotDelivered(); + + void setRedelivered(boolean b); + + Subscription getDeliveredSubscription(); + + void reject(); + + void reject(Subscription subscription); + + boolean isRejectedBy(Subscription subscription); + + void requeue(StoreContext storeContext) throws AMQException; + + void dequeue(final StoreContext storeContext) throws FailedDequeueException; + + void dispose(final StoreContext storeContext) throws MessageCleanupException; + + void restoreCredit(); + + void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException; + + boolean isQueueDeleted(); + + void addStateChangeListener(StateChangeListener listener); + boolean removeStateChangeListener(StateChangeListener listener); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java new file mode 100644 index 0000000000..d26d6af7b2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -0,0 +1,392 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.log4j.Logger; + +import java.util.Set; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.CopyOnWriteArraySet; + + +public class QueueEntryImpl implements QueueEntry +{ + + /** + * Used for debugging purposes. + */ + private static final Logger _log = Logger.getLogger(QueueEntryImpl.class); + + private final SimpleQueueEntryList _queueEntryList; + + private AMQMessage _message; + + + private Set _rejectedBy = null; + + private volatile EntryState _state = AVAILABLE_STATE; + + private static final + AtomicReferenceFieldUpdater + _stateUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, EntryState.class, "_state"); + + + private volatile Set _stateChangeListeners; + + private static final + AtomicReferenceFieldUpdater + _listenersUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, Set.class, "_stateChangeListeners"); + + + private static final + AtomicLongFieldUpdater + _entryIdUpdater = + AtomicLongFieldUpdater.newUpdater + (QueueEntryImpl.class, "_entryId"); + + + private volatile long _entryId; + + volatile QueueEntryImpl _next; + + + QueueEntryImpl(SimpleQueueEntryList queueEntryList) + { + this(queueEntryList,null,Long.MIN_VALUE); + _state = DELETED_STATE; + } + + + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) + { + _queueEntryList = queueEntryList; + _message = message; + + _entryIdUpdater.set(this, entryId); + } + + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) + { + _queueEntryList = queueEntryList; + _message = message; + } + + protected void setEntryId(long entryId) + { + _entryIdUpdater.set(this, entryId); + } + + protected long getEntryId() + { + return _entryId; + } + + public AMQQueue getQueue() + { + return _queueEntryList.getQueue(); + } + + public AMQMessage getMessage() + { + return _message; + } + + public long getSize() + { + return getMessage().getSize(); + } + + public boolean getDeliveredToConsumer() + { + return getMessage().getDeliveredToConsumer(); + } + + public boolean expired() throws AMQException + { + return getMessage().expired(getQueue()); + } + + public boolean isAcquired() + { + return _state.getState() == State.ACQUIRED; + } + + public boolean acquire() + { + return acquire(NON_SUBSCRIPTION_ACQUIRED_STATE); + } + + private boolean acquire(final EntryState state) + { + boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state); + if(acquired && _stateChangeListeners != null) + { + notifyStateChange(State.AVAILABLE, State.ACQUIRED); + } + + return acquired; + } + + public boolean acquire(Subscription sub) + { + return acquire(sub.getOwningState()); + } + + public boolean acquiredBySubscription() + { + + return (_state instanceof SubscriptionAcquiredState); + } + + public void setDeliveredToSubscription() + { + getMessage().setDeliveredToConsumer(); + } + + public void release() + { + _stateUpdater.set(this,AVAILABLE_STATE); + } + + public String debugIdentity() + { + return getMessage().debugIdentity(); + } + + + public boolean immediateAndNotDelivered() + { + return _message.immediateAndNotDelivered(); + } + + public void setRedelivered(boolean b) + { + getMessage().setRedelivered(b); + } + + public Subscription getDeliveredSubscription() + { + EntryState state = _state; + if (state instanceof SubscriptionAcquiredState) + { + return ((SubscriptionAcquiredState) state).getSubscription(); + } + else + { + return null; + } + + } + + public void reject() + { + reject(getDeliveredSubscription()); + } + + public void reject(Subscription subscription) + { + if (subscription != null) + { + if (_rejectedBy == null) + { + _rejectedBy = new HashSet(); + } + + _rejectedBy.add(subscription); + } + else + { + _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + } + } + + public boolean isRejectedBy(Subscription subscription) + { + + if (_rejectedBy != null) // We have subscriptions that rejected this message + { + return _rejectedBy.contains(subscription); + } + else // This messasge hasn't been rejected yet. + { + return false; + } + } + + + public void requeue(final StoreContext storeContext) throws AMQException + { + getQueue().requeue(storeContext, this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } + } + + public void dequeue(final StoreContext storeContext) throws FailedDequeueException + { + EntryState state = _state; + + if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) + { + getQueue().dequeue(storeContext, this); + if(_stateChangeListeners != null) + { + notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); + } + + } + + } + + private void notifyStateChange(final State oldState, final State newState) + { + for(StateChangeListener l : _stateChangeListeners) + { + l.stateChanged(this, oldState, newState); + } + } + + public void dispose(final StoreContext storeContext) throws MessageCleanupException + { + if(delete()) + { + getMessage().decrementReference(storeContext); + } + } + + public void restoreCredit() + { + EntryState state = _state; + if(state instanceof SubscriptionAcquiredState) + { + Subscription s = ((SubscriptionAcquiredState) _state).getSubscription(); + s.restoreCredit(this); + } + } + + public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + { + //if the queue is null then the message is waiting to be acked, but has been removed. + if (getQueue() != null) + { + dequeue(storeContext); + } + + dispose(storeContext); + } + + public boolean isQueueDeleted() + { + return getQueue().isDeleted(); + } + + public void addStateChangeListener(StateChangeListener listener) + { + Set listeners = _stateChangeListeners; + if(listeners == null) + { + _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet()); + listeners = _stateChangeListeners; + } + + listeners.add(listener); + } + + public boolean removeStateChangeListener(StateChangeListener listener) + { + Set listeners = _stateChangeListeners; + if(listeners != null) + { + return listeners.remove(listener); + } + + return false; + } + + + public int compareTo(final QueueEntry o) + { + QueueEntryImpl other = (QueueEntryImpl)o; + return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0; + } + + public QueueEntryImpl getNext() + { + + QueueEntryImpl next = nextNode(); + while(next != null && next.isDeleted()) + { + + final QueueEntryImpl newNext = next.nextNode(); + if(newNext != null) + { + SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext); + next = nextNode(); + } + else + { + next = null; + } + + } + return next; + } + + QueueEntryImpl nextNode() + { + return _next; + } + + public boolean isDeleted() + { + return _state == DELETED_STATE; + } + + public boolean delete() + { + EntryState state = _state; + + if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) + { + _queueEntryList.advanceHead(); + return true; + } + else + { + return false; + } + } + + public QueueEntryList getQueueEntryList() + { + return _queueEntryList; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java new file mode 100644 index 0000000000..c5c115a2d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java @@ -0,0 +1,30 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +public interface QueueEntryIterator +{ + boolean atTail(); + + QueueEntry getNode(); + + boolean advance(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java new file mode 100644 index 0000000000..313e076f61 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -0,0 +1,34 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +public interface QueueEntryList +{ + AMQQueue getQueue(); + + QueueEntry add(AMQMessage message); + + QueueEntry next(QueueEntry node); + + QueueEntryIterator iterator(); + + QueueEntry getHead(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java new file mode 100644 index 0000000000..4dbce45f67 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java @@ -0,0 +1,26 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +interface QueueEntryListFactory +{ + public QueueEntryList createQueueEntryList(AMQQueue queue); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java index f1e7c98387..959ca03c80 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -1,27 +1,27 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - - -public interface QueueNotificationListener -{ - void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 QueueNotificationListener +{ + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java new file mode 100644 index 0000000000..247402e442 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -0,0 +1,1671 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.AMQException; +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.configuration.Configured; +import org.apache.log4j.Logger; + +import javax.management.JMException; +import java.util.List; +import java.util.Set; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener +{ + private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + private final AMQShortString _name; + + /** null means shared */ + private final AMQShortString _owner; + + private final boolean _durable; + + /** If true, this queue is deleted when the last subscriber is removed */ + private final boolean _autoDelete; + + private final VirtualHost _virtualHost; + + /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ + private final ExchangeBindings _bindings = new ExchangeBindings(this); + + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + private final List _deleteTaskList = new CopyOnWriteArrayList(); + + private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); + + private final AtomicLong _atomicQueueSize = new AtomicLong(0L); + + private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); + + protected final SubscriptionList _subscriptionList = new SubscriptionList(this); + private final AtomicReference _lastSubscriptionNode = new AtomicReference(_subscriptionList.getHead()); + + private volatile Subscription _exclusiveSubscriber; + + + private final QueueEntryList _entries; + + + private final AMQQueueMBean _managedObject; + private final Executor _asyncDelivery; + private final AtomicLong _totalMessagesReceived = new AtomicLong(); + + + + /** max allowed size(KB) of a single message */ + @Configured(path = "maximumMessageSize", defaultValue = "0") + public long _maximumMessageSize; + + /** max allowed number of messages on a queue. */ + @Configured(path = "maximumMessageCount", defaultValue = "0") + public long _maximumMessageCount; + + /** max queue depth for the queue */ + @Configured(path = "maximumQueueDepth", defaultValue = "0") + public long _maximumQueueDepth; + + /** maximum message age before alerts occur */ + @Configured(path = "maximumMessageAge", defaultValue = "0") + public long _maximumMessageAge; + + /** the minimum interval between sending out consequetive alerts of the same type */ + @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") + public long _minimumAlertRepeatGap; + + + + private static final int MAX_ASYNC_DELIVERIES = 10; + + + private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); + + + private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); + private AtomicReference _asynchronousRunner = new AtomicReference(null); + private AtomicInteger _deliveredMessages = new AtomicInteger(); + + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException + { + this(name,durable,owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory()); + } + + protected SimpleAMQQueue(AMQShortString name, + boolean durable, + AMQShortString owner, + boolean autoDelete, + VirtualHost virtualHost, + QueueEntryListFactory entryListFactory) + throws AMQException + { + + if (name == null) + { + throw new IllegalArgumentException("Queue name must not be null"); + } + + if (virtualHost == null) + { + throw new IllegalArgumentException("Virtual Host must not be null"); + } + + _name = name; + _durable = durable; + _owner = owner; + _autoDelete = autoDelete; + _virtualHost = virtualHost; + _entries = entryListFactory.createQueueEntryList(this); + + _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); + + try + { + _managedObject = new AMQQueueMBean(this); + _managedObject.register(); + } + catch (JMException e) + { + throw new AMQException("AMQQueue MBean creation has failed ", e); + } + + + // This ensure that the notification checks for the configured alerts are created. + setMaximumMessageAge(_maximumMessageAge); + setMaximumMessageCount(_maximumMessageCount); + setMaximumMessageSize(_maximumMessageSize); + setMaximumQueueDepth(_maximumQueueDepth); + + } + + // ------ Getters and Setters + + public AMQShortString getName() + { + return _name; + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public AMQShortString getOwner() + { + return _owner; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + + // ------ bind and unbind + + public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + { + exchange.registerQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + } + + _bindings.addBinding(routingKey, arguments, exchange); + } + + public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + { + exchange.deregisterQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + } + + boolean removed = _bindings.remove(routingKey, arguments, exchange); + if(!removed) + { + _logger.error("Mismatch between queue bindings and exchange record of bindings"); + } + } + + + // ------ Manage Subscriptions + + public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException + { + + + if(isExclusiveSubscriber()) + { + throw new ExistingExclusiveSubscription(); + } + + if(exclusive) + { + if(getConsumerCount() != 0) + { + throw new ExistingSubscriptionPreventsExclusive(); + } + else + { + _exclusiveSubscriber = subscription; + + } + } + + + _activeSubscriberCount.incrementAndGet(); + subscription.setStateListener(this); + subscription.setLastSeenEntry(null,_entries.getHead()); + + if(!isDeleted()) + { + subscription.setQueue(this); + _subscriptionList.add(subscription); + if(isDeleted()) + { + subscription.queueDeleted(this); + } + } + else + { + // TODO + } + + + deliverAsync(subscription); + + } + + public synchronized void unregisterSubscription(final Subscription subscription) throws AMQException + { + if(subscription == null) + { + throw new NullPointerException("subscription argument is null"); + } + + boolean removed = _subscriptionList.remove(subscription); + + + + if(removed) + { + subscription.close(); + // No longer can the queue have an exclusive consumer + setExclusiveSubscriber(null); + + + QueueEntry lastSeen; + + while((lastSeen = subscription.getLastSeenEntry()) != null) + { + subscription.setLastSeenEntry(lastSeen, null); + } + + + + + // auto-delete queues must be deleted if there are no remaining subscribers + + if (_autoDelete && getConsumerCount() == 0) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Auto-deleteing queue:" + this); + } + + delete(); + + // 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 + subscription.queueDeleted(this); + } + } + + + } + + + // ------ Enqueue / Dequeue + + public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException + { + + + + incrementQueueCount(); + incrementQueueSize(message); + + _totalMessagesReceived.incrementAndGet(); + + + QueueEntry entry; + Subscription exclusiveSub = _exclusiveSubscriber; + + if(exclusiveSub != null) + { + exclusiveSub.getSendLock(); + + try + { + entry = _entries.add(message); + + deliverToSubscription(exclusiveSub, entry); + + + // where there is more than one producer there's a reasonable chance that even though there is + // no "queueing" we do not deliver because we get an interleving of _entries.add and + // deliverToSubscription between threads. Therefore have one more try. + if(!(entry.isAcquired() || entry.isDeleted())) + { + deliverToSubscription(exclusiveSub, entry); + } + } + finally + { + exclusiveSub.releaseSendLock(); + } + } + else + { + entry = _entries.add(message); + /* + + iterate over subscriptions and if any is at the end of the queue and can deliver this message, then deliver the message + + */ + SubscriptionList.SubscriptionNode node = _lastSubscriptionNode.get(); + SubscriptionList.SubscriptionNode nextNode = node.getNext(); + if(nextNode == null) + { + nextNode = _subscriptionList.getHead().getNext(); + } + while(nextNode != null) + { + if(_lastSubscriptionNode.compareAndSet(node, nextNode)) + { + break; + } + else + { + node = _lastSubscriptionNode.get(); + nextNode = node.getNext(); + if(nextNode == null) + { + nextNode = _subscriptionList.getHead().getNext(); + } + } + } + + + // always do one extra loop after we believe we've finished + // this catches the case where we *just* miss an update + int loops = 2; + + while(!(entry.isAcquired() || entry.isDeleted()) && loops != 0) + { + if(nextNode == null) + { + loops--; + nextNode = _subscriptionList.getHead(); + } + else + { + // if subscription at end, and active, offer + Subscription sub = nextNode.getSubscription(); + deliverToSubscription(sub, entry); + } + nextNode = nextNode.getNext(); + + } + } + + + if(entry.immediateAndNotDelivered()) + { + dequeue(storeContext, entry); + entry.dispose(storeContext); + } + else if(!(entry.isAcquired() || entry.isDeleted())) + { + checkSubscriptionsNotAheadOfDelivery(entry); + + deliverAsync(); + } + + + try + { + _managedObject.checkForNotification(entry.getMessage()); + } + catch (JMException e) + { + throw new AMQException("Unable to get notification from manage queue: " + e, e); + } + + + return entry; + + } + + private void deliverToSubscription(final Subscription sub, final QueueEntry entry) + throws AMQException + { + + sub.getSendLock(); + try + { + if(subscriptionReadyAndHasInterest(sub, entry) + && !sub.isSuspended()) + { + if( !sub.wouldSuspend(entry)) + { + if(!sub.isBrowser() && !entry.acquire(sub)) + { + // restore credit here that would have been taken away by wouldSuspend since we didn't manage + // to acquire the entry for this subscription + sub.restoreCredit(entry); + } + else + { + + deliverMessage(sub, entry); + + } + } + } + } + finally + { + sub.releaseSendLock(); + } + } + + protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) + { + // This method is only required for queues which mess with ordering + // Simple Queues don't :-) + } + + private void incrementQueueSize(final AMQMessage message) + { + getAtomicQueueSize().addAndGet(message.getSize()); + } + + private void incrementQueueCount() + { + getAtomicQueueCount().incrementAndGet(); + } + + private void deliverMessage(final Subscription sub, final QueueEntry entry) + throws AMQException + { + _deliveredMessages.incrementAndGet(); + sub.send(entry); + + } + + private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) + { + + // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no + // interest in. + QueueEntry node = sub.getLastSeenEntry(); + while(node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node)) ) + { + + QueueEntry newNode = _entries.next(node); + if(newNode != null) + { + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + else + { + node = null; + break; + } + + } + + + if(node == entry) + { + // If the first entry that subscription can process is the one we are trying to deliver to it, then we are + // good + return true; + } + else + { + // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing + // no-one else has updated it to something furhter on in the list + //TODO - check + //updateLastSeenEntry(sub, entry); + return false; + } + + } + + private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry) + { + QueueEntry node = sub.getLastSeenEntry(); + + if(node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) + { + do + { + if(sub.setLastSeenEntry(node,entry)) + { + return; + } + else + { + node = sub.getLastSeenEntry(); + } + } while (node != null && entry.compareTo(node) < 0); + } + + } + + public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException + { + + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards + while(subscriberIter.advance()) + { + Subscription sub = subscriberIter.getNode().getSubscription(); + + // we don't make browsers send the same stuff twice + if(!sub.isBrowser()) + { + updateLastSeenEntry(sub, entry); + } + } + + + deliverAsync(); + + + } + + public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + { + decrementQueueCount(); + decrementQueueSize(entry); + if(entry.acquiredBySubscription()) + { + _deliveredMessages.decrementAndGet(); + } + + try + { + AMQMessage msg = entry.getMessage(); + if(isDurable() && msg.isPersistent()) + { + _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); + } + //entry.dispose(storeContext); + + } + catch (MessageCleanupException e) + { + // Message was dequeued, but could not then be deleted + // though it is no longer referenced. This should be very + // rare and can be detected and cleaned up on recovery or + // done through some form of manual intervention. + _logger.error(e, e); + } + catch (AMQException e) + { + throw new FailedDequeueException(_name.toString(), e); + } + + + } + + private void decrementQueueSize(final QueueEntry entry) + { + getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); + } + + void decrementQueueCount() + { + getAtomicQueueCount().decrementAndGet(); + } + + public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException + { + /* TODO : This is wrong as the subscription may be suspended, we should instead change the state of the message + entry to resend and move back the subscription pointer. */ + + subscription.getSendLock(); + try + { + if(!subscription.isClosed()) + { + deliverMessage(subscription, entry); + return true; + } + else + { + return false; + } + } + finally + { + subscription.releaseSendLock(); + } + } + + + + + + public int getConsumerCount() + { + return _subscriptionList.size(); + } + + public int getActiveConsumerCount() + { + return _activeSubscriberCount.get(); + } + + public boolean isUnused() + { + return getConsumerCount() == 0; + } + + public boolean isEmpty() + { + return getMessageCount() == 0; + } + + public int getMessageCount() + { + return getAtomicQueueCount().get(); + } + + public long getQueueDepth() + { + return getAtomicQueueSize().get(); + } + + public int getUndeliveredMessageCount() + { + int count = getMessageCount() - _deliveredMessages.get(); + if(count < 0) + { + return 0; + } + else + { + return count; + } + } + + + public long getReceivedMessageCount() + { + return _totalMessagesReceived.get(); + } + + public long getOldestMessageArrivalTime() + { + QueueEntry entry = getOldestQueueEntry(); + return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); + } + + protected QueueEntry getOldestQueueEntry() + { + return _entries.next(_entries.getHead()); + } + + public boolean isDeleted() + { + return _deleted.get(); + } + + + + public List getMessagesOnTheQueue() + { + ArrayList entryList = new ArrayList(); + QueueEntryIterator queueListIterator = _entries.iterator(); + while(queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if(node != null && !node.isDeleted()) + { + entryList.add(node); + } + } + return entryList; + + } + + public void stateChange(Subscription sub, Subscription.State oldState, Subscription.State newState) + { + if(oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE) + { + _activeSubscriberCount.decrementAndGet(); + + } + else if(newState == Subscription.State.ACTIVE) + { + if(oldState != Subscription.State.ACTIVE) + { + _activeSubscriberCount.incrementAndGet(); + + } + deliverAsync(sub); + } + } + + public int compareTo(final AMQQueue o) + { + return _name.compareTo(o.getName()); + } + + public AtomicInteger getAtomicQueueCount() + { + return _atomicQueueCount; + } + + public AtomicLong getAtomicQueueSize() + { + return _atomicQueueSize; + } + + private boolean isExclusiveSubscriber() + { + return _exclusiveSubscriber != null; + } + + private void setExclusiveSubscriber(Subscription exclusiveSubscriber) + { + _exclusiveSubscriber = exclusiveSubscriber; + } + + public static interface QueueEntryFilter + { + public boolean accept(QueueEntry entry); + + public boolean filterComplete(); + } + + + + public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) + { + return getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return messageId >= fromMessageId && messageId <= toMessageId; + } + + public boolean filterComplete() + { + return false; + } + }); + } + + public QueueEntry getMessageOnTheQueue(final long messageId) + { + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + private boolean _complete; + + public boolean accept(QueueEntry entry) + { + _complete = entry.getMessage().getMessageId() == messageId; + return _complete; + } + + public boolean filterComplete() + { + return _complete; + } + }); + return entries.isEmpty() ? null : entries.get(0); + } + + + public List getMessagesOnTheQueue(QueueEntryFilter filter) + { + ArrayList entryList = new ArrayList(); + QueueEntryIterator queueListIterator = _entries.iterator(); + while(queueListIterator.advance() && !filter.filterComplete()) + { + QueueEntry node = queueListIterator.getNode(); + if(!node.isDeleted() && filter.accept(node)) + { + entryList.add(node); + } + } + return entryList; + + } + + + public void moveMessagesToAnotherQueue(final long fromMessageId, + final long toMessageId, + String queueName, + StoreContext storeContext) + { + + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + MessageStore store = getVirtualHost().getMessageStore(); + + + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return (messageId >= fromMessageId) + && (messageId <= toMessageId) + && entry.acquire(); + } + + public boolean filterComplete() + { + return false; + } + }); + + + try + { + store.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : entries) + { + AMQMessage message = entry.getMessage(); + + if(message.isPersistent() && toQueue.isDurable()) + { + store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + } + // dequeue does not decrement the refence count + entry.dequeue(storeContext); + } + + // Commit and flush the move transcations. + try + { + store.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + } + catch (AMQException e) + { + try + { + store.abortTran(storeContext); + } + catch (AMQException rollbackEx) + { + _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); + } + throw new RuntimeException(e); + } + + try + { + for (QueueEntry entry : entries) + { + toQueue.enqueue(storeContext, entry.getMessage()); + + } + } + catch (MessageCleanupException e) + { + throw new RuntimeException(e); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + + } + + public void copyMessagesToAnotherQueue(final long fromMessageId, + final long toMessageId, + String queueName, + final StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + MessageStore store = getVirtualHost().getMessageStore(); + + + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + if((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + if(!entry.isDeleted()) + { + return entry.getMessage().incrementReference(); + } + } + + return false; + } + + public boolean filterComplete() + { + return false; + } + }); + + try + { + store.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : entries) + { + AMQMessage message = entry.getMessage(); + + if(message.isReferenced() && message.isPersistent() && toQueue.isDurable()) + { + store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + } + } + + // Commit and flush the move transcations. + try + { + store.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + } + catch (AMQException e) + { + try + { + store.abortTran(storeContext); + } + catch (AMQException rollbackEx) + { + _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); + } + throw new RuntimeException(e); + } + + try + { + for (QueueEntry entry : entries) + { + if(entry.getMessage().isReferenced()) + { + toQueue.enqueue(storeContext, entry.getMessage()); + } + } + } + catch (MessageCleanupException e) + { + throw new RuntimeException(e); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + + } + + public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + { + + try + { + QueueEntryIterator queueListIterator = _entries.iterator(); + + + while(queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + + final long messageId = node.getMessage().getMessageId(); + + if((messageId >= fromMessageId) + && (messageId <= toMessageId) + && !node.isDeleted() + && node.acquire()) + { + node.discard(storeContext); + } + + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + // ------ Management functions + + + public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + { + QueueEntryIterator queueListIterator = _entries.iterator(); + boolean noDeletes = true; + + while(noDeletes && queueListIterator.advance() ) + { + QueueEntry node = queueListIterator.getNode(); + if(!node.isDeleted() && node.acquire()) + { + node.discard(storeContext); + noDeletes = false; + } + + } + } + + public long clearQueue(StoreContext storeContext) throws AMQException + { + + QueueEntryIterator queueListIterator = _entries.iterator(); + long count = 0; + + while(queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if(!node.isDeleted() && node.acquire()) + { + node.discard(storeContext); + count++; + } + + } + return count; + + } + + + public void addQueueDeleteTask(final Task task) + { + _deleteTaskList.add(task); + } + + public int delete() throws AMQException + { + if (!_deleted.getAndSet(true)) + { + + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); + + while (subscriptionIter.advance()) + { + Subscription s = subscriptionIter.getNode().getSubscription(); + if(s != null) + { + s.queueDeleted(this); + } + } + + _bindings.deregister(); + _virtualHost.getQueueRegistry().unregisterQueue(_name); + + + _managedObject.unregister(); + for (Task task : _deleteTaskList) + { + task.doTask(this); + } + + _deleteTaskList.clear(); + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + } + return getMessageCount(); + + } + + + public void deliverAsync() + { + _stateChangeCount.incrementAndGet(); + + Runner runner = new Runner(); + + if(_asynchronousRunner.compareAndSet(null,runner)) + { + _asyncDelivery.execute(runner); + } + } + + public void deliverAsync(Subscription sub) + { + _asyncDelivery.execute(new SubFlushRunner(sub)); + } + + private class Runner implements ReadWriteRunnable + { + public void run() + { + try + { + processQueue(this); + } + catch (AMQException e) + { + _logger.error(e); + } + + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } + } + + + private class SubFlushRunner implements ReadWriteRunnable + { + private final Subscription _sub; + + + public SubFlushRunner(Subscription sub) + { + _sub = sub; + } + + public void run() + { + boolean complete = false; + try + { + complete = flushSubscription(_sub, MAX_ASYNC_DELIVERIES); + + } + catch (AMQException e) + { + _logger.error(e); + } + if(!complete && !_sub.isSuspended()) + { + _asyncDelivery.execute(this); + } + + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } + } + + public void flushSubscription(Subscription sub) throws AMQException + { + flushSubscription(sub, Long.MAX_VALUE); + } + + public boolean flushSubscription(Subscription sub, long deliveries) throws AMQException + { + boolean atTail = false; + boolean advanced; + + while(!sub.isSuspended() && !atTail && deliveries != 0) + { + + advanced = false; + sub.getSendLock(); + try + { + if(sub.isActive()) + { + QueueEntry node = moveSubscriptionToNextNode(sub); + if(!(node.isAcquired() || node.isDeleted())) + { + if(!sub.isSuspended()) + { + if(sub.hasInterest(node)) + { + if(!sub.wouldSuspend(node)) + { + if(!sub.isBrowser() && !node.acquire(sub)) + { + sub.restoreCredit(node); + + } + else + { + deliveries--; + deliverMessage(sub, node); + + if(sub.isBrowser()) + { + QueueEntry newNode = _entries.next(node); + + if(newNode != null) + { + advanced = true; + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + } + } + + } + else + { + break; + } + } + else + { + // this subscription is not interested in this node so we can skip over it + QueueEntry newNode = _entries.next(node); + if(newNode != null) + { + sub.setLastSeenEntry(node, newNode); + } + } + } + + } + atTail = (_entries.next(node) == null) && !advanced; + + } + } + finally + { + sub.releaseSendLock(); + } + + } + + // if there's (potentially) more than one subscription the others will potentially not have been advanced to the + // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc + // which would give us memory "leak". + + if(!isExclusiveSubscriber()) + { + advanceAllSubscriptions(); + } + + if(atTail && sub.isAutoClose()) + { + unregisterSubscription(sub); + + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + } + + return atTail; + } + + protected void advanceAllSubscriptions() throws AMQException + { + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + while(subscriberIter.advance()) + { + SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); + Subscription sub = subNode.getSubscription(); + moveSubscriptionToNextNode(sub); + } + } + + private QueueEntry moveSubscriptionToNextNode(final Subscription sub) + throws AMQException + { + QueueEntry node = sub.getLastSeenEntry(); + + while(node != null && (node.isAcquired() || node.isDeleted() || node.expired())) + { + if(!node.isAcquired() && !node.isDeleted() && node.expired()) + { + if(node.acquire()) + { + final StoreContext reapingStoreContext = new StoreContext(); + node.discard(reapingStoreContext); + } + } + QueueEntry newNode = _entries.next(node); + if(newNode != null) + { + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + else + { + break; + } + + } + return node; + } + + + private void processQueue(Runnable runner) throws AMQException + { + long stateChangeCount; + long previousStateChangeCount = Long.MIN_VALUE; + boolean deliveryIncomplete = true; + + int extraLoops = 1; + int deliveries = MAX_ASYNC_DELIVERIES; + + _asynchronousRunner.compareAndSet(runner,null); + + while(deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete ) && _asynchronousRunner.compareAndSet(null,runner)) + { + // we want to have one extra loop after every subscription has reached the point where it cannot move + // further, just in case the advance of one subscription in the last loop allows a different subscription to + // move forward in the next iteration + + if(previousStateChangeCount != stateChangeCount) + { + extraLoops = 1; + } + + previousStateChangeCount = stateChangeCount; + deliveryIncomplete = _subscriptionList.size() != 0; + boolean done = true; + + + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); + //iterate over the subscribers and try to advance their pointer + while(subscriptionIter.advance()) + { + Subscription sub = subscriptionIter.getNode().getSubscription(); + if(sub != null) + { + sub.getSendLock(); + try + { + QueueEntry node = moveSubscriptionToNextNode(sub); + + if(node != null && sub.isActive()) + { + boolean advanced = false; + boolean subActive = false; + + if(!(node.isAcquired() || node.isDeleted())) + { + if(!sub.isSuspended()) + { + subActive = true; + if(sub.hasInterest(node)) + { + if(!sub.wouldSuspend(node)) + { + if(!sub.isBrowser() && !node.acquire(sub)) + { + sub.restoreCredit(node); + + } + else + { + deliverMessage(sub, node); + deliveries--; + + if(sub.isBrowser()) + { + QueueEntry newNode = _entries.next(node); + + if(newNode != null) + { + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + advanced = true; + } + + + } + } + done = false; + } + else + { + node.addStateChangeListener(new QueueEntryListener(sub,node)); + } + } + else + { + // this subscription is not interested in this node so we can skip over it + QueueEntry newNode = _entries.next(node); + if(newNode != null) + { + sub.setLastSeenEntry(node, newNode); + } + } + } + } + final boolean atTail = (_entries.next(node) == null); + + done = done && (!subActive || atTail); + + if(atTail && !advanced && sub.isAutoClose()) + { + unregisterSubscription(sub); + + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + + } + + } + } + finally + { + sub.releaseSendLock(); + } + } + if(done) + { + if(extraLoops == 0) + { + deliveryIncomplete = false; + } + else + { + extraLoops--; + } + } + else + { + extraLoops = 1; + } + } + + + + _asynchronousRunner.set(null); + } + + // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit + // therefore we should schedule this runner again (unless someone beats us to it :-) ). + if(deliveries == 0 && _asynchronousRunner.compareAndSet(null,runner)) + { + _asyncDelivery.execute(runner); + } + } + + + public void removeExpiredIfNoSubscribers() throws AMQException + { + + final StoreContext storeContext = new StoreContext(); + + QueueEntryIterator queueListIterator = _entries.iterator(); + + while(queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if(!node.isDeleted() && node.expired() && node.acquire()) + { + + node.discard(storeContext); + } + + } + + } + + + public long getMinimumAlertRepeatGap() + { + return _minimumAlertRepeatGap; + } + + public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) + { + _minimumAlertRepeatGap = minimumAlertRepeatGap; + } + + public long getMaximumMessageAge() + { + return _maximumMessageAge; + } + + public void setMaximumMessageAge(long maximumMessageAge) + { + _maximumMessageAge = maximumMessageAge; + if(maximumMessageAge == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT); + } + } + + public long getMaximumMessageCount() + { + return _maximumMessageCount; + } + + public void setMaximumMessageCount(final long maximumMessageCount) + { + _maximumMessageCount = maximumMessageCount; + if(maximumMessageCount == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); + } + + + + } + + public long getMaximumQueueDepth() + { + return _maximumQueueDepth; + } + + // Sets the queue depth, the max queue size + public void setMaximumQueueDepth(final long maximumQueueDepth) + { + _maximumQueueDepth = maximumQueueDepth; + if(maximumQueueDepth == 0L) + { + _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT); + } + + } + + public long getMaximumMessageSize() + { + return _maximumMessageSize; + } + + public void setMaximumMessageSize(final long maximumMessageSize) + { + _maximumMessageSize = maximumMessageSize; + if(maximumMessageSize == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT); + } + } + + + public Set getNotificationChecks() + { + return _notificationChecks; + } + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + private final class QueueEntryListener implements QueueEntry.StateChangeListener + { + private final QueueEntry _entry; + private final Subscription _sub; + + public QueueEntryListener(final Subscription sub, final QueueEntry entry) + { + _entry = entry; + _sub = sub; + } + + public boolean equals(Object o) + { + return _entry == ((QueueEntryListener)o)._entry && _sub == ((QueueEntryListener)o)._sub; + } + + public int hashCode() + { + return System.identityHashCode(_entry) ^ System.identityHashCode(_sub); + } + + public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState) + { + entry.removeStateChangeListener(this); + deliverAsync(_sub); + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java new file mode 100644 index 0000000000..a46c5ae2e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -0,0 +1,178 @@ +package org.apache.qpid.server.queue; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class SimpleQueueEntryList implements QueueEntryList +{ + private final QueueEntryImpl _head; + + private volatile QueueEntryImpl _tail; + + static final AtomicReferenceFieldUpdater + _tailUpdater = + AtomicReferenceFieldUpdater.newUpdater + (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail"); + + + private final AMQQueue _queue; + + static final AtomicReferenceFieldUpdater + _nextUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); + + + + + + public SimpleQueueEntryList(AMQQueue queue) + { + _queue = queue; + _head = new QueueEntryImpl(this); + _tail = _head; + } + + void advanceHead() + { + QueueEntryImpl head = _head.nextNode(); + while(head._next != null && head.isDeleted()) + { + + final QueueEntryImpl newhead = head.nextNode(); + if(newhead != null) + { + _nextUpdater.compareAndSet(_head,head, newhead); + } + head = _head.nextNode(); + } + } + + + public AMQQueue getQueue() + { + return _queue; + } + + + public QueueEntry add(AMQMessage message) + { + QueueEntryImpl node = new QueueEntryImpl(this, message); + for (;;) + { + QueueEntryImpl tail = _tail; + QueueEntryImpl next = tail.nextNode(); + if (tail == _tail) + { + if (next == null) + { + node.setEntryId(tail.getEntryId()+1); + if (_nextUpdater.compareAndSet(tail, null, node)) + { + _tailUpdater.compareAndSet(this, tail, node); + + return node; + } + } + else + { + _tailUpdater.compareAndSet(this,tail, next); + } + } + } + } + + public QueueEntry next(QueueEntry node) + { + return ((QueueEntryImpl)node).getNext(); + } + + + public class QueueEntryIteratorImpl implements QueueEntryIterator + { + + private QueueEntryImpl _lastNode; + + QueueEntryIteratorImpl(QueueEntryImpl startNode) + { + _lastNode = startNode; + } + + + public boolean atTail() + { + return _lastNode.nextNode() == null; + } + + public QueueEntry getNode() + { + + return _lastNode; + + } + + public boolean advance() + { + + if(!atTail()) + { + QueueEntryImpl nextNode = _lastNode.nextNode(); + while(nextNode.isDeleted() && nextNode.nextNode() != null) + { + nextNode = nextNode.nextNode(); + } + _lastNode = nextNode; + return true; + + } + else + { + return false; + } + + } + + } + + + public QueueEntryIterator iterator() + { + return new QueueEntryIteratorImpl(_head); + } + + + public QueueEntry getHead() + { + return _head; + } + + static class Factory implements QueueEntryListFactory + { + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new SimpleQueueEntryList(queue); + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java deleted file mode 100644 index 96ce6743ec..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.Queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; - -public interface Subscription -{ - void send(QueueEntry msg, AMQQueue queue) throws AMQException; - - boolean isSuspended(); - - void queueDeleted(AMQQueue queue) throws AMQException; - - boolean filtersMessages(); - - boolean hasInterest(QueueEntry msg); - - Queue getPreDeliveryQueue(); - - Queue getResendQueue(); - - Queue getNextQueue(Queue messages); - - void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst); - - void close(); - - boolean isClosed(); - - boolean isBrowser(); - - boolean wouldSuspend(QueueEntry msg); - - void addToResendQueue(QueueEntry msg); - - Object getSendLock(); - - AMQChannel getChannel(); - - void start(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java deleted file mode 100644 index 917f7c4e97..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -/** - * 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, AMQShortString consumerTag, boolean acks, - FieldTable filters, boolean noLocal, AMQQueue queue) throws AMQException; - - - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) - throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java deleted file mode 100644 index 05cd461582..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ /dev/null @@ -1,680 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.Queue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.filter.FilterManager; -import org.apache.qpid.server.filter.FilterManagerFactory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import org.apache.qpid.util.MessageQueue; -import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize; - -/** - * 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 _suspensionlogger = Logger.getLogger("Suspension"); - private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); - - public final AMQChannel channel; - - public final AMQProtocolSession protocolSession; - - public final AMQShortString consumerTag; - - private final Object _sessionKey; - - private MessageQueue _messages; - - private Queue _resendQueue; - - private final boolean _noLocal; - - /** True if messages need to be acknowledged */ - private final boolean _acks; - private FilterManager _filters; - private final boolean _isBrowser; - private final Boolean _autoClose; - private boolean _sentClose = false; - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - private AMQQueue _queue; - private final AtomicBoolean _sendLock = new AtomicBoolean(false); - - - public static class Factory implements SubscriptionFactory - { - public Subscription createSubscription(int channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, - boolean noLocal, AMQQueue queue) throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal, queue); - } - - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag) - throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false, null); - } - } - - public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks) - throws AMQException - { - this(channelId, protocolSession, consumerTag, acks, null, false, null); - } - - public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, - boolean noLocal, AMQQueue queue) - throws AMQException - { - AMQChannel channel = protocolSession.getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); - } - - this.channel = channel; - this.protocolSession = protocolSession; - this.consumerTag = consumerTag; - _sessionKey = protocolSession.getKey(); - _acks = acks; - _noLocal = noLocal; - _queue = queue; - - _filters = FilterManagerFactory.createManager(filters); - - - if (_filters != null) - { - Object isBrowser = filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); - if (isBrowser != null) - { - _isBrowser = (Boolean) isBrowser; - } - else - { - _isBrowser = false; - } - } - else - { - _isBrowser = false; - } - - - if (_filters != null) - { - Object autoClose = filters.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); - if (autoClose != null) - { - _autoClose = (Boolean) autoClose; - } - else - { - _autoClose = false; - } - } - else - { - _autoClose = false; - } - - - if (filtersMessages()) - { - _messages = new ConcurrentLinkedMessageQueueAtomicSize(); - } - else - { - // Reference the DeliveryManager - _messages = null; - } - } - - - public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, - AMQShortString 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. - * - * @param psc The subscriptionImpl to compare - * - * @return equality - */ - 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() - { - String subscriber = "[channel=" + channel + - ", consumerTag=" + consumerTag + - ", session=" + protocolSession.getKey() + - ", resendQueue=" + (_resendQueue != null); - - if (_resendQueue != null) - { - subscriber += ", resendSize=" + _resendQueue.size(); - } - - - return subscriber + "]"; - } - - /** - * 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 The message to send - * @param queue the Queue it has been sent from - * - * @throws AMQException - */ - public void send(QueueEntry msg, AMQQueue queue) throws AMQException - { - if (msg != null) - { - if (_isBrowser) - { - sendToBrowser(msg, queue); - } - else - { - sendToConsumer(channel.getStoreContext(), msg, queue); - } - } - else - { - _logger.error("Attempt to send Null message", new NullPointerException()); - } - } - - private void sendToBrowser(QueueEntry msg, AMQQueue queue) throws AMQException - { - // We don't decrement the reference here as we don't want to consume the message - // but we do want to send it to the client. - - synchronized (channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (_sendLock.get()) - { - _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!"); - } - - protocolSession.getProtocolOutputConverter().writeDeliver(msg.getMessage(), channel.getChannelId(), deliveryTag, consumerTag); - } - } - - private void sendToConsumer(StoreContext storeContext, QueueEntry entry, AMQQueue queue) - throws AMQException - { - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - final AMQMessage message = entry.getMessage(); - - if (!_acks) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("No ack mode so dequeuing message immediately: " + message.getMessageId()); - } - queue.dequeue(storeContext, entry); - } - - final ProtocolOutputConverter outputConverter = protocolSession.getProtocolOutputConverter(); - final int channelId = channel.getChannelId(); - - synchronized (channel) - { - final long deliveryTag = channel.getNextDeliveryTag(); - - - if (_acks) - { - channel.addUnacknowledgedMessage(entry, deliveryTag, consumerTag); - } - - outputConverter.writeDeliver(message, channelId, deliveryTag, consumerTag); - - - } - if (!_acks) - { - message.decrementReference(storeContext); - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - entry.setDeliveredToConsumer(); - } - } - - public boolean isSuspended() - { -// if (_suspensionlogger.isInfoEnabled()) -// { -// if (channel.isSuspended()) -// { -// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") channel's is susupended"); -// } -// if (_sendLock.get()) -// { -// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") has sendLock set so closing."); -// } -// } - return channel.isSuspended() || _sendLock.get(); - } - - /** - * Callback indicating that a queue has been deleted. - * - * @param queue The queue to delete - */ - public void queueDeleted(AMQQueue queue) throws AMQException - { - channel.queueDeleted(queue); - } - - public boolean filtersMessages() - { - return _filters != null || _noLocal; - } - - public boolean hasInterest(QueueEntry entry) - { - //check that the message hasn't been rejected - if (entry.isRejectedBy(this)) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); - } -// return false; - } - - - - //todo - client id should be recoreded and this test removed but handled below - if (_noLocal) - { - - final AMQProtocolSession publisher = entry.getMessage().getPublisher(); - if(publisher != null) - - { - // We don't want local messages so check to see if message is one we sent - Object localInstance; - Object msgInstance; - - if ((protocolSession.getClientProperties() != null) && - (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) - { - - if ((publisher.getClientProperties() != null) && - (msgInstance = publisher.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) - { - if (localInstance == msgInstance || localInstance.equals(msgInstance)) - { - // if (_logger.isTraceEnabled()) - // { - // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + - // msg.debugIdentity() + ")"); - // } - return false; - } - } - } - else - { - - localInstance = protocolSession.getClientIdentifier(); - //todo - client id should be recoreded and this test removed but handled here - - msgInstance = publisher.getClientIdentifier(); - if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance))) - { - // if (_logger.isTraceEnabled()) - // { - // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" + - // msg.debugIdentity() + ")"); - // } - return false; - } - } - - } - } - - - return checkFilters(entry); - - } - - private String id = String.valueOf(System.identityHashCode(this)); - - private String debugIdentity() - { - return id; - } - - private boolean checkFilters(QueueEntry msg) - { - return (_filters == null) || _filters.allAllow(msg.getMessage()); - } - - public Queue getPreDeliveryQueue() - { - return _messages; - } - - public void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst) - { - if (_messages != null) - { - if (deliverFirst) - { - _messages.pushHead(msg); - } - else - { - _messages.offer(msg); - } - } - } - - private boolean isAutoClose() - { - return _autoClose; - } - - public void close() - { - boolean closed = false; - synchronized (_sendLock) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Setting SendLock true:" + debugIdentity()); - } - - closed = _sendLock.getAndSet(true); - } - - if (closed) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Called close() on a closed subscription"); - } - - return; - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing subscription (" + debugIdentity() + "):" + this); - } - - if (_resendQueue != null && !_resendQueue.isEmpty()) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Requeuing closing subscription (" + debugIdentity() + "):" + this); - } - requeue(); - } - - //remove references in PDQ - if (_messages != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Clearing PDQ (" + debugIdentity() + "):" + this); - } - - _messages.clear(); - } - } - - private void autoclose() - { - close(); - - if (_autoClose && !_sentClose) - { - _logger.info("Closing autoclose subscription (" + debugIdentity() + "):" + this); - - boolean unregisteredOK = false; - try - { - unregisteredOK = channel.unsubscribeConsumer(protocolSession, consumerTag); - } - catch (AMQException e) - { - // Occurs if we cannot find the subscriber in the channel with protocolSession and consumerTag. - _logger.info("Unable to UnsubscribeConsumer :" + consumerTag +" so not going to send CancelOK."); - } - - if (unregisteredOK) - { - ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag); - _sentClose = true; - } - - } - } - - private void requeue() - { - if (_queue != null) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Requeuing :" + _resendQueue.size() + " messages"); - } - - while (!_resendQueue.isEmpty()) - { - QueueEntry resent = _resendQueue.poll(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Removed for resending:" + resent.debugIdentity()); - } - - resent.release(); - _queue.subscriberHasPendingResend(false, this, resent); - - try - { - channel.getTransactionalContext().deliver(resent, true); - } - catch (AMQException e) - { - _logger.error("MESSAGE LOSS : Unable to re-deliver messages", e); - } - } - - if (!_resendQueue.isEmpty()) - { - _logger.error("[MESSAGES LOST]Unable to re-deliver messages as queue is null."); - } - - _queue.subscriberHasPendingResend(false, this, null); - } - else - { - if (!_resendQueue.isEmpty()) - { - _logger.error("Unable to re-deliver messages as queue is null."); - } - } - - // Clear the messages - _resendQueue = null; - } - - - public boolean isClosed() - { - return _sendLock.get(); // This rather than _close is used to signify the subscriber is now closed. - } - - public boolean isBrowser() - { - return _isBrowser; - } - - public boolean wouldSuspend(QueueEntry msg) - { - return _acks && channel.wouldSuspend(msg.getMessage()); - } - - public Queue getResendQueue() - { - if (_resendQueue == null) - { - _resendQueue = new ConcurrentLinkedQueueAtomicSize(); - } - return _resendQueue; - } - - - public Queue getNextQueue(Queue messages) - { - if (_resendQueue != null && !_resendQueue.isEmpty()) - { - return _resendQueue; - } - - if (filtersMessages()) - { - if (isAutoClose()) - { - if (_messages.isEmpty()) - { - autoclose(); - return null; - } - } - return _messages; - } - else // we want the DM queue - { - return messages; - } - } - - public void addToResendQueue(QueueEntry msg) - { - // add to our resend queue - getResendQueue().add(msg); - - // Mark Queue has having content. - if (_queue == null) - { - _logger.error("Queue is null won't be able to resend messages"); - } - else - { - _queue.subscriberHasPendingResend(true, this, msg); - } - } - - public Object getSendLock() - { - return _sendLock; - } - - public AMQChannel getChannel() - { - return channel; - } - - public void start() - { - //Check to see if we need to autoclose - if (filtersMessages()) - { - if (isAutoClose()) - { - if (_messages.isEmpty()) - { - autoclose(); - } - } - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java deleted file mode 100644 index bc17bcca9c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; - -/** - * Abstraction of actor that will determine the subscriber to whom - * a message will be sent. - */ -public interface SubscriptionManager -{ - public List getSubscriptions(); - public boolean hasActiveSubscribers(); - public Subscription nextSubscriber(QueueEntry entry); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java deleted file mode 100644 index 882efd380d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.List; -import java.util.ListIterator; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; - -/** 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; - - private final Object _changeLock = new Object(); - private volatile boolean _exclusive; - - - /** Accessor for unit tests. */ - int getCurrentSubscriber() - { - return _currentSubscriber; - } - - public void addSubscriber(Subscription subscription) - { - synchronized (_changeLock) - { - _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) - { - // TODO: possibly need O(1) operation here. - - Subscription sub = null; - synchronized (_changeLock) - { - int subIndex = _subscriptions.indexOf(subscription); - - if (subIndex != -1) - { - //we can't just return the passed in subscription as it is a new object - // and doesn't contain the stored state we need. - //NOTE while this may be removed now anyone with an iterator will still have it in the list!! - sub = _subscriptions.remove(subIndex); - } - else - { - _log.error("Unable to remove from index(" + subIndex + ")subscription:" + subscription); - } - } - if (sub != null) - { - return sub; - } - 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(QueueEntry msg) - { - - - try - { - final Subscription result = nextSubscriberImpl(msg); - if (result == null) - { - _currentSubscriber = 0; - return nextSubscriberImpl(msg); - } - else - { - return result; - } - } - catch (IndexOutOfBoundsException e) - { - _currentSubscriber = 0; - return nextSubscriber(msg); - } - } - - private Subscription nextSubscriberImpl(QueueEntry msg) - { - if(_exclusive) - { - try - { - Subscription subscription = _subscriptions.get(0); - subscriberScanned(); - - if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) - { - if (subscription.hasInterest(msg)) - { - // if the queue is not empty then this client is ready to receive a message. - //FIXME the queue could be full of sent messages. - // Either need to clean all PDQs after sending a message - // OR have a clean up thread that runs the PDQs expunging the messages. - if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) - { - return subscription; - } - } - } - } - catch(IndexOutOfBoundsException e) - { - } - return null; - } - else - { - if (_subscriptions.isEmpty()) - { - return null; - } - final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); - while (iterator.hasNext()) - { - Subscription subscription = iterator.next(); - ++_currentSubscriber; - subscriberScanned(); - - if (!(subscription.isSuspended() || subscription.wouldSuspend(msg))) - { - if (subscription.hasInterest(msg)) - { - // if the queue is not empty then this client is ready to receive a message. - //FIXME the queue could be full of sent messages. - // Either need to clean all PDQs after sending a message - // OR have a clean up thread that runs the PDQs expunging the messages. - if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty()) - { - return subscription; - } - } - } - } - - return null; - } - } - - /** Overridden in test classes. */ - protected void subscriberScanned() - { - } - - public boolean isEmpty() - { - return _subscriptions.isEmpty(); - } - - public List getSubscriptions() - { - return _subscriptions; - } - - 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(); - } - - - public Object getChangeLock() - { - return _changeLock; - } - - public void setExclusive(final boolean exclusive) - { - _exclusive = exclusive; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 373a64e2eb..3ed8b0e55c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -26,7 +26,6 @@ import java.util.LinkedList; import java.util.List; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ContentChunk; @@ -48,29 +47,35 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle private final MessageStore _messageStore; + private final Long _messageId; private long _arrivalTime; - - public WeakReferenceMessageHandle(MessageStore messageStore) + public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore) { + _messageId = messageId; _messageStore = messageStore; } - public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException + public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException { ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); if (chb == null) { - MessageMetaData mmd = loadMessageMetaData(context, messageId); + MessageMetaData mmd = loadMessageMetaData(context); chb = mmd.getContentHeaderBody(); } return chb; } - private MessageMetaData loadMessageMetaData(StoreContext context, Long messageId) + public Long getMessageId() + { + return _messageId; + } + + private MessageMetaData loadMessageMetaData(StoreContext context) throws AMQException { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); + MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); populateFromMessageMetaData(mmd); return mmd; } @@ -82,11 +87,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); } - public int getBodyCount(StoreContext context, Long messageId) throws AMQException + public int getBodyCount(StoreContext context) throws AMQException { if (_contentBodies == null) { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId); + MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); int chunkCount = mmd.getContentChunkCount(); _contentBodies = new ArrayList>(chunkCount); for (int i = 0; i < chunkCount; i++) @@ -97,12 +102,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle return _contentBodies.size(); } - public long getBodySize(StoreContext context, Long messageId) throws AMQException + public long getBodySize(StoreContext context) throws AMQException { - return getContentHeaderBody(context, messageId).bodySize; + return getContentHeaderBody(context).bodySize; } - public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException + public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException { if (index > _contentBodies.size() - 1) { @@ -113,7 +118,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle ContentChunk cb = wr.get(); if (cb == null) { - cb = _messageStore.getContentBodyChunk(context, messageId, index); + cb = _messageStore.getContentBodyChunk(context, _messageId, index); _contentBodies.set(index, new WeakReference(cb)); } return cb; @@ -123,12 +128,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * Content bodies are set before the publish and header frames * * @param storeContext - * @param messageId * @param contentChunk * @param isLastContentBody * @throws AMQException */ - public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException { if (_contentBodies == null && isLastContentBody) { @@ -142,16 +146,16 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle } } _contentBodies.add(new WeakReference(contentChunk)); - _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, + _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, contentChunk, isLastContentBody); } - public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException + public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException { MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); if (bpb == null) { - MessageMetaData mmd = loadMessageMetaData(context, messageId); + MessageMetaData mmd = loadMessageMetaData(context); bpb = mmd.getMessagePublishInfo(); } @@ -168,12 +172,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle _redelivered = redelivered; } - public boolean isPersistent(StoreContext context, Long messageId) throws AMQException + public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(context, messageId); - return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + return true; } /** @@ -183,7 +184,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle * @param contentHeaderBody * @throws AMQException */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo publishBody, + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody) throws AMQException { @@ -199,24 +200,15 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); - _messageStore.storeMessageMetaData(storeContext, messageId, mmd); + _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); - populateFromMessageMetaData(mmd); - } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - _messageStore.removeMessage(storeContext, messageId); - } - - public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException - { - _messageStore.enqueueMessage(storeContext, queue.getName(), messageId); + populateFromMessageMetaData(mmd); } - public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException + public void removeMessage(StoreContext storeContext) throws AMQException { - _messageStore.dequeueMessage(storeContext, queue.getName(), messageId); + _messageStore.removeMessage(storeContext, _messageId); } public long getArrivalTime() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java deleted file mode 100644 index 6c71571807..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public interface WeightedSubscriptionManager extends SubscriptionManager -{ - public int getWeight(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 455983c6d8..d0dcd051f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -94,7 +94,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { try { - _instanceMap.get(instanceID).close(); + IApplicationRegistry instance = _instanceMap.get(instanceID); + if(instance != null) + { + instance.close(); + } } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 748e33ba7a..fef958000a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -61,11 +61,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry private PluginManager _pluginManager; - public ConfigurationFileApplicationRegistry(Configuration configuration) - { - super(configuration); - } - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { super(config(configurationURL)); @@ -81,7 +76,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - public static final Configuration config(File url) throws ConfigurationException + 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 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java index 5d439a99eb..00757a4f8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java @@ -1,37 +1,37 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; - -public enum Permission -{ - CONSUME, - PUBLISH, - CREATE, - ACCESS, - BIND, - UNBIND, - DELETE, - PURGE -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +public enum Permission +{ + CONSUME, + PUBLISH, + CREATE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 126ff22d69..9b784069dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -28,13 +28,9 @@ import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.access.Permission; import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; public class AllowAll implements ACLPlugin { - - private static final Logger _logger = ACLManager.getLogger(); - public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) { if (ACLManager.getLogger().isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index bd980c696c..cc22569d77 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -1,23 +1,3 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ package org.apache.qpid.server.store; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -25,7 +5,7 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; - +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.server.txn.TransactionalContext; @@ -41,7 +21,6 @@ import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import java.io.File; -import java.io.ByteArrayInputStream; import java.sql.DriverManager; import java.sql.Driver; import java.sql.Connection; @@ -60,6 +39,26 @@ import java.util.HashMap; import java.util.TreeMap; +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ public class DerbyMessageStore implements MessageStore { @@ -68,7 +67,7 @@ public class DerbyMessageStore implements MessageStore private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; - private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; + private static final String DERBY_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION"; @@ -92,39 +91,6 @@ public class DerbyMessageStore implements MessageStore private String _connectionURL; - - private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; - private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; - private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; - private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; - private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; - private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; - private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; - private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; - private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; - private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; - private static final String SELECT_FROM_BINDINGS = - "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; - private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; - private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; - private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; - private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; - private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; - private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; - private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; - private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; - private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; - private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; - private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; - private static final String SELECT_FROM_MESSAGE_META_DATA = - "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String SELECT_FROM_MESSAGE_CONTENT = - "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; - private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; - private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; - - private enum State { INITIAL, @@ -163,6 +129,10 @@ public class DerbyMessageStore implements MessageStore createOrOpenDatabase(databasePath); + + + + // this recovers durable queues and persistent messages recover(); @@ -175,7 +145,7 @@ public class DerbyMessageStore implements MessageStore { if(DRIVER_CLASS == null) { - DRIVER_CLASS = (Class) Class.forName(SQL_DRIVER_NAME); + DRIVER_CLASS = (Class) Class.forName(DERBY_DRIVER_NAME); } } @@ -193,7 +163,7 @@ public class DerbyMessageStore implements MessageStore createMessageMetaDataTable(conn); createMessageContentTable(conn); - conn.close(); + } @@ -204,10 +174,10 @@ public class DerbyMessageStore implements MessageStore { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_DB_VERSION_TABLE); + stmt.execute("CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"); stmt.close(); - PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); + PreparedStatement pstmt = conn.prepareStatement("INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"); pstmt.setInt(1, DB_VERSION); pstmt.execute(); pstmt.close(); @@ -221,8 +191,8 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(EXCHANGE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - - stmt.execute(CREATE_EXCHANGE_TABLE); + + stmt.execute("CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"); stmt.close(); } } @@ -232,7 +202,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_TABLE); + stmt.execute("CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"); stmt.close(); } } @@ -242,7 +212,8 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(BINDINGS_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_BINDINGS_TABLE); + stmt.execute("CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"); + stmt.close(); } @@ -254,7 +225,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_ENTRY_TABLE); + stmt.execute("CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"); stmt.close(); } @@ -266,7 +237,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); + stmt.execute("CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"); stmt.close(); } @@ -279,7 +250,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); + stmt.execute("CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"); stmt.close(); } @@ -290,7 +261,7 @@ public class DerbyMessageStore implements MessageStore private boolean tableExists(final String tableName, final Connection conn) throws SQLException { - PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); + PreparedStatement stmt = conn.prepareStatement("SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"); stmt.setString(1, tableName); ResultSet rs = stmt.executeQuery(); boolean exists = rs.next(); @@ -312,6 +283,8 @@ public class DerbyMessageStore implements MessageStore recoverExchanges(); +// + try { @@ -344,14 +317,15 @@ public class DerbyMessageStore implements MessageStore Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); + ResultSet rs = stmt.executeQuery("SELECT name, owner FROM " + QUEUE_TABLE_NAME); Map queueMap = new HashMap(); while(rs.next()) { String queueName = rs.getString(1); String owner = rs.getString(2); AMQShortString queueNameShortString = new AMQShortString(queueName); - AMQQueue q = new AMQQueue(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost); + AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + null); _virtualHost.getQueueRegistry().registerQueue(q); queueMap.put(queueNameShortString,q); @@ -379,7 +353,7 @@ public class DerbyMessageStore implements MessageStore Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); + ResultSet rs = stmt.executeQuery("SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME); Exchange exchange; while(rs.next()) @@ -417,7 +391,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); + PreparedStatement stmt = conn.prepareStatement("SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"); stmt.setString(1, exchange.getName().toString()); ResultSet rs = stmt.executeQuery(); @@ -450,7 +424,7 @@ public class DerbyMessageStore implements MessageStore argumentsFT = new FieldTable(buf,arguments.length()); } - queue.bind(bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT, exchange); + queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); } } } @@ -465,7 +439,9 @@ public class DerbyMessageStore implements MessageStore public void close() throws Exception { + _closed.getAndSet(true); + } public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException @@ -486,11 +462,12 @@ public class DerbyMessageStore implements MessageStore MessageMetaData mmd = getMessageMetaData(storeContext, messageId); try { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"); stmt.setLong(1,messageId); wrapper.setRequiresCommit(); int results = stmt.executeUpdate(); + if (results == 0) { if (localTx) @@ -507,7 +484,8 @@ public class DerbyMessageStore implements MessageStore _logger.debug("Deleted metadata for message " + messageId); } - stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); + + stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"); stmt.setLong(1,messageId); results = stmt.executeUpdate(); @@ -550,7 +528,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"); stmt.setString(1, exchange.getName().toString()); stmt.setString(2, exchange.getType().toString()); stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); @@ -564,6 +542,7 @@ public class DerbyMessageStore implements MessageStore if(conn != null) { conn.close(); + } } } @@ -582,7 +561,7 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"); stmt.setString(1, exchange.getName().toString()); int results = stmt.executeUpdate(); if(results == 0) @@ -627,20 +606,16 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob + PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"); stmt.setString(1, exchange.getName().toString() ); stmt.setString(2, queue.getName().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(args != null) { - /* This would be the Java 6 way of setting a Blob Blob blobArgs = conn.createBlob(); blobArgs.setBytes(0, args.getDataAsBytes()); stmt.setBlob(4, blobArgs); - */ - byte[] bytes = args.getDataAsBytes(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - stmt.setBinaryStream(4, bis, bytes.length); } else { @@ -687,7 +662,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"); stmt.setString(1, exchange.getName().toString() ); stmt.setString(2, queue.getName().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); @@ -736,7 +711,7 @@ public class DerbyMessageStore implements MessageStore Connection conn = newConnection(); PreparedStatement stmt = - conn.prepareStatement(INSERT_INTO_QUEUE); + conn.prepareStatement("INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"); stmt.setString(1, queue.getName().toString()); stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); @@ -758,13 +733,13 @@ public class DerbyMessageStore implements MessageStore private Connection newConnection() throws SQLException { - final Connection connection = DriverManager.getConnection(_connectionURL); - return connection; + return DriverManager.getConnection(_connectionURL); } - public void removeQueue(AMQShortString name) throws AMQException + public void removeQueue(final AMQQueue queue) throws AMQException { + AMQShortString name = queue.getName(); _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); Connection conn = null; @@ -772,7 +747,7 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"); stmt.setString(1, name.toString()); int results = stmt.executeUpdate(); @@ -808,16 +783,17 @@ public class DerbyMessageStore implements MessageStore } - public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + AMQShortString name = queue.getName(); try { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"); stmt.setString(1,name.toString()); stmt.setLong(2,messageId); stmt.executeUpdate(); @@ -848,16 +824,17 @@ public class DerbyMessageStore implements MessageStore } - public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { + AMQShortString name = queue.getName(); boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"); stmt.setString(1,name.toString()); stmt.setLong(2,messageId); int results = stmt.executeUpdate(); @@ -954,18 +931,17 @@ public class DerbyMessageStore implements MessageStore try { - Connection conn = connWrapper.getConnection(); if(connWrapper.requiresCommit()) { + Connection conn = connWrapper.getConnection(); conn.commit(); if (_logger.isDebugEnabled()) { _logger.debug("commit tran completed"); } - + conn.close(); } - conn.close(); } catch (SQLException e) { @@ -1026,25 +1002,21 @@ public class DerbyMessageStore implements MessageStore int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException - { + { boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"); stmt.setLong(1,messageId); stmt.setInt(2, index); byte[] chunkData = new byte[contentBody.getSize()]; contentBody.getData().duplicate().get(chunkData); - /* this would be the Java 6 way of doing things Blob dataAsBlob = conn.createBlob(); dataAsBlob.setBytes(1L, chunkData); stmt.setBlob(3, dataAsBlob); - */ - ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); - stmt.setBinaryStream(3, bis, chunkData.length); stmt.executeUpdate(); connWrapper.requiresCommit(); @@ -1076,7 +1048,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"); stmt.setLong(1,messageId); stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); @@ -1088,13 +1060,9 @@ public class DerbyMessageStore implements MessageStore byte[] underlying = new byte[bodySize]; ByteBuffer buf = ByteBuffer.wrap(underlying); headerBody.writePayload(buf); -/* Blob dataAsBlob = conn.createBlob(); dataAsBlob.setBytes(1L, underlying); stmt.setBlob(6, dataAsBlob); -*/ - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(6,bis,underlying.length); stmt.setInt(7, mmd.getContentChunkCount()); @@ -1128,7 +1096,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); + PreparedStatement stmt = conn.prepareStatement("SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"); stmt.setLong(1,messageId); ResultSet rs = stmt.executeQuery(); @@ -1213,7 +1181,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); + PreparedStatement stmt = conn.prepareStatement("SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"); stmt.setLong(1,messageId); stmt.setInt(2, index); ResultSet rs = stmt.executeQuery(); @@ -1300,7 +1268,7 @@ public class DerbyMessageStore implements MessageStore public void process() throws AMQException { - _queue.process(_context, _queue.createEntry(_message), false); + _queue.enqueue(_context, _message); } } @@ -1335,7 +1303,7 @@ public class DerbyMessageStore implements MessageStore TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + ResultSet rs = stmt.executeQuery("SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME); while (rs.next()) @@ -1349,7 +1317,7 @@ public class DerbyMessageStore implements MessageStore AMQQueue queue = queues.get(queueName); if (queue == null) { - queue = new AMQQueue(queueName, false, null, false, _virtualHost); + queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); _virtualHost.getQueueRegistry().registerQueue(queue); queues.put(queueName, queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 7a6e0b011f..b02eff957e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -26,9 +26,9 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; @@ -126,17 +126,17 @@ public class MemoryMessageStore implements MessageStore // Not required to do anything } - public void removeQueue(AMQShortString name) throws AMQException + public void removeQueue(final AMQQueue queue) throws AMQException { // Not required to do anything } - public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { // Not required to do anything } - public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException + public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { // Not required to do anything } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 2a83d9b649..e15e69a414 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -27,8 +27,8 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; /** @@ -138,33 +138,30 @@ public interface MessageStore /** * Removes the specified queue from the persistent store. * - * @param name The queue to remove. - * + * @param queue The queue to remove. * @throws AMQException If the operation fails for any reason. */ - void removeQueue(AMQShortString name) throws AMQException; + void removeQueue(final AMQQueue queue) throws AMQException; /** * Places a message onto a specified queue, in a given transactional context. * * @param context The transactional context for the operation. - * @param name The name of the queue to place the message on. + * @param queue The queue to place the message on. * @param messageId The message to enqueue. - * * @throws AMQException If the operation fails for any reason. */ - void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; /** * Extracts a message from a specified queue, in a given transactional context. * * @param context The transactional context for the operation. - * @param name The name of the queue to take the message from. + * @param queue The queue to place the message on. * @param messageId The message to dequeue. - * * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. */ - void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException; + void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; /** * Begins a transactional context. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index 3ee49d58cf..fdb56a1a55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -37,7 +37,7 @@ public class StoreContext public StoreContext() { - _name = super.toString(); + _name = "StoreContext"; } public StoreContext(String name) @@ -52,7 +52,10 @@ public class StoreContext public void setPayload(Object payload) { - _logger.debug("public void setPayload(Object payload = " + payload + "): called"); + if(_logger.isDebugEnabled()) + { + _logger.debug("public void setPayload(Object payload = " + payload + "): called"); + } _payload = payload; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java new file mode 100644 index 0000000000..fbc8b3af7d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java @@ -0,0 +1,29 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.AMQException; + +public interface ClientDeliveryMethod +{ + void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java new file mode 100644 index 0000000000..e2ed4104de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java @@ -0,0 +1,28 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; + +public interface RecordDeliveryMethod +{ + void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java new file mode 100644 index 0000000000..408defe453 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -0,0 +1,94 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; + +public interface Subscription +{ + + + public static enum State + { + ACTIVE, + SUSPENDED, + CLOSED + } + + public static interface StateListener + { + public void stateChange(Subscription sub, State oldState, State newState); + } + + AMQQueue getQueue(); + + QueueEntry.SubscriptionAcquiredState getOwningState(); + + void setQueue(AMQQueue queue); + + AMQChannel getChannel(); + + AMQShortString getConsumerTag(); + + boolean isSuspended(); + + boolean hasInterest(QueueEntry msg); + + boolean isAutoClose(); + + boolean isClosed(); + + boolean isBrowser(); + + void close(); + + boolean filtersMessages(); + + void send(QueueEntry msg) throws AMQException; + + void queueDeleted(AMQQueue queue); + + + boolean wouldSuspend(QueueEntry msg); + + void getSendLock(); + void releaseSendLock(); + + void resend(final QueueEntry entry) throws AMQException; + + void restoreCredit(final QueueEntry queueEntry); + + void setStateListener(final StateListener listener); + + QueueEntry getLastSeenEntry(); + + boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); + + + boolean isActive(); + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java new file mode 100644 index 0000000000..ce0362d73f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; + +/** + * 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, + AMQShortString consumerTag, + boolean acks, + FieldTable filters, + boolean noLocal, FlowCreditManager creditManager) throws AMQException; + + + Subscription createSubscription(AMQChannel channel, + AMQProtocolSession protocolSession, + AMQShortString consumerTag, + boolean acks, + FieldTable filters, + boolean noLocal, + FlowCreditManager creditManager, + ClientDeliveryMethod clientMethod, + RecordDeliveryMethod recordMethod + ) + throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java new file mode 100644 index 0000000000..5badbad642 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java @@ -0,0 +1,103 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactory; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.common.AMQPFilterTypes; + +public class SubscriptionFactoryImpl implements SubscriptionFactory +{ + + /* private SubscriptionFactoryImpl() + { + + }*/ + + public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager) throws AMQException + { + AMQChannel channel = protocolSession.getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); + } + ClientDeliveryMethod clientMethod = channel.getClientDeliveryMethod(); + RecordDeliveryMethod recordMethod = channel.getRecordDeliveryMethod(); + + + return createSubscription(channel, protocolSession, consumerTag, acks, filters, + noLocal, + creditManager, + clientMethod, + recordMethod + ); + } + + public Subscription createSubscription(final AMQChannel channel, + final AMQProtocolSession protocolSession, + final AMQShortString consumerTag, + final boolean acks, + final FieldTable filters, + final boolean noLocal, + final FlowCreditManager creditManager, + final ClientDeliveryMethod clientMethod, + final RecordDeliveryMethod recordMethod + ) + throws AMQException + { + boolean isBrowser; + + if (filters != null) + { + Boolean isBrowserObj = (Boolean) filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); + isBrowser = (isBrowserObj != null) && isBrowserObj.booleanValue(); + } + else + { + isBrowser = false; + } + + if(isBrowser) + { + return new SubscriptionImpl.BrowserSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + else if(acks) + { + return new SubscriptionImpl.AckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + else + { + return new SubscriptionImpl.NoAckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + } + + + public static final SubscriptionFactoryImpl INSTANCE = new SubscriptionFactoryImpl(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java new file mode 100644 index 0000000000..556b87590c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -0,0 +1,605 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; + +/** + * Encapsulation of a supscription to a queue.

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

      + */ +public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener +{ + + private StateListener _stateListener = new StateListener() + { + + public void stateChange(Subscription sub, State oldState, State newState) + { + + } + }; + + + private final AtomicReference _state = new AtomicReference(State.ACTIVE); + private final AtomicReference _queueContext = new AtomicReference(null); + private final ClientDeliveryMethod _deliveryMethod; + private final RecordDeliveryMethod _recordMethod; + + private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final Lock _stateChangeLock; + + static final class BrowserSubscription extends SubscriptionImpl + { + public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + + public boolean isBrowser() + { + return true; + } + + /** + * 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 The message to send + * @throws AMQException + */ + public void send(QueueEntry msg) throws AMQException + { + // We don't decrement the reference here as we don't want to consume the message + // but we do want to send it to the client. + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + sendToClient(msg, deliveryTag); + } + + } + } + + public static class NoAckSubscription extends SubscriptionImpl + { + public NoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + + public boolean isBrowser() + { + return false; + } + + /** + * 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 entry The message to send + * @throws AMQException + */ + public void send(QueueEntry entry) throws AMQException + { + + StoreContext storeContext = getChannel().getStoreContext(); + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + entry.dequeue(storeContext); + + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + + sendToClient(entry, deliveryTag); + + } + entry.dispose(storeContext); + } + finally + { + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. + // Is this what we want? + + entry.setDeliveredToSubscription(); + } + } + + public boolean wouldSuspend(QueueEntry msg) + { + return false; + } + + } + + static final class AckSubscription extends SubscriptionImpl + { + public AckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + public boolean isBrowser() + { + return false; + } + + + /** + * 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 entry The message to send + * @throws AMQException + */ + public void send(QueueEntry entry) throws AMQException + { + + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + + + recordMessageDelivery(entry, deliveryTag); + sendToClient(entry, deliveryTag); + + + } + } + finally + { + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. + // Is this what we want? + + entry.setDeliveredToSubscription(); + } + } + + + } + + + private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); + + private final AMQChannel _channel; + + private final AMQShortString _consumerTag; + + + private final boolean _noLocal; + + private final FlowCreditManager _creditManager; + + private FilterManager _filters; + + private final Boolean _autoClose; + + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + private AMQQueue _queue; + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + + + + public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable arguments, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + + _channel = channel; + _consumerTag = consumerTag; + + _creditManager = creditManager; + creditManager.addStateListener(this); + + _noLocal = noLocal; + + + _filters = FilterManagerFactory.createManager(arguments); + + _deliveryMethod = deliveryMethod; + _recordMethod = recordMethod; + + + _stateChangeLock = new ReentrantLock(); + + + if (arguments != null) + { + Object autoClose = arguments.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); + if (autoClose != null) + { + _autoClose = (Boolean) autoClose; + } + else + { + _autoClose = false; + } + } + else + { + _autoClose = false; + } + + + } + + + + public synchronized void setQueue(AMQQueue queue) + { + if(getQueue() != null) + { + throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); + } + _queue = queue; + } + + public String toString() + { + String subscriber = "[channel=" + _channel + + ", consumerTag=" + _consumerTag + + ", session=" + getProtocolSession().getKey() ; + + return subscriber + "]"; + } + + /** + * 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 The message to send + * @throws AMQException + */ + abstract public void send(QueueEntry msg) throws AMQException; + + + public boolean isSuspended() + { + return !isActive() || _channel.isSuspended() || _deleted.get(); + } + + /** + * Callback indicating that a queue has been deleted. + * + * @param queue The queue to delete + */ + public void queueDeleted(AMQQueue queue) + { + _deleted.set(true); +// _channel.queueDeleted(queue); + } + + public boolean filtersMessages() + { + return _filters != null || _noLocal; + } + + public boolean hasInterest(QueueEntry entry) + { + //check that the message hasn't been rejected + if (entry.isRejectedBy(this)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); + } +// return false; + } + + + + //todo - client id should be recoreded and this test removed but handled below + if (_noLocal) + { + final Object publisherId = entry.getMessage().getPublisherClientInstance(); + + // We don't want local messages so check to see if message is one we sent + Object localInstance; + + if (publisherId != null && (getProtocolSession().getClientProperties() != null) && + (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + { + if(publisherId.equals(localInstance)) + { + return false; + } + } + else + { + + localInstance = getProtocolSession().getClientIdentifier(); + //todo - client id should be recoreded and this test removed but handled here + + + if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) + { + return false; + } + } + + + } + + + if (_logger.isDebugEnabled()) + { + _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity()); + } + return checkFilters(entry); + + } + + private String id = String.valueOf(System.identityHashCode(this)); + + private String debugIdentity() + { + return id; + } + + private boolean checkFilters(QueueEntry msg) + { + return (_filters == null) || _filters.allAllow(msg.getMessage()); + } + + public boolean isAutoClose() + { + return _autoClose; + } + + public FlowCreditManager getCreditManager() + { + return _creditManager; + } + + + public void close() + { + boolean closed = false; + State state = getState(); + + _stateChangeLock.lock(); + try + { + while(!closed && state != State.CLOSED) + { + closed = _state.compareAndSet(state, State.CLOSED); + if(!closed) + { + state = getState(); + } + else + { + _stateListener.stateChange(this,state, State.CLOSED); + } + } + _creditManager.removeListener(this); + } + finally + { + _stateChangeLock.unlock(); + } + + + if (closed) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Called close() on a closed subscription"); + } + + return; + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing subscription (" + debugIdentity() + "):" + this); + } + } + + public boolean isClosed() + { + return getState() == State.CLOSED; + } + + + public boolean wouldSuspend(QueueEntry msg) + { + return !_creditManager.useCreditForMessage(msg.getMessage());//_channel.wouldSuspend(msg.getMessage()); + } + + public void getSendLock() + { + _stateChangeLock.lock(); + } + + public void releaseSendLock() + { + _stateChangeLock.unlock(); + } + + public void resend(final QueueEntry entry) throws AMQException + { + _queue.resend(entry, this); + } + + public AMQChannel getChannel() + { + return _channel; + } + + public AMQShortString getConsumerTag() + { + return _consumerTag; + } + + public AMQProtocolSession getProtocolSession() + { + return _channel.getProtocolSession(); + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void restoreCredit(final QueueEntry queueEntry) + { + _creditManager.addCredit(1, queueEntry.getSize()); + } + + + public void creditStateChanged(boolean hasCredit) + { + + if(hasCredit) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + else + { + // this is a hack to get round the issue of increasing bytes credit + _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE); + } + } + else + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + } + } + + public State getState() + { + return _state.get(); + } + + + public void setStateListener(final StateListener listener) + { + _stateListener = listener; + } + + + public QueueEntry getLastSeenEntry() + { + return _queueContext.get(); + } + + public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) + { + return _queueContext.compareAndSet(expected,newvalue); + } + + + protected void sendToClient(final QueueEntry entry, final long deliveryTag) + throws AMQException + { + _deliveryMethod.deliverToClient(this,entry,deliveryTag); + } + + + protected void recordMessageDelivery(final QueueEntry entry, final long deliveryTag) + { + _recordMethod.recordMessageDelivery(this,entry,deliveryTag); + } + + + public boolean isActive() + { + return getState() == State.ACTIVE; + } + + public QueueEntry.SubscriptionAcquiredState getOwningState() + { + return _owningState; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java new file mode 100644 index 0000000000..3fbb6bfa4a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java @@ -0,0 +1,247 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.subscription.Subscription; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.nio.ByteBuffer; + +public class SubscriptionList +{ + + private final SubscriptionNode _head = new SubscriptionNode(); + + private AtomicReference _tail = new AtomicReference(_head); + private final AMQQueue _queue; + private AtomicInteger _size = new AtomicInteger(); + + + public final class SubscriptionNode + { + private final AtomicBoolean _deleted = new AtomicBoolean(); + private final AtomicReference _next = new AtomicReference(); + private final Subscription _sub; + + + public SubscriptionNode() + { + + _sub = null; + _deleted.set(true); + } + + public SubscriptionNode(final Subscription sub) + { + _sub = sub; + } + + + public SubscriptionNode getNext() + { + + SubscriptionNode next = nextNode(); + while(next != null && next.isDeleted()) + { + + final SubscriptionNode newNext = next.nextNode(); + if(newNext != null) + { + _next.compareAndSet(next, newNext); + next = nextNode(); + } + else + { + next = null; + } + + } + return next; + } + + private SubscriptionNode nextNode() + { + return _next.get(); + } + + public boolean isDeleted() + { + return _deleted.get(); + } + + + public boolean delete() + { + if(_deleted.compareAndSet(false,true)) + { + _size.decrementAndGet(); + advanceHead(); + return true; + } + else + { + return false; + } + } + + + public Subscription getSubscription() + { + return _sub; + } + } + + + public SubscriptionList(AMQQueue queue) + { + _queue = queue; + } + + private void advanceHead() + { + SubscriptionNode head = _head.nextNode(); + while(head._next.get() != null && head.isDeleted()) + { + + final SubscriptionNode newhead = head.nextNode(); + if(newhead != null) + { + _head._next.compareAndSet(head, newhead); + } + head = _head.nextNode(); + } + } + + + public SubscriptionNode add(Subscription sub) + { + SubscriptionNode node = new SubscriptionNode(sub); + for (;;) + { + SubscriptionNode tail = _tail.get(); + SubscriptionNode next = tail.nextNode(); + if (tail == _tail.get()) + { + if (next == null) + { + if (tail._next.compareAndSet(null, node)) + { + _tail.compareAndSet(tail, node); + _size.incrementAndGet(); + return node; + } + } + else + { + _tail.compareAndSet(tail, next); + } + } + } + + } + + public boolean remove(Subscription sub) + { + SubscriptionNode node = _head.getNext(); + while(node != null) + { + if(sub.equals(node._sub) && node.delete()) + { + return true; + } + node = node.getNext(); + } + return false; + } + + + public class SubscriptionNodeIterator + { + + private SubscriptionNode _lastNode; + + SubscriptionNodeIterator(SubscriptionNode startNode) + { + _lastNode = startNode; + } + + + public boolean atTail() + { + return _lastNode.nextNode() == null; + } + + public SubscriptionNode getNode() + { + + return _lastNode; + + } + + public boolean advance() + { + + if(!atTail()) + { + SubscriptionNode nextNode = _lastNode.nextNode(); + while(nextNode.isDeleted() && nextNode.nextNode() != null) + { + nextNode = nextNode.nextNode(); + } + _lastNode = nextNode; + return true; + + } + else + { + return false; + } + + } + + } + + + public SubscriptionNodeIterator iterator() + { + return new SubscriptionNodeIterator(_head); + } + + + public SubscriptionNode getHead() + { + return _head; + } + + public int size() + { + return _size.get(); + } + + + +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java index 23aaf56876..b67bb98e28 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -97,6 +97,10 @@ public class ConnectorConfiguration defaultValue = "false") public boolean _multiThreadNIO; + @Configured(path = "advanced.useWriteBiasedPool", + defaultValue = "false") + public boolean useBiasedWrites; + public IoAcceptor createAcceptor() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java deleted file mode 100644 index 988f589339..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.StoreContext; - -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(StoreContext context) 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(StoreContext context) - { - // No-op can't be done here has this is before the message has been attempted to be delivered. - /*try - { - _msg.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - _returns.add(e); - }*/ - } - - public void rollback(StoreContext context) - { - // NO OP - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 2307b94566..ad8303ec5d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -24,18 +24,16 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.ack.TxAck; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.*; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import java.util.LinkedList; import java.util.List; +import java.util.ArrayList; /** A transactional context that only supports local transactions. */ public class LocalTransactionalContext implements TransactionalContext @@ -44,7 +42,7 @@ public class LocalTransactionalContext implements TransactionalContext private final TxnBuffer _txnBuffer = new TxnBuffer(); - private final List _postCommitDeliveryList = new LinkedList(); + private final List _postCommitDeliveryList = new ArrayList(); /** * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are @@ -52,81 +50,112 @@ public class LocalTransactionalContext implements TransactionalContext */ private TxAck _ackOp; - private List _returnMessages; - - private final MessageStore _messageStore; - - private final StoreContext _storeContext; - private boolean _inTran = false; /** Are there messages to deliver. NOT Has the message been delivered */ private boolean _messageDelivered = false; + private final AMQChannel _channel; - private static class DeliveryDetails + + private abstract class DeliveryAction { - public QueueEntry entry; - private boolean deliverFirst; + abstract public void process() throws AMQException; - public DeliveryDetails(QueueEntry entry, boolean deliverFirst) + } + + private class RequeueAction extends DeliveryAction + { + public QueueEntry entry; + + public RequeueAction(QueueEntry entry) { this.entry = entry; - this.deliverFirst = deliverFirst; + } + + public void process() throws AMQException + { + entry.requeue(getStoreContext()); + } + } + + private class PublishAction extends DeliveryAction + { + private final AMQQueue _queue; + private final AMQMessage _message; + + public PublishAction(final AMQQueue queue, final AMQMessage message) + { + _queue = queue; + _message = message; + } + + public void process() throws AMQException + { + + QueueEntry entry = _queue.enqueue(getStoreContext(),_message); + + if(entry.immediateAndNotDelivered()) + { + getReturnMessages().add(new NoConsumersException(_message)); + } } } - public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext, - List returnMessages) + public LocalTransactionalContext(final AMQChannel channel) { - _messageStore = messageStore; - _storeContext = storeContext; - _returnMessages = returnMessages; - // _txnBuffer.enlist(new StoreMessageOperation(messageStore)); + _channel = channel; } public StoreContext getStoreContext() { - return _storeContext; + return _channel.getStoreContext(); } + public List getReturnMessages() + { + return _channel.getReturnMessages(); + } + + public MessageStore getMessageStore() + { + return _channel.getMessageStore(); + } + + public void rollback() throws AMQException { - _txnBuffer.rollback(_storeContext); + _txnBuffer.rollback(getStoreContext()); // Hack to deal with uncommitted non-transactional writes - if (_messageStore.inTran(_storeContext)) + if (getMessageStore().inTran(getStoreContext())) { - _messageStore.abortTran(_storeContext); + getMessageStore().abortTran(getStoreContext()); _inTran = false; } _postCommitDeliveryList.clear(); } - public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException + public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException { // A publication will result in the enlisting of several // TxnOps. The first is an op that will store the message. // Following that (and ordering is important), an op will // be added for every queue onto which the message is - // enqueued. Finally a cleanup op will be added to decrement - // the reference associated with the routing. - // message.incrementReference(); - _postCommitDeliveryList.add(new DeliveryDetails(entry, deliverFirst)); + // enqueued. + _postCommitDeliveryList.add(new PublishAction(queue, message)); _messageDelivered = true; - _txnBuffer.enlist(new CleanupMessageOperation(entry.getMessage(), _returnMessages)); - /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); - if (_log.isDebugEnabled()) - { - _log.debug("Incrementing ref count on message and enlisting cleanup operation - id " + - message.getMessageId()); - } - message.incrementReference(); + + } + + public void requeue(QueueEntry entry) throws AMQException + { + _postCommitDeliveryList.add(new RequeueAction(entry)); _messageDelivered = true; - */ } + private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException { if (!unacknowledgedMessageMap.contains(deliveryTag)) @@ -147,10 +176,8 @@ public class LocalTransactionalContext implements TransactionalContext // 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 @@ -189,7 +216,7 @@ public class LocalTransactionalContext implements TransactionalContext _log.debug("Starting transaction on message store: " + this); } - _messageStore.beginTran(_storeContext); + getMessageStore().beginTran(getStoreContext()); _inTran = true; } } @@ -212,22 +239,22 @@ public class LocalTransactionalContext implements TransactionalContext if (_messageDelivered && _inTran) { - _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); + _txnBuffer.enlist(new StoreMessageOperation(getMessageStore())); } // fixme fail commit here ... QPID-440 try { - _txnBuffer.commit(_storeContext); + _txnBuffer.commit(getStoreContext()); } finally { _messageDelivered = false; - _inTran = _messageStore.inTran(_storeContext); + _inTran = getMessageStore().inTran(getStoreContext()); } try { - postCommitDelivery(_returnMessages); + postCommitDelivery(); } catch (AMQException e) { @@ -236,7 +263,7 @@ public class LocalTransactionalContext implements TransactionalContext } } - private void postCommitDelivery(List returnMessages) throws AMQException + private void postCommitDelivery() throws AMQException { if (_log.isDebugEnabled()) { @@ -245,18 +272,9 @@ public class LocalTransactionalContext implements TransactionalContext try { - for (DeliveryDetails dd : _postCommitDeliveryList) + for (DeliveryAction dd : _postCommitDeliveryList) { - dd.entry.process(_storeContext, dd.deliverFirst); - - try - { - dd.entry.checkDeliveredToConsumer(); - } - catch (NoConsumersException nce) - { - returnMessages.add(nce); - } + dd.process(); } } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index cac3489f4c..18f1836185 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -22,19 +22,14 @@ package org.apache.qpid.server.txn; import java.util.LinkedList; import java.util.List; -import java.util.Set; 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.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.*; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; @@ -49,6 +44,8 @@ public class NonTransactionalContext implements TransactionalContext /** Where to put undeliverable messages */ private final List _returnMessages; + + private final MessageStore _messageStore; private final StoreContext _storeContext; @@ -56,12 +53,6 @@ public class NonTransactionalContext implements TransactionalContext /** Whether we are in a transaction */ private boolean _inTran; - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, - List returnMessages, Set browsedAcks) - { - this(messageStore,storeContext,channel,returnMessages); - } - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, List returnMessages) { @@ -97,19 +88,22 @@ public class NonTransactionalContext implements TransactionalContext // Does not apply to this context } - public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException + public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException { - try + QueueEntry entry = queue.enqueue(_storeContext, message); + + //following check implements the functionality + //required by the 'immediate' flag: + if(entry.immediateAndNotDelivered()) { - entry.process(_storeContext, deliverFirst); - //following check implements the functionality - //required by the 'immediate' flag: - entry.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - _returnMessages.add(e); + _returnMessages.add(new NoConsumersException(entry.getMessage())); } + + } + + public void requeue(QueueEntry entry) throws AMQException + { + entry.requeue(_storeContext); } public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, @@ -118,7 +112,7 @@ public class NonTransactionalContext implements TransactionalContext { final boolean debug = _log.isDebugEnabled(); - + ; if (multiple) { if (deliveryTag == 0) @@ -130,7 +124,7 @@ public class NonTransactionalContext implements TransactionalContext unacknowledgedMessageMap.size()); unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - public boolean callback(UnacknowledgedMessage message) throws AMQException + public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException { if (debug) { @@ -140,6 +134,7 @@ public class NonTransactionalContext implements TransactionalContext { beginTranIfNecessary(); } + message.restoreCredit(); //Message has been ack so discard it. This will dequeue and decrement the reference. message.discard(_storeContext); @@ -159,27 +154,27 @@ public class NonTransactionalContext implements TransactionalContext throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); } - LinkedList acked = new LinkedList(); + LinkedList acked = new LinkedList(); unacknowledgedMessageMap.drainTo(acked, deliveryTag); - for (UnacknowledgedMessage msg : acked) + for (QueueEntry msg : acked) { - if (debug) - { - _log.debug("Discarding message: " + msg.getMessage().getMessageId()); - } - if(msg.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } + if (debug) + { + _log.debug("Discarding message: " + msg.getMessage().getMessageId()); + } + if(msg.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(_storeContext); } } } else { - UnacknowledgedMessage msg; + QueueEntry msg; msg = unacknowledgedMessageMap.remove(deliveryTag); if (msg == null) @@ -208,13 +203,11 @@ public class NonTransactionalContext implements TransactionalContext msg.getMessage().getMessageId()); } } - if(_inTran) { _messageStore.commitTran(_storeContext); _inTran = false; } - } public void messageFullyReceived(boolean persistent) throws AMQException @@ -228,6 +221,6 @@ public class NonTransactionalContext implements TransactionalContext public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException { - _channel.processReturns(protocolSession); + _channel.processReturns(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java index 6016ecc1a5..647ba66fb4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -25,6 +25,7 @@ import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.StoreContext; /** @@ -106,18 +107,26 @@ public interface TransactionalContext void rollback() throws AMQException; /** - * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a - * redelivery, and should be placed on the front of the queue. + * Delivers the specified message to the specified queue. * *

      This is an 'enqueue' operation. * - * @param entry The message to deliver, and the queue to deliver to. - * @param deliverFirst true to place the message on the front of the queue for redelivery, false - * for normal FIFO message ordering. - * + * @param queue + * @param message The message to deliver * @throws AMQException If the message cannot be delivered for any reason. */ - void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException; + void deliver(final AMQQueue queue, AMQMessage message) throws AMQException; + + /** + * Requeues the specified message entry (message queue pair) + * + * + * @param queueEntry The message,queue pair + * + * @throws AMQException If the message cannot be delivered for any reason. + */ + void requeue(QueueEntry queueEntry) throws AMQException; + /** * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 70a76dd8c2..85d804457e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -1,44 +1,44 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; - -/** - * The management interface exposed to allow management of an Exchange. - * @version 0.1 - */ -public interface ManagedVirtualHost -{ - static final String TYPE = "VirtualHost"; - - /** - * Returns the name of the managed virtualHost. - * @return the name of the exchange. - * @throws java.io.IOException - */ - @MBeanAttribute(name="Name", description= TYPE + " Name") - String getName() throws IOException; - - -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; + +/** + * The management interface exposed to allow management of an Exchange. + * @version 0.1 + */ +public interface ManagedVirtualHost +{ + static final String TYPE = "VirtualHost"; + + /** + * Returns the name of the managed virtualHost. + * @return the name of the exchange. + * @throws java.io.IOException + */ + @MBeanAttribute(name="Name", description= TYPE + " Name") + String getName() throws IOException; + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 90dc7432b2..8b764efa42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -71,8 +71,8 @@ public class VirtualHost implements Accessable private ACLPlugin _accessManager; - private Timer _houseKeepingTimer; - + private final Timer _houseKeepingTimer = new Timer("Queue-housekeeping", true); + private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public void setAccessableName(String name) @@ -172,25 +172,22 @@ public class VirtualHost implements Accessable _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); - - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); - initialiseHouseKeeping(hostConfig); } private void initialiseHouseKeeping(final Configuration hostConfig) { - + long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); - + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if (period != 0L) + if(period != 0L) { class RemoveExpiredMessagesTask extends TimerTask { public void run() { - for (AMQQueue q : _queueRegistry.getQueues()) + for(AMQQueue q : _queueRegistry.getQueues()) { try @@ -199,7 +196,7 @@ public class VirtualHost implements Accessable } catch (AMQException e) { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e); throw new RuntimeException(e); } } @@ -207,11 +204,11 @@ public class VirtualHost implements Accessable } _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); + period/2, + period); } } - + private void initialiseMessageStore(Configuration config) throws Exception { String messageStoreClass = config.getString("store.class"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 9b1619c609..27917fac8a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -1,70 +1,70 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -public class VirtualHostRegistry -{ - private final Map _registry = new ConcurrentHashMap(); - - - private String _defaultVirtualHostName; - - public synchronized void registerVirtualHost(VirtualHost host) throws Exception - { - if(_registry.containsKey(host.getName())) - { - throw new Exception("Virtual Host with name " + host.getName() + " already registered."); - } - _registry.put(host.getName(),host); - } - - public VirtualHost getVirtualHost(String name) - { - if(name == null || name.trim().length() == 0 ) - { - name = getDefaultVirtualHostName(); - } - - return _registry.get(name); - } - - private String getDefaultVirtualHostName() - { - return _defaultVirtualHostName; - } - - public void setDefaultVirtualHostName(String defaultVirtualHostName) - { - _defaultVirtualHostName = defaultVirtualHostName; - } - - - public Collection getVirtualHosts() - { - return new ArrayList(_registry.values()); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class VirtualHostRegistry +{ + private final Map _registry = new ConcurrentHashMap(); + + + private String _defaultVirtualHostName; + + public synchronized void registerVirtualHost(VirtualHost host) throws Exception + { + if(_registry.containsKey(host.getName())) + { + throw new Exception("Virtual Host with name " + host.getName() + " already registered."); + } + _registry.put(host.getName(),host); + } + + public VirtualHost getVirtualHost(String name) + { + if(name == null || name.trim().length() == 0 ) + { + name = getDefaultVirtualHostName(); + } + + return _registry.get(name); + } + + private String getDefaultVirtualHostName() + { + return _defaultVirtualHostName; + } + + public void setDefaultVirtualHostName(String defaultVirtualHostName) + { + _defaultVirtualHostName = defaultVirtualHostName; + } + + + public Collection getVirtualHosts() + { + return new ArrayList(_registry.values()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java index edc900f401..faa7b85d58 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -25,11 +25,11 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.configuration.Configuration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.tools.messagestore.commands.Clear; import org.apache.qpid.tools.messagestore.commands.Command; import org.apache.qpid.tools.messagestore.commands.Copy; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java index a5b3a87616..0869d9a497 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.tools.messagestore.commands; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.server.queue.AMQQueue; public class Copy extends Move { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java index 218d5f04ed..731f6140f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -24,6 +24,7 @@ import org.apache.commons.codec.binary.Hex; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; @@ -255,7 +256,7 @@ public class Dump extends Show String title, boolean routing, boolean headers, boolean messageHeaders) { List single = new LinkedList(); - single.add(new QueueEntry(null,msg)); + single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE)); List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index 7e21253fab..a8dd58ca83 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -21,7 +21,7 @@ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.store.StoreContext; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java index f187e26593..5e99997863 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -20,9 +20,8 @@ */ package org.apache.qpid.tools.messagestore.commands; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.server.queue.AMQQueue; public class Purge extends Move { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java index fd7d4c3f13..ff59568374 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java @@ -22,9 +22,9 @@ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.tools.messagestore.MessageStoreTool; import java.util.LinkedList; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index a6dccf0f36..2fa017fc64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -26,6 +26,7 @@ import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.tools.messagestore.MessageStoreTool; @@ -33,7 +34,6 @@ import org.apache.qpid.tools.utils.Console; import java.util.LinkedList; import java.util.List; -import java.util.StringTokenizer; public class Show extends AbstractCommand { -- cgit v1.2.1 From 6914ef1fd32597442c8a4dff89a3675c82932084 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 19 Jun 2008 13:29:23 +0000 Subject: QPID-950 : Fixed Derby Message Store git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@669480 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 183 +++++++++++++-------- 1 file changed, 111 insertions(+), 72 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index cc22569d77..9d22e2b929 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -1,11 +1,32 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ package org.apache.qpid.server.store; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueueFactory; + import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.server.txn.TransactionalContext; @@ -21,6 +42,7 @@ import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import java.io.File; +import java.io.ByteArrayInputStream; import java.sql.DriverManager; import java.sql.Driver; import java.sql.Connection; @@ -39,26 +61,6 @@ import java.util.HashMap; import java.util.TreeMap; -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ public class DerbyMessageStore implements MessageStore { @@ -67,7 +69,7 @@ public class DerbyMessageStore implements MessageStore private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; - private static final String DERBY_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; + private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION"; @@ -91,6 +93,39 @@ public class DerbyMessageStore implements MessageStore private String _connectionURL; + + private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; + private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; + private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; + private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; + private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; + private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; + private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; + private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; + private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; + private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; + private static final String SELECT_FROM_BINDINGS = + "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; + private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; + private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; + private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; + private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; + private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; + private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; + private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; + private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; + private static final String SELECT_FROM_MESSAGE_META_DATA = + "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_FROM_MESSAGE_CONTENT = + "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; + private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; + private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; + + private enum State { INITIAL, @@ -129,10 +164,6 @@ public class DerbyMessageStore implements MessageStore createOrOpenDatabase(databasePath); - - - - // this recovers durable queues and persistent messages recover(); @@ -145,7 +176,7 @@ public class DerbyMessageStore implements MessageStore { if(DRIVER_CLASS == null) { - DRIVER_CLASS = (Class) Class.forName(DERBY_DRIVER_NAME); + DRIVER_CLASS = (Class) Class.forName(SQL_DRIVER_NAME); } } @@ -163,7 +194,7 @@ public class DerbyMessageStore implements MessageStore createMessageMetaDataTable(conn); createMessageContentTable(conn); - + conn.close(); } @@ -174,10 +205,10 @@ public class DerbyMessageStore implements MessageStore { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"); + stmt.execute(CREATE_DB_VERSION_TABLE); stmt.close(); - PreparedStatement pstmt = conn.prepareStatement("INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"); + PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); pstmt.setInt(1, DB_VERSION); pstmt.execute(); pstmt.close(); @@ -191,8 +222,8 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(EXCHANGE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - - stmt.execute("CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"); + + stmt.execute(CREATE_EXCHANGE_TABLE); stmt.close(); } } @@ -202,7 +233,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"); + stmt.execute(CREATE_QUEUE_TABLE); stmt.close(); } } @@ -212,8 +243,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(BINDINGS_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"); - + stmt.execute(CREATE_BINDINGS_TABLE); stmt.close(); } @@ -225,7 +255,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"); + stmt.execute(CREATE_QUEUE_ENTRY_TABLE); stmt.close(); } @@ -237,7 +267,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"); + stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); stmt.close(); } @@ -250,7 +280,7 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"); + stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); stmt.close(); } @@ -261,7 +291,7 @@ public class DerbyMessageStore implements MessageStore private boolean tableExists(final String tableName, final Connection conn) throws SQLException { - PreparedStatement stmt = conn.prepareStatement("SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"); + PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); stmt.setString(1, tableName); ResultSet rs = stmt.executeQuery(); boolean exists = rs.next(); @@ -283,8 +313,6 @@ public class DerbyMessageStore implements MessageStore recoverExchanges(); -// - try { @@ -317,7 +345,7 @@ public class DerbyMessageStore implements MessageStore Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT name, owner FROM " + QUEUE_TABLE_NAME); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); Map queueMap = new HashMap(); while(rs.next()) { @@ -353,7 +381,7 @@ public class DerbyMessageStore implements MessageStore Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME); + ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); Exchange exchange; while(rs.next()) @@ -391,7 +419,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement("SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"); + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); stmt.setString(1, exchange.getName().toString()); ResultSet rs = stmt.executeQuery(); @@ -425,6 +453,7 @@ public class DerbyMessageStore implements MessageStore } queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + } } } @@ -439,9 +468,7 @@ public class DerbyMessageStore implements MessageStore public void close() throws Exception { - _closed.getAndSet(true); - } public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException @@ -462,12 +489,11 @@ public class DerbyMessageStore implements MessageStore MessageMetaData mmd = getMessageMetaData(storeContext, messageId); try { - PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); stmt.setLong(1,messageId); wrapper.setRequiresCommit(); int results = stmt.executeUpdate(); - if (results == 0) { if (localTx) @@ -484,8 +510,7 @@ public class DerbyMessageStore implements MessageStore _logger.debug("Deleted metadata for message " + messageId); } - - stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"); + stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); stmt.setLong(1,messageId); results = stmt.executeUpdate(); @@ -528,7 +553,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); stmt.setString(1, exchange.getName().toString()); stmt.setString(2, exchange.getType().toString()); stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); @@ -542,7 +567,6 @@ public class DerbyMessageStore implements MessageStore if(conn != null) { conn.close(); - } } } @@ -561,7 +585,7 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); stmt.setString(1, exchange.getName().toString()); int results = stmt.executeUpdate(); if(results == 0) @@ -606,16 +630,20 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob - PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); stmt.setString(1, exchange.getName().toString() ); stmt.setString(2, queue.getName().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(args != null) { + /* This would be the Java 6 way of setting a Blob Blob blobArgs = conn.createBlob(); blobArgs.setBytes(0, args.getDataAsBytes()); stmt.setBlob(4, blobArgs); + */ + byte[] bytes = args.getDataAsBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + stmt.setBinaryStream(4, bis, bytes.length); } else { @@ -662,7 +690,7 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob - PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); stmt.setString(1, exchange.getName().toString() ); stmt.setString(2, queue.getName().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); @@ -711,7 +739,7 @@ public class DerbyMessageStore implements MessageStore Connection conn = newConnection(); PreparedStatement stmt = - conn.prepareStatement("INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"); + conn.prepareStatement(INSERT_INTO_QUEUE); stmt.setString(1, queue.getName().toString()); stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); @@ -733,12 +761,12 @@ public class DerbyMessageStore implements MessageStore private Connection newConnection() throws SQLException { - return DriverManager.getConnection(_connectionURL); + final Connection connection = DriverManager.getConnection(_connectionURL); + return connection; } public void removeQueue(final AMQQueue queue) throws AMQException { - AMQShortString name = queue.getName(); _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); Connection conn = null; @@ -747,7 +775,7 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); stmt.setString(1, name.toString()); int results = stmt.executeUpdate(); @@ -785,15 +813,15 @@ public class DerbyMessageStore implements MessageStore public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { + AMQShortString name = queue.getName(); boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - AMQShortString name = queue.getName(); try { - PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); stmt.setString(1,name.toString()); stmt.setLong(2,messageId); stmt.executeUpdate(); @@ -826,15 +854,15 @@ public class DerbyMessageStore implements MessageStore public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { - AMQShortString name = queue.getName(); + boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { - PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); stmt.setString(1,name.toString()); stmt.setLong(2,messageId); int results = stmt.executeUpdate(); @@ -931,17 +959,18 @@ public class DerbyMessageStore implements MessageStore try { + Connection conn = connWrapper.getConnection(); if(connWrapper.requiresCommit()) { - Connection conn = connWrapper.getConnection(); conn.commit(); if (_logger.isDebugEnabled()) { _logger.debug("commit tran completed"); } - conn.close(); + } + conn.close(); } catch (SQLException e) { @@ -1002,21 +1031,25 @@ public class DerbyMessageStore implements MessageStore int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException - { + { boolean localTx = getOrCreateTransaction(context); Connection conn = getConnection(context); ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { - PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); stmt.setLong(1,messageId); stmt.setInt(2, index); byte[] chunkData = new byte[contentBody.getSize()]; contentBody.getData().duplicate().get(chunkData); + /* this would be the Java 6 way of doing things Blob dataAsBlob = conn.createBlob(); dataAsBlob.setBytes(1L, chunkData); stmt.setBlob(3, dataAsBlob); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); + stmt.setBinaryStream(3, bis, chunkData.length); stmt.executeUpdate(); connWrapper.requiresCommit(); @@ -1048,7 +1081,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); stmt.setLong(1,messageId); stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); @@ -1060,9 +1093,13 @@ public class DerbyMessageStore implements MessageStore byte[] underlying = new byte[bodySize]; ByteBuffer buf = ByteBuffer.wrap(underlying); headerBody.writePayload(buf); +/* Blob dataAsBlob = conn.createBlob(); dataAsBlob.setBytes(1L, underlying); stmt.setBlob(6, dataAsBlob); +*/ + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(6,bis,underlying.length); stmt.setInt(7, mmd.getContentChunkCount()); @@ -1096,7 +1133,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement("SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"); + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); stmt.setLong(1,messageId); ResultSet rs = stmt.executeQuery(); @@ -1181,7 +1218,7 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement("SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"); + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); stmt.setLong(1,messageId); stmt.setInt(2, index); ResultSet rs = stmt.executeQuery(); @@ -1269,6 +1306,7 @@ public class DerbyMessageStore implements MessageStore public void process() throws AMQException { _queue.enqueue(_context, _message); + } } @@ -1303,7 +1341,7 @@ public class DerbyMessageStore implements MessageStore TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); while (rs.next()) @@ -1318,6 +1356,7 @@ public class DerbyMessageStore implements MessageStore if (queue == null) { queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); + _virtualHost.getQueueRegistry().registerQueue(queue); queues.put(queueName, queue); } -- cgit v1.2.1 From cd633e9ec729c628f38ac4c3021f6223e68d81bb Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 20 Jun 2008 09:37:20 +0000 Subject: QPID-1144 : Reference count drops to zero too early for immediate messages in a txn git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@669841 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/txn/LocalTransactionalContext.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index ad8303ec5d..3c71282c57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -93,11 +93,19 @@ public class LocalTransactionalContext implements TransactionalContext public void process() throws AMQException { - QueueEntry entry = _queue.enqueue(getStoreContext(),_message); + _message.incrementReference(); + try + { + QueueEntry entry = _queue.enqueue(getStoreContext(),_message); - if(entry.immediateAndNotDelivered()) + if(entry.immediateAndNotDelivered()) + { + getReturnMessages().add(new NoConsumersException(_message)); + } + } + finally { - getReturnMessages().add(new NoConsumersException(_message)); + _message.decrementReference(getStoreContext()); } } } -- cgit v1.2.1 From 5c6e95a122f69ae7eb556b6dad08c79402d28f92 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 20 Jun 2008 13:17:40 +0000 Subject: QPID-1101 : Updated Direct Exchange so it does not modify lists of queues git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@669885 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/DirectExchange.java | 2 +- .../org/apache/qpid/server/exchange/Index.java | 29 ++++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 5dcc2cf143..4da639567a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -198,7 +198,7 @@ public class DirectExchange extends AbstractExchange _logger.debug("Publishing message to queue " + queues); } - payload.enqueue(queues); + payload.enqueue(queues); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index 4f1f550e94..9bf82a3730 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -44,15 +45,15 @@ class Index 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; - } + queues = new ArrayList(); + } + else + { + queues = new ArrayList(queues); } + //next call is atomic, so there is no race to create the list + _index.put(key, queues); + if(queues.contains(queue)) { return false; @@ -68,10 +69,18 @@ class Index List queues = _index.get(key); if (queues != null) { + queues = new ArrayList(queues); boolean removed = queues.remove(queue); - if (queues.size() == 0) + if(removed) { - _index.remove(key); + if (queues.size() == 0) + { + _index.remove(key); + } + else + { + _index.put(key, queues); + } } return removed; } -- cgit v1.2.1 From 2dfa3fe2e626ae8cc26b519531b8281e2ed7055d Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 1 Jul 2008 13:56:39 +0000 Subject: QPID-887: name housekeeping thread properly. Apply patch from suran at wso2 dot com git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@673082 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 8b764efa42..f69751b708 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -71,7 +71,7 @@ public class VirtualHost implements Accessable private ACLPlugin _accessManager; - private final Timer _houseKeepingTimer = new Timer("Queue-housekeeping", true); + private final Timer _houseKeepingTimer; private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; @@ -146,6 +146,7 @@ public class VirtualHost implements Accessable // This isn't needed to be registered //_virtualHostMBean.register(); + _houseKeepingTimer = new Timer("Queue-housekeeping-"+name, true); _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); _exchangeFactory.initialise(hostConfig); -- cgit v1.2.1 From f15d072783f7cfe756cffe2a49dbf3c29fb44d8a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Jul 2008 16:28:53 +0000 Subject: QPID-871 - Added a ConnectionRegistry per Virtualhost to track the open connections. Altered the ApplicationRegistry so that when the shutdown hook is fired it: Unbinds from the listening sockets Then closes each virtualhost which in turn closes all the active TCP connections before closing the MessageStore thus preventing any logged errors occuring as a result of the active TCP connection performing an action on the closed store. Test provided MessageStoreShutdownTest which uses the new InternalBrokerBaseCase and InternalTestProtocolSession classes to perform system testing of the Broker without TCP framing or client codebase. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@674085 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 24 ++++- .../qpid/server/connection/ConnectionRegistry.java | 73 ++++++++++++++ .../server/connection/IConnectionRegistry.java | 38 ++++++++ .../server/protocol/AMQMinaProtocolSession.java | 105 +++++++++++++++------ .../qpid/server/protocol/AMQProtocolSession.java | 5 + .../qpid/server/registry/ApplicationRegistry.java | 88 ++++++++++++++++- .../ConfigurationFileApplicationRegistry.java | 42 --------- .../qpid/server/registry/IApplicationRegistry.java | 15 ++- .../qpid/server/util/NullApplicationRegistry.java | 49 ---------- .../qpid/server/virtualhost/VirtualHost.java | 23 ++++- 10 files changed, 331 insertions(+), 131 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 41d7f6c067..8ad2ace1b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -34,7 +34,6 @@ 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.common.FixedSizeByteBufferAllocator; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; @@ -421,7 +420,8 @@ public class Main bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); } - acceptor.bind(bindAddress, handler, sconfig); + bind(acceptor, bindAddress, handler, sconfig); + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -432,7 +432,8 @@ public class Main try { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + bind(acceptor, new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); @@ -455,6 +456,23 @@ public class Main } } + /** + * Ensure that any bound Acceptors are recorded in the registry so they can be closed later. + * + * @param acceptor + * @param bindAddress + * @param handler + * @param sconfig + * + * @throws IOException from the acceptor.bind command + */ + private void bind(IoAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException + { + acceptor.bind(bindAddress, handler, sconfig); + + ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor); + } + public static void main(String[] args) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java new file mode 100644 index 0000000000..d287595e2d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.connection; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.protocol.AMQConstant; + +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.List; + +public class ConnectionRegistry implements IConnectionRegistry +{ + private List _registry = new CopyOnWriteArrayList(); + + private VirtualHost _virtualHost; + + public ConnectionRegistry(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public void initialise() + { + + } + + /** Close all of the currently open connections. */ + public void close() throws AMQException + { + while (!_registry.isEmpty()) + { + AMQProtocolSession connection = _registry.get(0); + + connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", + 0, 0, + connection.getProtocolOutputConverter().getProtocolMajorVersion(), + connection.getProtocolOutputConverter().getProtocolMinorVersion(), + (Throwable) null), true); + } + } + + public void registerConnection(AMQProtocolSession connnection) + { + _registry.add(connnection); + } + + public void deregisterConnection(AMQProtocolSession connnection) + { + _registry.remove(connnection); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java new file mode 100644 index 0000000000..d64fde1c20 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.connection; + +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +public interface IConnectionRegistry +{ + + public void initialise(); + + public void close() throws AMQException; + + public void registerConnection(AMQProtocolSession connnection); + + public void deregisterConnection(AMQProtocolSession connnection); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index bdb16d0fcb..b4075b81ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -25,6 +25,7 @@ import org.apache.log4j.Logger; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoServiceConfig; import org.apache.mina.common.IoSession; +import org.apache.mina.common.CloseFuture; import org.apache.mina.transport.vmpipe.VmPipeAddress; import org.apache.qpid.AMQChannelException; @@ -99,7 +100,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private Object _lastSent; - private boolean _closed; + protected boolean _closed; // maximum number of channels this session should have private long _maxNoOfChannels = 1000; @@ -115,13 +116,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private MethodDispatcher _dispatcher; private ProtocolSessionIdentifier _sessionIdentifier; + private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L; + private org.apache.mina.common.WriteFuture _lastWriteFuture; + public ManagedObject getManagedObject() { return _managedObject; } public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) - throws AMQException + throws AMQException { _stateManager = new AMQStateManager(virtualHostRegistry, this); _minaProtocolSession = session; @@ -145,7 +149,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, - AMQStateManager stateManager) throws AMQException + AMQStateManager stateManager) throws AMQException { _stateManager = stateManager; _minaProtocolSession = session; @@ -199,7 +203,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } private void frameReceived(AMQFrame frame) throws AMQException - { + { int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); @@ -222,15 +226,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { if (_logger.isInfoEnabled()) { - _logger.info("Channel[" + channelId + "] awaiting closure ignoring"); + _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); } + closeProtocolSession(); return; } } - - try { body.handle(channelId, this); @@ -258,7 +261,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable String locales = "en_US"; - AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), (short) getProtocolMinorVersion(), null, @@ -266,7 +268,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable locales.getBytes()); _minaProtocolSession.write(responseBody.generateFrame(0)); - } catch (AMQException e) { @@ -332,27 +333,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.info("Closing connection due to: " + e.getMessage()); } - closeSession(); - AMQConnectionException ce = - evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, - AMQConstant.CHANNEL_ERROR.getName().toString()); + evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(ce.getCloseFrame(channelId)); + closeConnection(channelId, ce, false); } } catch (AMQConnectionException e) { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - markChannelAwaitingCloseOk(channelId); - closeSession(); - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(e.getCloseFrame(channelId)); + closeConnection(channelId, e, false); } } catch (Exception e) @@ -365,7 +355,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.error("Unexpected exception while processing frame. Closing connection.", e); - _minaProtocolSession.close(); + closeProtocolSession(); } } @@ -399,7 +389,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public void writeFrame(AMQDataBlock frame) { _lastSent = frame; - _minaProtocolSession.write(frame); + + _lastWriteFuture = _minaProtocolSession.write(frame); } public AMQShortString getContextKey() @@ -431,7 +422,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public AMQChannel getChannel(int channelId) throws AMQException { final AMQChannel channel = - ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); + ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); if ((channel == null) || channel.isClosing()) { return null; @@ -464,8 +455,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable if (_channelMap.size() == _maxNoOfChannels) { String errorMessage = - toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels - + "); can't create channel"; + toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels + + "); can't create channel"; _logger.error(errorMessage); throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); } @@ -619,6 +610,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable if (!_closed) { _closed = true; + + if (_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + closeAllChannels(); if (_managedObject != null) { @@ -632,9 +629,54 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } } + public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + markChannelAwaitingCloseOk(channelId); + closeSession(); + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(e.getCloseFrame(channelId)); + + if (closeProtocolSession) + { + closeProtocolSession(); + } + } + + public void closeProtocolSession() + { + closeProtocolSession(true); + } + + public void closeProtocolSession(boolean waitLast) + { + _logger.debug("Waiting for last write to join."); + if (waitLast && (_lastWriteFuture != null)) + { + _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); + } + + _logger.debug("REALLY Closing protocol session:" + _minaProtocolSession); + final CloseFuture future = _minaProtocolSession.close(); + future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); + + try + { + _stateManager.changeState(AMQState.CONNECTION_CLOSED); + } + catch (AMQException e) + { + _logger.info(e.getMessage()); + } + } + public String toString() { - return _minaProtocolSession.getRemoteAddress() + "("+(getAuthorizedID() == null ? "?" : getAuthorizedID().getName()+")"); + return _minaProtocolSession.getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")"); } public String dump() @@ -752,6 +794,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public void setVirtualHost(VirtualHost virtualHost) throws AMQException { _virtualHost = virtualHost; + + _virtualHost.getConnectionRegistry().registerConnection(this); + _managedObject = createMBean(); _managedObject.register(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index c3400029da..1bac601225 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -25,6 +25,7 @@ import javax.security.sasl.SaslServer; import org.apache.qpid.AMQException; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.*; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -150,6 +151,10 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession /** This must be called when the session is _closed in order to free up any resources managed by the session. */ void closeSession() throws AMQException; + /** This must be called to close the session in order to free up any resources managed by the session. */ + void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException; + + /** @return a key that uniquely identifies this session */ Object getKey(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index d0dcd051f0..863f837462 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -24,9 +24,17 @@ import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.mina.common.IoAcceptor; import java.util.HashMap; import java.util.Map; +import java.net.InetSocketAddress; /** * An abstract application registry that provides access to configuration information and handles the @@ -48,6 +56,21 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; + protected final Map _acceptors = new HashMap(); + + protected ManagedObjectRegistry _managedObjectRegistry; + + protected AuthenticationManager _authenticationManager; + + protected VirtualHostRegistry _virtualHostRegistry; + + protected ACLPlugin _accessManager; + + protected PrincipalDatabaseManager _databaseManager; + + protected PluginManager _pluginManager; + + static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -57,7 +80,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { public void run() { - _logger.info("Shutting down application registries..."); removeAll(); } } @@ -90,6 +112,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + /** + * Method to cleanly shutdown specified registry running in this JVM + * + * @param instanceID the instance to shutdown + */ + public static void remove(int instanceID) { try @@ -111,8 +139,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + /** Method to cleanly shutdown all registries currently running in this JVM */ public static void removeAll() - { + { Object[] keys = _instanceMap.keySet().toArray(); for (Object k : keys) { @@ -162,6 +191,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void close() throws Exception { + //Stop incomming connections + unbind(); + + //Shutdown virtualhosts for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) { virtualHost.close(); @@ -174,11 +207,31 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + private void unbind() + { + synchronized (_acceptors) + { + for (InetSocketAddress bindAddress : _acceptors.keySet()) + { + IoAcceptor acceptor = _acceptors.get(bindAddress); + acceptor.unbind(bindAddress); + } + } + } + public Configuration getConfiguration() { return _configuration; } + public void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor) + { + synchronized (_acceptors) + { + _acceptors.put(bindAddress, acceptor); + } + } + public T getConfiguredObject(Class instanceType) { T instance = (T) _configuredObjects.get(instanceType); @@ -204,4 +257,35 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _APPLICATION_REGISTRY = clazz; } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public ACLPlugin getAccessManager() + { + return _accessManager; + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public PluginManager getPluginManager() + { + return _pluginManager; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index fef958000a..baab56a4a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -48,18 +48,6 @@ import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private ACLPlugin _accessManager; - - private PrincipalDatabaseManager _databaseManager; - - private VirtualHostRegistry _virtualHostRegistry; - - private PluginManager _pluginManager; - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { @@ -145,39 +133,9 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public ACLPlugin getAccessManager() - { - return _accessManager; - } - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public PrincipalDatabaseManager getDatabaseManager() - { - return _databaseManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - public Collection getVirtualHostNames() { return getConfiguration().getList("virtualhosts.virtualhost.name"); } - public PluginManager getPluginManager() - { - return _pluginManager; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index ca10fbdba2..597ef042f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.registry; import java.util.Collection; +import java.net.InetSocketAddress; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.ManagedObjectRegistry; @@ -29,6 +30,7 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.mina.common.IoAcceptor; public interface IApplicationRegistry { @@ -39,6 +41,10 @@ public interface IApplicationRegistry */ void initialise() throws Exception; + /** + * Shutdown this Registry + * @throws Exception - //fixme needs to be made more specific + */ void close() throws Exception; /** @@ -71,5 +77,12 @@ public interface IApplicationRegistry ACLPlugin getAccessManager(); PluginManager getPluginManager(); - + + /** + * Register any acceptors for this registry + * @param bindAddress The address that the acceptor has been bound with + * @param acceptor The acceptor in use + */ + void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 0acfa84f31..87aa15be84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -42,19 +42,6 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public class NullApplicationRegistry extends ApplicationRegistry { - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private VirtualHostRegistry _virtualHostRegistry; - - private ACLPlugin _accessManager; - - private PrincipalDatabaseManager _databaseManager; - - private PluginManager _pluginManager; - - public NullApplicationRegistry() { super(new MapConfiguration(new HashMap())); @@ -84,47 +71,11 @@ public class NullApplicationRegistry extends ApplicationRegistry } - public Configuration getConfiguration() - { - return _configuration; - } - - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public PrincipalDatabaseManager getDatabaseManager() - { - return _databaseManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - public Collection getVirtualHostNames() { String[] hosts = {"test"}; return Arrays.asList(hosts); } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public ACLPlugin getAccessManager() - { - return _accessManager; - } - - public PluginManager getPluginManager() - { - return _pluginManager; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index f69751b708..977bd84491 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -26,6 +26,8 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.log4j.Logger; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.connection.ConnectionRegistry; +import org.apache.qpid.server.connection.IConnectionRegistry; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.Accessable; @@ -55,6 +57,8 @@ public class VirtualHost implements Accessable private final String _name; + private ConnectionRegistry _connectionRegistry; + private QueueRegistry _queueRegistry; private ExchangeRegistry _exchangeRegistry; @@ -74,7 +78,8 @@ public class VirtualHost implements Accessable private final Timer _houseKeepingTimer; private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; - + + public void setAccessableName(String name) { _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" @@ -86,6 +91,10 @@ public class VirtualHost implements Accessable return _name; } + public IConnectionRegistry getConnectionRegistry() + { + return _connectionRegistry; + } /** * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any @@ -143,8 +152,8 @@ public class VirtualHost implements Accessable _name = name; _virtualHostMBean = new VirtualHostMBean(); - // This isn't needed to be registered - //_virtualHostMBean.register(); + + _connectionRegistry = new ConnectionRegistry(this); _houseKeepingTimer = new Timer("Queue-housekeeping-"+name, true); _queueRegistry = new DefaultQueueRegistry(this); @@ -283,14 +292,20 @@ public class VirtualHost implements Accessable public ACLPlugin getAccessManager() { return _accessManager; - } + } public void close() throws Exception { + //Stop Housekeeping if (_houseKeepingTimer != null) { _houseKeepingTimer.cancel(); } + + //Stop Connections + _connectionRegistry.close(); + + //Close MessageStore if (_messageStore != null) { _messageStore.close(); -- cgit v1.2.1 From 1d3fdff5bd662c118ce4fd95fd12a1d41c25f494 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 7 Jul 2008 14:44:54 +0000 Subject: QPID-474 Make sure that our SASL servers actually, y'know, validate the password AmqPlainSaslServer.java: Actually check password PlainSaslServer.java: Actually check password SaslServerTestCase.java: base test case for testing our SASL impls AMQPlainSaslServerTest.java: test the AMQPlainSaslServer dealie PlainSaslServerTest.java: test the PlainSaslServer TestPrincipalDatabase.java: Mockish TestPrincipalDatabase git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@674510 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/auth/sasl/amqplain/AmqPlainSaslServer.java | 9 ++++++--- .../qpid/server/security/auth/sasl/plain/PlainSaslServer.java | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java index 7842f376fb..9f56b8521a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java @@ -68,12 +68,15 @@ public class AmqPlainSaslServer implements SaslServer PasswordCallback passwordCb = new PasswordCallback("prompt", false); // TODO: should not get pwd as a String but as a char array... String pwd = (String) ft.getString("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()) + String storedPwd = new String(passwordCb.getPassword()); + if (storedPwd.equals(pwd)) + { + _complete = true; + } + if (authzCb.isAuthorized() && _complete) { _authorizationId = authzCb.getAuthenticationID(); return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java index 36aeb77fe1..45fb9a4e42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -72,17 +72,19 @@ public class PlainSaslServer implements SaslServer // 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()) + String storedPwd = new String(passwordCb.getPassword()); + if (storedPwd.equals(pwd)) + { + _complete = true; + } + if (authzCb.isAuthorized() && _complete) { _authorizationId = authzCb.getAuthenticationID(); return null; -- cgit v1.2.1 From b633025863a1040d71d3834696aeb5856a8da58b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 15 Jul 2008 11:35:54 +0000 Subject: QPID-1175 : VirtualHost now validates that name is non-null and non-empty. Full protocol validation of the virtualhost name has not been performed. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@676883 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 977bd84491..b25a56344e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -149,6 +149,11 @@ public class VirtualHost implements Accessable public VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception { + if (name == null || name.length() == 0) + { + throw new IllegalArgumentException("Illegal name (" + name + ") for virtualhost."); + } + _name = name; _virtualHostMBean = new VirtualHostMBean(); -- cgit v1.2.1 From 3e93cf6e12cbe10f16b3c98357c5fc36e8a3e345 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 15 Jul 2008 11:42:55 +0000 Subject: QPID-1172 : Moved unregistration out of the sendLock. Potential refactor possible between processQueue and flushSubscription git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@676887 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 414 +++++++++------------ 1 file changed, 175 insertions(+), 239 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 247402e442..f06e3598a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -82,16 +82,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private volatile Subscription _exclusiveSubscriber; - private final QueueEntryList _entries; - private final AMQQueueMBean _managedObject; private final Executor _asyncDelivery; private final AtomicLong _totalMessagesReceived = new AtomicLong(); - - /** max allowed size(KB) of a single message */ @Configured(path = "maximumMessageSize", defaultValue = "0") public long _maximumMessageSize; @@ -112,14 +108,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") public long _minimumAlertRepeatGap; - - private static final int MAX_ASYNC_DELIVERIES = 10; - private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); - private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); private AtomicReference _asynchronousRunner = new AtomicReference(null); private AtomicInteger _deliveredMessages = new AtomicInteger(); @@ -127,7 +119,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException { - this(name,durable,owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory()); + this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); } protected SimpleAMQQueue(AMQShortString name, @@ -136,7 +128,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory) - throws AMQException + throws AMQException { if (name == null) @@ -168,7 +160,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new AMQException("AMQQueue MBean creation has failed ", e); } - // This ensure that the notification checks for the configured alerts are created. setMaximumMessageAge(_maximumMessageAge); setMaximumMessageCount(_maximumMessageCount); @@ -204,7 +195,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _virtualHost; } - // ------ bind and unbind public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException @@ -227,27 +217,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } boolean removed = _bindings.remove(routingKey, arguments, exchange); - if(!removed) + if (!removed) { _logger.error("Mismatch between queue bindings and exchange record of bindings"); } } - // ------ Manage Subscriptions public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException { - - if(isExclusiveSubscriber()) + if (isExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); } - if(exclusive) + if (exclusive) { - if(getConsumerCount() != 0) + if (getConsumerCount() != 0) { throw new ExistingSubscriptionPreventsExclusive(); } @@ -258,16 +246,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - _activeSubscriberCount.incrementAndGet(); subscription.setStateListener(this); - subscription.setLastSeenEntry(null,_entries.getHead()); + subscription.setLastSeenEntry(null, _entries.getHead()); - if(!isDeleted()) + if (!isDeleted()) { subscription.setQueue(this); _subscriptionList.add(subscription); - if(isDeleted()) + if (isDeleted()) { subscription.queueDeleted(this); } @@ -277,39 +264,32 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // TODO } - deliverAsync(subscription); } public synchronized void unregisterSubscription(final Subscription subscription) throws AMQException { - if(subscription == null) + if (subscription == null) { throw new NullPointerException("subscription argument is null"); } boolean removed = _subscriptionList.remove(subscription); - - - if(removed) + if (removed) { subscription.close(); // No longer can the queue have an exclusive consumer setExclusiveSubscriber(null); - QueueEntry lastSeen; - while((lastSeen = subscription.getLastSeenEntry()) != null) + while ((lastSeen = subscription.getLastSeenEntry()) != null) { subscription.setLastSeenEntry(lastSeen, null); } - - - // auto-delete queues must be deleted if there are no remaining subscribers if (_autoDelete && getConsumerCount() == 0) @@ -324,30 +304,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // 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 subscription.queueDeleted(this); - } + } } - } - // ------ Enqueue / Dequeue public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException { - - incrementQueueCount(); incrementQueueSize(message); _totalMessagesReceived.incrementAndGet(); - - QueueEntry entry; + QueueEntry entry; Subscription exclusiveSub = _exclusiveSubscriber; - if(exclusiveSub != null) + if (exclusiveSub != null) { exclusiveSub.getSendLock(); @@ -357,11 +332,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliverToSubscription(exclusiveSub, entry); - // where there is more than one producer there's a reasonable chance that even though there is // no "queueing" we do not deliver because we get an interleving of _entries.add and // deliverToSubscription between threads. Therefore have one more try. - if(!(entry.isAcquired() || entry.isDeleted())) + if (!(entry.isAcquired() || entry.isDeleted())) { deliverToSubscription(exclusiveSub, entry); } @@ -381,13 +355,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener */ SubscriptionList.SubscriptionNode node = _lastSubscriptionNode.get(); SubscriptionList.SubscriptionNode nextNode = node.getNext(); - if(nextNode == null) + if (nextNode == null) { nextNode = _subscriptionList.getHead().getNext(); } - while(nextNode != null) + while (nextNode != null) { - if(_lastSubscriptionNode.compareAndSet(node, nextNode)) + if (_lastSubscriptionNode.compareAndSet(node, nextNode)) { break; } @@ -395,21 +369,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { node = _lastSubscriptionNode.get(); nextNode = node.getNext(); - if(nextNode == null) + if (nextNode == null) { nextNode = _subscriptionList.getHead().getNext(); } } } - // always do one extra loop after we believe we've finished // this catches the case where we *just* miss an update int loops = 2; - while(!(entry.isAcquired() || entry.isDeleted()) && loops != 0) + while (!(entry.isAcquired() || entry.isDeleted()) && loops != 0) { - if(nextNode == null) + if (nextNode == null) { loops--; nextNode = _subscriptionList.getHead(); @@ -425,20 +398,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - - if(entry.immediateAndNotDelivered()) + if (entry.immediateAndNotDelivered()) { dequeue(storeContext, entry); entry.dispose(storeContext); } - else if(!(entry.isAcquired() || entry.isDeleted())) + else if (!(entry.isAcquired() || entry.isDeleted())) { checkSubscriptionsNotAheadOfDelivery(entry); deliverAsync(); } - try { _managedObject.checkForNotification(entry.getMessage()); @@ -448,7 +419,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new AMQException("Unable to get notification from manage queue: " + e, e); } - return entry; } @@ -460,12 +430,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.getSendLock(); try { - if(subscriptionReadyAndHasInterest(sub, entry) - && !sub.isSuspended()) + if (subscriptionReadyAndHasInterest(sub, entry) + && !sub.isSuspended()) { - if( !sub.wouldSuspend(entry)) + if (!sub.wouldSuspend(entry)) { - if(!sub.isBrowser() && !entry.acquire(sub)) + if (!sub.isBrowser() && !entry.acquire(sub)) { // restore credit here that would have been taken away by wouldSuspend since we didn't manage // to acquire the entry for this subscription @@ -516,11 +486,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no // interest in. QueueEntry node = sub.getLastSeenEntry(); - while(node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node)) ) + while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node))) { QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { sub.setLastSeenEntry(node, newNode); node = sub.getLastSeenEntry(); @@ -533,8 +503,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - - if(node == entry) + if (node == entry) { // If the first entry that subscription can process is the one we are trying to deliver to it, then we are // good @@ -555,11 +524,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { QueueEntry node = sub.getLastSeenEntry(); - if(node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) + if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) { do { - if(sub.setLastSeenEntry(node,entry)) + if (sub.setLastSeenEntry(node, entry)) { return; } @@ -567,7 +536,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { node = sub.getLastSeenEntry(); } - } while (node != null && entry.compareTo(node) < 0); + } + while (node != null && entry.compareTo(node) < 0); } } @@ -577,28 +547,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards - while(subscriberIter.advance()) + while (subscriberIter.advance()) { Subscription sub = subscriberIter.getNode().getSubscription(); // we don't make browsers send the same stuff twice - if(!sub.isBrowser()) + if (!sub.isBrowser()) { updateLastSeenEntry(sub, entry); } } - deliverAsync(); - } public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException { decrementQueueCount(); decrementQueueSize(entry); - if(entry.acquiredBySubscription()) + if (entry.acquiredBySubscription()) { _deliveredMessages.decrementAndGet(); } @@ -606,7 +574,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener try { AMQMessage msg = entry.getMessage(); - if(isDurable() && msg.isPersistent()) + if (isDurable() && msg.isPersistent()) { _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); } @@ -626,7 +594,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new FailedDequeueException(_name.toString(), e); } - } private void decrementQueueSize(final QueueEntry entry) @@ -647,7 +614,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener subscription.getSendLock(); try { - if(!subscription.isClosed()) + if (!subscription.isClosed()) { deliverMessage(subscription, entry); return true; @@ -663,10 +630,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - - - - public int getConsumerCount() { return _subscriptionList.size(); @@ -700,7 +663,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public int getUndeliveredMessageCount() { int count = getMessageCount() - _deliveredMessages.get(); - if(count < 0) + if (count < 0) { return 0; } @@ -710,7 +673,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public long getReceivedMessageCount() { return _totalMessagesReceived.get(); @@ -732,16 +694,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _deleted.get(); } - - public List getMessagesOnTheQueue() { ArrayList entryList = new ArrayList(); QueueEntryIterator queueListIterator = _entries.iterator(); - while(queueListIterator.advance()) + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); - if(node != null && !node.isDeleted()) + if (node != null && !node.isDeleted()) { entryList.add(node); } @@ -752,14 +712,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void stateChange(Subscription sub, Subscription.State oldState, Subscription.State newState) { - if(oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE) + if (oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE) { _activeSubscriberCount.decrementAndGet(); } - else if(newState == Subscription.State.ACTIVE) - { - if(oldState != Subscription.State.ACTIVE) + else if (newState == Subscription.State.ACTIVE) + { + if (oldState != Subscription.State.ACTIVE) { _activeSubscriberCount.incrementAndGet(); @@ -800,55 +760,52 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean filterComplete(); } - - public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) { return getMessagesOnTheQueue(new QueueEntryFilter() - { + { - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessage().getMessageId(); - return messageId >= fromMessageId && messageId <= toMessageId; - } + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return messageId >= fromMessageId && messageId <= toMessageId; + } - public boolean filterComplete() - { - return false; - } - }); + public boolean filterComplete() + { + return false; + } + }); } public QueueEntry getMessageOnTheQueue(final long messageId) { List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - private boolean _complete; + { + private boolean _complete; - public boolean accept(QueueEntry entry) - { - _complete = entry.getMessage().getMessageId() == messageId; - return _complete; - } + public boolean accept(QueueEntry entry) + { + _complete = entry.getMessage().getMessageId() == messageId; + return _complete; + } - public boolean filterComplete() - { - return _complete; - } - }); + public boolean filterComplete() + { + return _complete; + } + }); return entries.isEmpty() ? null : entries.get(0); } - public List getMessagesOnTheQueue(QueueEntryFilter filter) { ArrayList entryList = new ArrayList(); QueueEntryIterator queueListIterator = _entries.iterator(); - while(queueListIterator.advance() && !filter.filterComplete()) + while (queueListIterator.advance() && !filter.filterComplete()) { QueueEntry node = queueListIterator.getNode(); - if(!node.isDeleted() && filter.accept(node)) + if (!node.isDeleted() && filter.accept(node)) { entryList.add(node); } @@ -857,7 +814,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void moveMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, @@ -867,24 +823,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); MessageStore store = getVirtualHost().getMessageStore(); - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessage().getMessageId(); - return (messageId >= fromMessageId) - && (messageId <= toMessageId) - && entry.acquire(); - } + { - public boolean filterComplete() - { - return false; - } - }); + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return (messageId >= fromMessageId) + && (messageId <= toMessageId) + && entry.acquire(); + } + public boolean filterComplete() + { + return false; + } + }); try { @@ -895,7 +849,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { AMQMessage message = entry.getMessage(); - if(message.isPersistent() && toQueue.isDurable()) + if (message.isPersistent() && toQueue.isDurable()) { store.enqueueMessage(storeContext, toQueue, message.getMessageId()); } @@ -943,7 +897,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new RuntimeException(e); } - } public void copyMessagesToAnotherQueue(final long fromMessageId, @@ -954,30 +907,29 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); MessageStore store = getVirtualHost().getMessageStore(); - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { + { - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessage().getMessageId(); - if((messageId >= fromMessageId) - && (messageId <= toMessageId)) - { - if(!entry.isDeleted()) - { - return entry.getMessage().incrementReference(); - } - } + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + if ((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + if (!entry.isDeleted()) + { + return entry.getMessage().incrementReference(); + } + } - return false; - } + return false; + } - public boolean filterComplete() - { - return false; - } - }); + public boolean filterComplete() + { + return false; + } + }); try { @@ -988,7 +940,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { AMQMessage message = entry.getMessage(); - if(message.isReferenced() && message.isPersistent() && toQueue.isDurable()) + if (message.isReferenced() && message.isPersistent() && toQueue.isDurable()) { store.enqueueMessage(storeContext, toQueue, message.getMessageId()); } @@ -1021,7 +973,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { for (QueueEntry entry : entries) { - if(entry.getMessage().isReferenced()) + if (entry.getMessage().isReferenced()) { toQueue.enqueue(storeContext, entry.getMessage()); } @@ -1036,7 +988,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new RuntimeException(e); } - } public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) @@ -1046,17 +997,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { QueueEntryIterator queueListIterator = _entries.iterator(); - - while(queueListIterator.advance()) + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); final long messageId = node.getMessage().getMessageId(); - if((messageId >= fromMessageId) - && (messageId <= toMessageId) - && !node.isDeleted() - && node.acquire()) + if ((messageId >= fromMessageId) + && (messageId <= toMessageId) + && !node.isDeleted() + && node.acquire()) { node.discard(storeContext); } @@ -1072,16 +1022,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Management functions - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException { QueueEntryIterator queueListIterator = _entries.iterator(); boolean noDeletes = true; - while(noDeletes && queueListIterator.advance() ) + while (noDeletes && queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); - if(!node.isDeleted() && node.acquire()) + if (!node.isDeleted() && node.acquire()) { node.discard(storeContext); noDeletes = false; @@ -1096,10 +1045,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; - while(queueListIterator.advance()) + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); - if(!node.isDeleted() && node.acquire()) + if (!node.isDeleted() && node.acquire()) { node.discard(storeContext); count++; @@ -1110,7 +1059,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void addQueueDeleteTask(final Task task) { _deleteTaskList.add(task); @@ -1126,7 +1074,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener while (subscriptionIter.advance()) { Subscription s = subscriptionIter.getNode().getSubscription(); - if(s != null) + if (s != null) { s.queueDeleted(this); } @@ -1135,7 +1083,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); - _managedObject.unregister(); for (Task task : _deleteTaskList) { @@ -1149,15 +1096,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void deliverAsync() { _stateChangeCount.incrementAndGet(); Runner runner = new Runner(); - if(_asynchronousRunner.compareAndSet(null,runner)) - { + if (_asynchronousRunner.compareAndSet(null, runner)) + { _asyncDelivery.execute(runner); } } @@ -1193,12 +1139,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - private class SubFlushRunner implements ReadWriteRunnable { private final Subscription _sub; - public SubFlushRunner(Subscription sub) { _sub = sub; @@ -1216,7 +1160,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _logger.error(e); } - if(!complete && !_sub.isSuspended()) + if (!complete && !_sub.isSuspended()) { _asyncDelivery.execute(this); } @@ -1244,25 +1188,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean atTail = false; boolean advanced; - while(!sub.isSuspended() && !atTail && deliveries != 0) + while (!sub.isSuspended() && !atTail && deliveries != 0) { advanced = false; sub.getSendLock(); try { - if(sub.isActive()) + if (sub.isActive()) { QueueEntry node = moveSubscriptionToNextNode(sub); - if(!(node.isAcquired() || node.isDeleted())) + if (!(node.isAcquired() || node.isDeleted())) { - if(!sub.isSuspended()) + if (!sub.isSuspended()) { - if(sub.hasInterest(node)) + if (sub.hasInterest(node)) { - if(!sub.wouldSuspend(node)) + if (!sub.wouldSuspend(node)) { - if(!sub.isBrowser() && !node.acquire(sub)) + if (!sub.isBrowser() && !node.acquire(sub)) { sub.restoreCredit(node); @@ -1272,11 +1216,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliveries--; deliverMessage(sub, node); - if(sub.isBrowser()) + if (sub.isBrowser()) { QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { advanced = true; sub.setLastSeenEntry(node, newNode); @@ -1295,7 +1239,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { // this subscription is not interested in this node so we can skip over it QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { sub.setLastSeenEntry(node, newNode); } @@ -1318,12 +1262,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc // which would give us memory "leak". - if(!isExclusiveSubscriber()) + if (!isExclusiveSubscriber()) { advanceAllSubscriptions(); } - if(atTail && sub.isAutoClose()) + if (atTail && sub.isAutoClose()) { unregisterSubscription(sub); @@ -1337,7 +1281,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener protected void advanceAllSubscriptions() throws AMQException { SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); - while(subscriberIter.advance()) + while (subscriberIter.advance()) { SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); Subscription sub = subNode.getSubscription(); @@ -1349,19 +1293,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throws AMQException { QueueEntry node = sub.getLastSeenEntry(); - - while(node != null && (node.isAcquired() || node.isDeleted() || node.expired())) + + while (node != null && (node.isAcquired() || node.isDeleted() || node.expired())) { - if(!node.isAcquired() && !node.isDeleted() && node.expired()) + if (!node.isAcquired() && !node.isDeleted() && node.expired()) { - if(node.acquire()) + if (node.acquire()) { final StoreContext reapingStoreContext = new StoreContext(); node.discard(reapingStoreContext); } } QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { sub.setLastSeenEntry(node, newNode); node = sub.getLastSeenEntry(); @@ -1375,7 +1319,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return node; } - private void processQueue(Runnable runner) throws AMQException { long stateChangeCount; @@ -1385,51 +1328,51 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener int extraLoops = 1; int deliveries = MAX_ASYNC_DELIVERIES; - _asynchronousRunner.compareAndSet(runner,null); + _asynchronousRunner.compareAndSet(runner, null); - while(deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete ) && _asynchronousRunner.compareAndSet(null,runner)) + while (deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) { // we want to have one extra loop after every subscription has reached the point where it cannot move // further, just in case the advance of one subscription in the last loop allows a different subscription to // move forward in the next iteration - if(previousStateChangeCount != stateChangeCount) + if (previousStateChangeCount != stateChangeCount) { extraLoops = 1; } - + previousStateChangeCount = stateChangeCount; deliveryIncomplete = _subscriptionList.size() != 0; boolean done = true; - SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); //iterate over the subscribers and try to advance their pointer - while(subscriptionIter.advance()) + while (subscriptionIter.advance()) { + boolean closeConsumer = false; Subscription sub = subscriptionIter.getNode().getSubscription(); - if(sub != null) + if (sub != null) { sub.getSendLock(); try { QueueEntry node = moveSubscriptionToNextNode(sub); - if(node != null && sub.isActive()) + if (node != null && sub.isActive()) { boolean advanced = false; boolean subActive = false; - if(!(node.isAcquired() || node.isDeleted())) + if (!(node.isAcquired() || node.isDeleted())) { - if(!sub.isSuspended()) + if (!sub.isSuspended()) { subActive = true; - if(sub.hasInterest(node)) + if (sub.hasInterest(node)) { - if(!sub.wouldSuspend(node)) + if (!sub.wouldSuspend(node)) { - if(!sub.isBrowser() && !node.acquire(sub)) + if (!sub.isBrowser() && !node.acquire(sub)) { sub.restoreCredit(node); @@ -1439,32 +1382,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliverMessage(sub, node); deliveries--; - if(sub.isBrowser()) + if (sub.isBrowser()) { QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { sub.setLastSeenEntry(node, newNode); node = sub.getLastSeenEntry(); advanced = true; } - } } done = false; } else { - node.addStateChangeListener(new QueueEntryListener(sub,node)); + node.addStateChangeListener(new QueueEntryListener(sub, node)); } } else { // this subscription is not interested in this node so we can skip over it QueueEntry newNode = _entries.next(node); - if(newNode != null) + if (newNode != null) { sub.setLastSeenEntry(node, newNode); } @@ -1475,25 +1417,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener done = done && (!subActive || atTail); - if(atTail && !advanced && sub.isAutoClose()) - { - unregisterSubscription(sub); - - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); - - } - + closeConsumer = (atTail && !advanced && sub.isAutoClose()); } } finally { sub.releaseSendLock(); } + + if (closeConsumer) + { + unregisterSubscription(sub); + + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + } + } - if(done) + if (done) { - if(extraLoops == 0) + if (extraLoops == 0) { deliveryIncomplete = false; } @@ -1508,20 +1451,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - - _asynchronousRunner.set(null); } // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit // therefore we should schedule this runner again (unless someone beats us to it :-) ). - if(deliveries == 0 && _asynchronousRunner.compareAndSet(null,runner)) + if (deliveries == 0 && _asynchronousRunner.compareAndSet(null, runner)) { _asyncDelivery.execute(runner); } } - public void removeExpiredIfNoSubscribers() throws AMQException { @@ -1529,10 +1469,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntryIterator queueListIterator = _entries.iterator(); - while(queueListIterator.advance()) + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); - if(!node.isDeleted() && node.expired() && node.acquire()) + if (!node.isDeleted() && node.expired() && node.acquire()) { node.discard(storeContext); @@ -1542,7 +1482,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public long getMinimumAlertRepeatGap() { return _minimumAlertRepeatGap; @@ -1561,7 +1500,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setMaximumMessageAge(long maximumMessageAge) { _maximumMessageAge = maximumMessageAge; - if(maximumMessageAge == 0L) + if (maximumMessageAge == 0L) { _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); } @@ -1579,7 +1518,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setMaximumMessageCount(final long maximumMessageCount) { _maximumMessageCount = maximumMessageCount; - if(maximumMessageCount == 0L) + if (maximumMessageCount == 0L) { _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); } @@ -1588,8 +1527,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); } - - } public long getMaximumQueueDepth() @@ -1601,7 +1538,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setMaximumQueueDepth(final long maximumQueueDepth) { _maximumQueueDepth = maximumQueueDepth; - if(maximumQueueDepth == 0L) + if (maximumQueueDepth == 0L) { _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); } @@ -1620,7 +1557,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setMaximumMessageSize(final long maximumMessageSize) { _maximumMessageSize = maximumMessageSize; - if(maximumMessageSize == 0L) + if (maximumMessageSize == 0L) { _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); } @@ -1630,7 +1567,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public Set getNotificationChecks() { return _notificationChecks; @@ -1654,7 +1590,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean equals(Object o) { - return _entry == ((QueueEntryListener)o)._entry && _sub == ((QueueEntryListener)o)._sub; + return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub; } public int hashCode() -- cgit v1.2.1 From a74ffb4bd042bfb8edefb3e539b92dcd0589a2e0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Jul 2008 12:41:06 +0000 Subject: QPID-1181 : Added additional logging to help diagnose a NullPointerException git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@677263 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/registry/ApplicationRegistry.java | 2 +- .../main/java/org/apache/qpid/server/util/NullApplicationRegistry.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 863f837462..a355edee9a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -44,7 +44,7 @@ import java.net.InetSocketAddress; */ public abstract class ApplicationRegistry implements IApplicationRegistry { - private static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); + protected static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); private static Map _instanceMap = new HashMap(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 87aa15be84..ee5f9d5e88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -49,6 +49,8 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { + _logger.info("Initialising NullApplicationRegistry"); + _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); Properties users = new Properties(); -- cgit v1.2.1 From 1fa9984f40a0b6d2b8bc94dab775a234c2fc029c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Jul 2008 16:27:11 +0000 Subject: QPID-871 : The shutdown change had a spurious getInstance() call which would case a new instance of ID 1 to be created if there wasn't one, it would then procede to shutdown that MBeanServer not the MBeanServer attached to the ApplicationRegistry that is being shutdown. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@677327 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ApplicationRegistry.java | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index a355edee9a..63171d583a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -70,7 +70,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected PluginManager _pluginManager; - static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -123,15 +122,18 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { IApplicationRegistry instance = _instanceMap.get(instanceID); - if(instance != null) + if (instance != null) { + if (_logger.isInfoEnabled()) + { + _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); + } instance.close(); } } catch (Exception e) { - _logger.error("Error shutting down message store: " + e, e); - + _logger.error("Error shutting down Application Registry(" + instanceID + "): " + e, e); } finally { @@ -141,7 +143,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry /** Method to cleanly shutdown all registries currently running in this JVM */ public static void removeAll() - { + { Object[] keys = _instanceMap.keySet().toArray(); for (Object k : keys) { @@ -191,6 +193,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void close() throws Exception { + if (_logger.isInfoEnabled()) + { + _logger.info("Shutting down ApplicationRegistry:"+this); + } + //Stop incomming connections unbind(); @@ -201,9 +208,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } // close the rmi registry(if any) started for management - if (getInstance().getManagedObjectRegistry() != null) + if (getManagedObjectRegistry() != null) { - getInstance().getManagedObjectRegistry().close(); + getManagedObjectRegistry().close(); } } @@ -252,7 +259,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return instance; } - public static void setDefaultApplicationRegistry(String clazz) { _APPLICATION_REGISTRY = clazz; -- cgit v1.2.1 From 8f84b0db27ba46ce5a4048435c2e3609b4476cf9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 17 Jul 2008 16:33:03 +0000 Subject: QPID-1182 : Added additional logging to identify the exception that caused Authentication to fail. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@677633 13f79535-47bb-0310-9956-ffa450edef68 --- .../handler/ConnectionSecureOkMethodHandler.java | 16 +++++++-------- .../handler/ConnectionStartOkMethodHandler.java | 5 ++++- .../server/security/auth/AuthenticationResult.java | 24 ++++++++++++++++++++-- .../PrincipalDatabaseAuthenticationManager.java | 7 +------ 4 files changed, 34 insertions(+), 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index 193c3a088b..621003be90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -57,9 +57,6 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener { AMQProtocolSession session = stateManager.getProtocolSession(); - - //fixme Vhost not defined yet - //session.getVirtualHost().getAuthenticationManager(); AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); SaslServer ss = session.getSaslServer(); @@ -72,11 +69,12 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener 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); + Exception cause = authResult.getCause(); + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + // This should be abstracted + stateManager.changeState(AMQState.CONNECTION_CLOSING); ConnectionCloseBody connectionCloseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), @@ -84,7 +82,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener body.getClazz(), body.getMethod()); - session.writeFrame(connectionCloseBody.generateFrame(0) ); + session.writeFrame(connectionCloseBody.generateFrame(0)); disposeSaslServer(session); break; case SUCCESS: @@ -96,7 +94,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionStartOkMethodHandler.getConfiguredFrameSize(), HeartbeatConfig.getInstance().getDelay()); session.writeFrame(tuneBody.generateFrame(0)); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); disposeSaslServer(session); break; case CONTINUE: diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index f02121c89f..f53e56601b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -93,7 +93,10 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< switch (authResult.status) { case ERROR: - _logger.info("Authentication failed"); + Exception cause = authResult.getCause(); + + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + stateManager.changeState(AMQState.CONNECTION_CLOSING); ConnectionCloseBody closeBody = diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java index 0e3aea4de0..3f846b9dd0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.security.auth; +import javax.security.sasl.SaslException; + public class AuthenticationResult { public enum AuthenticationStatus @@ -29,15 +31,33 @@ public class AuthenticationResult public AuthenticationStatus status; public byte[] challenge; + + private Exception cause; + + public AuthenticationResult(AuthenticationStatus status) + { + this(null, status, null); + } public AuthenticationResult(byte[] challenge, AuthenticationStatus status) + { + this(challenge, status, null); + } + + public AuthenticationResult(AuthenticationStatus error, Exception cause) + { + this(null, error, cause); + } + + public AuthenticationResult(byte[] challenge, AuthenticationStatus status, Exception cause) { this.status = status; this.challenge = challenge; + this.cause = cause; } - public AuthenticationResult(AuthenticationStatus status) + public Exception getCause() { - this.status = status; + return cause; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index f589140e8e..e5bf3edfca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -230,12 +230,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan } catch (SaslException e) { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); } } - - public AuthenticationResult isAuthorize(VirtualHost vhost, String username) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - } } -- cgit v1.2.1 From bd91d29be3a1f51ebad2e618cd5848d98059f777 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 23 Jul 2008 10:30:26 +0000 Subject: QPID-1187 : The broker did not correctly handle subscriptions that would suspend due to exhaustion of bytes credit. The processQueue loop would spin, this fix marks the subscription inactive for that loop in processQueue so it will stop processing that subscription and ultimately the whole processQueue loop if required. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@679059 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index f06e3598a7..4b7da30800 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1397,8 +1397,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } done = false; } - else + else // Not enough Credit for message and wouldSuspend { + //QPID-1187 - Treat the subscription as suspended for this message + // and wait for the message to be removed to continue delivery. + subActive = false; + node.addStateChangeListener(new QueueEntryListener(sub, node)); } } -- cgit v1.2.1 From 011ba4a3e4990077c468f122a9575018a9f09965 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 7 Aug 2008 11:15:01 +0000 Subject: QPID-1218: Boost broker performance by lots. AMQMessage: Allow references to be incremented in a pile IncomingMessage: Increment message references in one go, flatten delivery loop a little. Make _destinationQueues an ArrayList, massively increasing performance. Iter ate through it with indexing AccessResult: don't use StringBuilder so much Update tests and exchanges to reflect new API usage, almost all of this is just type narrowing except for Topic where there's an extra copy, but it isn't too bad relative to the number of HashSet and HashMap operations that go on inside there. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683583 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/DirectExchange.java | 2 +- .../qpid/server/exchange/HeadersExchange.java | 2 +- .../org/apache/qpid/server/exchange/Index.java | 10 ++-- .../apache/qpid/server/exchange/TopicExchange.java | 9 ++-- .../org/apache/qpid/server/queue/AMQMessage.java | 11 ++-- .../apache/qpid/server/queue/IncomingMessage.java | 61 ++++++---------------- .../qpid/server/security/access/AccessResult.java | 13 +++-- 7 files changed, 41 insertions(+), 67 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 4da639567a..616f47bd24 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -191,7 +191,7 @@ public class DirectExchange extends AbstractExchange final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); - final List queues = (routingKey == null) ? null : _index.get(routingKey); + final ArrayList queues = (routingKey == null) ? null : _index.get(routingKey); if (_logger.isDebugEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index d1bea3410b..1ee1f35de6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -249,7 +249,7 @@ public class HeadersExchange extends AbstractExchange _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); } boolean routed = false; - Collection queues = new ArrayList(); + ArrayList queues = new ArrayList(); for (Registration e : _bindings) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index 9bf82a3730..ec83161029 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -37,12 +37,12 @@ import org.apache.qpid.server.queue.AMQQueue; */ class Index { - private ConcurrentMap> _index - = new ConcurrentHashMap>(); + private ConcurrentMap> _index + = new ConcurrentHashMap>(); synchronized boolean add(AMQShortString key, AMQQueue queue) { - List queues = _index.get(key); + ArrayList queues = _index.get(key); if(queues == null) { queues = new ArrayList(); @@ -66,7 +66,7 @@ class Index synchronized boolean remove(AMQShortString key, AMQQueue queue) { - List queues = _index.get(key); + ArrayList queues = _index.get(key); if (queues != null) { queues = new ArrayList(queues); @@ -87,7 +87,7 @@ class Index return false; } - List get(AMQShortString key) + ArrayList get(AMQShortString key) { return _index.get(key); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index d07501a188..c18cc337fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -32,7 +32,6 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.topic.TopicParser; import org.apache.qpid.server.exchange.topic.TopicMatcherResult; @@ -48,9 +47,6 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicInteger; import java.lang.ref.WeakReference; public class TopicExchange extends AbstractExchange @@ -532,7 +528,10 @@ public class TopicExchange extends AbstractExchange final AMQShortString routingKey = payload.getRoutingKey(); - Collection queues = getMatchedQueues(payload, routingKey); + // The copy here is unfortunate, but not too bad relevant to the amount of + // things created and copied in getMatchedQueues + ArrayList queues = new ArrayList(); + queues.addAll(getMatchedQueues(payload, routingKey)); if(queues == null || queues.isEmpty()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 0e5e7aa68c..a485649410 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -291,12 +291,17 @@ public class AMQMessage implements Filterable return this; } - /** Threadsafe. Increment the reference count on the message. */ public boolean incrementReference() { - if(_referenceCount.incrementAndGet() <= 1) + return incrementReference(1); + } + + /* Threadsafe. Increment the reference count on the message. */ + public boolean incrementReference(int count) + { + if(_referenceCount.addAndGet(count) <= 1) { - _referenceCount.decrementAndGet(); + _referenceCount.addAndGet(-count); return false; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 9d769d7582..6b498d4d98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; +import java.util.ArrayList; import java.util.Collection; public class IncomingMessage implements Filterable @@ -63,7 +64,7 @@ public class IncomingMessage implements Filterable * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done * by the message handle. */ - private Collection _destinationQueues; + private ArrayList _destinationQueues; private AMQProtocolSession _publisher; private MessageStore _messageStore; @@ -134,21 +135,13 @@ public class IncomingMessage implements Filterable if(_destinationQueues != null) { - for (AMQQueue q : _destinationQueues) + for (int i = 0; i < _destinationQueues.size(); i++) { - if(q.isDurable()) - { - - _messageStore.enqueueMessage(_txnContext.getStoreContext(), q, _messageId); - } + _messageStore.enqueueMessage(_txnContext.getStoreContext(), + _destinationQueues.get(i), _messageId); } } - } - - - - } public AMQMessage deliverToQueues() @@ -157,10 +150,9 @@ public class IncomingMessage implements Filterable // we get a reference to the destination queues now so that we can clear the // transient message data as quickly as possible - Collection destinationQueues = _destinationQueues; if (_logger.isDebugEnabled()) { - _logger.debug("Delivering message " + _messageId + " to " + destinationQueues); + _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); } AMQMessage message = null; @@ -178,10 +170,7 @@ public class IncomingMessage implements Filterable message.setExpiration(_expiration); message.setClientIdentifier(_publisher.getSessionIdentifier()); - - - - if ((destinationQueues == null) || destinationQueues.isEmpty()) + if ((_destinationQueues == null) || _destinationQueues.size() == 0) { if (isMandatory() || isImmediate()) @@ -196,10 +185,9 @@ public class IncomingMessage implements Filterable } else { - // TODO - int offset; - final int queueCount = destinationQueues.size(); + final int queueCount = _destinationQueues.size(); + message.incrementReference(queueCount); if(queueCount == 1) { offset = 0; @@ -212,33 +200,16 @@ public class IncomingMessage implements Filterable offset = -offset; } } - - int i = 0; - for (AMQQueue q : destinationQueues) + for (int i = offset; i < queueCount; i++) { - if(++i > offset) - { - // Increment the references to this message for each queue delivery. - message.incrementReference(); - // normal deliver so add this message at the end. - _txnContext.deliver(q, message); - } + // normal deliver so add this message at the end. + _txnContext.deliver(_destinationQueues.get(i), message); } - i = 0; - if(offset != 0) + for (int i = 0; i < offset; i++) { - for (AMQQueue q : destinationQueues) - { - if(i++ < offset) - { - // Increment the references to this message for each queue delivery. - message.incrementReference(); - // normal deliver so add this message at the end. - _txnContext.deliver(q, message); - } - } + // normal deliver so add this message at the end. + _txnContext.deliver(_destinationQueues.get(i), message); } - } // we then allow the transactional context to do something with the message content @@ -329,7 +300,7 @@ public class IncomingMessage implements Filterable _exchange.route(this); } - public void enqueue(final Collection queues) + public void enqueue(final ArrayList queues) { _destinationQueues = queues; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java index 89cead69b3..86f155d862 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -27,23 +27,23 @@ public class AccessResult GRANTED, REFUSED } - StringBuilder _authorizer; - AccessStatus _status; + private String _authorizer; + private AccessStatus _status; public AccessResult(ACLPlugin authorizer, AccessStatus status) { _status = status; - _authorizer = new StringBuilder(authorizer.getPluginName()); + _authorizer = authorizer.getPluginName(); } public void setAuthorizer(ACLPlugin authorizer) { - _authorizer.append(authorizer.getPluginName()); + _authorizer += authorizer.getPluginName(); } public String getAuthorizer() { - return _authorizer.toString(); + return _authorizer; } public void setStatus(AccessStatus status) @@ -58,8 +58,7 @@ public class AccessResult public void addAuthorizer(ACLPlugin accessManager) { - _authorizer.insert(0, "->"); - _authorizer.insert(0, accessManager.getPluginName()); + _authorizer = accessManager.getPluginName() + "->" + _authorizer; } -- cgit v1.2.1 From 76b778b88e693f70fac39c8a8ef5d5d5fd62e8b6 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 7 Aug 2008 12:07:29 +0000 Subject: QPID-1218: fix stupid used-only-by-tests method breakage that I have exposed git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683597 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/IncomingMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 6b498d4d98..6287172ce8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -137,7 +137,7 @@ public class IncomingMessage implements Filterable { for (int i = 0; i < _destinationQueues.size(); i++) { - _messageStore.enqueueMessage(_txnContext.getStoreContext(), + store.enqueueMessage(_txnContext.getStoreContext(), _destinationQueues.get(i), _messageId); } } -- cgit v1.2.1 From b35cc139f0d8126a3581c507196046c4f03923bf Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 7 Aug 2008 15:37:36 +0000 Subject: QPID-1195 , QPID-1193 Initial changes to allow bind and queue arguments to be stored and recovered from the MessageStore. Created a test to validate that the stored values can be recovered. DerbyStore hasn't fully been implemented. Surrounding work has been done and tested with BDBMessageStore. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683632 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../configuration/VirtualHostConfiguration.java | 2 +- .../qpid/server/exchange/DirectExchange.java | 12 +++- .../qpid/server/handler/QueueDeclareHandler.java | 2 +- .../apache/qpid/server/queue/AMQPriorityQueue.java | 6 +- .../org/apache/qpid/server/queue/AMQQueue.java | 1 + .../apache/qpid/server/queue/AMQQueueFactory.java | 2 +- .../apache/qpid/server/queue/ExchangeBinding.java | 84 ++++++++++++++++++++++ .../apache/qpid/server/queue/ExchangeBindings.java | 53 -------------- .../qpid/server/queue/PriorityQueueList.java | 5 ++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 7 +- .../qpid/server/store/DerbyMessageStore.java | 7 +- .../qpid/server/store/MemoryMessageStore.java | 9 ++- .../org/apache/qpid/server/store/MessageStore.java | 11 ++- 14 files changed, 138 insertions(+), 65 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 88d5360f3e..6312aed5bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -180,7 +180,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr null); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue); + _messageStore.createQueue(queue, null); } Configuration virtualHostDefaultQueueConfiguration = diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index bd3e5b1f72..984106277f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -197,7 +197,7 @@ public class VirtualHostConfiguration if (queue.isDurable()) { - messageStore.createQueue(queue); + messageStore.createQueue(queue, null); } queueRegistry.registerQueue(queue); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 616f47bd24..e39c005750 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -166,11 +166,19 @@ public class DirectExchange extends AbstractExchange assert routingKey != null; if (!_index.add(routingKey, queue)) { - _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); + if (_logger.isDebugEnabled()) + { + _logger.debug("Queue (" + queue.getName() + ")" + queue + " is already registered with routing key " + routingKey); + } } else { - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); + if (_logger.isDebugEnabled()) + { + _logger.debug("Binding queue(" + queue.getName() + ") " + queue + " with routing key " + routingKey + + (args == null ? "" : " and arguments " + args.toString()) + + " to exchange " + this); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 379ec7a7d6..447482ccf3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -117,7 +117,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; + List getExchangeBindings(); void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 431b76754f..9dfc4449bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -28,7 +28,7 @@ import org.apache.qpid.AMQException; public class AMQQueueFactory { - private static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java new file mode 100644 index 0000000000..a2fcab9e73 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +public class ExchangeBinding +{ + private final Exchange _exchange; + private final AMQShortString _routingKey; + private final FieldTable _arguments; + + private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + + ExchangeBinding(AMQShortString routingKey, Exchange exchange) + { + this(routingKey, exchange, EMPTY_ARGUMENTS); + } + + ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) + { + _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; + _exchange = exchange; + _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; + } + + void unbind(AMQQueue queue) throws AMQException + { + _exchange.deregisterQueue(_routingKey, queue, _arguments); + } + + public Exchange getExchange() + { + return _exchange; + } + + public AMQShortString getRoutingKey() + { + return _routingKey; + } + + public FieldTable getArguments() + { + return _arguments; + } + + public int hashCode() + { + return (_exchange == null ? 0 : _exchange.hashCode()) + + (_routingKey == null ? 0 : _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); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index d2e5a02508..fb839c1783 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -36,59 +36,6 @@ import org.apache.qpid.server.exchange.Exchange; */ class ExchangeBindings { - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); - - static class ExchangeBinding - { - private final Exchange _exchange; - private final AMQShortString _routingKey; - private final FieldTable _arguments; - - ExchangeBinding(AMQShortString routingKey, Exchange exchange) - { - this(routingKey, exchange, EMPTY_ARGUMENTS); - } - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) - { - _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; - _exchange = exchange; - _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; - } - - void unbind(AMQQueue queue) throws AMQException - { - _exchange.deregisterQueue(_routingKey, queue, _arguments); - } - - public Exchange getExchange() - { - return _exchange; - } - - public AMQShortString getRoutingKey() - { - return _routingKey; - } - - public int hashCode() - { - return (_exchange == null ? 0 : _exchange.hashCode()) - + (_routingKey == null ? 0 : _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; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java index e6628832cb..fd46a8a5ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -42,6 +42,11 @@ public class PriorityQueueList implements QueueEntryList } } + public int getPriorities() + { + return _priorities; + } + public AMQQueue getQueue() { return _queue; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 4b7da30800..1674c26232 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -82,7 +82,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private volatile Subscription _exclusiveSubscriber; - private final QueueEntryList _entries; + protected final QueueEntryList _entries; private final AMQQueueMBean _managedObject; private final Executor _asyncDelivery; @@ -223,6 +223,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + public List getExchangeBindings() + { + return new ArrayList(_bindings.getExchangeBindings()); + } + // ------ Manage Subscriptions public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 9d22e2b929..bfbba8c00f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -728,7 +728,7 @@ public class DerbyMessageStore implements MessageStore } - public void createQueue(AMQQueue queue) throws AMQException + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException { _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); @@ -1281,6 +1281,11 @@ public class DerbyMessageStore implements MessageStore } + public boolean isPersistent() + { + return true; + } + private void checkNotClosed() throws MessageStoreClosedException { if (_closed.get()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index b02eff957e..f8d8404b89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -121,7 +121,7 @@ public class MemoryMessageStore implements MessageStore } - public void createQueue(AMQQueue queue) throws AMQException + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException { // Not required to do anything } @@ -213,7 +213,12 @@ public class MemoryMessageStore implements MessageStore return bodyList.get(index); } - private void checkNotClosed() throws MessageStoreClosedException + public boolean isPersistent() + { + return false; + } + + private void checkNotClosed() throws MessageStoreClosedException { if (_closed.get()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index e15e69a414..9e855bcc09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -131,9 +131,10 @@ public interface MessageStore * * @param queue The queue to store. * + * @param arguments The additional arguments to the binding * @throws AMQException If the operation fails for any reason. */ - void createQueue(AMQQueue queue) throws AMQException; + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; /** * Removes the specified queue from the persistent store. @@ -255,4 +256,12 @@ public interface MessageStore * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. */ ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; + + /** + * Is this store capable of persisting the data + * + * @return true if this store is capable of persisting data + */ + boolean isPersistent(); + } -- cgit v1.2.1 From f52882c8db0bccb18e9b1ccaea7ac2824f10c423 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 8 Aug 2008 10:31:26 +0000 Subject: QPID-1224: add methods to get the list of message ids from a queue, with optional offset. Test class for this. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683932 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 4 ++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index f7bc2ddafa..c9c252f06d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -104,6 +104,10 @@ public interface AMQQueue extends Managable, Comparable List getMessagesOnTheQueue(long fromMessageId, long toMessageId); + List getMessagesOnTheQueue(int num); + + List getMessagesOnTheQueue(int num, int offest); + QueueEntry getMessageOnTheQueue(long messageId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 1674c26232..b0f700d4a1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1613,4 +1613,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliverAsync(_sub); } } + + public List getMessagesOnTheQueue(int num) + { + return getMessagesOnTheQueue(num, 0); + } + + public List getMessagesOnTheQueue(int num, int offset) + { + ArrayList ids = new ArrayList(num); + QueueEntryIterator it = _entries.iterator(); + for (int i = 0; i < offset; i++) + { + it.advance(); + } + + for (int i = 0; i < num && !it.atTail(); i++) + { + it.advance(); + ids.add(it.getNode().getMessage().getMessageId()); + } + return ids; + } } \ No newline at end of file -- cgit v1.2.1 From c380d44a02b738bfe3af61e1badb862102946de8 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 8 Aug 2008 12:19:41 +0000 Subject: QPID-1136 : Provided a fix for the leak in UnacknowledgedMessage when acking. Added a new InternalBrokerBaseCase for performing testing on the broker without using the client libraries. This allows for testing closer to AMQP. Merged from M2.1.x git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683949 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/ack/UnacknowledgedMessageMap.java | 5 +++-- .../server/ack/UnacknowledgedMessageMapImpl.java | 9 +++++++-- .../qpid/server/txn/NonTransactionalContext.java | 22 +++++----------------- 3 files changed, 15 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index 8e5b631f96..c80a96f967 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -28,6 +28,7 @@ import java.util.Map; import org.apache.qpid.AMQException; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; public interface UnacknowledgedMessageMap { @@ -55,8 +56,8 @@ public interface UnacknowledgedMessageMap QueueEntry remove(long deliveryTag); - void drainTo(Collection destination, long deliveryTag) throws AMQException; - + public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException; + Collection cancelAllMessages(); void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index 79208ab426..ef48b60bcd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.ack; +import org.apache.qpid.server.store.StoreContext; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; @@ -160,7 +161,8 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void drainTo(Collection destination, long deliveryTag) throws AMQException + public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException + { synchronized (_lock) { @@ -175,6 +177,10 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + unacked.getValue().discard(storeContext); + it.remove(); _unackedSize -= unacked.getValue().getMessage().getSize(); @@ -182,7 +188,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap unacked.getValue().restoreCredit(); - destination.add(unacked.getValue()); if (unacked.getKey() == deliveryTag) { break; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 18f1836185..03d59d3ab9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -154,28 +154,13 @@ public class NonTransactionalContext implements TransactionalContext throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); } - LinkedList acked = new LinkedList(); - unacknowledgedMessageMap.drainTo(acked, deliveryTag); - for (QueueEntry msg : acked) - { - if (debug) - { - _log.debug("Discarding message: " + msg.getMessage().getMessageId()); - } - if(msg.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); - } + unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext); } } else { QueueEntry msg; - msg = unacknowledgedMessageMap.remove(deliveryTag); + msg = unacknowledgedMessageMap.get(deliveryTag); if (msg == null) { @@ -197,6 +182,9 @@ public class NonTransactionalContext implements TransactionalContext //Message has been ack so discard it. This will dequeue and decrement the reference. msg.discard(_storeContext); + unacknowledgedMessageMap.remove(deliveryTag); + + if (debug) { _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + -- cgit v1.2.1 From 8ecc4ecc20d23685c8e2a835b855bfb60fdf5bf7 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 8 Aug 2008 17:08:37 +0000 Subject: QPID-1218 Optionally use IoTransport, it's hot, but doesn't pass all the tests yet. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@684016 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQMinaProtocolSession.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index b4075b81ac..12231e4882 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -50,6 +50,7 @@ import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.transport.network.io.IoSender; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -845,4 +846,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { return (_clientVersion == null) ? null : _clientVersion.toString(); } + + public void setSender(IoSender sender) + { + // No-op, interface munging between this and AMQProtocolSession + } + + public void init() + { + // No-op, interface munging between this and AMQProtocolSession + } } -- cgit v1.2.1 From f0721a07d2b15df249a1e60ec15fdbd2aab053c6 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Sat, 9 Aug 2008 06:03:24 +0000 Subject: QPID-1218: cleaned up the interface to IoTransport a bit; added IoAcceptor; fixed Session tracking of sync point; default JAVA inside qpid-run git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@684182 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 12231e4882..64914b407d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -50,7 +50,7 @@ import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.transport.network.io.IoSender; +import org.apache.qpid.transport.Sender; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -847,7 +847,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable return (_clientVersion == null) ? null : _clientVersion.toString(); } - public void setSender(IoSender sender) + public void setSender(Sender sender) { // No-op, interface munging between this and AMQProtocolSession } -- cgit v1.2.1 From 0a1d0288f6df1144cf8ebf2a288cc4cda51e3e5a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 11 Aug 2008 11:01:28 +0000 Subject: QPID-1193 : re-added createQueue(AMQQueue queue) method, after code review call. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@684710 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/store/DerbyMessageStore.java | 5 +++++ .../java/org/apache/qpid/server/store/MemoryMessageStore.java | 6 ++++++ .../src/main/java/org/apache/qpid/server/store/MessageStore.java | 9 +++++++++ 3 files changed, 20 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index bfbba8c00f..743a736884 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -728,6 +728,11 @@ public class DerbyMessageStore implements MessageStore } + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException { _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index f8d8404b89..587c85fc12 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -121,6 +121,12 @@ public class MemoryMessageStore implements MessageStore } + + public void createQueue(AMQQueue queue) throws AMQException + { + // Not requred to do anything + } + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException { // Not required to do anything diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 9e855bcc09..f2910acb77 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -126,6 +126,15 @@ public interface MessageStore */ void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + /** * Makes the specified queue persistent. * -- cgit v1.2.1 From 68d53aee4983a6df581eae7d5e70dbfbd5556861 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 11 Aug 2008 11:17:33 +0000 Subject: QPID-1193 : Actually removed the calls that pass in the ugly null git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@684714 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../org/apache/qpid/server/configuration/VirtualHostConfiguration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 6312aed5bf..88d5360f3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -180,7 +180,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr null); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue, null); + _messageStore.createQueue(queue); } Configuration virtualHostDefaultQueueConfiguration = diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 984106277f..bd3e5b1f72 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -197,7 +197,7 @@ public class VirtualHostConfiguration if (queue.isDurable()) { - messageStore.createQueue(queue, null); + messageStore.createQueue(queue); } queueRegistry.registerQueue(queue); -- cgit v1.2.1 From 8404b22733da9eed0769c4ed4967990ea6611e7d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 12 Aug 2008 09:36:08 +0000 Subject: QPID-1136 : Fixed Flow Control problem due to this change and added test to validate that Flow Control is operating correctly git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@685104 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/ack/TxAck.java | 1 - .../qpid/server/ack/UnacknowledgedMessageMapImpl.java | 4 +--- .../java/org/apache/qpid/server/queue/QueueEntry.java | 2 -- .../org/apache/qpid/server/queue/QueueEntryImpl.java | 16 ++++++---------- .../apache/qpid/server/txn/NonTransactionalContext.java | 1 - 5 files changed, 7 insertions(+), 17 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index caf34f13bd..db3a05eb52 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -116,7 +116,6 @@ public class TxAck implements TxnOp //make persistent changes, i.e. dequeue and decrementReference for (QueueEntry msg : _unacked.values()) { - msg.restoreCredit(); //Message has been ack so discard it. This will dequeue and decrement the reference. msg.discard(storeContext); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index ef48b60bcd..c567387662 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -94,7 +94,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap if(message != null) { _unackedSize -= message.getMessage().getSize(); - message.restoreCredit(); + } return message; @@ -185,8 +185,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap _unackedSize -= unacked.getValue().getMessage().getSize(); - unacked.getValue().restoreCredit(); - if (unacked.getKey() == deliveryTag) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index dd967a7cb1..2657c459a9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -175,8 +175,6 @@ public interface QueueEntry extends Comparable void dispose(final StoreContext storeContext) throws MessageCleanupException; - void restoreCredit(); - void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException; boolean isQueueDeleted(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index d26d6af7b2..dbad5438dc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -256,6 +256,12 @@ public class QueueEntryImpl implements QueueEntry if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) { + if (state instanceof SubscriptionAcquiredState) + { + Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); + s.restoreCredit(this); + } + getQueue().dequeue(storeContext, this); if(_stateChangeListeners != null) { @@ -282,16 +288,6 @@ public class QueueEntryImpl implements QueueEntry } } - public void restoreCredit() - { - EntryState state = _state; - if(state instanceof SubscriptionAcquiredState) - { - Subscription s = ((SubscriptionAcquiredState) _state).getSubscription(); - s.restoreCredit(this); - } - } - public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException { //if the queue is null then the message is waiting to be acked, but has been removed. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 03d59d3ab9..28af36e3db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -134,7 +134,6 @@ public class NonTransactionalContext implements TransactionalContext { beginTranIfNecessary(); } - message.restoreCredit(); //Message has been ack so discard it. This will dequeue and decrement the reference. message.discard(_storeContext); -- cgit v1.2.1 From 910fad9a0c17d465f7a7e23b6063095bbda3e310 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 19 Aug 2008 10:03:07 +0000 Subject: QPID-1202: Rebind durable subscriptions if the arguments have changed TopicExchange: take field arguments into account when determining if topic binding already exists when binding, but not for regular isBound(). DurableSubscriptionTest: add test case for QPID-1202 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@687010 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/exchange/TopicExchange.java | 33 ++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index c18cc337fe..59a8339346 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -115,11 +115,13 @@ public class TopicExchange extends AbstractExchange { private final AMQShortString _bindingKey; private final AMQQueue _queue; + private final FieldTable _args; - public Binding(AMQShortString bindingKey, AMQQueue queue) + public Binding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) { _bindingKey = bindingKey; _queue = queue; + _args = args; } public AMQShortString getBindingKey() @@ -134,7 +136,7 @@ public class TopicExchange extends AbstractExchange public int hashCode() { - return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 + _queue.hashCode(); + return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); } public boolean equals(Object o) @@ -382,7 +384,7 @@ public class TopicExchange extends AbstractExchange routingKey = rKey; } - Binding binding = new Binding(rKey, queue); + Binding binding = new Binding(rKey, queue, args); if(_bindings.containsKey(binding)) { @@ -544,14 +546,29 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) { - return isBound(routingKey, queue); + Binding binding = new Binding(routingKey, queue, arguments); + if (arguments == null) + { + return _bindings.containsKey(binding); + } + else + { + FieldTable o = _bindings.get(binding); + if (o != null) + { + return o.equals(arguments); + } + else + { + return false; + } + + } } public boolean isBound(AMQShortString routingKey, AMQQueue queue) { - Binding binding = new Binding(routingKey, queue); - - return _bindings.containsKey(binding); + return isBound(routingKey, null, queue); } public boolean isBound(AMQShortString routingKey) @@ -590,7 +607,7 @@ public class TopicExchange extends AbstractExchange assert queue != null; assert rKey != null; - Binding binding = new Binding(rKey, queue); + Binding binding = new Binding(rKey, queue, args); if (!_bindings.containsKey(binding)) -- cgit v1.2.1 From 2c7aeaccc3fa471f54aad62f0fc4dd455ca0179f Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 20 Aug 2008 16:26:16 +0000 Subject: QPID-1202: TopicExchance.removeFilteredQueue: if there are no instances of the filter, it's ok to remove it. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@687382 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/exchange/TopicExchange.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 59a8339346..bc303a219d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -216,17 +216,20 @@ public class TopicExchange extends AbstractExchange if(filters != null) { Integer instances = filters.get(filter); - if(instances == 1) + if(instances != null) { - filters.remove(filter); - if(filters.isEmpty()) + if(instances == 1) { - _filteredQueues.remove(queue); + filters.remove(filter); + if(filters.isEmpty()) + { + _filteredQueues.remove(queue); + } + } + else + { + filters.put(filter, instances - 1); } - } - else if(instances != null) - { - filters.put(filter, instances - 1); } } -- cgit v1.2.1 From deddc77062722283a69ab1beb64172bb5be1a07a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 21 Aug 2008 13:15:25 +0000 Subject: Stopped the broker closing the ProtocolSessions as this was causing the client to lock in Mina seemingly missing the notify for the CloseFuture and hangs indefinately git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@687741 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 64914b407d..aec032bb54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -230,7 +230,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); } - closeProtocolSession(); + +// closeProtocolSession(); return; } } @@ -272,7 +273,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } catch (AMQException e) { - _logger.error("Received incorrect protocol initiation", e); + _logger.info("Received incorrect protocol initiation:" + e.getMessage()); _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); @@ -356,7 +357,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.error("Unexpected exception while processing frame. Closing connection.", e); - closeProtocolSession(); +// closeProtocolSession(); } } @@ -655,9 +656,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public void closeProtocolSession(boolean waitLast) { - _logger.debug("Waiting for last write to join."); if (waitLast && (_lastWriteFuture != null)) { + _logger.debug("Waiting for last write to join."); _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); } -- cgit v1.2.1 From 48c6f80d5cb49715256d1e192c0ab13fcea3d245 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 21 Aug 2008 13:22:22 +0000 Subject: Sorry went crazy with git and didn't meant to commit this change git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@687749 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index aec032bb54..239d9d8822 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -230,8 +230,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); } - -// closeProtocolSession(); + closeProtocolSession(); return; } } @@ -273,7 +272,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } catch (AMQException e) { - _logger.info("Received incorrect protocol initiation:" + e.getMessage()); + _logger.error("Received incorrect protocol initiation", e); _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); @@ -357,7 +356,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _logger.error("Unexpected exception while processing frame. Closing connection.", e); -// closeProtocolSession(); + closeProtocolSession(); } } -- cgit v1.2.1 From 4ea404d310f53d8bd9a3342d568108f6f1111a9a Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 21 Aug 2008 13:53:28 +0000 Subject: QPID-1167: reset queue notification lists when creating queues. Pull out defaults centrally. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@687764 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 7 ------ .../configuration/VirtualHostConfiguration.java | 13 +++++----- .../qpid/server/handler/QueueDeclareHandler.java | 8 +----- .../org/apache/qpid/server/queue/AMQQueue.java | 4 +++ .../apache/qpid/server/queue/AMQQueueFactory.java | 29 +++++++++++++++++++--- .../apache/qpid/server/queue/SimpleAMQQueue.java | 15 ++++++++++- 6 files changed, 51 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 88d5360f3e..fc6057afd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -183,13 +183,6 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr _messageStore.createQueue(queue); } - Configuration virtualHostDefaultQueueConfiguration = - VirtualHostConfiguration.getDefaultQueueConfiguration(queue); - if (virtualHostDefaultQueueConfiguration != null) - { - Configurator.configure(queue, virtualHostDefaultQueueConfiguration); - } - _queueRegistry.registerQueue(queue); } catch (AMQException ex) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index bd3e5b1f72..2ee8f54a2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -130,13 +130,13 @@ public class VirtualHostConfiguration } } - public static CompositeConfiguration getDefaultQueueConfiguration(AMQQueue queue) + public static CompositeConfiguration getDefaultQueueConfiguration(VirtualHost host) { CompositeConfiguration queueConfiguration = null; if (_config == null) return null; - Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + queue.getVirtualHost().getName()); + Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + host.getName()); if (vHostConfiguration == null) return null; @@ -193,7 +193,10 @@ public class VirtualHostConfiguration queue = AMQQueueFactory.createAMQQueueImpl(queueName, durable, owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, - autodelete /* Therefore autodelete makes no sence */, virtualHost, arguments); + autodelete /* Therefore autodelete makes no sence */, + virtualHost, + arguments, + queueConfiguration); if (queue.isDurable()) { @@ -247,10 +250,6 @@ public class VirtualHostConfiguration } } - - - - Configurator.configure(queue, queueConfiguration); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 447482ccf3..3047643021 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -203,13 +203,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener { public void doTask(AMQQueue queue) throws AMQException; } + + void configure(Configuration virtualHostDefaultQueueConfiguration); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 9dfc4449bb..19e98f416d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -20,8 +20,10 @@ */ package org.apache.qpid.server.queue; +import org.apache.commons.configuration.Configuration; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.AMQException; @@ -30,23 +32,44 @@ public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + public static AMQQueue createAMQQueueImpl(AMQShortString name, + boolean durable, + AMQShortString owner, + boolean autoDelete, + VirtualHost virtualHost, final FieldTable arguments) + + throws AMQException + { + + return createAMQQueueImpl(name, durable, owner, autoDelete, + virtualHost, arguments, + VirtualHostConfiguration.getDefaultQueueConfiguration(virtualHost)); + } + public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, final FieldTable arguments) + VirtualHost virtualHost, final FieldTable arguments, + Configuration queueConfiguration) throws AMQException { final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + AMQQueue q = null; if(priorities > 1) { - return new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); + q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); } else { - return new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + } + if (q != null && queueConfiguration != null) + { + q.configure(queueConfiguration); } + return q; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b0f700d4a1..29c3f68286 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -3,6 +3,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.store.MessageStore; @@ -14,6 +15,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.configuration.Configured; +import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import javax.management.JMException; @@ -160,12 +162,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new AMQException("AMQQueue MBean creation has failed ", e); } + resetNotifications(); + + } + + private void resetNotifications() + { // This ensure that the notification checks for the configured alerts are created. setMaximumMessageAge(_maximumMessageAge); setMaximumMessageCount(_maximumMessageCount); setMaximumMessageSize(_maximumMessageSize); setMaximumQueueDepth(_maximumQueueDepth); - } // ------ Getters and Setters @@ -1635,4 +1642,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } return ids; } + + public void configure(Configuration queueConfiguration) + { + Configurator.configure(this, queueConfiguration); + resetNotifications(); + } } \ No newline at end of file -- cgit v1.2.1 From 32b6fe75c94f7d016c9a101e63d179a656d3ea14 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 22 Aug 2008 15:21:08 +0000 Subject: QPID-1258 add ASL to java files that were missing it git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@688094 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/AccessRequestHandler.java | 21 +++++++++++++++++++++ .../handler/BasicRecoverSyncMethodHandler.java | 21 +++++++++++++++++++++ .../qpid/server/handler/QueueUnbindHandler.java | 21 +++++++++++++++++++++ .../output/amqp0_9/ProtocolOutputConverterImpl.java | 21 +++++++++++++++++++++ 4 files changed, 84 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java index c13a69b793..e64eaeae76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.qpid.framing.*; import org.apache.qpid.server.state.StateAwareMethodListener; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java index 15484273c8..2c264c3d45 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.log4j.Logger; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index d73e33d6c8..6331a0365d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.log4j.Logger; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index c76c262edd..65184fe744 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.output.amqp0_9; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.mina.common.ByteBuffer; -- cgit v1.2.1 From d3b8773888202a69c6df43a7783cc7faed667aeb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 2 Sep 2008 14:28:52 +0000 Subject: QPID-579 : Make broker stop on startup errors git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@691262 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 8ad2ace1b2..f3b54034e7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -198,23 +198,31 @@ public class Main { System.out.println(e.getMessage()); _brokerLogger.error("Initialisation Error : " + e.getMessage()); - + shutdown(1); } catch (ConfigurationException e) { System.out.println("Error configuring message broker: " + e); _brokerLogger.error("Error configuring message broker: " + e); e.printStackTrace(); + shutdown(1); } - catch (Exception e) + catch (Throwable e) { - System.out.println("Error intialising message broker: " + e); - _brokerLogger.error("Error intialising message broker: " + e); + System.out.println("Error initialising message broker: " + e); + _brokerLogger.error("Error initialising message broker: " + e); e.printStackTrace(); + shutdown(1); } } } + protected void shutdown(int status) + { + ApplicationRegistry.removeAll(); + System.exit(status); + } + protected void startup() throws InitException, ConfigurationException, Exception { final String QpidHome = System.getProperty(QPID_HOME); -- cgit v1.2.1 From 4861d93f7ae5c084603fcd0fccc73054620a7093 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 2 Sep 2008 14:30:47 +0000 Subject: QPID-1266 - Provide a stop() method on AMQQueue to stop all processing on that queue thus shutting down the ThreadPool. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@691263 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueue.java | 2 ++ .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 7 ++++++- .../java/org/apache/qpid/server/virtualhost/VirtualHost.java | 11 ++++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 90d7109df8..03ccbe7ce4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -161,6 +161,8 @@ public interface AMQQueue extends Managable, Comparable void deliverAsync(); + void stop(); + /** * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 29c3f68286..1184ba1d19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1102,12 +1102,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _deleteTaskList.clear(); - ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + stop(); } return getMessageCount(); } + public void stop() + { + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + } + public void deliverAsync() { _stateChangeCount.incrementAndGet(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index b25a56344e..71f6c8ed44 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -301,11 +301,20 @@ public class VirtualHost implements Accessable public void close() throws Exception { + //Stop the Queues processing + if (_queueRegistry != null) + { + for (AMQQueue queue : _queueRegistry.getQueues()) + { + queue.stop(); + } + } + //Stop Housekeeping if (_houseKeepingTimer != null) { _houseKeepingTimer.cancel(); - } + } //Stop Connections _connectionRegistry.close(); -- cgit v1.2.1 From 898c10ed8e9f04a7d919df1f8900779b5f5af725 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 3 Sep 2008 16:00:10 +0000 Subject: QPID-1269 : Added queue registration as part of the creation via the Factory. Updated direct creations to use the factory.. where possible. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@691643 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 19e98f416d..be8c19d18f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -70,6 +70,9 @@ public class AMQQueueFactory { q.configure(queueConfiguration); } + + //Register the new queue + virtualHost.getQueueRegistry().registerQueue(q); return q; } } -- cgit v1.2.1 From 03e2a3ab68f35e70967659b248709612b3a09a87 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 3 Sep 2008 16:26:38 +0000 Subject: QPID-1266 : Provided test for new stop() method. Updated RefCountExService to allow retrieval of the referenceCount. Updated AMQQueue to only perform stop() actions once, such as releasing the RefCountExService. Updated instances where new virtualhosts were not added to the VHostRegistry. See supplemental JIRA for removing the need for this. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@691661 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 13 ++++++++++++- .../org/apache/qpid/server/virtualhost/VirtualHost.java | 7 ++++--- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 1184ba1d19..6631bc3559 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -117,6 +117,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); private AtomicReference _asynchronousRunner = new AtomicReference(null); private AtomicInteger _deliveredMessages = new AtomicInteger(); + private AtomicBoolean _stopped = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -1110,7 +1111,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void stop() { - ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + if (!_stopped.getAndSet(true)) + { + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + } + else + { + if(_logger.isDebugEnabled()) + { + _logger.debug("Queue " + getName() + " already stopped"); + } + } } public void deliverAsync() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 71f6c8ed44..9229863c35 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -301,6 +301,10 @@ public class VirtualHost implements Accessable public void close() throws Exception { + + //Stop Connections + _connectionRegistry.close(); + //Stop the Queues processing if (_queueRegistry != null) { @@ -316,9 +320,6 @@ public class VirtualHost implements Accessable _houseKeepingTimer.cancel(); } - //Stop Connections - _connectionRegistry.close(); - //Close MessageStore if (_messageStore != null) { -- cgit v1.2.1 From 97b01de1192a55d895c319cef2535867a4ec588e Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Thu, 11 Sep 2008 14:46:00 +0000 Subject: QPID-1190 Changed logging for protocol negotiation on client connect to be less alarming, amended to info level log message with no stack trace git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@694282 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 239d9d8822..4b69842c49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -272,7 +272,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } catch (AMQException e) { - _logger.error("Received incorrect protocol initiation", e); + _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion()); _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); -- cgit v1.2.1 From 09f60acd6ba474bfeed068f10d966938f806ff77 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 18 Sep 2008 16:12:46 +0000 Subject: QPID-1286: make sure priority queues don't mess with deleted subscriptions AMQPriorityQueue: don't advance deleted subscriptions AMQPriorityQueueTest: Add test class for priority queues SimpleAMQQueueTest: Add more tests PriorityTest: Check for more message orders git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@696686 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index e14ed0f41d..d7aef34a10 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -52,8 +52,12 @@ public class AMQPriorityQueue extends SimpleAMQQueue while(subIter.advance() && !entry.isAcquired()) { final Subscription subscription = subIter.getNode().getSubscription(); + if (subIter.getNode().isDeleted()) + { + continue; + } QueueEntry subnode = subscription.getLastSeenEntry(); - while((entry.compareTo(subnode) < 0) && !entry.isAcquired()) + while(entry.compareTo(subnode) < 0 && !entry.isAcquired()) { if(subscription.setLastSeenEntry(subnode,entry)) { -- cgit v1.2.1 From 900f75b3cf84ce63ce9be678ab945b76344ea956 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 18 Sep 2008 16:17:24 +0000 Subject: QPID-1287: Allow boolean element in virtual host file. Add test for this. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@696691 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/VirtualHostConfiguration.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 2ee8f54a2b..705e84752b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -179,13 +179,18 @@ public class VirtualHostConfiguration boolean autodelete = queueConfiguration.getBoolean("autodelete", false); String owner = queueConfiguration.getString("owner", null); FieldTable arguments = null; - Integer priorities = queueConfiguration.getInteger("priorities", null); - if(priorities != null && priorities.intValue() > 1) + boolean priority = queueConfiguration.getBoolean("priority", false); + int priorities = queueConfiguration.getInt("priorities", -1); + if(priority || priorities > 0) { if(arguments == null) { arguments = new FieldTable(); } + if (priorities < 0) + { + priorities = 10; + } arguments.put(new AMQShortString("x-qpid-priorities"), priorities); } -- cgit v1.2.1 From 0d1daf623f9820887028ec0a7bafbfff06ed08ec Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 19 Sep 2008 15:20:05 +0000 Subject: QPID-1286: Change test and variable names as per review. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@697130 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index d7aef34a10..34a70c6969 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -52,12 +52,8 @@ public class AMQPriorityQueue extends SimpleAMQQueue while(subIter.advance() && !entry.isAcquired()) { final Subscription subscription = subIter.getNode().getSubscription(); - if (subIter.getNode().isDeleted()) - { - continue; - } QueueEntry subnode = subscription.getLastSeenEntry(); - while(entry.compareTo(subnode) < 0 && !entry.isAcquired()) + while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()) { if(subscription.setLastSeenEntry(subnode,entry)) { -- cgit v1.2.1 From 18292d4d79110ab776cc094b4d0d590a29af8d80 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 25 Sep 2008 18:31:49 +0000 Subject: This is a fix for the problem identified in QPID-943. If msg-auth is configured as true in config.xml the user_id in message properties is verified against the id used at authentication. If not an exception with error code 403 is thrown. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@699044 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 22 +++-------- .../apache/qpid/server/queue/IncomingMessage.java | 17 ++++++-- .../server/queue/UnauthorizedAccessException.java | 45 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 847c8b8459..3cd343e1b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -42,6 +42,7 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.UnauthorizedAccessException; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; @@ -115,12 +116,7 @@ public class AMQChannel // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - private boolean _closing; - - @Configured(path = "advanced.enableJMSXUserID", - defaultValue = "false") - public boolean ENABLE_JMSXUserID; - + private boolean _closing; public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -180,16 +176,6 @@ public class AMQChannel _log.debug("Content header received on channel " + _channelId); } - if (ENABLE_JMSXUserID) - { - //Set JMSXUserID - BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeaderBody.properties; - //fixme: fudge for QPID-677 - properties.getHeaders().keySet(); - - properties.setUserId(_session.getAuthorizedID().getName()); - } - _currentMessage.setContentHeaderBody(contentHeaderBody); _currentMessage.setExpiration(); @@ -217,6 +203,10 @@ public class AMQChannel { _returnMessages.add(e); } + catch(UnauthorizedAccessException ex) + { + _returnMessages.add(ex); + } finally { // callback to allow the context to do any post message processing diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 6287172ce8..fc96aa901a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -52,6 +52,8 @@ public class IncomingMessage implements Filterable private final Long _messageId; private final TransactionalContext _txnContext; + private static final boolean MSG_AUTH = + ApplicationRegistry.getInstance().getConfiguration().getBoolean("security.msg-auth", false); /** @@ -69,7 +71,7 @@ public class IncomingMessage implements Filterable private AMQProtocolSession _publisher; private MessageStore _messageStore; private long _expiration; - + private Exchange _exchange; @@ -164,12 +166,21 @@ public class IncomingMessage implements Filterable _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), _messagePublishInfo, getContentHeaderBody()); - + + message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); message.setExpiration(_expiration); message.setClientIdentifier(_publisher.getSessionIdentifier()); + AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; + + if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) + { + throw new UnauthorizedAccessException("Acccess Refused",message); + } + if ((_destinationQueues == null) || _destinationQueues.size() == 0) { @@ -274,7 +285,7 @@ public class IncomingMessage implements Filterable return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2; } - + public boolean isRedelivered() { return false; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java new file mode 100644 index 0000000000..295cb266b9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; + +/** + * UnauthorizedAccessException is a {@link RequiredDeliveryException} that represents the failure case where a message + * is published with a user id different from the one used when creating the connection . + * The AMQP status code, 403, is always used to report this condition. + * + */ + +public class UnauthorizedAccessException extends RequiredDeliveryException +{ + public UnauthorizedAccessException(String msg, AMQMessage amqMessage) + { + super(msg, amqMessage); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.ACCESS_REFUSED; + } +} -- cgit v1.2.1 From 9b99bf71e6f2ee38cb1a18cf6100923149393172 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Oct 2008 09:18:46 +0000 Subject: QPID-1266 : Updates based on review git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@701326 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 7 ------- 1 file changed, 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 6631bc3559..9b196e4e3d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1115,13 +1115,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { ReferenceCountingExecutorService.getInstance().releaseExecutorService(); } - else - { - if(_logger.isDebugEnabled()) - { - _logger.debug("Queue " + getName() + " already stopped"); - } - } } public void deliverAsync() -- cgit v1.2.1 From 88bd4b814b7d9ba395c59493d47292a1b4d15dcd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Oct 2008 09:19:43 +0000 Subject: QPID-1101 : Merge of changes from M2 to allow Configuration to be loaded and modified before being given the the ApplicationRegistry git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@701328 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ConfigurationFileApplicationRegistry.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index baab56a4a4..815299da4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -48,6 +48,10 @@ import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { + public ConfigurationFileApplicationRegistry(Configuration configuration) + { + super(configuration); + } public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { @@ -64,7 +68,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - private static final Configuration config(File url) throws ConfigurationException + public 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 -- cgit v1.2.1 From 5af0b7353c19fcf20f9ca803dc72854a2266e4a6 Mon Sep 17 00:00:00 2001 From: Lahiru Gunathilake Date: Wed, 8 Oct 2008 07:37:02 +0000 Subject: resolving jira 1329. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@702745 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/filter/UnaryExpression.java | 227 +++++++++------------ 1 file changed, 97 insertions(+), 130 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 799a38af5a..1681958a38 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -35,32 +35,24 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class UnaryExpression implements Expression -{ +public abstract class UnaryExpression implements Expression { private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); protected Expression right; - public static Expression createNegate(Expression left) - { + public static Expression createNegate(Expression left) { return new NegativeExpression(left); } - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) - { + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { // Use a HashSet if there are many elements. Collection t; - if (elements.size() == 0) - { + if (elements.size() == 0) { t = null; - } - else if (elements.size() < 5) - { + } else if (elements.size() < 5) { t = elements; - } - else - { + } else { t = new HashSet(elements); } @@ -69,63 +61,53 @@ public abstract class UnaryExpression implements Expression return new InExpression(right, inList, not); } - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression - { - public BooleanUnaryExpression(Expression left) - { + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { + public BooleanUnaryExpression(Expression left) { super(left); } - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); + public boolean matches(Filterable message) throws E { + Object object = null; + try{ + object = evaluate(message); + }catch(Exception ex) + { + ex.printStackTrace(); + } return (object != null) && (object == Boolean.TRUE); } } + ; - public static BooleanExpression createNOT(BooleanExpression left) - { + public static BooleanExpression createNOT(BooleanExpression left) { return new NotExpression(left); } - public static BooleanExpression createXPath(final String xpath) - { + public static BooleanExpression createXPath(final String xpath) { return new XPathExpression(xpath); } - public static BooleanExpression createXQuery(final String xpath) - { + public static BooleanExpression createXQuery(final String xpath) { return new XQueryExpression(xpath); } - public static BooleanExpression createBooleanCast(Expression left) - { + public static BooleanExpression createBooleanCast(Expression left) { return new BooleanCastExpression(left); } - private static Number negate(Number left) - { + private static Number negate(Number left) { Class clazz = left.getClass(); - if (clazz == Integer.class) - { + if (clazz == Integer.class) { return new Integer(-left.intValue()); - } - else if (clazz == Long.class) - { + } else if (clazz == Long.class) { return new Long(-left.longValue()); - } - else if (clazz == Float.class) - { + } else if (clazz == Float.class) { return new Float(-left.floatValue()); - } - else if (clazz == Double.class) - { + } else if (clazz == Double.class) { return new Double(-left.doubleValue()); - } - else if (clazz == BigDecimal.class) - { + } else if (clazz == BigDecimal.class) { // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it // as a Big decimal. But it gets Negated right away.. to here we try to covert it back @@ -133,39 +115,32 @@ public abstract class UnaryExpression implements Expression BigDecimal bd = (BigDecimal) left; bd = bd.negate(); - if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) - { + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { return new Long(Long.MIN_VALUE); } return bd; - } - else - { + } else { throw new RuntimeException("Don't know how to negate: " + left); } } - public UnaryExpression(Expression left) - { + public UnaryExpression(Expression left) { this.right = left; } - public Expression getRight() - { + public Expression getRight() { return right; } - public void setRight(Expression expression) - { + public void setRight(Expression expression) { right = expression; } /** * @see java.lang.Object#toString() */ - public String toString() - { + public String toString() { return "(" + getExpressionSymbol() + " " + right.toString() + ")"; } @@ -174,8 +149,7 @@ public abstract class UnaryExpression implements Expression * * @see java.lang.Object#hashCode() */ - public int hashCode() - { + public int hashCode() { return toString().hashCode(); } @@ -184,11 +158,9 @@ public abstract class UnaryExpression implements Expression * * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object o) - { + public boolean equals(Object o) { - if ((o == null) || !this.getClass().equals(o.getClass())) - { + if ((o == null) || !this.getClass().equals(o.getClass())) { return false; } @@ -204,74 +176,73 @@ public abstract class UnaryExpression implements Expression */ public abstract String getExpressionSymbol(); - private static class NegativeExpression extends UnaryExpression - { - public NegativeExpression(final Expression left) - { + private static class NegativeExpression extends UnaryExpression { + public NegativeExpression(final Expression left) { super(left); } - public Object evaluate(Filterable message) throws E - { - Object rvalue = right.evaluate(message); - if (rvalue == null) + public Object evaluate(Filterable message) throws E { + Object rvalue = null; + try{ + rvalue = right.evaluate(message); + }catch(Exception ex) { + ex.printStackTrace(); + } + + if (rvalue == null) { return null; } - if (rvalue instanceof Number) - { + if (rvalue instanceof Number) { return negate((Number) rvalue); } return null; } - public String getExpressionSymbol() - { + public String getExpressionSymbol() { return "-"; } } - private static class InExpression extends BooleanUnaryExpression - { + private static class InExpression extends BooleanUnaryExpression { private final Collection _inList; private final boolean _not; - public InExpression(final PropertyExpression right, final Collection inList, final boolean not) - { + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) { super(right); _inList = inList; _not = not; } - public Object evaluate(Filterable message) throws E - { + public Object evaluate(Filterable message) throws E { - Object rvalue = right.evaluate(message); - if (rvalue == null) + Object rvalue = null; + try{ + rvalue = right.evaluate(message); + } + catch(Exception ex) { + ex.printStackTrace(); + } + if (rvalue == null) { return null; } - if (rvalue.getClass() != String.class) - { + if (rvalue.getClass() != String.class) { return null; } - if (((_inList != null) && _inList.contains(rvalue)) ^ _not) - { + if (((_inList != null) && _inList.contains(rvalue)) ^ _not) { return Boolean.TRUE; - } - else - { + } else { return Boolean.FALSE; } } - public String toString() - { + public String toString() { StringBuffer answer = new StringBuffer(); answer.append(right); answer.append(" "); @@ -279,11 +250,9 @@ public abstract class UnaryExpression implements Expression answer.append(" ( "); int count = 0; - for (Iterator i = _inList.iterator(); i.hasNext();) - { + for (Iterator i = _inList.iterator(); i.hasNext();) { Object o = (Object) i.next(); - if (count != 0) - { + if (count != 0) { answer.append(", "); } @@ -296,73 +265,71 @@ public abstract class UnaryExpression implements Expression return answer.toString(); } - public String getExpressionSymbol() - { - if (_not) - { + public String getExpressionSymbol() { + if (_not) { return "NOT IN"; - } - else - { + } else { return "IN"; } } } - private static class NotExpression extends BooleanUnaryExpression - { - public NotExpression(final BooleanExpression left) - { + private static class NotExpression extends BooleanUnaryExpression { + public NotExpression(final BooleanExpression left) { super(left); } - public Object evaluate(Filterable message) throws E - { - Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) - { + public Object evaluate(Filterable message) throws E { + Boolean lvalue = null; + try { + lvalue = (Boolean) right.evaluate(message); + } catch (Exception ex) { + ex.printStackTrace(); + + } + + if (lvalue == null) { return null; } return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } - public String getExpressionSymbol() - { + public String getExpressionSymbol() { return "NOT"; } } - private static class BooleanCastExpression extends BooleanUnaryExpression - { - public BooleanCastExpression(final Expression left) - { + private static class BooleanCastExpression extends BooleanUnaryExpression { + public BooleanCastExpression(final Expression left) { super(left); } - public Object evaluate(Filterable message) throws E - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { + public Object evaluate(Filterable message) throws E { + Object rvalue = null; + try { + rvalue = right.evaluate(message); + } catch (Exception ex) { + ex.printStackTrace(); + } + if (rvalue == null) { return null; } - if (!rvalue.getClass().equals(Boolean.class)) - { + if (!rvalue.getClass().equals(Boolean.class)) { return Boolean.FALSE; } return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } - public String toString() - { + public String toString() { return right.toString(); } - public String getExpressionSymbol() - { + public String getExpressionSymbol() { return ""; } } -- cgit v1.2.1 From 529a47e659c636a700d9d405bd9b5c750ce18e0a Mon Sep 17 00:00:00 2001 From: Lahiru Gunathilake Date: Thu, 9 Oct 2008 12:46:04 +0000 Subject: revert the commit. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@703155 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/filter/UnaryExpression.java | 227 ++++++++++++--------- 1 file changed, 130 insertions(+), 97 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 1681958a38..799a38af5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -35,24 +35,32 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class UnaryExpression implements Expression { +public abstract class UnaryExpression implements Expression +{ private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); protected Expression right; - public static Expression createNegate(Expression left) { + public static Expression createNegate(Expression left) + { return new NegativeExpression(left); } - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + { // Use a HashSet if there are many elements. Collection t; - if (elements.size() == 0) { + if (elements.size() == 0) + { t = null; - } else if (elements.size() < 5) { + } + else if (elements.size() < 5) + { t = elements; - } else { + } + else + { t = new HashSet(elements); } @@ -61,53 +69,63 @@ public abstract class UnaryExpression implements Expression return new InExpression(right, inList, not); } - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { - public BooleanUnaryExpression(Expression left) { + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + { + public BooleanUnaryExpression(Expression left) + { super(left); } - public boolean matches(Filterable message) throws E { - Object object = null; - try{ - object = evaluate(message); - }catch(Exception ex) - { - ex.printStackTrace(); - } + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } } - ; - public static BooleanExpression createNOT(BooleanExpression left) { + public static BooleanExpression createNOT(BooleanExpression left) + { return new NotExpression(left); } - public static BooleanExpression createXPath(final String xpath) { + public static BooleanExpression createXPath(final String xpath) + { return new XPathExpression(xpath); } - public static BooleanExpression createXQuery(final String xpath) { + public static BooleanExpression createXQuery(final String xpath) + { return new XQueryExpression(xpath); } - public static BooleanExpression createBooleanCast(Expression left) { + public static BooleanExpression createBooleanCast(Expression left) + { return new BooleanCastExpression(left); } - private static Number negate(Number left) { + private static Number negate(Number left) + { Class clazz = left.getClass(); - if (clazz == Integer.class) { + if (clazz == Integer.class) + { return new Integer(-left.intValue()); - } else if (clazz == Long.class) { + } + else if (clazz == Long.class) + { return new Long(-left.longValue()); - } else if (clazz == Float.class) { + } + else if (clazz == Float.class) + { return new Float(-left.floatValue()); - } else if (clazz == Double.class) { + } + else if (clazz == Double.class) + { return new Double(-left.doubleValue()); - } else if (clazz == BigDecimal.class) { + } + else if (clazz == BigDecimal.class) + { // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it // as a Big decimal. But it gets Negated right away.. to here we try to covert it back @@ -115,32 +133,39 @@ public abstract class UnaryExpression implements Expression BigDecimal bd = (BigDecimal) left; bd = bd.negate(); - if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) + { return new Long(Long.MIN_VALUE); } return bd; - } else { + } + else + { throw new RuntimeException("Don't know how to negate: " + left); } } - public UnaryExpression(Expression left) { + public UnaryExpression(Expression left) + { this.right = left; } - public Expression getRight() { + public Expression getRight() + { return right; } - public void setRight(Expression expression) { + public void setRight(Expression expression) + { right = expression; } /** * @see java.lang.Object#toString() */ - public String toString() { + public String toString() + { return "(" + getExpressionSymbol() + " " + right.toString() + ")"; } @@ -149,7 +174,8 @@ public abstract class UnaryExpression implements Expression * * @see java.lang.Object#hashCode() */ - public int hashCode() { + public int hashCode() + { return toString().hashCode(); } @@ -158,9 +184,11 @@ public abstract class UnaryExpression implements Expression * * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object o) { + public boolean equals(Object o) + { - if ((o == null) || !this.getClass().equals(o.getClass())) { + if ((o == null) || !this.getClass().equals(o.getClass())) + { return false; } @@ -176,73 +204,74 @@ public abstract class UnaryExpression implements Expression */ public abstract String getExpressionSymbol(); - private static class NegativeExpression extends UnaryExpression { - public NegativeExpression(final Expression left) { + private static class NegativeExpression extends UnaryExpression + { + public NegativeExpression(final Expression left) + { super(left); } - public Object evaluate(Filterable message) throws E { - Object rvalue = null; - try{ - rvalue = right.evaluate(message); - }catch(Exception ex) + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) { - ex.printStackTrace(); - } - - if (rvalue == null) { return null; } - if (rvalue instanceof Number) { + if (rvalue instanceof Number) + { return negate((Number) rvalue); } return null; } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "-"; } } - private static class InExpression extends BooleanUnaryExpression { + private static class InExpression extends BooleanUnaryExpression + { private final Collection _inList; private final boolean _not; - public InExpression(final PropertyExpression right, final Collection inList, final boolean not) { + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) + { super(right); _inList = inList; _not = not; } - public Object evaluate(Filterable message) throws E { + public Object evaluate(Filterable message) throws E + { - Object rvalue = null; - try{ - rvalue = right.evaluate(message); - } - catch(Exception ex) + Object rvalue = right.evaluate(message); + if (rvalue == null) { - ex.printStackTrace(); - } - if (rvalue == null) { return null; } - if (rvalue.getClass() != String.class) { + if (rvalue.getClass() != String.class) + { return null; } - if (((_inList != null) && _inList.contains(rvalue)) ^ _not) { + if (((_inList != null) && _inList.contains(rvalue)) ^ _not) + { return Boolean.TRUE; - } else { + } + else + { return Boolean.FALSE; } } - public String toString() { + public String toString() + { StringBuffer answer = new StringBuffer(); answer.append(right); answer.append(" "); @@ -250,9 +279,11 @@ public abstract class UnaryExpression implements Expression answer.append(" ( "); int count = 0; - for (Iterator i = _inList.iterator(); i.hasNext();) { + for (Iterator i = _inList.iterator(); i.hasNext();) + { Object o = (Object) i.next(); - if (count != 0) { + if (count != 0) + { answer.append(", "); } @@ -265,71 +296,73 @@ public abstract class UnaryExpression implements Expression return answer.toString(); } - public String getExpressionSymbol() { - if (_not) { + public String getExpressionSymbol() + { + if (_not) + { return "NOT IN"; - } else { + } + else + { return "IN"; } } } - private static class NotExpression extends BooleanUnaryExpression { - public NotExpression(final BooleanExpression left) { + private static class NotExpression extends BooleanUnaryExpression + { + public NotExpression(final BooleanExpression left) + { super(left); } - public Object evaluate(Filterable message) throws E { - Boolean lvalue = null; - try { - lvalue = (Boolean) right.evaluate(message); - } catch (Exception ex) { - ex.printStackTrace(); - - } - - if (lvalue == null) { + public Object evaluate(Filterable message) throws E + { + Boolean lvalue = (Boolean) right.evaluate(message); + if (lvalue == null) + { return null; } return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return "NOT"; } } - private static class BooleanCastExpression extends BooleanUnaryExpression { - public BooleanCastExpression(final Expression left) { + private static class BooleanCastExpression extends BooleanUnaryExpression + { + public BooleanCastExpression(final Expression left) + { super(left); } - public Object evaluate(Filterable message) throws E { - Object rvalue = null; - try { - rvalue = right.evaluate(message); - } catch (Exception ex) { - ex.printStackTrace(); - } - if (rvalue == null) { + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { return null; } - if (!rvalue.getClass().equals(Boolean.class)) { + if (!rvalue.getClass().equals(Boolean.class)) + { return Boolean.FALSE; } return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; - } - public String toString() { + public String toString() + { return right.toString(); } - public String getExpressionSymbol() { + public String getExpressionSymbol() + { return ""; } } -- cgit v1.2.1 From 205e035f834266257e383d17bd80d83abcc1fe2a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 9 Oct 2008 17:43:41 +0000 Subject: QPID-1331 : Modified the BrowserSubscription to be consistent with the NoAck Subscription. Added Test QueueBrowserUsesNoAckTest to validate the change. Note that the Credit Manager Suspends the subscriber not the channel when credit is exhausted. JIRA to follow. So to check if the subscription was suspended I needed to make a MockChannel and give it access to the subscriber map in the Channel. The test also needed to be able to interrogate the state of the Subscription which was not part of the Subscription interface, but was used by all subscriptions. So promoted to the interface and implemented the stubs in the various helper/test classes. Added the ability to browse() via the InternalBrokerBaseCase and prevented a NPE when there were no messages returned via getDelivers. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@703212 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQChannel.java | 3 +-- .../org/apache/qpid/server/subscription/Subscription.java | 2 ++ .../apache/qpid/server/subscription/SubscriptionImpl.java | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 3cd343e1b2..a668016f93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -93,8 +93,7 @@ public class AMQChannel private IncomingMessage _currentMessage; /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */ - private final Map _tag2SubscriptionMap = new HashMap(); - + protected final Map _tag2SubscriptionMap = new HashMap(); private final MessageStore _messageStore; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 408defe453..9419572399 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -82,6 +82,8 @@ public interface Subscription void setStateListener(final StateListener listener); + public State getState(); + QueueEntry getLastSeenEntry(); boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 556b87590c..df84270275 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -79,6 +79,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } + @Override public boolean isBrowser() { return true; @@ -91,6 +92,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage * @param msg The message to send * @throws AMQException */ + @Override public void send(QueueEntry msg) throws AMQException { // We don't decrement the reference here as we don't want to consume the message @@ -103,6 +105,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } } + + @Override + public boolean wouldSuspend(QueueEntry msg) + { + return false; + } + } public static class NoAckSubscription extends SubscriptionImpl @@ -118,6 +127,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } + @Override public boolean isBrowser() { return false; @@ -130,6 +140,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage * @param entry The message to send * @throws AMQException */ + @Override public void send(QueueEntry entry) throws AMQException { @@ -166,6 +177,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } } + @Override public boolean wouldSuspend(QueueEntry msg) { return false; @@ -185,6 +197,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); } + @Override public boolean isBrowser() { return false; @@ -198,6 +211,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage * @param entry The message to send * @throws AMQException */ + @Override public void send(QueueEntry entry) throws AMQException { -- cgit v1.2.1 From 637a0b2ee76aeafd31e278ba0d259e34477fe748 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 10 Oct 2008 14:41:08 +0000 Subject: QPID-1314: Make sure all messags that are enqueued are dequeued. SimpleAMQQueue - dequeue messages if they are persistent, regardless of queue durability. SimpleAMQQueueTest - make sure that all messages which are stored are removed properly. TestableMemoryMessageStore - override enqueue/dequeue so it's possible to determine what is in the queue at any given point in time. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@703485 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 9b196e4e3d..bfbcb9e22f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -587,7 +587,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener try { AMQMessage msg = entry.getMessage(); - if (isDurable() && msg.isPersistent()) + if (msg.isPersistent()) { _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); } -- cgit v1.2.1 From 5fd9c10b439c33fcd3a15ec101f903abbeeb5ab0 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 15 Oct 2008 14:15:58 +0000 Subject: QPID-1356: Write message to disk before delivering it to queues. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@704925 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/IncomingMessage.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index fc96aa901a..896747fc83 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -181,6 +181,10 @@ public class IncomingMessage implements Filterable throw new UnauthorizedAccessException("Acccess Refused",message); } + // we then allow the transactional context to do something with the message content + // now that it has all been received, before we attempt delivery + _txnContext.messageFullyReceived(isPersistent()); + if ((_destinationQueues == null) || _destinationQueues.size() == 0) { @@ -223,9 +227,6 @@ public class IncomingMessage implements Filterable } } - // we then allow the transactional context to do something with the message content - // now that it has all been received, before we attempt delivery - _txnContext.messageFullyReceived(isPersistent()); message.clearStoreContext(); return message; } -- cgit v1.2.1 From 3de95a81342b12b59463d10c7b184a54c8677aec Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 15 Oct 2008 14:34:32 +0000 Subject: QPID-1356: move commit even higher, before the auth check. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@704928 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/IncomingMessage.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 896747fc83..b994040131 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -173,6 +173,10 @@ public class IncomingMessage implements Filterable message.setExpiration(_expiration); message.setClientIdentifier(_publisher.getSessionIdentifier()); + // 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()); + AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; @@ -181,10 +185,6 @@ public class IncomingMessage implements Filterable throw new UnauthorizedAccessException("Acccess Refused",message); } - // we then allow the transactional context to do something with the message content - // now that it has all been received, before we attempt delivery - _txnContext.messageFullyReceived(isPersistent()); - if ((_destinationQueues == null) || _destinationQueues.size() == 0) { -- cgit v1.2.1 From a4fd313c939484dcf157effcfa12cfeb02c264e1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 15 Oct 2008 16:05:32 +0000 Subject: QPID-1101 : Reverted change, for some reason I can't seem to find where this code was used, agree it was a poor approach. Will document a better one on QPID-1103 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@704945 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ConfigurationFileApplicationRegistry.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 815299da4c..a555b72dcf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -48,11 +48,6 @@ import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { - public ConfigurationFileApplicationRegistry(Configuration configuration) - { - super(configuration); - } - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { super(config(configurationURL)); @@ -68,7 +63,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - public static final Configuration config(File url) throws ConfigurationException + 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 -- cgit v1.2.1 From 613206be5872b25118b5476ceb5f4dda3edd0a6b Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 17 Oct 2008 16:09:51 +0000 Subject: QPID-1315: BasicBytesFlowControl doesn't wait long enough to determine if the 3rd message is going to be delivered accidently. It also ack'd every message, which was not it's intent, so use acknowledgeThis() instead. Refactor common code out of processQueue and flushSubscription into attemptDelivery. Make sure sendLock is held when closing the consumer. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@705657 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 20 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 251 ++++++++------------- 2 files changed, 114 insertions(+), 157 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index a668016f93..0e2645689c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -336,7 +336,14 @@ public class AMQChannel Subscription sub = _tag2SubscriptionMap.remove(consumerTag); if (sub != null) { - sub.getQueue().unregisterSubscription(sub); + try { + sub.getSendLock(); + sub.getQueue().unregisterSubscription(sub); + } + finally + { + sub.releaseSendLock(); + } return true; } else @@ -395,7 +402,16 @@ public class AMQChannel Subscription sub = me.getValue(); - sub.getQueue().unregisterSubscription(sub); + try + { + sub.getSendLock(); + sub.getQueue().unregisterSubscription(sub); + } + finally + { + sub.releaseSendLock(); + } + } _tag2SubscriptionMap.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index bfbcb9e22f..bc335d0ba5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1174,7 +1174,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean complete = false; try { - complete = flushSubscription(_sub, MAX_ASYNC_DELIVERIES); + complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); } catch (AMQException e) @@ -1204,79 +1204,28 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener flushSubscription(sub, Long.MAX_VALUE); } - public boolean flushSubscription(Subscription sub, long deliveries) throws AMQException + public boolean flushSubscription(Subscription sub, Long deliveries) throws AMQException { boolean atTail = false; - boolean advanced; while (!sub.isSuspended() && !atTail && deliveries != 0) { - - advanced = false; - sub.getSendLock(); - try + try { - if (sub.isActive()) + sub.getSendLock(); + atTail = attemptDelivery(sub, deliveries); + if (atTail && sub.isAutoClose()) { - QueueEntry node = moveSubscriptionToNextNode(sub); - if (!(node.isAcquired() || node.isDeleted())) - { - if (!sub.isSuspended()) - { - if (sub.hasInterest(node)) - { - if (!sub.wouldSuspend(node)) - { - if (!sub.isBrowser() && !node.acquire(sub)) - { - sub.restoreCredit(node); - - } - else - { - deliveries--; - deliverMessage(sub, node); - - if (sub.isBrowser()) - { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - advanced = true; - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - } - } - - } - else - { - break; - } - } - else - { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - } - } - } - - } - atTail = (_entries.next(node) == null) && !advanced; + unregisterSubscription(sub); + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); } } finally { sub.releaseSendLock(); } - } // if there's (potentially) more than one subscription the others will potentially not have been advanced to the @@ -1287,16 +1236,72 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { advanceAllSubscriptions(); } + return atTail; + } - if (atTail && sub.isAutoClose()) + private boolean attemptDelivery(Subscription sub, Long deliveries) throws AMQException + { + boolean atTail = false; + boolean advanced = false; + boolean subActive = sub.isActive(); + if (subActive) { - unregisterSubscription(sub); + QueueEntry node = moveSubscriptionToNextNode(sub); + if (!(node.isAcquired() || node.isDeleted())) + { + if (!sub.isSuspended()) + { + if (sub.hasInterest(node)) + { + if (!sub.wouldSuspend(node)) + { + if (!sub.isBrowser() && !node.acquire(sub)) + { + sub.restoreCredit(node); - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); - } + } + else + { + deliveries--; + deliverMessage(sub, node); - return atTail; + if (sub.isBrowser()) + { + QueueEntry newNode = _entries.next(node); + + if (newNode != null) + { + advanced = true; + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + } + } + + } + else // Not enough Credit for message and wouldSuspend + { + //QPID-1187 - Treat the subscription as suspended for this message + // and wait for the message to be removed to continue delivery. + subActive = false; + node.addStateChangeListener(new QueueEntryListener(sub, node)); + } + } + else + { + // this subscription is not interested in this node so we can skip over it + QueueEntry newNode = _entries.next(node); + if (newNode != null) + { + sub.setLastSeenEntry(node, newNode); + } + } + } + + } + atTail = (_entries.next(node) == null) && !advanced; + } + return atTail || !subActive; } protected void advanceAllSubscriptions() throws AMQException @@ -1347,7 +1352,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean deliveryIncomplete = true; int extraLoops = 1; - int deliveries = MAX_ASYNC_DELIVERIES; + Long deliveries = new Long(MAX_ASYNC_DELIVERIES); _asynchronousRunner.compareAndSet(runner, null); @@ -1372,110 +1377,46 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { boolean closeConsumer = false; Subscription sub = subscriptionIter.getNode().getSubscription(); - if (sub != null) + sub.getSendLock(); + try { - sub.getSendLock(); - try + if (sub != null) { - QueueEntry node = moveSubscriptionToNextNode(sub); - if (node != null && sub.isActive()) + QueueEntry node = moveSubscriptionToNextNode(sub); + if (node != null) { - boolean advanced = false; - boolean subActive = false; - - if (!(node.isAcquired() || node.isDeleted())) - { - if (!sub.isSuspended()) - { - subActive = true; - if (sub.hasInterest(node)) - { - if (!sub.wouldSuspend(node)) - { - if (!sub.isBrowser() && !node.acquire(sub)) - { - sub.restoreCredit(node); - - } - else - { - deliverMessage(sub, node); - deliveries--; - - if (sub.isBrowser()) - { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - advanced = true; - } - - } - } - done = false; - } - else // Not enough Credit for message and wouldSuspend - { - //QPID-1187 - Treat the subscription as suspended for this message - // and wait for the message to be removed to continue delivery. - subActive = false; - - node.addStateChangeListener(new QueueEntryListener(sub, node)); - } - } - else - { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - } - } - } - } - final boolean atTail = (_entries.next(node) == null); - - done = done && (!subActive || atTail); - - closeConsumer = (atTail && !advanced && sub.isAutoClose()); + done = attemptDelivery(sub, deliveries); } } - finally + if (done) { - sub.releaseSendLock(); - } - - if (closeConsumer) - { - unregisterSubscription(sub); - - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); - } + if (extraLoops == 0) + { + deliveryIncomplete = false; + if (sub.isAutoClose()) + { + unregisterSubscription(sub); - } - if (done) - { - if (extraLoops == 0) - { - deliveryIncomplete = false; + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + } + } + else + { + extraLoops--; + } } else { - extraLoops--; + extraLoops = 1; } } - else + finally { - extraLoops = 1; + sub.releaseSendLock(); } } - _asynchronousRunner.set(null); } -- cgit v1.2.1 From cd9fd453bd479531ac3cec401fdc6e25a74209c8 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 23 Oct 2008 11:33:45 +0000 Subject: QPID-1385 : Extracted annonymous class from AMQChannel.resend(boolean), Added new Mock Objects to the broke to allow direct testing of the new class. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@707344 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 58 +---------- .../qpid/server/ExtractResendAndRequeue.java | 110 +++++++++++++++++++++ 2 files changed, 112 insertions(+), 56 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 0e2645689c..0fd2b5c83a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -22,9 +22,7 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; @@ -60,7 +58,6 @@ import java.util.Map; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; public class AMQChannel { @@ -594,60 +591,9 @@ public class AMQChannel // Process the Unacked-Map. // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. + _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, + msgToResend, requeue, _storeContext)); - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException - { - - AMQMessage msg = message.getMessage(); - msg.setRedelivered(true); - final Subscription subscription = message.getDeliveredSubscription(); - if (subscription != null) - { - // Consumer exists - if (!subscription.isClosed()) - { - msgToResend.put(deliveryTag, message); - } - else // consumer has gone - { - msgToRequeue.put(deliveryTag, message); - } - } - else - { - // Message has no consumer tag, so was "delivered" to a GET - // or consumer no longer registered - // cannot resend, so re-queue. - if (!message.isQueueDeleted()) - { - if (requeue) - { - msgToRequeue.put(deliveryTag, message); - } - else - { - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); - } - } - else - { - message.discard(_storeContext); - _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); - } - } - - // false means continue processing - return false; - } - - public void visitComplete() - { - } - }); - - _unacknowledgedMessageMap.clear(); // Process Messages to Resend if (_log.isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java new file mode 100644 index 0000000000..4f5461bc0e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -0,0 +1,110 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import java.util.Map; + +public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor +{ + private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class); + + private Map _msgToRequeue; + private Map _msgToResend; + private boolean _requeueIfUnabletoResend; + private StoreContext _storeContext; + private UnacknowledgedMessageMap _unacknowledgedMessageMap; + + public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, + Map msgToRequeue, + Map msgToResend, + boolean requeueIfUnabletoResend, + StoreContext storeContext) + { + _unacknowledgedMessageMap = unacknowledgedMessageMap; + _msgToRequeue = msgToRequeue; + _msgToResend = msgToResend; + _requeueIfUnabletoResend = requeueIfUnabletoResend; + _storeContext = storeContext; + } + + @Override + public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException + { + + AMQMessage msg = message.getMessage(); + msg.setRedelivered(true); + final Subscription subscription = message.getDeliveredSubscription(); + if (subscription != null) + { + // Consumer exists + if (!subscription.isClosed()) + { + _msgToResend.put(deliveryTag, message); + } + else // consumer has gone + { + _msgToRequeue.put(deliveryTag, message); + } + } + else + { + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (!message.isQueueDeleted()) + { + if (_requeueIfUnabletoResend) + { + _msgToRequeue.put(deliveryTag, message); + } + else + { + message.discard(_storeContext); + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + } + } + else + { + message.discard(_storeContext); + _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + } + } + + // false means continue processing + return false; + } + + @Override + public void visitComplete() + { + _unacknowledgedMessageMap.clear(); + } + +} -- cgit v1.2.1 From 06a41e8beb398df3bdb85247a39734e4d0790970 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 24 Oct 2008 15:41:36 +0000 Subject: QPID-1390 : Allow Authentication Manager to correctly close git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@707657 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ApplicationRegistry.java | 20 ++++++++++++++++++-- .../security/auth/manager/AuthenticationManager.java | 1 + .../PrincipalDatabaseAuthenticationManager.java | 5 +++++ 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 63171d583a..c9c3acf61b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -27,8 +27,11 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.plugins.PluginManager; import org.apache.mina.common.IoAcceptor; @@ -207,11 +210,24 @@ public abstract class ApplicationRegistry implements IApplicationRegistry virtualHost.close(); } + // Replace above with this +// _virtualHostRegistry.close(); + +// _accessManager.close(); + +// _databaseManager.close(); + + _authenticationManager.close(); + +// _databaseManager.close(); + // close the rmi registry(if any) started for management - if (getManagedObjectRegistry() != null) + if (_managedObjectRegistry != null) { - getManagedObjectRegistry().close(); + _managedObjectRegistry.close(); } + +// _pluginManager.close(); } private void unbind() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index bb94e0b7bf..d1803124a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -34,4 +34,5 @@ public interface AuthenticationManager AuthenticationResult authenticate(SaslServer server, byte[] response); + void close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index e5bf3edfca..7fbb68e861 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -233,4 +233,9 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); } } + + public void close() + { + Security.removeProvider(PROVIDER_NAME); + } } -- cgit v1.2.1 From 91c8efb24178ad4923d25bdc276635d33d589ff1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 24 Oct 2008 15:43:03 +0000 Subject: QPID-1394 : Registration of JCAProvider is incorrect in client and broker SASL configurations git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@707658 13f79535-47bb-0310-9956-ffa450edef68 --- .../manager/PrincipalDatabaseAuthenticationManager.java | 13 +++++++++---- .../apache/qpid/server/security/auth/sasl/JCAProvider.java | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 7fbb68e861..2cbbdc85ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -23,9 +23,7 @@ package org.apache.qpid.server.security.auth.manager; import org.apache.log4j.Logger; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.SubsetConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.JCAProvider; @@ -59,6 +57,8 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan private Map> _serverCreationProperties = new HashMap>(); private AuthenticationManager _default = null; + /** The name for the required SASL Server mechanisms */ + public static final String PROVIDER_NAME= "AMQSASLProvider-Server"; public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception { @@ -101,10 +101,15 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan if (providerMap.size() > 0) { // Ensure we are used before the defaults - if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1) + if (Security.insertProviderAt(new JCAProvider(PROVIDER_NAME, providerMap), 1) == -1) { - _logger.warn("Unable to set order of providers."); + _logger.error("Unable to load custom SASL providers. Qpid custom SASL authenticators unavailable."); } + else + { + _logger.info("Additional SASL providers successfully registered."); + } + } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java index fd4ad86055..d6a09d8217 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -28,12 +28,11 @@ import javax.security.sasl.SaslServerFactory; public final class JCAProvider extends Provider { - public JCAProvider(Map> providerMap) + public JCAProvider(String name, Map> providerMap) { - super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + + super(name, 1.0, "A JCA provider that registers all " + "AMQ SASL providers that want to be registered"); register(providerMap); - //Security.addProvider(this); } private void register(Map> providerMap) -- cgit v1.2.1 From b6356941a047f4d8dffbe314e6bff3900574c3cb Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 24 Oct 2008 16:20:16 +0000 Subject: QPID-1315: Fix style issue, iterator control usage as per review comments from rgodfrey. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@707672 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 3 ++- .../apache/qpid/server/queue/SimpleAMQQueue.java | 23 ++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 0fd2b5c83a..26ac562fb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -333,7 +333,8 @@ public class AMQChannel Subscription sub = _tag2SubscriptionMap.remove(consumerTag); if (sub != null) { - try { + try + { sub.getSendLock(); sub.getQueue().unregisterSubscription(sub); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index bc335d0ba5..7e7e8b2114 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1204,16 +1204,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener flushSubscription(sub, Long.MAX_VALUE); } - public boolean flushSubscription(Subscription sub, Long deliveries) throws AMQException + public boolean flushSubscription(Subscription sub, Long iterations) throws AMQException { boolean atTail = false; - while (!sub.isSuspended() && !atTail && deliveries != 0) + while (!sub.isSuspended() && !atTail && iterations != 0) { try { sub.getSendLock(); - atTail = attemptDelivery(sub, deliveries); + atTail = attemptDelivery(sub); if (atTail && sub.isAutoClose()) { unregisterSubscription(sub); @@ -1221,6 +1221,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); } + else if (!atTail) + { + iterations--; + } } finally { @@ -1239,7 +1243,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return atTail; } - private boolean attemptDelivery(Subscription sub, Long deliveries) throws AMQException + private boolean attemptDelivery(Subscription sub) throws AMQException { boolean atTail = false; boolean advanced = false; @@ -1258,11 +1262,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (!sub.isBrowser() && !node.acquire(sub)) { sub.restoreCredit(node); - } else { - deliveries--; deliverMessage(sub, node); if (sub.isBrowser()) @@ -1352,11 +1354,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean deliveryIncomplete = true; int extraLoops = 1; - Long deliveries = new Long(MAX_ASYNC_DELIVERIES); + Long iterations = new Long(MAX_ASYNC_DELIVERIES); _asynchronousRunner.compareAndSet(runner, null); - while (deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) + while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) { // we want to have one extra loop after every subscription has reached the point where it cannot move // further, just in case the advance of one subscription in the last loop allows a different subscription to @@ -1386,7 +1388,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = moveSubscriptionToNextNode(sub); if (node != null) { - done = attemptDelivery(sub, deliveries); + done = attemptDelivery(sub); } } if (done) @@ -1409,6 +1411,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } else { + iterations--; extraLoops = 1; } } @@ -1422,7 +1425,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit // therefore we should schedule this runner again (unless someone beats us to it :-) ). - if (deliveries == 0 && _asynchronousRunner.compareAndSet(null, runner)) + if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner)) { _asyncDelivery.execute(runner); } -- cgit v1.2.1 From 910e7a4269782e8131134b73d4d569761c5fa4a2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 2 Dec 2008 23:27:18 +0000 Subject: QPID-1501 : Remove @Override annotations to allow compilation under JDK 1.5 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@722670 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java | 2 -- .../java/org/apache/qpid/server/subscription/SubscriptionImpl.java | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 4f5461bc0e..29494c4118 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -54,7 +54,6 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor _storeContext = storeContext; } - @Override public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException { @@ -101,7 +100,6 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor return false; } - @Override public void visitComplete() { _unacknowledgedMessageMap.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index df84270275..a616c2ea35 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -79,7 +79,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } - @Override public boolean isBrowser() { return true; @@ -127,7 +126,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } - @Override public boolean isBrowser() { return false; @@ -197,7 +195,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); } - @Override + public boolean isBrowser() { return false; -- cgit v1.2.1 From 6bbe2170a2328d8eca09150acf9a3d3f316fc3c5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 3 Dec 2008 12:26:40 +0000 Subject: QPID-1482 : Patch provided by Robert Gemmell, To allow PLAIN authentication via JMX Console. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@722865 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 73 +++------------------- 1 file changed, 7 insertions(+), 66 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 4caae2b26f..659f806d58 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -28,6 +28,7 @@ import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrinci import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; import javax.management.JMException; import javax.management.MBeanServer; @@ -36,13 +37,6 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; import java.io.IOException; import java.lang.management.ManagementFactory; import java.rmi.RemoteException; @@ -128,10 +122,15 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } else if (db instanceof PlainPasswordFilePrincipalDatabase) { + PlainInitialiser initialiser = new PlainInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); env.put("jmx.remote.profiles", "SASL/PLAIN"); - env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); } + //workaround NPE generated from env map classloader issue when using Eclipse 3.4 to launch + env.put("jmx.remote.profile.provider.class.loader", this.getClass().getClassLoader()); + // Enable the SSL security and server authentication /* SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); @@ -222,62 +221,4 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } } - /** This class is used for SASL enabled JMXConnector for performing user authentication. */ - private class UserCallbackHandler implements CallbackHandler - { - private final PrincipalDatabase _principalDatabase; - - protected UserCallbackHandler(PrincipalDatabase database) - { - _principalDatabase = database; - } - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - // Retrieve callbacks - NameCallback ncb = null; - PasswordCallback pcb = null; - for (int i = 0; i < callbacks.length; i++) - { - if (callbacks[i] instanceof NameCallback) - { - ncb = (NameCallback) callbacks[i]; - } - else if (callbacks[i] instanceof PasswordCallback) - { - pcb = (PasswordCallback) callbacks[i]; - } - else if (callbacks[i] instanceof AuthorizeCallback) - { - ((AuthorizeCallback) callbacks[i]).setAuthorized(true); - } - else - { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - - boolean authorized = false; - // Process retrieval of password; can get password if username is available in NameCallback - if ((ncb != null) && (pcb != null)) - { - String username = ncb.getDefaultName(); - try - { - authorized = _principalDatabase.verifyPassword(username, pcb.getPassword()); - } - catch (AccountNotFoundException e) - { - IOException ioe = new IOException("User not authorized. " + e); - ioe.initCause(e); - throw ioe; - } - } - - if (!authorized) - { - throw new IOException("User not authorized."); - } - } - } } -- cgit v1.2.1 From 93d7a8b0e385c703a175a99bc7795c9cb541d355 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 5 Dec 2008 17:11:08 +0000 Subject: QPID-1503 : Update to Base64 to correctly save password file. Pulled User out of Base64MD5 to allow better testing. Added unit test case for Base64 and User git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@723792 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 134 ++------------------- 1 file changed, 10 insertions(+), 124 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 348bccb4e9..86a0b7d961 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -21,30 +21,26 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; +import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.EncoderException; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.BufferedReader; import java.io.FileReader; -import java.io.UnsupportedEncodingException; +import java.io.IOException; import java.io.PrintStream; -import java.util.regex.Pattern; -import java.util.Map; +import java.security.Principal; import java.util.HashMap; -import java.util.List; import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.NoSuchAlgorithmException; +import java.util.regex.Pattern; /** * Represents a user database where the account information is stored in a simple flat file. @@ -64,7 +60,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase private Map _saslServers; AMQUserManagementMBean _mbean; - private static final String DEFAULT_ENCODING = "utf-8"; + public static final String DEFAULT_ENCODING = "utf-8"; private Map _users = new HashMap(); private ReentrantLock _userUpdate = new ReentrantLock(); @@ -284,7 +280,6 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return true; } - public Map getMechanisms() { return _saslServers; @@ -325,7 +320,6 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - private void loadPasswordFile() throws IOException { try @@ -382,6 +376,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { tmp.delete(); } + try { writer = new PrintStream(tmp); @@ -394,6 +389,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase if (result == null || result.length < 2 || result[0].startsWith("#")) { writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); continue; } @@ -485,114 +481,4 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - private class User implements Principal - { - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - User(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be lenght 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public User(String name, char[] password) - { - _name = name; - setPassword(password); - } - - public String getName() - { - return _name; - } - - public String toString() - { - if (_logger.isDebugEnabled()) - { - return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); - } - else - { - return _name; - } - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - _encodedPassword = null; - } - - - byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - _encodedPassword = (new Base64()).encode(byteArray); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - - } } -- cgit v1.2.1 From 08b3fc94f70d5f10cc7682ce198dcb8761706878 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 5 Dec 2008 17:20:48 +0000 Subject: QPID-1503 : Update to Base64 to correctly save password file. Pulled User out of Base64MD5 to allow better testing. Added unit test case for Base64 and User git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@723795 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/security/auth/database/User.java | 121 +++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java new file mode 100644 index 0000000000..9ff9cd25cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java @@ -0,0 +1,121 @@ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; + +public class User implements Principal +{ + private static final Logger _logger = Logger.getLogger(User.class); + + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + User(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public User(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + if (_logger.isDebugEnabled()) + { + return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); + } + else + { + return _name; + } + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + _encodedPassword = (new Base64()).encode(byteArray); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} \ No newline at end of file -- cgit v1.2.1 From 2a8dee1b13f1e974224a0c0313c5d7c9f30766a6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 9 Dec 2008 15:17:44 +0000 Subject: QPID-1503 : Updates based on code review git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@724743 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 20 ++-- .../server/security/auth/database/HashedUser.java | 114 +++++++++++++++++++ .../qpid/server/security/auth/database/User.java | 121 --------------------- 3 files changed, 124 insertions(+), 131 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 86a0b7d961..a2a0be926e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -61,7 +61,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase AMQUserManagementMBean _mbean; public static final String DEFAULT_ENCODING = "utf-8"; - private Map _users = new HashMap(); + private Map _users = new HashMap(); private ReentrantLock _userUpdate = new ReentrantLock(); public Base64MD5PasswordFilePrincipalDatabase() @@ -165,7 +165,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { - User user = _users.get(principal.getName()); + HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -215,7 +215,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return false; } - User user = new User(principal.getName(), password); + HashedUser user = new HashedUser(principal.getName(), password); try { @@ -245,7 +245,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase public boolean deletePrincipal(Principal principal) throws AccountNotFoundException { - User user = _users.get(principal.getName()); + HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -309,7 +309,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase */ private char[] lookupPassword(String name) { - User user = _users.get(name); + HashedUser user = _users.get(name); if (user == null) { return null; @@ -341,7 +341,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - User user = new User(result); + HashedUser user = new HashedUser(result); _logger.info("Created user:" + user); _users.put(user.getName(), user); } @@ -393,7 +393,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - User user = _users.get(result[0]); + HashedUser user = _users.get(result[0]); if (user == null) { @@ -411,7 +411,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { try { - byte[] encodedPassword = user.getEncodePassword(); + byte[] encodedPassword = user.getEncodedPassword(); writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); writer.write(encodedPassword); @@ -429,14 +429,14 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - for (User user : _users.values()) + for (HashedUser user : _users.values()) { if (user.isModified()) { byte[] encodedPassword; try { - encodedPassword = user.getEncodePassword(); + encodedPassword = user.getEncodedPassword(); writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); writer.write(encodedPassword); writer.println(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java new file mode 100644 index 0000000000..723a1c0cc6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -0,0 +1,114 @@ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; + +public class HashedUser implements Principal +{ + private static final Logger _logger = Logger.getLogger(HashedUser.class); + + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + HashedUser(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public HashedUser(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + _encodedPassword = (new Base64()).encode(byteArray); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java deleted file mode 100644 index 9ff9cd25cb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/User.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; - -public class User implements Principal -{ - private static final Logger _logger = Logger.getLogger(User.class); - - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - User(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be length 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public User(String name, char[] password) - { - _name = name; - setPassword(password); - } - - public String getName() - { - return _name; - } - - public String toString() - { - if (_logger.isDebugEnabled()) - { - return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); - } - else - { - return _name; - } - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - _encodedPassword = null; - } - - byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - _encodedPassword = (new Base64()).encode(byteArray); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - -} \ No newline at end of file -- cgit v1.2.1 From 5b0299abeef865d74ebf827bedd0a26f4d6d8ab1 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 9 Dec 2008 17:03:30 +0000 Subject: QPID-1503: Add more tests for Base64MD5PasswordFilePrincipalDatabase, fix buglets. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@724779 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index a2a0be926e..cca9deb6da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -109,6 +109,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase /** * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * If you want to change the password for a user, use updatePassword instead. * * @param principal The Principal to set the password for * @param callback The PasswordCallback to call setPassword on @@ -152,17 +153,31 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { char[] pwd = lookupPassword(principal); - int index = 0; - boolean verified = true; - - while (verified & index < password.length) + return compareCharArray(pwd, password); + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) { - verified = (pwd[index] == password[index]); - index++; + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } } - return verified; + return equal; } + /** + * Changes the password for the specified user + * + * @param principal to change the password for + * @param password plaintext password to set the password too + */ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { HashedUser user = _users.get(principal.getName()); -- cgit v1.2.1 From 51166ac18a7f450828b0467e72406e575c98c439 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 9 Dec 2008 17:23:17 +0000 Subject: QPID-1469: Fix NullPointerException, add test for deleteUser which would expose this. Patch from gemmellr@dcs.gla.ac.uk git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@724787 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/access/management/AMQUserManagementMBean.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index a8ae03cc5d..32ec3a3bbc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -441,7 +441,12 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana private String getCurrentJMXUser() { AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + if (subject == null) + { + return "Unknown user, authentication Subject was null"; + } // Retrieve JMXPrincipal from Subject Set principals = subject.getPrincipals(JMXPrincipal.class); -- cgit v1.2.1 From c0c24c9412a1a9b95049d2bc534f6c2ad1d80c4b Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Tue, 16 Dec 2008 04:14:52 +0000 Subject: Added the ASF license header to the following files. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@726943 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/auth/database/HashedUser.java | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java index 723a1c0cc6..4d92e3fb4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -1,3 +1,23 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ package org.apache.qpid.server.security.auth.database; import org.apache.commons.codec.EncoderException; @@ -111,4 +131,4 @@ public class HashedUser implements Principal _modified = false; } -} \ No newline at end of file +} -- cgit v1.2.1 From 83cf9b595ce30e1379290356870dbba33144c8d8 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 16 Dec 2008 14:40:52 +0000 Subject: QPID-1536 : Convert Base64MD5PrincipalDatabase to accept plain text password input and do the hashing locally. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727057 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/auth/database/Base64HashedUser.java | 149 +++++++++++++++++++++ .../Base64MD5PasswordFilePrincipalDatabase.java | 16 +-- .../server/security/auth/database/HashedUser.java | 134 ------------------ 3 files changed, 157 insertions(+), 142 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java new file mode 100644 index 0000000000..2caccebb2a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java @@ -0,0 +1,149 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.MessageDigest; + +public class Base64HashedUser implements Principal +{ + private static final Logger _logger = Logger.getLogger(Base64HashedUser.class); + + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + Base64HashedUser(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + return md.digest(); + } + + + public Base64HashedUser(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + + _encodedPassword = (new Base64()).encode(getMD5(byteArray)); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index cca9deb6da..0f0c0309db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -61,7 +61,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase AMQUserManagementMBean _mbean; public static final String DEFAULT_ENCODING = "utf-8"; - private Map _users = new HashMap(); + private Map _users = new HashMap(); private ReentrantLock _userUpdate = new ReentrantLock(); public Base64MD5PasswordFilePrincipalDatabase() @@ -180,7 +180,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase */ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { - HashedUser user = _users.get(principal.getName()); + Base64HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -230,7 +230,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return false; } - HashedUser user = new HashedUser(principal.getName(), password); + Base64HashedUser user = new Base64HashedUser(principal.getName(), password); try { @@ -260,7 +260,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase public boolean deletePrincipal(Principal principal) throws AccountNotFoundException { - HashedUser user = _users.get(principal.getName()); + Base64HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -324,7 +324,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase */ private char[] lookupPassword(String name) { - HashedUser user = _users.get(name); + Base64HashedUser user = _users.get(name); if (user == null) { return null; @@ -356,7 +356,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - HashedUser user = new HashedUser(result); + Base64HashedUser user = new Base64HashedUser(result); _logger.info("Created user:" + user); _users.put(user.getName(), user); } @@ -408,7 +408,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - HashedUser user = _users.get(result[0]); + Base64HashedUser user = _users.get(result[0]); if (user == null) { @@ -444,7 +444,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - for (HashedUser user : _users.values()) + for (Base64HashedUser user : _users.values()) { if (user.isModified()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java deleted file mode 100644 index 4d92e3fb4c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java +++ /dev/null @@ -1,134 +0,0 @@ -/* -* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; - -public class HashedUser implements Principal -{ - private static final Logger _logger = Logger.getLogger(HashedUser.class); - - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - HashedUser(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be length 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public HashedUser(String name, char[] password) - { - _name = name; - setPassword(password); - } - - public String getName() - { - return _name; - } - - public String toString() - { - return _name; - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - _encodedPassword = null; - } - - byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - _encodedPassword = (new Base64()).encode(byteArray); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - -} -- cgit v1.2.1 From b34234b5d93acc8c840ed412712069a549e2a86d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 16 Dec 2008 15:49:33 +0000 Subject: QPID-1538 : Ensure that RMI connections use our custom Invoker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727068 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 659f806d58..0a9f993dcc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -59,7 +59,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry private final MBeanServer _mbeanServer; private Registry _rmiRegistry; private JMXServiceURL _jmxURL; - + public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; public static final int MANAGEMENT_PORT_DEFAULT = 8999; @@ -73,10 +73,9 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer = platformServer ? ManagementFactory.getPlatformMBeanServer() - : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); } - public void start() throws IOException { // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent @@ -91,12 +90,13 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT); + Map env = new HashMap(); + if (security) { // For SASL using JMXMP _jmxURL = new JMXServiceURL("jmxmp", null, port); - Map env = new HashMap(); Map map = appRegistry.getDatabaseManager().getDatabases(); PrincipalDatabase db = null; @@ -139,18 +139,20 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); */ - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - cs.start(); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL"); + _log.warn("JMX: Starting JMXConnector server on port '" + port + "' with SASL"); } else { - startJMXConnectorServer(port); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled"); + env = null; + _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); + _log.warn("JMX: Starting JMXConnector server on port '" + port + "' with security disabled"); } + + + startJMXConnectorServer(port, env); + _log.warn("JMX: Started JMXConnector server on port '" + port + "'"); + } /** @@ -158,13 +160,18 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * * @param port * + * @param env * @throws IOException */ - private void startJMXConnectorServer(int port) throws IOException + private void startJMXConnectorServer(int port, Map env) throws IOException { startRMIRegistry(port); - _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); + + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); } -- cgit v1.2.1 From f0e4111a46b538c8a5b785c9b2577993f9153b46 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 16 Dec 2008 15:50:35 +0000 Subject: QPID-1537 : Version all the MBeans to allow changes in the API contracts. Set AMQUserManagementMBean to version 2 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727070 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 6 +----- .../java/org/apache/qpid/server/exchange/AbstractExchange.java | 6 +----- .../java/org/apache/qpid/server/exchange/ManagedExchange.java | 1 + .../java/org/apache/qpid/server/management/AMQManagedObject.java | 4 ++-- .../org/apache/qpid/server/management/DefaultManagedObject.java | 8 +++++++- .../java/org/apache/qpid/server/management/ManagedBroker.java | 4 ++-- .../org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 4 +--- .../java/org/apache/qpid/server/protocol/ManagedConnection.java | 1 + .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../src/main/java/org/apache/qpid/server/queue/ManagedQueue.java | 1 + .../server/security/access/management/AMQUserManagementMBean.java | 2 +- .../qpid/server/security/access/management/UserManagement.java | 4 ++++ .../org/apache/qpid/server/virtualhost/ManagedVirtualHost.java | 1 + .../main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 2 +- 14 files changed, 25 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index fc6057afd2..12efaec777 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -42,12 +42,8 @@ import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -79,7 +75,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { - super(ManagedBroker.class, ManagedBroker.TYPE); + super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); _virtualHostMBean = virtualHostMBean; VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 8d24626b73..b6c741bbec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,13 +38,9 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.List; -import java.util.Map; - public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; @@ -81,7 +77,7 @@ public abstract class AbstractExchange implements Exchange, Managable public ExchangeMBean() throws NotCompliantMBeanException { - super(ManagedExchange.class, ManagedExchange.TYPE); + super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); } protected void init() throws OpenDataException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index 5d6d68b3c8..317ff385ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -40,6 +40,7 @@ import org.apache.qpid.server.queue.ManagedQueue; public interface ManagedExchange { static final String TYPE = "Exchange"; + static final int VERSION = 1; /** * Returns the name of the managed exchange. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java index a2c2bd62a2..c6e07f6f48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -50,10 +50,10 @@ public abstract class AMQManagedObject extends DefaultManagedObject protected MBeanInfo _mbeanInfo; - protected AMQManagedObject(Class managementInterface, String typeName) + protected AMQManagedObject(Class managementInterface, String typeName, int version) throws NotCompliantMBeanException { - super(managementInterface, typeName); + super(managementInterface, typeName, version); buildMBeanInfo(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 84526dbc11..d0b96afe6f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -39,13 +39,15 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana private Class _managementInterface; private String _typeName; + private int _version; - protected DefaultManagedObject(Class managementInterface, String typeName) + protected DefaultManagedObject(Class managementInterface, String typeName, int version) throws NotCompliantMBeanException { super(managementInterface); _managementInterface = managementInterface; _typeName = typeName; + _version = version; } public String getType() @@ -115,6 +117,10 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(getHierarchicalName(this)); objectName.append("name=").append(name); + objectName.append(","); + objectName.append("version=").append(_version); + + return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index 45e2e91ed7..c18417fc43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -40,12 +40,13 @@ public interface ManagedBroker { static final String TYPE = "VirtualHostManager"; + static final int VERSION = 1 ; + /** * Creates a new Exchange. * @param name * @param type * @param durable - * @param passive * @throws IOException * @throws JMException */ @@ -73,7 +74,6 @@ public interface ManagedBroker * @param queueName * @param durable * @param owner - * @param autoDelete * @throws IOException * @throws JMException */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index bd072985c4..5dd3cc075a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,7 +37,6 @@ */ package org.apache.qpid.server.protocol; -import java.security.Principal; import java.util.Date; import java.util.List; @@ -58,7 +57,6 @@ import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.MethodRegistry; @@ -93,7 +91,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException { - super(ManagedConnection.class, ManagedConnection.TYPE); + super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); _session = session; String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index e6e713ac6d..e75b09a0cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -41,6 +41,7 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedConnection { static final String TYPE = "Connection"; + static final int VERSION = 1; @MBeanAttribute(name = "ClientId", description = "Client Id") String getClientId(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 2ed6be77c6..9745257c79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -100,7 +100,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException { - super(ManagedQueue.class, ManagedQueue.TYPE); + super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); _queue = queue; _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 2bc94995e9..e0d131a5d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -41,6 +41,7 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedQueue { static final String TYPE = "Queue"; + static final int VERSION = 1; /** * Returns the Name of the ManagedQueue. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 32ec3a3bbc..b0de873cb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -104,7 +104,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public AMQUserManagementMBean() throws JMException { - super(UserManagement.class, UserManagement.TYPE); + super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); } public String getObjectInstanceName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java index 658d7ebbd3..d125fd6be4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java @@ -33,8 +33,11 @@ import java.io.IOException; public interface UserManagement { + String TYPE = "UserManagement"; + int VERSION = 2; + //********** Operations *****************// /** * set password for user @@ -115,4 +118,5 @@ public interface UserManagement impact = MBeanOperationInfo.INFO) TabularData viewUsers(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 85d804457e..f4c81fbbb8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.management.MBeanAttribute; public interface ManagedVirtualHost { static final String TYPE = "VirtualHost"; + static final int VERSION = 1; /** * Returns the name of the managed virtualHost. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9229863c35..9b8c97872a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -104,7 +104,7 @@ public class VirtualHost implements Accessable { public VirtualHostMBean() throws NotCompliantMBeanException { - super(ManagedVirtualHost.class, "VirtualHost"); + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); } public String getObjectInstanceName() -- cgit v1.2.1 From 331073e6e3ae084a036eebf0ec4ea843cdc99c7c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 17 Dec 2008 10:20:21 +0000 Subject: QPID-1537 : Reverted r727070 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727335 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 6 +++++- .../java/org/apache/qpid/server/exchange/AbstractExchange.java | 6 +++++- .../java/org/apache/qpid/server/exchange/ManagedExchange.java | 1 - .../java/org/apache/qpid/server/management/AMQManagedObject.java | 4 ++-- .../org/apache/qpid/server/management/DefaultManagedObject.java | 8 +------- .../java/org/apache/qpid/server/management/ManagedBroker.java | 4 ++-- .../org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 4 +++- .../java/org/apache/qpid/server/protocol/ManagedConnection.java | 1 - .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../src/main/java/org/apache/qpid/server/queue/ManagedQueue.java | 1 - .../server/security/access/management/AMQUserManagementMBean.java | 2 +- .../qpid/server/security/access/management/UserManagement.java | 4 ---- .../org/apache/qpid/server/virtualhost/ManagedVirtualHost.java | 1 - .../main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 2 +- 14 files changed, 21 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 12efaec777..fc6057afd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -42,8 +42,12 @@ import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -75,7 +79,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { - super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); + super(ManagedBroker.class, ManagedBroker.TYPE); _virtualHostMBean = virtualHostMBean; VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index b6c741bbec..8d24626b73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,9 +38,13 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.List; +import java.util.Map; + public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; @@ -77,7 +81,7 @@ public abstract class AbstractExchange implements Exchange, Managable public ExchangeMBean() throws NotCompliantMBeanException { - super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); + super(ManagedExchange.class, ManagedExchange.TYPE); } protected void init() throws OpenDataException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index 317ff385ab..5d6d68b3c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -40,7 +40,6 @@ import org.apache.qpid.server.queue.ManagedQueue; public interface ManagedExchange { static final String TYPE = "Exchange"; - static final int VERSION = 1; /** * Returns the name of the managed exchange. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java index c6e07f6f48..a2c2bd62a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -50,10 +50,10 @@ public abstract class AMQManagedObject extends DefaultManagedObject protected MBeanInfo _mbeanInfo; - protected AMQManagedObject(Class managementInterface, String typeName, int version) + protected AMQManagedObject(Class managementInterface, String typeName) throws NotCompliantMBeanException { - super(managementInterface, typeName, version); + super(managementInterface, typeName); buildMBeanInfo(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index d0b96afe6f..84526dbc11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -39,15 +39,13 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana private Class _managementInterface; private String _typeName; - private int _version; - protected DefaultManagedObject(Class managementInterface, String typeName, int version) + protected DefaultManagedObject(Class managementInterface, String typeName) throws NotCompliantMBeanException { super(managementInterface); _managementInterface = managementInterface; _typeName = typeName; - _version = version; } public String getType() @@ -117,10 +115,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(getHierarchicalName(this)); objectName.append("name=").append(name); - objectName.append(","); - objectName.append("version=").append(_version); - - return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index c18417fc43..45e2e91ed7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -40,13 +40,12 @@ public interface ManagedBroker { static final String TYPE = "VirtualHostManager"; - static final int VERSION = 1 ; - /** * Creates a new Exchange. * @param name * @param type * @param durable + * @param passive * @throws IOException * @throws JMException */ @@ -74,6 +73,7 @@ public interface ManagedBroker * @param queueName * @param durable * @param owner + * @param autoDelete * @throws IOException * @throws JMException */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 5dd3cc075a..bd072985c4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,6 +37,7 @@ */ package org.apache.qpid.server.protocol; +import java.security.Principal; import java.util.Date; import java.util.List; @@ -57,6 +58,7 @@ import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.MethodRegistry; @@ -91,7 +93,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException { - super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); + super(ManagedConnection.class, ManagedConnection.TYPE); _session = session; String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index e75b09a0cb..e6e713ac6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -41,7 +41,6 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedConnection { static final String TYPE = "Connection"; - static final int VERSION = 1; @MBeanAttribute(name = "ClientId", description = "Client Id") String getClientId(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 9745257c79..2ed6be77c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -100,7 +100,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException { - super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); + super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index e0d131a5d9..2bc94995e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -41,7 +41,6 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedQueue { static final String TYPE = "Queue"; - static final int VERSION = 1; /** * Returns the Name of the ManagedQueue. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index b0de873cb2..32ec3a3bbc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -104,7 +104,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public AMQUserManagementMBean() throws JMException { - super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); + super(UserManagement.class, UserManagement.TYPE); } public String getObjectInstanceName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java index d125fd6be4..658d7ebbd3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java @@ -33,11 +33,8 @@ import java.io.IOException; public interface UserManagement { - String TYPE = "UserManagement"; - int VERSION = 2; - //********** Operations *****************// /** * set password for user @@ -118,5 +115,4 @@ public interface UserManagement impact = MBeanOperationInfo.INFO) TabularData viewUsers(); - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index f4c81fbbb8..85d804457e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -31,7 +31,6 @@ import org.apache.qpid.server.management.MBeanAttribute; public interface ManagedVirtualHost { static final String TYPE = "VirtualHost"; - static final int VERSION = 1; /** * Returns the name of the managed virtualHost. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9b8c97872a..9229863c35 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -104,7 +104,7 @@ public class VirtualHost implements Accessable { public VirtualHostMBean() throws NotCompliantMBeanException { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); + super(ManagedVirtualHost.class, "VirtualHost"); } public String getObjectInstanceName() -- cgit v1.2.1 From a4cf90b0fab93c20e76055352e6a063120996da4 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 17 Dec 2008 10:24:54 +0000 Subject: QPID-1536 : Reverted r727057 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727336 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/auth/database/Base64HashedUser.java | 149 --------------------- .../Base64MD5PasswordFilePrincipalDatabase.java | 16 +-- .../server/security/auth/database/HashedUser.java | 134 ++++++++++++++++++ 3 files changed, 142 insertions(+), 157 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java deleted file mode 100644 index 2caccebb2a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64HashedUser.java +++ /dev/null @@ -1,149 +0,0 @@ -/* -* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.MessageDigest; - -public class Base64HashedUser implements Principal -{ - private static final Logger _logger = Logger.getLogger(Base64HashedUser.class); - - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - Base64HashedUser(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be length 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException - { - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - return md.digest(); - } - - - public Base64HashedUser(String name, char[] password) - { - _name = name; - setPassword(password); - } - - public String getName() - { - return _name; - } - - public String toString() - { - return _name; - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - _encodedPassword = null; - } - - byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - - _encodedPassword = (new Base64()).encode(getMD5(byteArray)); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 0f0c0309db..cca9deb6da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -61,7 +61,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase AMQUserManagementMBean _mbean; public static final String DEFAULT_ENCODING = "utf-8"; - private Map _users = new HashMap(); + private Map _users = new HashMap(); private ReentrantLock _userUpdate = new ReentrantLock(); public Base64MD5PasswordFilePrincipalDatabase() @@ -180,7 +180,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase */ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { - Base64HashedUser user = _users.get(principal.getName()); + HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -230,7 +230,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return false; } - Base64HashedUser user = new Base64HashedUser(principal.getName(), password); + HashedUser user = new HashedUser(principal.getName(), password); try { @@ -260,7 +260,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase public boolean deletePrincipal(Principal principal) throws AccountNotFoundException { - Base64HashedUser user = _users.get(principal.getName()); + HashedUser user = _users.get(principal.getName()); if (user == null) { @@ -324,7 +324,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase */ private char[] lookupPassword(String name) { - Base64HashedUser user = _users.get(name); + HashedUser user = _users.get(name); if (user == null) { return null; @@ -356,7 +356,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - Base64HashedUser user = new Base64HashedUser(result); + HashedUser user = new HashedUser(result); _logger.info("Created user:" + user); _users.put(user.getName(), user); } @@ -408,7 +408,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase continue; } - Base64HashedUser user = _users.get(result[0]); + HashedUser user = _users.get(result[0]); if (user == null) { @@ -444,7 +444,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } - for (Base64HashedUser user : _users.values()) + for (HashedUser user : _users.values()) { if (user.isModified()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java new file mode 100644 index 0000000000..4d92e3fb4c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -0,0 +1,134 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; + +public class HashedUser implements Principal +{ + private static final Logger _logger = Logger.getLogger(HashedUser.class); + + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + HashedUser(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public HashedUser(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + _encodedPassword = (new Base64()).encode(byteArray); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} -- cgit v1.2.1 From 69e2032f10cffc877f8183454ad01bce92fae774 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 17 Dec 2008 11:17:32 +0000 Subject: QPID-1538 : Reverted r727068 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@727343 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 35 +++++++++------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 0a9f993dcc..659f806d58 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -59,7 +59,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry private final MBeanServer _mbeanServer; private Registry _rmiRegistry; private JMXServiceURL _jmxURL; - + public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; public static final int MANAGEMENT_PORT_DEFAULT = 8999; @@ -73,9 +73,10 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer = platformServer ? ManagementFactory.getPlatformMBeanServer() - : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); } + public void start() throws IOException { // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent @@ -90,13 +91,12 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT); - Map env = new HashMap(); - if (security) { // For SASL using JMXMP _jmxURL = new JMXServiceURL("jmxmp", null, port); + Map env = new HashMap(); Map map = appRegistry.getDatabaseManager().getDatabases(); PrincipalDatabase db = null; @@ -139,20 +139,18 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); */ - _log.warn("JMX: Starting JMXConnector server on port '" + port + "' with SASL"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL"); } else { - env = null; - _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); - _log.warn("JMX: Starting JMXConnector server on port '" + port + "' with security disabled"); + startJMXConnectorServer(port); + _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled"); } - - - startJMXConnectorServer(port, env); - _log.warn("JMX: Started JMXConnector server on port '" + port + "'"); - } /** @@ -160,18 +158,13 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * * @param port * - * @param env * @throws IOException */ - private void startJMXConnectorServer(int port, Map env) throws IOException + private void startJMXConnectorServer(int port) throws IOException { startRMIRegistry(port); - - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); - - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - + _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); cs.start(); } -- cgit v1.2.1 From dbc3a3c0c6d19b953a866b771bf65fe74886f178 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 9 Jan 2009 12:03:03 +0000 Subject: QPID-1563: Use createTempFile git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@733016 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/management/AMQUserManagementMBean.java | 16 ++-------------- .../database/Base64MD5PasswordFilePrincipalDatabase.java | 6 +----- 2 files changed, 3 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 32ec3a3bbc..7ff3bd3541 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -396,23 +396,11 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.lock(); try { - // remove old temporary file - File tmp = new File(_accessFileName + ".tmp"); - if (tmp.exists()) - { - tmp.delete(); - } - - //remove old backup - File old = new File(_accessFileName + ".old"); - if (old.exists()) - { - old.delete(); - } + // Create temporary file + File tmp = File.createTempFile(_accessFileName, ".tmp"); // Rename current file File rights = new File(_accessFileName); - rights.renameTo(old); FileOutputStream output = new FileOutputStream(tmp); _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index cca9deb6da..bf459542de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -386,11 +386,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase BufferedReader reader = null; PrintStream writer = null; - File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp"); - if (tmp.exists()) - { - tmp.delete(); - } + File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); try { -- cgit v1.2.1 From bd1a4199a986f882e1aadc212be929b3d4484b1b Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 20 Jan 2009 11:06:37 +0000 Subject: QPID-1600: Add tests for PrincipalPermissions, document arguments to authorise and grant. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@735993 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissions.java | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 23073e0613..dd207dc001 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -60,6 +60,22 @@ public class PrincipalPermissions _permissions = new ConcurrentHashMap(); } + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: none + * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly + * CREATE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey + * or + * AMQShortString exchangeName, AMQShortString Class + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ public void grant(Permission permission, Object... parameters) { switch (permission) @@ -306,6 +322,20 @@ public class PrincipalPermissions } + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey + * CONSUME: AMQQueue queue + * CREATE: QueueDeclareBody obj || ExchangeDeclareBody obj + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ public boolean authorise(Permission permission, Object... parameters) { -- cgit v1.2.1 From 14942da3ac0ecd5adcbd6dd7675f648a7d6f425c Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 22 Jan 2009 17:06:25 +0000 Subject: Remove unused class JmsConsumer git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@736715 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/jms/JmsConsumer.java | 110 --------------------- 1 file changed, 110 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java deleted file mode 100644 index c08fae4e4e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.jms; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -public class JmsConsumer -{ - private int _prefetchValue; - - private PrefetchUnits _prefetchUnits; - - private boolean _noLocal; - - private boolean _autoAck; - - private boolean _exclusive; - - private AMQProtocolSession _protocolSession; - - public enum PrefetchUnits - { - OCTETS, - MESSAGES - } - - public int getPrefetchValue() - { - return _prefetchValue; - } - - public void setPrefetchValue(int prefetchValue) - { - _prefetchValue = prefetchValue; - } - - public PrefetchUnits getPrefetchUnits() - { - return _prefetchUnits; - } - - public void setPrefetchUnits(PrefetchUnits prefetchUnits) - { - _prefetchUnits = prefetchUnits; - } - - public boolean isNoLocal() - { - return _noLocal; - } - - public void setNoLocal(boolean noLocal) - { - _noLocal = noLocal; - } - - public boolean isAutoAck() - { - return _autoAck; - } - - public void setAutoAck(boolean autoAck) - { - _autoAck = autoAck; - } - - public boolean isExclusive() - { - return _exclusive; - } - - public void setExclusive(boolean exclusive) - { - _exclusive = exclusive; - } - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void setProtocolSession(AMQProtocolSession protocolSession) - { - _protocolSession = protocolSession; - } - - public void deliverMessage() throws AMQException - { - - } -} -- cgit v1.2.1 From 194a33e5c59f50df05a7f3f04b4bc395295450d7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 26 Jan 2009 16:53:12 +0000 Subject: QPID-1533 : Patch from Robert Gemmell, Fixes the reload tab in UserManagement to actually reload the PrincipalDatabase file from disk. Not just the jmxaccess rights file. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@737746 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/management/AMQUserManagementMBean.java | 16 ++++++---------- .../database/Base64MD5PasswordFilePrincipalDatabase.java | 5 +++++ .../database/PlainPasswordFilePrincipalDatabase.java | 5 +++++ .../server/security/auth/database/PrincipalDatabase.java | 5 +++++ .../auth/database/PropertiesPrincipalDatabase.java | 5 +++++ 5 files changed, 26 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 7ff3bd3541..f04aecd0a5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -226,27 +226,23 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public boolean reloadData() { - try - { try { loadAccessFile(); + _principalDatabase.reload(); } catch (ConfigurationException e) { _logger.info("Reload failed due to:" + e); return false; } - + catch (IOException e) + { + _logger.info("Reload failed due to:" + e); + return false; + } // Reload successful return true; - } - catch (IOException e) - { - _logger.info("Reload failed due to:" + e); - // Reload unsuccessful - return false; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index bf459542de..69ad9014db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -492,4 +492,9 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } + public void reload() throws IOException + { + loadPasswordFile(); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 352d41a0ba..9da954d74f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -237,4 +237,9 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } } + + public void reload() throws IOException + { + //This PD is not cached, so do nothing. + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index a82f9ed40b..ef37e043a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -92,6 +92,11 @@ public interface PrincipalDatabase */ Principal getUser(String username); + /** + * Reload the database to its ensure contents are up to date + * @throws IOException If there was an error reloading the database + */ + void reload() throws IOException; public Map getMechanisms(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index c8a4add0f1..ff8851306f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -161,4 +161,9 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase return null; } } + + public void reload() throws IOException + { + //No file to update from, so do nothing. + } } -- cgit v1.2.1 From 29b5d4051bff5f84be912927af3221fce077830e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 26 Jan 2009 17:10:29 +0000 Subject: QPID-1493 : Patch from Robert Gemmell : Corrected inaccurate exception. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@737753 13f79535-47bb-0310-9956-ffa450edef68 --- .../auth/database/ConfigurationFilePrincipalDatabaseManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 15c62a62e4..fc96776a3a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -95,7 +95,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab PrincipalDatabase pd = databases.get(name); if (pd != null) { - throw new Exception("Duplicate principal database name not provided"); + throw new Exception("Duplicate principal database name not permitted"); } _logger.info("Initialised principal database '" + name + "' successfully"); -- cgit v1.2.1 From f635dc00fe03b7930154cc8e8a06dc0aa17039ab Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 4 Feb 2009 15:33:26 +0000 Subject: QPID-1626: Make ACLPlugin a more sensible interface, get rid of the giant switch in SimpleXML. Handlers shouldn't rely on the plugin throwing an exception for flow control, they now check the return value and do the right thing themselves. AllowAll, DenyAll now extend BasicACLPlugin. PrinciplePermissions(Test): futz with the interface a little so that it's easier to call from an ACLPlugin implementation. Leave the giant switch alone as it's quite fragile, and throws rocks at cats. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@740769 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/handler/BasicConsumeMethodHandler.java | 9 +- .../qpid/server/handler/BasicGetMethodHandler.java | 5 +- .../server/handler/BasicPublishMethodHandler.java | 7 +- .../handler/ConnectionOpenMethodHandler.java | 5 +- .../server/handler/ExchangeDeclareHandler.java | 10 +- .../qpid/server/handler/ExchangeDeleteHandler.java | 8 +- .../qpid/server/handler/QueueBindHandler.java | 6 +- .../qpid/server/handler/QueueDeclareHandler.java | 9 +- .../qpid/server/handler/QueueDeleteHandler.java | 5 +- .../qpid/server/handler/QueuePurgeHandler.java | 5 +- .../qpid/server/handler/QueueUnbindHandler.java | 5 +- .../qpid/server/security/access/ACLPlugin.java | 60 ++--- .../qpid/server/security/access/Permission.java | 3 +- .../security/access/PrincipalPermissions.java | 241 +++++++++---------- .../server/security/access/plugins/AllowAll.java | 40 +--- .../security/access/plugins/BasicACLPlugin.java | 123 ++++++++++ .../server/security/access/plugins/DenyAll.java | 30 ++- .../server/security/access/plugins/SimpleXML.java | 255 ++++++++++++++------- 18 files changed, 526 insertions(+), 300 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 5342a7f518..08610f24cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -97,8 +97,13 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { //Perform ACLs - virtualHost.getAccessManager().authorise(session, Permission.BIND, body, exch, queue, routingKey); + if (!virtualHost.getAccessManager().authoriseBind(session, exch, + queue, routingKey)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } if (!exch.isBound(routingKey, body.getArguments(), queue)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 3047643021..71f38cb28a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -78,11 +78,14 @@ public class QueueDeclareHandler implements StateAwareMethodListener 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName; - AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; - AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; - //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName; + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - // Get the queues map - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } - if (create_queues == null) - { - create_queues = new ConcurrentHashMap(); - createRights.put(CREATE_QUEUES_KEY, create_queues); - } + //Allow all temp queues to be created + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); - //Allow all temp queues to be created - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - //Create empty list of queues - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } - if (create_queues_queues == null) + // We are granting CREATE rights to all temporary queues only + if (parameters.length == 1) + { + return; + } + + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) { - create_queues_queues = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); } - // We are granting CREATE rights to all temporary queues only - if (parameters.length == 1) + if (exchangeName != null) { - return; + queue.put(exchangeName, routingKey); } - // if we have a queueName then we need to store any associated exchange / rk bindings - if (queueName != null) - { - Map queue = (Map) create_queues_queues.get(queueName); - if (queue == null) - { - queue = new ConcurrentHashMap(); - create_queues_queues.put(queueName, queue); - } + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } - if (exchangeName != null) - { - queue.put(exchangeName, routingKey); - } + // Store the exchange that we are being granted rights to. This will be used as part of binding - //If no exchange is specified then the presence of the queueName in the map says any exchange is ok - } + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - // Store the exchange that we are being granted rights to. This will be used as part of binding + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } - //Lookup the list of exchanges - Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); - if (create_queues_exchanges == null) + if (exchanges == null) { - create_queues_exchanges = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); } - //if we have an exchange - if (exchangeName != null) + //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY + exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) { - //Retrieve the list of permitted exchanges. - Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); - if (exchanges == null) + if (rKeys == null) { - exchanges = new ConcurrentHashMap(); - create_queues_exchanges.put(exchangeName, exchanges); + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); } - //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY - exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); - - //Store the binding details of queue/rk for this exchange. - if (queueName != null) - { - //Retrieve the list of permitted routingKeys. - Map rKeys = (Map) exchanges.get(exchangeName); - - if (rKeys == null) - { - rKeys = new ConcurrentHashMap(); - exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); - } - - rKeys.put(queueName, routingKey); - } + rKeys.put(queueName, routingKey); } } - else // Create Exchange : AMQShortString exchangeName , AMQShortString Class + break; + case CREATEEXCHANGE: + // Parameters AMQShortString exchangeName , AMQShortString Class + Map rights = (Map) _permissions.get(permission); + if (rights == null) { - Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY); + rights = new ConcurrentHashMap(); + _permissions.put(permission, rights); + } - if (create_exchanges == null) - { - create_exchanges = new ConcurrentHashMap(); - createRights.put(CREATE_EXCHANGES_KEY, create_exchanges); - } + Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); + if (create_exchanges == null) + { + create_exchanges = new ConcurrentHashMap(); + rights.put(CREATE_EXCHANGES_KEY, create_exchanges); + } - //Should perhaps error if parameters[0] is null; - AMQShortString exchangeName = parameters.length > 0 ? (AMQShortString) parameters[0] : null; - AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + //Should perhaps error if parameters[0] is null; + AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; + AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); - //Store the exchangeName / class mapping if the mapping is null - createRights.put(exchangeName, className); - } + //Store the exchangeName / class mapping if the mapping is null + rights.put(name, className); break; case DELETE: break; @@ -330,7 +329,8 @@ public class PrincipalPermissions * ACCESS: none * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey * CONSUME: AMQQueue queue - * CREATE: QueueDeclareBody obj || ExchangeDeclareBody obj + * CREATEQUEUE: Boolean autodelete, AMQShortString name + * CREATEEXCHANGE: AMQShortString exchangeName * DELETE: none * PUBLISH: Exchange exchange, AMQShortString routingKey * PURGE: none @@ -352,7 +352,7 @@ public class PrincipalPermissions AMQShortString routingKey = (AMQShortString) parameters[3]; //Get all Create Rights for this user - Map bindCreateRights = (Map) _permissions.get(Permission.CREATE); + Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); //Look up the Queue Creation Rights Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); @@ -435,7 +435,7 @@ public class PrincipalPermissions return true; } - case CREATE:// Paramters : QueueDeclareBody || ExchangeDeclareBody + case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name Map createRights = (Map) _permissions.get(permission); @@ -445,46 +445,33 @@ public class PrincipalPermissions return false; } - if (parameters.length == 1) - { - if (parameters[0] instanceof QueueDeclareBody) - { - QueueDeclareBody body = (QueueDeclareBody) parameters[0]; - - //Look up the Queue Creation Rights - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues allowed to be created - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - - AMQShortString queueName = body.getQueue(); + //Look up the Queue Creation Rights + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + //Lookup the list of queues allowed to be created + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - if (body.getAutoDelete())// we have a temporary queue - { - return (Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY); - } - else - { - // If there is a white list then check - return create_queues_queues == null || create_queues_queues.containsKey(queueName); - } - } - else if (parameters[0] instanceof ExchangeDeclareBody) - { - ExchangeDeclareBody body = (ExchangeDeclareBody) parameters[0]; + AMQShortString queueName = (AMQShortString) parameters[1]; + Boolean autoDelete = (Boolean) parameters[0]; - AMQShortString exchangeName = body.getExchange(); + if (autoDelete)// we have a temporary queue + { + return (Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY); + } + else + { + // If there is a white list then check + return create_queues_queues == null || create_queues_queues.containsKey(queueName); + } + case CREATEEXCHANGE: + Map rights = (Map) _permissions.get(permission); - Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY); + AMQShortString exchangeName = (AMQShortString) parameters[0]; - // If the exchange list is doesn't exist then all is allowed else check the valid exchanges - return create_exchanges == null || create_exchanges.containsKey(exchangeName); - } - } - break; + // If the exchange list is doesn't exist then all is allowed else + // check the valid exchanges + return rights == null || rights.containsKey(exchangeName); case CONSUME: // Parameters : AMQQueue if (parameters.length == 1 && parameters[0] instanceof AMQQueue) @@ -557,7 +544,7 @@ public class PrincipalPermissions // Otherwise exchange must be listed in the white list // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(parameters[0])) + if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) { return false; } @@ -565,7 +552,7 @@ public class PrincipalPermissions { // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(parameters[0]); + HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); // Having no routingKeys in the map then all are allowed. if (routingKeys == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 9b784069dd..f78c9a2e16 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -20,40 +20,10 @@ */ package org.apache.qpid.server.security.access.plugins; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.access.Permission; import org.apache.commons.configuration.Configuration; -public class AllowAll implements ACLPlugin +public class AllowAll extends BasicACLPlugin { - public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) - { - if (ACLManager.getLogger().isDebugEnabled()) - { - ACLManager.getLogger().debug("Allowing user:" + session.getAuthorizedID() + " for :" + permission.toString() - + " on " + body.getClass().getSimpleName() - + (parameters == null || parameters.length == 0 ? "" : "-" + accessablesToString(parameters))); - } - - return new AccessResult(this, AccessResult.AccessStatus.GRANTED); - } - - public static String accessablesToString(Object[] accessObject) - { - StringBuilder sb = new StringBuilder(); - - for (Object access : accessObject) - { - sb.append(access.getClass().getSimpleName() + ":" + access.toString() + ", "); - } - - return sb.delete(sb.length() - 2, sb.length()).toString(); - } public String getPluginName() { @@ -62,7 +32,13 @@ public class AllowAll implements ACLPlugin public void setConfiguaration(Configuration config) { - //no-op + // no-op } + @Override + protected boolean getResult() + { + // Always allow + return true; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java new file mode 100644 index 0000000000..26d3162f3a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public abstract class BasicACLPlugin implements ACLPlugin +{ + + // Returns true or false if the plugin should authorise or deny the request + protected abstract boolean getResult(); + + @Override + public boolean authoriseBind(AMQProtocolSession session, Exchange exch, + AMQQueue queue, AMQShortString routingKey) + { + return getResult(); + } + + @Override + public boolean authoriseConnect(AMQProtocolSession session, + VirtualHost virtualHost) + { + return getResult(); + } + + @Override + public boolean authoriseConsume(AMQProtocolSession session, boolean noAck, + AMQQueue queue) + { + return getResult(); + } + + @Override + public boolean authoriseConsume(AMQProtocolSession session, + boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, + AMQQueue queue) + { + return getResult(); + } + + @Override + public boolean authoriseCreateExchange(AMQProtocolSession session, + boolean autoDelete, boolean durable, AMQShortString exchangeName, + boolean internal, boolean nowait, boolean passive, + AMQShortString exchangeType) + { + return getResult(); + } + + @Override + public boolean authoriseCreateQueue(AMQProtocolSession session, + boolean autoDelete, boolean durable, boolean exclusive, + boolean nowait, boolean passive, AMQShortString queue) + { + return getResult(); + } + + @Override + public boolean authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + return getResult(); + } + + @Override + public boolean authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + return getResult(); + } + + @Override + public boolean authorisePublish(AMQProtocolSession session, + boolean immediate, boolean mandatory, AMQShortString routingKey, + Exchange e) + { + return getResult(); + } + + @Override + public boolean authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + return getResult(); + } + + @Override + public boolean authoriseUnbind(AMQProtocolSession session, Exchange exch, + AMQShortString routingKey, AMQQueue queue) + { + return getResult(); + } + + @Override + public void setConfiguaration(Configuration config) + { + // no-op + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 80c125e737..1645236382 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -20,29 +20,29 @@ */ package org.apache.qpid.server.security.access.plugins; +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.AMQConnectionException; -import org.apache.commons.configuration.Configuration; -public class DenyAll implements ACLPlugin +public class DenyAll extends BasicACLPlugin { - public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException + public AccessResult authorise(AMQProtocolSession session, + Permission permission, AMQMethodBody body, Object... parameters) + throws AMQConnectionException { if (ACLManager.getLogger().isInfoEnabled()) { + ACLManager.getLogger().info( + "Denying user:" + session.getAuthorizedID()); } - ACLManager.getLogger().info("Denying user:" + session.getAuthorizedID() + " for :" + permission.toString() - + " on " + body.getClass().getSimpleName() - + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters))); - - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "DenyAll Plugin"); + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "DenyAll Plugin"); } public String getPluginName() @@ -52,6 +52,14 @@ public class DenyAll implements ACLPlugin public void setConfiguaration(Configuration config) { - //no-op + // no-op } + + @Override + protected boolean getResult() + { + // Always deny + return false; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 251f4e6330..4fe1f8e777 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -32,11 +32,13 @@ import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.security.access.PrincipalPermissions; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -69,16 +71,16 @@ public class SimpleXML implements ACLPlugin } /** - * Publish format takes - * Exchange + Routing Key Pairs - * - * @param config XML Configuration + * Publish format takes Exchange + Routing Key Pairs + * + * @param config + * XML Configuration */ private void processPublish(Configuration config) { Configuration publishConfig = config.subset("security.access_control_list.publish"); - //Process users that have full publish permission + // Process users that have full publish permission String[] users = publishConfig.getStringArray("users.user"); for (String user : users) @@ -92,33 +94,33 @@ public class SimpleXML implements ACLPlugin while (!exchangeConfig.isEmpty()) { - //Get Exchange Name + // Get Exchange Name AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); - //Get Routing Keys + // Get Routing Keys int keyCount = 0; Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); while (!routingkeyConfig.isEmpty()) { - //Get RoutingKey Value + // Get RoutingKey Value AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); - //Apply Exchange + RoutingKey permissions to Users + // Apply Exchange + RoutingKey permissions to Users users = routingkeyConfig.getStringArray("users.user"); for (String user : users) { grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); } - //Apply permissions to Groups + // Apply permissions to Groups // Check for more configs keyCount++; routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); } - //Apply Exchange wide permissions to Users + // Apply Exchange wide permissions to Users users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); for (String user : users) @@ -126,7 +128,7 @@ public class SimpleXML implements ACLPlugin grant(Permission.PUBLISH, user, exchangeName); } - //Apply permissions to Groups + // Apply permissions to Groups exchangeCount++; exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); } @@ -155,20 +157,20 @@ public class SimpleXML implements ACLPlugin while (!queueConfig.isEmpty()) { - //Get queue Name + // Get queue Name AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); // if there is no name then there may be a temporary element boolean temporary = queueConfig.containsKey("temporary"); boolean ownQueues = queueConfig.containsKey("own_queues"); - //Process permissions for this queue + // Process permissions for this queue String[] users = queueConfig.getStringArray("users.user"); for (String user : users) { grant(Permission.CONSUME, user, queueName, temporary, ownQueues); } - //See if we have another config + // See if we have another config queueCount++; queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); } @@ -192,7 +194,7 @@ public class SimpleXML implements ACLPlugin while (!queueConfig.isEmpty()) { - //Get queue Name + // Get queue Name AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); // if there is no name then there may be a temporary element @@ -207,17 +209,16 @@ public class SimpleXML implements ACLPlugin AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); - //Process permissions for this queue + // Process permissions for this queue String[] users = exchangeConfig.getStringArray("users.user"); for (String user : users) { - grant(Permission.CREATE, user, temporary, - (queueName.equals("") ? null : queueName), - (exchange.equals("") ? null : exchange), - (routingKey.equals("") ? null : routingKey)); + grant(Permission.CREATEEXCHANGE, user, exchange); + grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange + .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); } - //See if we have another config + // See if we have another config exchangeCount++; exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); } @@ -227,10 +228,10 @@ public class SimpleXML implements ACLPlugin for (String user : users) { - grant(Permission.CREATE, user, temporary, queueName); + grant(Permission.CREATEQUEUE, user, temporary, queueName); } - //See if we have another config + // See if we have another config queueCount++; queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); } @@ -244,14 +245,14 @@ public class SimpleXML implements ACLPlugin AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); - //Process permissions for this queue + // Process permissions for this queue String[] users = exchangeConfig.getStringArray("users.user"); for (String user : users) { - grant(Permission.CREATE, user, exchange, clazz); + grant(Permission.CREATEEXCHANGE, user, exchange, clazz); } - //See if we have another config + // See if we have another config exchangeCount++; exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); } @@ -261,10 +262,10 @@ public class SimpleXML implements ACLPlugin for (String user : users) { - grant(Permission.CREATE, user); + grant(Permission.CREATEEXCHANGE, user); + grant(Permission.CREATEQUEUE, user); } - } public String getPluginName() @@ -272,71 +273,153 @@ public class SimpleXML implements ACLPlugin return "Simple"; } - public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException + @Override + public boolean authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { - String error = ""; - - if (ACLManager.getLogger().isInfoEnabled()) + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else { - ACLManager.getLogger().info("Simple Authorisation processing user:" + session.getAuthorizedID() + " for :" + permission.toString() - + " on " + body.getClass().getSimpleName() - + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters))); + return principalPermissions.authorise(Permission.BIND, null, exch, queue, routingKey); } + } - String username = session.getAuthorizedID().getName(); + @Override + public boolean authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.ACCESS); + } + } - //Get the Users Permissions - PrincipalPermissions permissions = _users.get(username); + @Override + public boolean authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.CONSUME, queue); + } + } - if (permissions != null) + @Override + public boolean authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + boolean nowait, AMQQueue queue) + { + return authoriseConsume(session, noAck, queue); + } + + @Override + public boolean authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) { - switch (permission) - { - case ACCESS: - return GRANTED; - case BIND: // Body QueueDeclareBody - Parameters : Exchange, Queue, QueueName - // Body QueueBindBody - Paramters : Exchange, Queue, QueueName - if (parameters.length == 3) - { - // Parameters : Exchange, Queue, RoutingKey - if (permissions.authorise(Permission.BIND, body, parameters[0], parameters[1], parameters[2])) - { - return GRANTED; - } - } - break; - case CONSUME: // Parameters : none - if (parameters.length == 1 && permissions.authorise(Permission.CONSUME, parameters[0])) - { - return GRANTED; - } - break; - case CREATE: // Body : QueueDeclareBody | ExchangeDeclareBody - Parameters : none - if (permissions.authorise(Permission.CREATE, body)) - { - return GRANTED; - } - break; - case PUBLISH: // Body : BasicPublishBody Parameters : exchange - if (parameters.length == 1 && parameters[0] instanceof Exchange) - { - if (permissions.authorise(Permission.PUBLISH, ((Exchange) parameters[0]).getName(), - ((BasicPublishBody) body).getRoutingKey())) - { - return GRANTED; - } - } - break; - case PURGE: - break; - case DELETE: - break; - case UNBIND: - break; - } + return false; + } + else + { + return principalPermissions.authorise(Permission.CREATEEXCHANGE, exchangeName); + } + } + + @Override + public boolean authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + boolean nowait, boolean passive, AMQShortString queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; } + else + { + return principalPermissions.authorise(Permission.CREATEQUEUE, autoDelete, queue); + } + } - //todo potential refactor this ConnectionException Out of here - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, error); + @Override + public boolean authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.DELETE); + } + } + + @Override + public boolean authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.DELETE); + } + } + + @Override + public boolean authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AMQShortString routingKey, Exchange e) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.PUBLISH, e, routingKey); + } + } + + @Override + public boolean authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.PURGE); + } + } + + @Override + public boolean authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return false; + } + else + { + return principalPermissions.authorise(Permission.UNBIND); + } } } -- cgit v1.2.1 From 5e264eb11619b5088776a36546acd06415299314 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Feb 2009 17:07:46 +0000 Subject: QPID-1628 : Moved Redelivered from AMQMessage to QueueEntry Added PropertyExpressionTest to test Redelivered Property git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@741634 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 25 ++++---- .../qpid/server/ExtractResendAndRequeue.java | 25 ++++---- .../qpid/server/filter/PropertyExpression.java | 17 +++--- .../qpid/server/handler/BasicGetMethodHandler.java | 2 +- .../server/output/ProtocolOutputConverter.java | 5 +- .../amqp0_8/ProtocolOutputConverterImpl.java | 24 +++++--- .../amqp0_9/ProtocolOutputConverterImpl.java | 69 +++++++++++----------- .../org/apache/qpid/server/queue/AMQMessage.java | 12 +--- .../apache/qpid/server/queue/AMQMessageHandle.java | 4 -- .../apache/qpid/server/queue/AMQQueueMBean.java | 6 +- .../qpid/server/queue/InMemoryMessageHandle.java | 11 ---- .../qpid/server/queue/MessageHandleFactory.java | 3 + .../org/apache/qpid/server/queue/QueueEntry.java | 5 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 23 +++++++- .../qpid/server/subscription/SubscriptionImpl.java | 2 +- .../qpid/tools/messagestore/commands/Show.java | 2 +- 16 files changed, 120 insertions(+), 115 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 26ac562fb2..5fde08cbdd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -491,7 +491,7 @@ public class AMQChannel if (!unacked.isQueueDeleted()) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(true); // Ensure message is released for redelivery unacked.release(); @@ -522,7 +522,7 @@ public class AMQChannel if (unacked != null) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(true); // Ensure message is released for redelivery if (!unacked.isQueueDeleted()) @@ -611,13 +611,10 @@ public class AMQChannel for (Map.Entry entry : msgToResend.entrySet()) { - QueueEntry message = entry.getValue(); + QueueEntry queueEntry = entry.getValue(); long deliveryTag = entry.getKey(); - - - AMQMessage msg = message.getMessage(); - AMQQueue queue = message.getQueue(); + AMQQueue queue = queueEntry.getQueue(); // Our Java Client will always suspend the channel when resending! // If the client has requested the messages be resent then it is @@ -635,16 +632,16 @@ public class AMQChannel // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. - msg.setRedelivered(true); + queueEntry.setRedelivered(true); - Subscription sub = message.getDeliveredSubscription(); + Subscription sub = queueEntry.getDeliveredSubscription(); if (sub != null) { - if(!queue.resend(message, sub)) + if(!queue.resend(queueEntry, sub)) { - msgToRequeue.put(deliveryTag, message); + msgToRequeue.put(deliveryTag, queueEntry); } } else @@ -652,11 +649,11 @@ public class AMQChannel if (_log.isInfoEnabled()) { - _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + _log.info("DeliveredSubscription not recorded so just requeueing(" + queueEntry.toString() + ")to prevent loss"); } // move this message to requeue - msgToRequeue.put(deliveryTag, message); + msgToRequeue.put(deliveryTag, queueEntry); } } // for all messages // } else !isSuspend @@ -888,7 +885,7 @@ public class AMQChannel public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException { - getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag()); + getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), deliveryTag, sub.getConsumerTag()); } }; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 29494c4118..097ac27399 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -54,22 +54,21 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor _storeContext = storeContext; } - public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException + public boolean callback(final long deliveryTag, QueueEntry queueEntry) throws AMQException { - - AMQMessage msg = message.getMessage(); - msg.setRedelivered(true); - final Subscription subscription = message.getDeliveredSubscription(); + + queueEntry.setRedelivered(true); + final Subscription subscription = queueEntry.getDeliveredSubscription(); if (subscription != null) { // Consumer exists if (!subscription.isClosed()) { - _msgToResend.put(deliveryTag, message); + _msgToResend.put(deliveryTag, queueEntry); } else // consumer has gone { - _msgToRequeue.put(deliveryTag, message); + _msgToRequeue.put(deliveryTag, queueEntry); } } else @@ -77,22 +76,22 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor // Message has no consumer tag, so was "delivered" to a GET // or consumer no longer registered // cannot resend, so re-queue. - if (!message.isQueueDeleted()) + if (!queueEntry.isQueueDeleted()) { if (_requeueIfUnabletoResend) { - _msgToRequeue.put(deliveryTag, message); + _msgToRequeue.put(deliveryTag, queueEntry); } else { - message.discard(_storeContext); - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + queueEntry.discard(_storeContext); + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + queueEntry); } } else { - message.discard(_storeContext); - _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + queueEntry.discard(_storeContext); + _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + queueEntry); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index b30c70dac3..fa276169bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -71,13 +71,7 @@ public class PropertyExpression implements Expression JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() - { - public Object evaluate(Filterable message) throws E - { - return message.isRedelivered(); - } - }); + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new RedeliveredExpression()); } private final String name; @@ -265,4 +259,13 @@ public class PropertyExpression implements Expression } } + + private static class RedeliveredExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + return message.isRedelivered(); + } + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 001b7858ec..0f492a21bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -130,7 +130,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener +public class AMQMessage { /** Used for debugging purposes. */ private static final Logger _log = Logger.getLogger(AMQMessage.class); @@ -396,16 +396,6 @@ public class AMQMessage implements Filterable return _messageHandle.getMessagePublishInfo(getStoreContext()); } - public boolean isRedelivered() - { - return _messageHandle.isRedelivered(); - } - - public void setRedelivered(boolean redelivered) - { - _messageHandle.setRedelivered(redelivered); - } - public long getArrivalTime() { return _messageHandle.getArrivalTime(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java index 0ddd4e4d92..93ac21fc7c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -63,10 +63,6 @@ public interface AMQMessageHandle MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; - boolean isRedelivered(); - - void setRedelivered(boolean redelivered); - boolean isPersistent(); void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 2ed6be77c6..6f478dffd7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -397,11 +397,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que // Create the tabular list of message header contents for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) { - AMQMessage msg = list.get(i - 1).getMessage(); + QueueEntry queueEntry = list.get(i - 1); + AMQMessage msg = queueEntry.getMessage(); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, + queueEntry.isRedelivered() }; CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); _messageList.put(messageData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 35ad5be4e0..2a7c90a81e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -109,17 +109,6 @@ public class InMemoryMessageHandle implements AMQMessageHandle return _messagePublishInfo; } - public boolean isRedelivered() - { - return _redelivered; - } - - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - public boolean isPersistent() { return false; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java index 0b214ca336..7573a629c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -42,5 +42,8 @@ public class MessageHandleFactory { return new InMemoryMessageHandle(messageId); } + +// return new AMQMessage(messageId, store, persistent); } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 2657c459a9..0df976a620 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -24,11 +24,8 @@ import org.apache.qpid.server.subscription.Subscription; * under the License. * */ -public interface QueueEntry extends Comparable +public interface QueueEntry extends Comparable, Filterable { - - - public static enum State { AVAILABLE, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index dbad5438dc..fe9686e906 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.log4j.Logger; @@ -44,6 +45,7 @@ public class QueueEntryImpl implements QueueEntry private AMQMessage _message; + private boolean _redelivered; private Set _rejectedBy = null; @@ -186,9 +188,26 @@ public class QueueEntryImpl implements QueueEntry return _message.immediateAndNotDelivered(); } - public void setRedelivered(boolean b) + public ContentHeaderBody getContentHeaderBody() throws AMQException { - getMessage().setRedelivered(b); + return _message.getContentHeaderBody(); + } + + public boolean isPersistent() throws AMQException + { + return _message.isPersistent(); + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + // todo - here we could mark this message as redelivered so we don't have to mark + // all messages on recover as redelivered. } public Subscription getDeliveredSubscription() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index a616c2ea35..be11eb7b84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -434,7 +434,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private boolean checkFilters(QueueEntry msg) { - return (_filters == null) || _filters.allAllow(msg.getMessage()); + return (_filters == null) || _filters.allAllow(msg); } public boolean isAutoClose() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index 2fa017fc64..b5a91c8da6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -358,7 +358,7 @@ public class Show extends AbstractCommand ispersitent.add("n/a"); } - isredelivered.add(msg.isRedelivered() ? "true" : "false"); + isredelivered.add(entry.isRedelivered() ? "true" : "false"); isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); -- cgit v1.2.1 From 3714d8c6b136ec4c91935683ae719a4ccfd8e075 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 9 Feb 2009 13:46:00 +0000 Subject: QPID-1652 : Created MessagePublishInfoImpl and Unit Test, removed the several annoynmous classes that did all the same work. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@742496 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 30 ++-------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 743a736884..f23983641b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -29,6 +29,7 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.AMQException; @@ -1148,34 +1149,7 @@ public class DerbyMessageStore implements MessageStore final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); final boolean mandatory = (rs.getShort(3) != (short)0); final boolean immediate = (rs.getShort(4) != (short)0); - MessagePublishInfo info = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return exchange; - } - - public void setExchange(AMQShortString exchange) - { - - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return mandatory; - } - - public AMQShortString getRoutingKey() - { - return routingKey; - } - } ; + MessagePublishInfo info = new MessagePublishInfoImpl(exchange,immediate,mandatory,routingKey); Blob dataAsBlob = rs.getBlob(5); -- cgit v1.2.1 From d7ba7d6fdf756080b2862a48a892526ef40e163f Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 9 Feb 2009 17:03:57 +0000 Subject: QPID-1626: Add per-virtualhost authorization plugins. PluginManager: add support for getting ACLPluginFactories from OSGi and the ones we already know about. *ApplicationRegistry*: return an ACLManager, not an ACLPlugin from getAccessManager. ACLManager: use PluginManager to get all the available plugins. When being asked to authorize a particular request, hold a vote amongst all the plugins as to whether to allow or deny access. ACLPlugin: return a ALLOWED/DENIED/ABSTAIN vote result. Fix typo in method name. ACLPluginFactory: Factory class for ACLPlugins. AccessResult: just use class SimpleName instead of getPluginName PrincipalPermissions: return AuthzResult instead of boolean. Might want to maek use of Abstain for things it doesn't actually acare about instead of defaulting to Allowed. AllowAll, DenyAll, BasicACLPlugin, SimpleXML: add Factory, return AuthzResult instead of boolean. VirtualHost: get a new ACLManager and configure it with the virtualhost security section. Ensure that old config files which have the access_control_list outside of the main security.access section continue to work. MockPluginManager: add mock class for tests PluginTest: not having any plugins now returns an empty set, not null MockAMQQueue: support name attribute ACLManagerTest: tests for ACLManager class ExchangeDenier, QueueDenier: new test classes for ACLManagerTest PrincipalPermissionsTest: check for correct return result, not true/false anymore Move plugin configuration to section, not git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@742626 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 47 ++- .../qpid/server/registry/ApplicationRegistry.java | 6 +- .../ConfigurationFileApplicationRegistry.java | 6 +- .../qpid/server/registry/IApplicationRegistry.java | 3 +- .../qpid/server/security/access/ACLManager.java | 322 +++++++++++++++------ .../qpid/server/security/access/ACLPlugin.java | 31 +- .../server/security/access/ACLPluginFactory.java | 32 ++ .../qpid/server/security/access/AccessResult.java | 6 +- .../security/access/AuthorizationManager.java | 6 + .../security/access/PrincipalPermissions.java | 62 ++-- .../server/security/access/plugins/AllowAll.java | 24 +- .../security/access/plugins/BasicACLPlugin.java | 32 +- .../server/security/access/plugins/DenyAll.java | 26 +- .../server/security/access/plugins/SimpleXML.java | 79 ++--- .../qpid/server/util/NullApplicationRegistry.java | 13 +- .../qpid/server/virtualhost/VirtualHost.java | 32 +- 16 files changed, 501 insertions(+), 226 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 9191ecf6ed..1b7919e8b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -30,6 +30,11 @@ import org.apache.felix.framework.cache.BundleCache; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.access.plugins.DenyAll; +import org.apache.qpid.server.security.access.plugins.SimpleXML; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.util.tracker.ServiceTracker; @@ -46,8 +51,10 @@ public class PluginManager private Felix _felix = null; private ServiceTracker _exchangeTracker = null; + private ServiceTracker _securityTracker = null; private Activator _activator = null; private boolean _empty; + private Map _securityPlugins; public PluginManager(String plugindir) throws Exception { @@ -115,8 +122,13 @@ public class PluginManager try { _felix.start(); + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); _exchangeTracker.open(); + + _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); + _exchangeTracker.open(); + } catch (BundleException e) { @@ -124,22 +136,37 @@ public class PluginManager } } - public Map> getExchanges() - { - if (_empty) - { - return null; - } - Map>exchanges = new HashMap>(); - for (Object service : _exchangeTracker.getServices()) + private Map getServices(ServiceTracker tracker) + { + Mapexchanges = new HashMap(); + + if (tracker != null) { - if (service instanceof ExchangeType) + for (Object service : tracker.getServices()) { - exchanges.put(service.getClass().getName(), (ExchangeType) service); + exchanges.put(service.getClass().getName(), (type) service); } } return exchanges; } + + public Map> getExchanges() + { + return getServices(_exchangeTracker); + } + + public Map getSecurityPlugins() + { + if (_securityPlugins == null) + { + _securityPlugins = getServices(_securityTracker); + // A little gross that we have to add them here, but not all the plugins are OSGIfied + _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); + _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); + _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); + } + return _securityPlugins; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index c9c3acf61b..02124a3737 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -67,7 +67,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected VirtualHostRegistry _virtualHostRegistry; - protected ACLPlugin _accessManager; + protected ACLManager _accessManager; protected PrincipalDatabaseManager _databaseManager; @@ -285,9 +285,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _virtualHostRegistry; } - public ACLPlugin getAccessManager() + public ACLManager getAccessManager() { - return _accessManager; + return new ACLManager(_configuration, _pluginManager); } public ManagedObjectRegistry getManagedObjectRegistry() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index a555b72dcf..c34c4bf80a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -94,8 +94,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _virtualHostRegistry = new VirtualHostRegistry(); - _accessManager = ACLManager.loadACLManager("default", _configuration); + _pluginManager = new PluginManager(_configuration.getString("plugin-directory")); + _accessManager = new ACLManager(_configuration, _pluginManager); + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); @@ -104,8 +106,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _managedObjectRegistry.start(); - _pluginManager = new PluginManager(_configuration.getString("plugin-directory")); - initialiseVirtualHosts(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 597ef042f9..e68dca285c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -28,6 +28,7 @@ import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.mina.common.IoAcceptor; @@ -74,7 +75,7 @@ public interface IApplicationRegistry VirtualHostRegistry getVirtualHostRegistry(); - ACLPlugin getAccessManager(); + ACLManager getAccessManager(); PluginManager getPluginManager(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index 539f32a732..356ee815dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -20,142 +20,300 @@ */ package org.apache.qpid.server.security.access; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.plugins.DenyAll; -import org.apache.qpid.configuration.PropertyUtils; import org.apache.log4j.Logger; - -import java.util.List; -import java.lang.reflect.Method; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.virtualhost.VirtualHost; public class ACLManager { private static final Logger _logger = Logger.getLogger(ACLManager.class); + private PluginManager _pluginManager; + private Map _allSecurityPlugins = new HashMap(); + private Map _globalPlugins = new HashMap(); + private Map _hostPlugins = new HashMap(); - public static ACLPlugin loadACLManager(String name, Configuration hostConfig) throws ConfigurationException + public ACLManager(Configuration configuration, PluginManager manager) { - ACLPlugin aclPlugin = ApplicationRegistry.getInstance().getAccessManager(); + this(configuration, manager, null); + } - if (hostConfig == null) - { - _logger.warn("No Configuration specified. Using default ACLPlugin '" + aclPlugin.getPluginName() - + "' for VirtualHost:'" + name + "'"); - return aclPlugin; - } + public ACLManager(Configuration configuration, PluginManager manager, ACLPluginFactory securityPlugin) + { + _pluginManager = manager; - String accessClass = hostConfig.getString("security.access.class"); - if (accessClass == null) + if (manager == null) // No plugin manager, no plugins { - - _logger.warn("No ACL Plugin specified. Using default ACL Plugin '" + aclPlugin.getPluginName() + - "' for VirtualHost:'" + name + "'"); - return aclPlugin; + return; } - Object o; - try + _allSecurityPlugins = _pluginManager.getSecurityPlugins(); + if (securityPlugin != null) { - o = Class.forName(accessClass).newInstance(); - } - catch (Exception e) - { - throw new ConfigurationException("Error initialising ACL: " + e, e); + _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); } - if (!(o instanceof ACLPlugin)) - { - throw new ConfigurationException("ACL Plugins must implement the ACLPlugin interface"); - } + _globalPlugins = configurePlugins(configuration); + } - initialiseAccessControl((ACLPlugin) o, hostConfig); - aclPlugin = getManager((ACLPlugin) o); - if (_logger.isInfoEnabled()) + public void configureHostPlugins(Configuration hostConfig) + { + _hostPlugins = configurePlugins(hostConfig); + } + + public Map configurePlugins(Configuration configuration) + { + Configuration securityConfig = configuration.subset("security"); + Map plugins = new HashMap(); + Iterator keys = securityConfig.getKeys(); + Collection handledTags = new HashSet(); + while (keys.hasNext()) { - _logger.info("Initialised ACL Plugin '" + aclPlugin.getPluginName() - + "' for virtualhost '" + name + "' successfully"); + // Splitting the string is necessary here because of the way that getKeys() returns only + // bottom level children + String tag = ((String) keys.next()).split("\\.", 2)[0]; + + if (!handledTags.contains(tag)) + { + for (ACLPluginFactory plugin : _allSecurityPlugins.values()) + { + if (plugin.supportsTag(tag)) + { + _logger.warn("Plugin handling security section "+tag+" is "+plugin.getClass().getSimpleName()); + handledTags.add(tag); + plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); + } + } + } + if (!handledTags.contains(tag)) + { + _logger.warn("No plugin handled security section "+tag); + } } + return plugins; + } - return aclPlugin; + public static Logger getLogger() + { + return _logger; } - - private static void initialiseAccessControl(ACLPlugin accessManager, Configuration config) - throws ConfigurationException + private abstract class AccessCheck { - //First provide the ACLPlugin with the host configuration + abstract AuthzResult allowed(ACLPlugin plugin); + } - accessManager.setConfiguaration(config); + private boolean checkAllPlugins(AccessCheck checker) + { + AuthzResult result = AuthzResult.ABSTAIN; + HashMap remainingPlugins = new HashMap(); + remainingPlugins.putAll(_globalPlugins); + for (Entry plugin : _hostPlugins.entrySet()) + { + result = checker.allowed(plugin.getValue()); + if (result == AuthzResult.DENIED) + { + // Something vetoed the access, we're done + return false; + } + else if (result == AuthzResult.ALLOWED) + { + // Remove plugin from global check list since + // host allow overrides global allow + remainingPlugins.remove(plugin.getKey()); + } + } + + for (ACLPlugin plugin : remainingPlugins.values()) + { + result = checker.allowed(plugin); + if (result == AuthzResult.DENIED) + { + return false; + } + } + return true; + } - //Provide additional attribute customisation. - String baseName = "security.access.attributes.attribute."; - List argumentNames = config.getList(baseName + "name"); - List argumentValues = config.getList(baseName + "value"); - for (int i = 0; i < argumentNames.size(); i++) + public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue, + final AMQShortString routingKey) + { + return checkAllPlugins(new AccessCheck() { - String argName = argumentNames.get(i); - if (argName == null || argName.length() == 0) + + @Override + AuthzResult allowed(ACLPlugin plugin) { - throw new ConfigurationException("Access Control argument names must have length >= 1 character"); + return plugin.authoriseBind(session, exch, queue, routingKey); } - if (Character.isLowerCase(argName.charAt(0))) + + }); + } + + public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); + return plugin.authoriseConnect(session, virtualHost); } - String methodName = "set" + argName; - Method method = null; - try + + }); + } + + public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - method = accessManager.getClass().getMethod(methodName, String.class); + return plugin.authoriseConsume(session, noAck, queue); } - catch (NoSuchMethodException e) + + }); + } + + public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck, + final boolean noLocal, final boolean nowait, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - //do nothing as method will be null + return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue); } - if (method == null) + }); + } + + public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete, + final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, + final boolean passive, final AMQShortString exchangeType) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() + - " hence unable to configure access control. The method must be public and " + - "have a single String argument with a void return type"); + return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait, + passive, exchangeType); } - try + + }); + } + + public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete, + final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, + final AMQShortString queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i))); + return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue); } - catch (Exception e) + + }); + } + + public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause()); - ce.initCause(e); - throw ce; + return plugin.authoriseDelete(session, queue); } - } + + }); } + public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseDelete(session, exchange); + } - private static ACLPlugin getManager(ACLPlugin manager) + }); + } + + public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory, + final AMQShortString routingKey, final Exchange e) { - if (manager == null) + return checkAllPlugins(new AccessCheck() { - if (ApplicationRegistry.getInstance().getAccessManager() == null) + + @Override + AuthzResult allowed(ACLPlugin plugin) { - return new DenyAll(); + return plugin.authorisePublish(session, immediate, mandatory, routingKey, e); } - else + + }); + } + + public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) { - return ApplicationRegistry.getInstance().getAccessManager(); + return plugin.authorisePurge(session, queue); } - } - else + + }); + } + + public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch, + final AMQShortString routingKey, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() { - return manager; - } + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseUnbind(session, exch, routingKey, queue); + } + + }); } - public static Logger getLogger() + public void addHostPlugin(ACLPlugin aclPlugin) { - return _logger; + _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java index 164fbad911..ca760f3360 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -29,36 +29,41 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public interface ACLPlugin { - String getPluginName(); + public enum AuthzResult + { + ALLOWED, + DENIED, + ABSTAIN + } - void setConfiguaration(Configuration config); + void setConfiguration(Configuration config); // These return true if the plugin thinks the action should be allowed, and false if not. - boolean authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); - boolean authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - boolean authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue); - boolean authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); + AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); - boolean authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); + AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); - boolean authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue); - boolean authoriseDelete(AMQProtocolSession session, AMQQueue queue); + AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue); - boolean authoriseDelete(AMQProtocolSession session, Exchange exchange); + AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange); - boolean authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e); - boolean authorisePurge(AMQProtocolSession session, AMQQueue queue); + AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue); - boolean authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); + AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java new file mode 100644 index 0000000000..aee6af93d0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java @@ -0,0 +1,32 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.commons.configuration.Configuration; + +public interface ACLPluginFactory +{ + + public boolean supportsTag(String name); + + public ACLPlugin newInstance(Configuration config); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java index 86f155d862..d722da4ae0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -33,12 +33,12 @@ public class AccessResult public AccessResult(ACLPlugin authorizer, AccessStatus status) { _status = status; - _authorizer = authorizer.getPluginName(); + _authorizer = authorizer.getClass().getSimpleName(); } public void setAuthorizer(ACLPlugin authorizer) { - _authorizer += authorizer.getPluginName(); + _authorizer += authorizer.getClass().getSimpleName(); } public String getAuthorizer() @@ -58,7 +58,7 @@ public class AccessResult public void addAuthorizer(ACLPlugin accessManager) { - _authorizer = accessManager.getPluginName() + "->" + _authorizer; + _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java new file mode 100644 index 0000000000..9527120f30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java @@ -0,0 +1,6 @@ +package org.apache.qpid.server.security.access; + +public class AuthorizationManager +{ + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 00c63ede7c..35b76bcf32 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.QueueBindBody; import org.apache.qpid.framing.QueueDeclareBody; import org.apache.qpid.framing.ExchangeDeclareBody; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; import org.apache.qpid.server.exchange.Exchange; import java.util.*; @@ -336,13 +337,13 @@ public class PrincipalPermissions * PURGE: none * UNBIND: none */ - public boolean authorise(Permission permission, Object... parameters) + public AuthzResult authorise(Permission permission, Object... parameters) { switch (permission) { case ACCESS: - return true; // This is here for completeness but the SimpleXML ACLManager never calls it. + return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it. // The existence of this user specific PP can be validated in the map SimpleXML maintains. case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey @@ -368,7 +369,7 @@ public class PrincipalPermissions if (exchangeDetails == null) //Then all queue can be bound to all exchanges. { - return true; + return AuthzResult.ALLOWED; } // Check to see if we have a white list of routingkeys to check @@ -378,7 +379,7 @@ public class PrincipalPermissions if (rkeys == null) { // There is no routingkey white list - return true; + return AuthzResult.ALLOWED; } else { @@ -400,7 +401,7 @@ public class PrincipalPermissions } - return matched; + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } @@ -425,14 +426,14 @@ public class PrincipalPermissions // Check to see if the requested exchange is allowed. Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); - return (Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY); + return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } //no white list so all allowed, drop through to return true below. } // not a temporary queue and no white list so all allowed. - return true; + return AuthzResult.ALLOWED; } case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name @@ -442,7 +443,7 @@ public class PrincipalPermissions // If there are no create rights then deny request if (createRights == null) { - return false; + return AuthzResult.DENIED; } //Look up the Queue Creation Rights @@ -457,12 +458,20 @@ public class PrincipalPermissions if (autoDelete)// we have a temporary queue { - return (Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY); + return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } else { // If there is a white list then check - return create_queues_queues == null || create_queues_queues.containsKey(queueName); + if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } + } case CREATEEXCHANGE: Map rights = (Map) _permissions.get(permission); @@ -471,7 +480,14 @@ public class PrincipalPermissions // If the exchange list is doesn't exist then all is allowed else // check the valid exchanges - return rights == null || rights.containsKey(exchangeName); + if (rights == null || rights.containsKey(exchangeName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } case CONSUME: // Parameters : AMQQueue if (parameters.length == 1 && parameters[0] instanceof AMQQueue) @@ -492,11 +508,11 @@ public class PrincipalPermissions // Of course the exclusivity will not be broken. { // if not limited to ownQueuesOnly then ok else check queue Owner. - return !ownQueuesOnly || queue.getOwner().equals(_user); + return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } else { - return false; + return AuthzResult.DENIED; } } @@ -508,21 +524,21 @@ public class PrincipalPermissions { if (queue.getOwner().equals(_user)) { - return queues.size() == 0 || queues.contains(queue.getName()); + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } else { - return false; + return AuthzResult.DENIED; } } // If we are - return queues.size() == 0 || queues.contains(queue.getName()); + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } // Can't authenticate without the right parameters - return false; + return AuthzResult.DENIED; case DELETE: break; @@ -531,7 +547,7 @@ public class PrincipalPermissions if (publishRights == null) { - return false; + return AuthzResult.DENIED; } Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); @@ -539,14 +555,14 @@ public class PrincipalPermissions // Having no exchanges listed gives full publish rights to all exchanges if (exchanges == null) { - return true; + return AuthzResult.ALLOWED; } // Otherwise exchange must be listed in the white list // If the map doesn't have the exchange then it isn't allowed if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) { - return false; + return AuthzResult.DENIED; } else { @@ -557,7 +573,7 @@ public class PrincipalPermissions // Having no routingKeys in the map then all are allowed. if (routingKeys == null) { - return true; + return AuthzResult.ALLOWED; } else { @@ -581,7 +597,7 @@ public class PrincipalPermissions matched = publishRKey.equals(rkey); } } - return matched; + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } case PURGE: @@ -591,6 +607,6 @@ public class PrincipalPermissions } - return false; + return AuthzResult.DENIED; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index f78c9a2e16..4af178574b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -21,24 +21,34 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; public class AllowAll extends BasicACLPlugin { - public String getPluginName() + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() { - return "AllowAll"; - } + public boolean supportsTag(String name) + { + return false; + } - public void setConfiguaration(Configuration config) + public ACLPlugin newInstance(Configuration config) + { + return new AllowAll(); + } + }; + + public String getPluginName() { - // no-op + return this.getClass().getSimpleName(); } @Override - protected boolean getResult() + protected AuthzResult getResult() { // Always allow - return true; + return AuthzResult.ALLOWED; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java index 26d3162f3a..f7e537b02b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -33,31 +33,31 @@ public abstract class BasicACLPlugin implements ACLPlugin { // Returns true or false if the plugin should authorise or deny the request - protected abstract boolean getResult(); + protected abstract AuthzResult getResult(); @Override - public boolean authoriseBind(AMQProtocolSession session, Exchange exch, + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return getResult(); } @Override - public boolean authoriseConnect(AMQProtocolSession session, + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) { return getResult(); } @Override - public boolean authoriseConsume(AMQProtocolSession session, boolean noAck, + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) { return getResult(); } @Override - public boolean authoriseConsume(AMQProtocolSession session, + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { @@ -65,7 +65,7 @@ public abstract class BasicACLPlugin implements ACLPlugin } @Override - public boolean authoriseCreateExchange(AMQProtocolSession session, + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) @@ -74,7 +74,7 @@ public abstract class BasicACLPlugin implements ACLPlugin } @Override - public boolean authoriseCreateQueue(AMQProtocolSession session, + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { @@ -82,19 +82,19 @@ public abstract class BasicACLPlugin implements ACLPlugin } @Override - public boolean authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) { return getResult(); } @Override - public boolean authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) { return getResult(); } @Override - public boolean authorisePublish(AMQProtocolSession session, + public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { @@ -102,22 +102,28 @@ public abstract class BasicACLPlugin implements ACLPlugin } @Override - public boolean authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) { return getResult(); } @Override - public boolean authoriseUnbind(AMQProtocolSession session, Exchange exch, + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return getResult(); } @Override - public void setConfiguaration(Configuration config) + public void setConfiguration(Configuration config) { // no-op } + public boolean supportsTag(String name) + { + // This plugin doesn't support any tags + return false; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 1645236382..26a76c9af1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -26,11 +26,26 @@ import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; public class DenyAll extends BasicACLPlugin { + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return false; + } + + public ACLPlugin newInstance(Configuration config) + { + return new DenyAll(); + } + }; + public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException @@ -47,19 +62,14 @@ public class DenyAll extends BasicACLPlugin public String getPluginName() { - return "DenyAll"; - } - - public void setConfiguaration(Configuration config) - { - // no-op + return getClass().getSimpleName(); } @Override - protected boolean getResult() + protected AuthzResult getResult() { // Always deny - return false; + return AuthzResult.DENIED; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 4fe1f8e777..2cc0c530de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -35,9 +35,11 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.security.access.PrincipalPermissions; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; @@ -48,6 +50,21 @@ import java.util.concurrent.ConcurrentHashMap; */ public class SimpleXML implements ACLPlugin { + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return name.startsWith("access_control_list"); + } + + public ACLPlugin newInstance(Configuration config) + { + SimpleXML plugin = new SimpleXML(); + plugin.setConfiguration(config); + return plugin; + } + }; + private Map _users; private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); @@ -56,7 +73,7 @@ public class SimpleXML implements ACLPlugin _users = new ConcurrentHashMap(); } - public void setConfiguaration(Configuration config) + public void setConfiguration(Configuration config) { processConfig(config); } @@ -78,7 +95,7 @@ public class SimpleXML implements ACLPlugin */ private void processPublish(Configuration config) { - Configuration publishConfig = config.subset("security.access_control_list.publish"); + Configuration publishConfig = config.subset("access_control_list.publish"); // Process users that have full publish permission String[] users = publishConfig.getStringArray("users.user"); @@ -149,7 +166,7 @@ public class SimpleXML implements ACLPlugin private void processConsume(Configuration config) { - Configuration consumeConfig = config.subset("security.access_control_list.consume"); + Configuration consumeConfig = config.subset("access_control_list.consume"); // Process queue limited users int queueCount = 0; @@ -186,7 +203,7 @@ public class SimpleXML implements ACLPlugin private void processCreate(Configuration config) { - Configuration createConfig = config.subset("security.access_control_list.create"); + Configuration createConfig = config.subset("access_control_list.create"); // Process create permissions for queue creation int queueCount = 0; @@ -273,13 +290,12 @@ public class SimpleXML implements ACLPlugin return "Simple"; } - @Override - public boolean authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -287,13 +303,12 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -301,13 +316,12 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -315,21 +329,19 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return authoriseConsume(session, noAck, queue); } - @Override - public boolean authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -337,14 +349,13 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -352,13 +363,12 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -366,13 +376,12 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -380,14 +389,13 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -395,13 +403,12 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { @@ -409,17 +416,17 @@ public class SimpleXML implements ACLPlugin } } - @Override - public boolean authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); if (principalPermissions == null) { - return false; + return AuthzResult.DENIED; } else { return principalPermissions.authorise(Permission.UNBIND); } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index ee5f9d5e88..83b18e7a47 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -27,16 +27,13 @@ import java.util.Properties; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.MapConfiguration; -import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; -import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -59,13 +56,13 @@ public class NullApplicationRegistry extends ApplicationRegistry _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); - _accessManager = new AllowAll(); + _accessManager = new ACLManager(_configuration, _pluginManager, AllowAll.FACTORY); _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); _managedObjectRegistry = new NoopManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - VirtualHost dummyHost = new VirtualHost("test", getConfiguration()); + VirtualHost dummyHost = new VirtualHost("test", _configuration); _virtualHostRegistry.registerVirtualHost(dummyHost); _virtualHostRegistry.setDefaultVirtualHostName("test"); _pluginManager = new PluginManager(""); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9229863c35..1a0d0ce8de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,35 +20,35 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Timer; +import java.util.TimerTask; + import javax.management.NotCompliantMBeanException; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.exchange.DefaultExchangeFactory; import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.AMQException; - -import java.util.Timer; -import java.util.TimerTask; public class VirtualHost implements Accessable { @@ -73,7 +73,7 @@ public class VirtualHost implements Accessable private AuthenticationManager _authenticationManager; - private ACLPlugin _accessManager; + private ACLManager _accessManager; private final Timer _houseKeepingTimer; @@ -183,8 +183,9 @@ public class VirtualHost implements Accessable _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); - _accessManager = ACLManager.loadACLManager(name, hostConfig); - + _accessManager = ApplicationRegistry.getInstance().getAccessManager(); + _accessManager.configureHostPlugins(hostConfig); + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); initialiseHouseKeeping(hostConfig); @@ -258,7 +259,6 @@ public class VirtualHost implements Accessable return instance; } - public String getName() { return _name; @@ -294,7 +294,7 @@ public class VirtualHost implements Accessable return _authenticationManager; } - public ACLPlugin getAccessManager() + public ACLManager getAccessManager() { return _accessManager; } -- cgit v1.2.1 From 63048485534658385fc2be777713d96e5ed472fa Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 11 Feb 2009 11:18:58 +0000 Subject: Merge branch 'QPID-1583' Conflicts: qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@743304 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/plugins/AbstractACLPlugin.java | 99 ++++++++++++++ .../access/plugins/network/FirewallFactory.java | 44 +++++++ .../access/plugins/network/FirewallPlugin.java | 146 +++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java new file mode 100644 index 0000000000..682135bc25 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java @@ -0,0 +1,99 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. + */ +public abstract class AbstractACLPlugin implements ACLPlugin +{ + + private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; + + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, + AMQShortString routingKey) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + boolean nowait, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) + { + // TODO Auto-generated method stub + return null; + } + + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, + boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AMQShortString routingKey, Exchange e) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, + AMQQueue queue) + { + return DEFAULT_ANSWER; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java new file mode 100644 index 0000000000..7fcf4a0494 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins.network; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; + +public class FirewallFactory implements ACLPluginFactory +{ + + @Override + public ACLPlugin newInstance(Configuration config) + { + FirewallPlugin plugin = new FirewallPlugin(); + plugin.setConfiguration(config); + return plugin; + } + + @Override + public boolean supportsTag(String name) + { + return name.equals("firewall"); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java new file mode 100644 index 0000000000..c0089d5e12 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -0,0 +1,146 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins.network; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.regex.Pattern; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.util.NetMatcher; + +import sun.net.util.IPAddressUtil; + +public class FirewallPlugin extends AbstractACLPlugin +{ + + public class FirewallRule + { + + private AuthzResult _access; + private NetMatcher _network; + private Pattern _hostnamePattern; + + public FirewallRule(String access, String network, String hostname) + { + _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + _network = (network != null) ? new NetMatcher(new String[]{network}) : null; + _hostnamePattern = (hostname != null) ? Pattern.compile(hostname) : null; + } + + public boolean match(InetAddress remote) + { + if (_hostnamePattern != null) + { + return _hostnamePattern.matcher(remote.getCanonicalHostName()).matches(); + } + else + { + return _network.matchInetNetwork(remote); + } + } + + public AuthzResult getAccess() + { + return _access; + } + + } + + private AuthzResult _default = AuthzResult.ABSTAIN; + private FirewallRule[] _rules; + + @Override + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + if (!(session instanceof AMQMinaProtocolSession)) + { + return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which mean MINA right now + } + + InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session); + + if (addr == null) + { + return AuthzResult.ABSTAIN; // Not an Inet socket on the other end + } + + boolean match = false; + for (FirewallRule rule : _rules) + { + match = rule.match(addr); + if (match) + { + return rule.getAccess(); + } + } + return _default; + + } + + private InetAddress getInetAdressFromMinaSession(AMQMinaProtocolSession session) + { + SocketAddress remote = session.getIOSession().getRemoteAddress(); + if (remote instanceof InetSocketAddress) + { + return ((InetSocketAddress) remote).getAddress(); + } + else + { + return null; + } + } + + @Override + public void setConfiguration(Configuration config) + { + // Get default action + String defaultAction = config.getString("[@default-action]"); + if (defaultAction == null) { + _default = AuthzResult.ABSTAIN; + } + else if (defaultAction.toLowerCase().equals("allow")) + { + _default = AuthzResult.ALLOWED; + } + else + { + _default = AuthzResult.DENIED; + } + + int numRules = config.getList("rule[@access]").size(); // all rules must + // have an access + // attribute + _rules = new FirewallRule[numRules]; + for (int i = 0; i < numRules; i++) + { + FirewallRule rule = new FirewallRule((String) config.getProperty("rule(" + i + ")[@access]"), + (String) config.getProperty("rule(" + i + ")[@network]"), (String) config.getProperty("rule(" + i + + ")[@hostname]")); + _rules[i] = rule; + } + } +} -- cgit v1.2.1 From a03d0ca88d863c1df1dc274ae98785a9d325e038 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 11 Feb 2009 12:38:31 +0000 Subject: QPDI-1583: Implement support for comma-seperated lists of networks and hostnames. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@743311 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/plugins/network/FirewallPlugin.java | 76 ++++++++++++++++------ 1 file changed, 55 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index c0089d5e12..cb8b6f6fed 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.security.access.plugins.network; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.List; import java.util.regex.Pattern; import org.apache.commons.configuration.Configuration; @@ -32,8 +33,6 @@ import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.util.NetMatcher; -import sun.net.util.IPAddressUtil; - public class FirewallPlugin extends AbstractACLPlugin { @@ -42,20 +41,54 @@ public class FirewallPlugin extends AbstractACLPlugin private AuthzResult _access; private NetMatcher _network; - private Pattern _hostnamePattern; + private Pattern[] _hostnamePatterns; - public FirewallRule(String access, String network, String hostname) + public FirewallRule(String access, List networks, List hostnames) { _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - _network = (network != null) ? new NetMatcher(new String[]{network}) : null; - _hostnamePattern = (hostname != null) ? Pattern.compile(hostname) : null; + + if (networks != null && networks.size() > 0) + { + String[] networkStrings = objListToStringArray(networks); + _network = new NetMatcher(networkStrings); + } + + if (hostnames != null && hostnames.size() > 0) + { + int i = 0; + _hostnamePatterns = new Pattern[hostnames.size()]; + for (String hostname : objListToStringArray(hostnames)) + { + _hostnamePatterns[i++] = Pattern.compile(hostname); + } + } + + } + + private String[] objListToStringArray(List objList) + { + String[] networkStrings = new String[objList.size()]; + int i = 0; + for (Object network : objList) + { + networkStrings[i++] = (String) network; + } + return networkStrings; } public boolean match(InetAddress remote) { - if (_hostnamePattern != null) + if (_hostnamePatterns != null) { - return _hostnamePattern.matcher(remote.getCanonicalHostName()).matches(); + String hostname = remote.getCanonicalHostName(); + for (Pattern pattern : _hostnamePatterns) + { + if (pattern.matcher(hostname).matches()) + { + return true; + } + } + return false; } else { @@ -78,16 +111,17 @@ public class FirewallPlugin extends AbstractACLPlugin { if (!(session instanceof AMQMinaProtocolSession)) { - return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which mean MINA right now + return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which + // mean MINA right now } InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session); - + if (addr == null) { return AuthzResult.ABSTAIN; // Not an Inet socket on the other end } - + boolean match = false; for (FirewallRule rule : _rules) { @@ -107,7 +141,7 @@ public class FirewallPlugin extends AbstractACLPlugin if (remote instanceof InetSocketAddress) { return ((InetSocketAddress) remote).getAddress(); - } + } else { return null; @@ -119,27 +153,27 @@ public class FirewallPlugin extends AbstractACLPlugin { // Get default action String defaultAction = config.getString("[@default-action]"); - if (defaultAction == null) { + if (defaultAction == null) + { _default = AuthzResult.ABSTAIN; - } + } else if (defaultAction.toLowerCase().equals("allow")) { _default = AuthzResult.ALLOWED; } - else + else { _default = AuthzResult.DENIED; } - + int numRules = config.getList("rule[@access]").size(); // all rules must - // have an access - // attribute + // have an access + // attribute _rules = new FirewallRule[numRules]; for (int i = 0; i < numRules; i++) { - FirewallRule rule = new FirewallRule((String) config.getProperty("rule(" + i + ")[@access]"), - (String) config.getProperty("rule(" + i + ")[@network]"), (String) config.getProperty("rule(" + i - + ")[@hostname]")); + FirewallRule rule = new FirewallRule(config.getString("rule(" + i + ")[@access]"), config.getList("rule(" + + i + ")[@network]"), config.getList("rule(" + i + ")[@hostname]")); _rules[i] = rule; } } -- cgit v1.2.1 From 45096aedbcef046740a7eb8e139f3a287c0e8e8b Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 11 Feb 2009 15:17:19 +0000 Subject: QPID-430: Fix message age alerting so that it works on queues which are otherwise inactive. AMQQueue, VirtualHost, MockAMQQueue: change name of removeExpiredIfNoSubscribers to checkMessageStatus. AMQQueueMBean: remove unthrown exception SimpleAMQQueue: add notification checks to checkMessageStatus, remove catch for JMException which checkForNotification no longer throws. NullApplicationRegistry: set small housekeeping check period so that it runs freuqently and tests don't need to sleep for excessive periods of time AMQQueueAlertTest: remove subsequent send, notification alerts shouldn't depend on queue activity. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@743357 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/AMQQueue.java | 8 +++++--- .../org/apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 21 ++++++++------------- .../qpid/server/util/NullApplicationRegistry.java | 3 ++- .../apache/qpid/server/virtualhost/VirtualHost.java | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 03ccbe7ce4..f6d406b653 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -149,9 +149,11 @@ public interface AMQQueue extends Managable, Comparable long clearQueue(StoreContext storeContext) throws AMQException; - - - void removeExpiredIfNoSubscribers() throws AMQException; + /** + * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. + * @throws AMQException + */ + void checkMessageStatus() throws AMQException; Set getNotificationChecks(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 6f478dffd7..f5853bd303 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -246,7 +246,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que /** * Checks if there is any notification to be send to the listeners */ - public void checkForNotification(AMQMessage msg) throws AMQException, JMException + public void checkForNotification(AMQMessage msg) throws AMQException { final Set notificationChecks = _queue.getNotificationChecks(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 7e7e8b2114..547df7856d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -423,17 +423,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliverAsync(); } - try - { - _managedObject.checkForNotification(entry.getMessage()); - } - catch (JMException e) - { - throw new AMQException("Unable to get notification from manage queue: " + e, e); - } - + _managedObject.checkForNotification(entry.getMessage()); + return entry; - } private void deliverToSubscription(final Subscription sub, final QueueEntry entry) @@ -1431,7 +1423,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public void removeExpiredIfNoSubscribers() throws AMQException + @Override + public void checkMessageStatus() throws AMQException { final StoreContext storeContext = new StoreContext(); @@ -1443,10 +1436,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.expired() && node.acquire()) { - node.discard(storeContext); + } + else + { + _managedObject.checkForNotification(node.getMessage()); } - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 83b18e7a47..88ad87b9c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -49,7 +49,8 @@ public class NullApplicationRegistry extends ApplicationRegistry _logger.info("Initialising NullApplicationRegistry"); _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); - + _configuration.addProperty("housekeeping.expiredMessageCheckPeriod", "200"); + Properties users = new Properties(); users.put("guest", "guest"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 1a0d0ce8de..de4c8ac1ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -208,7 +208,7 @@ public class VirtualHost implements Accessable try { - q.removeExpiredIfNoSubscribers(); + q.checkMessageStatus(); } catch (AMQException e) { -- cgit v1.2.1 From 64d9444c6da714ed7831fa122dfdaaa2ddda3b4a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Feb 2009 11:19:38 +0000 Subject: QPID-1629 : Fully test MessageHandles before move git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744074 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/InMemoryMessageHandle.java | 7 ++++++- .../apache/qpid/server/queue/WeakReferenceMessageHandle.java | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java index 2a7c90a81e..1092f67d94 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -75,7 +75,12 @@ public class InMemoryMessageHandle implements AMQMessageHandle public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException { - if (index > _contentBodies.size() - 1) + if(_contentBodies == null) + { + throw new RuntimeException("No ContentBody has been set"); + } + + if (index > _contentBodies.size() - 1 || index < 0) { throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + (_contentBodies.size() - 1)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java index 3ed8b0e55c..804d2c2131 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -109,7 +109,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException { - if (index > _contentBodies.size() - 1) + if(_contentBodies == null) + { + throw new RuntimeException("No ContentBody has been set"); + } + + if (index > _contentBodies.size() - 1 || index < 0) { throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + (_contentBodies.size() - 1)); @@ -197,8 +202,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle final long arrivalTime = System.currentTimeMillis(); - - MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); + MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies == null ? 0 : _contentBodies.size(), arrivalTime); _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); -- cgit v1.2.1 From 90588ea3686949802323f938934fba05e7b97d1c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Feb 2009 11:22:14 +0000 Subject: QPID-1628 : Further tiding up of imports no longer requried. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744076 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java | 2 -- .../java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java | 4 ---- .../java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java | 1 - .../src/main/java/org/apache/qpid/server/exchange/MessageRouter.java | 1 - .../main/java/org/apache/qpid/server/exchange/NoRouteException.java | 1 - .../main/java/org/apache/qpid/server/filter/BooleanExpression.java | 2 -- .../main/java/org/apache/qpid/server/filter/ComparisonExpression.java | 2 -- .../main/java/org/apache/qpid/server/filter/ConstantExpression.java | 2 -- .../src/main/java/org/apache/qpid/server/filter/Expression.java | 2 -- .../src/main/java/org/apache/qpid/server/filter/FilterManager.java | 2 -- .../src/main/java/org/apache/qpid/server/filter/LogicExpression.java | 2 -- .../src/main/java/org/apache/qpid/server/filter/MessageFilter.java | 2 -- .../main/java/org/apache/qpid/server/filter/SimpleFilterManager.java | 1 - .../src/main/java/org/apache/qpid/server/filter/XPathExpression.java | 1 - .../src/main/java/org/apache/qpid/server/filter/XQueryExpression.java | 1 - .../main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java | 1 - .../main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java | 3 --- .../org/apache/qpid/server/flow/MessageAndBytesCreditManager.java | 2 -- .../broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java | 3 --- .../main/java/org/apache/qpid/server/txn/NonTransactionalContext.java | 1 - 20 files changed, 36 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 097ac27399..1723d46ef0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -21,9 +21,7 @@ package org.apache.qpid.server; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index c567387662..efdadd4922 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -24,14 +24,10 @@ import org.apache.qpid.server.store.StoreContext; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.txn.TransactionalContext; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 0ab8208d88..f28ba0d0de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -24,7 +24,6 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java index db9beb6da7..f0c2d3903e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.IncomingMessage; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java index d18ad7ab14..d44afa8494 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -23,7 +23,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.IncomingMessage; /** * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index 9beb9798d0..dd3e17a870 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -20,8 +20,6 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 921005c462..65d9a8c221 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -27,8 +27,6 @@ import java.util.HashSet; import java.util.List; import java.util.regex.Pattern; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 3ed2286f2e..c58adaf35f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -25,8 +25,6 @@ package org.apache.qpid.server.filter; import java.math.BigDecimal; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index f2ebe41d26..fd41f5bacc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -20,8 +20,6 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java index dd3c126ee5..c37578f8e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -23,9 +23,7 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; -import org.apache.qpid.AMQException; public interface FilterManager { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index 094363ed9a..e376dcd409 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -20,8 +20,6 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index 58fc55f8e6..38e3424be5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.filter; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; public interface MessageFilter diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index cb738e1489..864a87a14f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; public class SimpleFilterManager implements FilterManager diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index 1311178fb1..24ddd1c678 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import java.lang.reflect.Constructor; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index c13f81cd08..ff6360e752 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -18,7 +18,6 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; // diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index cc67776682..9db3f17fdb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -28,7 +28,6 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import org.apache.xpath.CachedXPathAPI; import org.w3c.dom.Document; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java index 96a1071135..0743e4bb8d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -3,9 +3,6 @@ package org.apache.qpid.server.flow; import org.apache.qpid.server.queue.AMQMessage; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Set; -import java.util.HashSet; /* * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java index 9c377481de..5f0acec03f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -2,8 +2,6 @@ package org.apache.qpid.server.flow; import org.apache.qpid.server.queue.AMQMessage; -import java.util.concurrent.atomic.AtomicLong; - /* * * Licensed to the Apache Software Foundation (ASF) under one diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index f6d406b653..2d4a9c4b40 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,14 +20,11 @@ */ package org.apache.qpid.server.queue; -import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 28af36e3db..acb2e93818 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.txn; -import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; -- cgit v1.2.1 From bc5378a4b3220ec8c1e700c5fe705d983b4b0c7b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Feb 2009 11:24:44 +0000 Subject: QPID-1629 : Convered AMQMessage to Interface and created concrete Transient/PersistentAMQMessage implementations Removed the use of WeakReferences from PersistentAMQMessage and therefore the need to have a StoreContext on get requests. NOTE: this checking will break persistent recovery. Coverted all uses of *MessageHandle to AMQMessage. A number of tests (SimpleAMQQueueTest, TxAckTest.TestMessage, AbstractHeaderExchangeTestBase.Message) still use a custom constructor on Transient/PersistentAMQMessage. This is because they have their own Message implemntations that are used for testing. However, I'm sure they could be modified to override the required functionality rather than attempt to use the existing Factory and Wrap the resulting Message. A new JIRA to address this QPID-1659. QPID-1628 : The update to MessageFactory removes the commented out code git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744079 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 6 +- .../amqp0_8/ProtocolOutputConverterImpl.java | 39 +- .../amqp0_9/ProtocolOutputConverterImpl.java | 36 +- .../org/apache/qpid/server/queue/AMQMessage.java | 436 +++---------------- .../apache/qpid/server/queue/AMQQueueMBean.java | 62 +-- .../qpid/server/queue/InMemoryMessageHandle.java | 151 ------- .../apache/qpid/server/queue/IncomingMessage.java | 42 +- .../apache/qpid/server/queue/MessageFactory.java | 41 ++ .../qpid/server/queue/MessageHandleFactory.java | 49 --- .../qpid/server/queue/NotificationCheck.java | 17 +- .../qpid/server/queue/PersistentAMQMessage.java | 84 ++++ .../qpid/server/queue/PriorityQueueList.java | 21 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 2 +- .../qpid/server/queue/TransientAMQMessage.java | 469 +++++++++++++++++++++ .../server/queue/WeakReferenceMessageHandle.java | 223 ---------- .../qpid/server/store/DerbyMessageStore.java | 16 +- .../qpid/tools/messagestore/commands/Show.java | 32 +- 17 files changed, 731 insertions(+), 995 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 5fde08cbdd..3b290b3d51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -35,12 +35,12 @@ import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.queue.MessageFactory; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.UnauthorizedAccessException; +import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; @@ -108,7 +108,7 @@ public class AMQChannel private final List _returnMessages = new LinkedList(); - private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + private MessageFactory _messageHandleFactory = new MessageFactory(); // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index 4949e5b41d..ea94f23ff9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -28,7 +28,6 @@ package org.apache.qpid.server.output.amqp0_8; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -37,8 +36,6 @@ import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.AMQException; -import org.apache.mina.common.ByteBuffer; - import java.util.Iterator; public class ProtocolOutputConverterImpl implements ProtocolOutputConverter @@ -79,11 +76,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, message.getContentHeaderBody()); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - - - final int bodyCount = messageHandle.getBodyCount(storeContext); + final int bodyCount = message.getBodyCount(); if(bodyCount == 0) { @@ -100,7 +93,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + ContentChunk cb = message.getContentChunk(0); AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; @@ -112,7 +105,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // for(int i = 1; i < bodyCount; i++) { - cb = messageHandle.getContentChunk(storeContext, i); + cb = message.getContentChunk(i); writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -126,8 +119,6 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter public void writeGetOk(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) throws AMQException { final AMQMessage message = queueEntry.getMessage(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); AMQDataBlock deliver = createEncodedGetOkFrame(queueEntry, channelId, deliveryTag, queueSize); @@ -135,7 +126,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, message.getContentHeaderBody()); - final int bodyCount = messageHandle.getBodyCount(storeContext); + final int bodyCount = message.getBodyCount(); if(bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, @@ -150,7 +141,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + ContentChunk cb = message.getContentChunk(0); AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; @@ -162,7 +153,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // for(int i = 1; i < bodyCount; i++) { - cb = messageHandle.getContentChunk(storeContext, i); + cb = message.getContentChunk(i); writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); } @@ -179,7 +170,6 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter final AMQMessage message = queueEntry.getMessage(); final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); BasicDeliverBody deliverBody = @@ -188,18 +178,14 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter queueEntry.isRedelivered(), pb.getExchange(), pb.getRoutingKey()); - AMQFrame deliverFrame = deliverBody.generateFrame(channelId); - - - return deliverFrame; + return deliverBody.generateFrame(channelId); } private AMQDataBlock createEncodedGetOkFrame(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) throws AMQException { final AMQMessage message = queueEntry.getMessage(); - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); BasicGetOkBody getOkBody = @@ -208,9 +194,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter pb.getExchange(), pb.getRoutingKey(), queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; + return getOkBody.generateFrame(channelId); } public byte getProtocolMinorVersion() @@ -231,9 +215,8 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter replyText, message.getMessagePublishInfo().getExchange(), message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; + return basicReturnBody.generateFrame(channelId); + } public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index 00a15d2d50..b71b118275 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -28,9 +28,7 @@ import java.util.Iterator; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.framing.*; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; @@ -77,12 +75,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter AMQBody deliverBody = createEncodedDeliverFrame(queueEntry, channelId, deliveryTag, consumerTag); final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - - - final int bodyCount = messageHandle.getBodyCount(storeContext); + final int bodyCount = message.getBodyCount(); if(bodyCount == 0) { @@ -99,7 +92,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + ContentChunk cb = message.getContentChunk(0); AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); @@ -111,7 +104,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // for(int i = 1; i < bodyCount; i++) { - cb = messageHandle.getContentChunk(storeContext, i); + cb = message.getContentChunk(i); writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); } @@ -123,9 +116,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) { - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - contentHeaderBody); - return contentHeader; + return ContentHeaderBody.createAMQFrame(channelId, contentHeaderBody); } @@ -133,15 +124,13 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter { final AMQMessage message = queueEntry.getMessage(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); AMQFrame deliver = createEncodedGetOkFrame(queueEntry, channelId, deliveryTag, queueSize); AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - final int bodyCount = messageHandle.getBodyCount(storeContext); + final int bodyCount = message.getBodyCount(); if(bodyCount == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, @@ -156,7 +145,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // Optimise the case where we have a single content body. In that case we create a composite block // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + ContentChunk cb = message.getContentChunk(0); AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; @@ -168,7 +157,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter // for(int i = 1; i < bodyCount; i++) { - cb = messageHandle.getContentChunk(storeContext, i); + cb = message.getContentChunk(i); writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); } @@ -190,7 +179,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter final AMQShortString exchangeName = pb.getExchange(); final AMQShortString routingKey = pb.getRoutingKey(); - final AMQBody returnBlock = new AMQBody() + return new AMQBody() { public AMQBody _underlyingBody; @@ -238,7 +227,6 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter throw new AMQException("This block should never be dispatched!"); } }; - return returnBlock; } private AMQFrame createEncodedGetOkFrame(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) @@ -253,9 +241,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter pb.getExchange(), pb.getRoutingKey(), queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - - return getOkFrame; + return getOkBody.generateFrame(channelId); } public byte getProtocolMinorVersion() @@ -276,9 +262,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter replyText, message.getMessagePublishInfo().getExchange(), message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); - - return returnFrame; + return basicReturnBody.generateFrame(channelId); } public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index d73d37f48d..2bd6e612f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -20,363 +20,52 @@ */ package org.apache.qpid.server.queue; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionalContext; - +import org.apache.qpid.AMQException; import java.util.Iterator; -import java.util.concurrent.atomic.AtomicInteger; -/** - * A deliverable message. - */ -public class AMQMessage +public interface AMQMessage { - /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(AMQMessage.class); - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - private final AMQMessageHandle _messageHandle; - - /** Holds the transactional context in which this message is being processed. */ - private StoreContext _storeContext; - - /** Flag to indicate that this message requires 'immediate' delivery. */ - - private static final byte IMMEDIATE = 0x01; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - - private static final byte DELIVERED_TO_CONSUMER = 0x02; - - private byte _flags = 0; - - private long _expiration; - - private final long _size; - - private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; - private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - - - - /** - * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory - * therefore is memory-efficient. - */ - private class BodyFrameIterator implements Iterator - { - private int _channel; - - private int _index = -1; - private AMQProtocolSession _protocolSession; - - private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - _channel = channel; - _protocolSession = protocolSession; - } - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Unable to get body count: " + e, e); - - return false; - } - } - - public AMQDataBlock next() - { - try - { - - AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - ++_index)); - - return new AMQFrame(_channel, cb); - } - catch (AMQException e) - { - // have no choice but to throw a runtime exception - throw new RuntimeException("Error getting content body: " + e, e); - } - - } - - private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() - { - return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public void clearStoreContext() - { - _storeContext = new StoreContext(); - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - private class BodyContentIterator implements Iterator - { - - private int _index = -1; - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Error getting body count: " + e, e); - - return false; - } - } - - public ContentChunk next() - { - try - { - return _messageHandle.getContentChunk(getStoreContext(), ++_index); - } - catch (AMQException e) - { - throw new RuntimeException("Error getting content body: " + e, e); - } - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageId - * @param store - * @param factory - * - * @throws AMQException - */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws AMQException - { - _messageHandle = factory.createMessageHandle(messageId, store, true); - _storeContext = txnConext.getStoreContext(); - _size = _messageHandle.getBodySize(txnConext.getStoreContext()); - } - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageHandle - * - * @throws AMQException - */ - public AMQMessage( - AMQMessageHandle messageHandle, - StoreContext storeConext, - MessagePublishInfo info) - throws AMQException - { - _messageHandle = messageHandle; - _storeContext = storeConext; - - if(info.isImmediate()) - { - _flags |= IMMEDIATE; - } - _size = messageHandle.getBodySize(storeConext); - - } + //Get Content relating to this message + Long getMessageId(); - protected AMQMessage(AMQMessage msg) throws AMQException - { - _messageHandle = msg._messageHandle; - _storeContext = msg._storeContext; - _flags = msg._flags; - _size = msg._size; + Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel); - } + Iterator getContentBodyIterator(); + ContentHeaderBody getContentHeaderBody(); - public String debugIdentity() - { - return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; - } + ContentChunk getContentChunk(int index); - public void setExpiration(final long expiration) - { + Object getPublisherClientInstance(); - _expiration = expiration; + Object getPublisherIdentifier(); - } + MessagePublishInfo getMessagePublishInfo(); - public boolean isReferenced() - { - return _referenceCount.get() > 0; - } + int getBodyCount(); - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); - } + long getSize(); - public Iterator getContentBodyIterator() - { - return new BodyContentIterator(); - } + long getArrivalTime(); - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - return _messageHandle.getContentHeaderBody(getStoreContext()); - } - - public Long getMessageId() - { - return _messageHandle.getMessageId(); - } - - /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic - * operation. - */ - public AMQMessage takeReference() - { - incrementReference(); // _referenceCount.incrementAndGet(); - - return this; - } - - public boolean incrementReference() - { - return incrementReference(1); - } - - /* Threadsafe. Increment the reference count on the message. */ - public boolean incrementReference(int count) - { - if(_referenceCount.addAndGet(count) <= 1) - { - _referenceCount.addAndGet(-count); - return false; - } - else - { - return true; - } - - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @param storeContext - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException - { - - int count = _referenceCount.decrementAndGet(); - - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (count == 0) - { - // set the reference count way below 0 so that we can detect that the message has been deleted - // this is to guard against the message being spontaneously recreated (from the mgmt console) - // by copying from other queues at the same time as it is being removed. - _referenceCount.set(Integer.MIN_VALUE/2); - - try - { - // must check if the handle is null since there may be cases where we decide to throw away a message - // and the handle has not yet been constructed - if (_messageHandle != null) - { - _messageHandle.removeMessage(storeContext); - } - } - catch (AMQException e) - { - // to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException(getMessageId(), e); - } - } - else - { - if (count < 0) - { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() - + " has gone below 0."); - } - } - } - + //Check the status of this message /** * Called selectors to determin if the message has already been sent * * @return _deliveredToConsumer */ - public boolean getDeliveredToConsumer() - { - return (_flags & DELIVERED_TO_CONSUMER) != 0; - } - - public boolean isPersistent() throws AMQException - { - return _messageHandle.isPersistent(); - } + boolean getDeliveredToConsumer(); /** * Called to enforce the 'immediate' flag. @@ -384,89 +73,62 @@ public class AMQMessage * @returns true if the message is marked for immediate delivery but has not been marked as delivered * to a consumer */ - public boolean immediateAndNotDelivered() - { - - return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; - - } - - public MessagePublishInfo getMessagePublishInfo() throws AMQException - { - return _messageHandle.getMessagePublishInfo(getStoreContext()); - } - - public long getArrivalTime() - { - return _messageHandle.getArrivalTime(); - } + boolean immediateAndNotDelivered(); /** * Checks to see if the message has expired. If it has the message is dequeued. * - * @param queue The queue to check the expiration against. (Currently not used) - * * @return true if the message has expire * - * @throws AMQException + * @throws org.apache.qpid.AMQException */ - public boolean expired(AMQQueue queue) throws AMQException - { + boolean expired() throws AMQException; - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } + /** Is this a persistent message + * + * @return true if the message is persistent + */ + boolean isPersistent(); - return false; - } /** * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). * And for selector efficiency. */ - public void setDeliveredToConsumer() - { - _flags |= DELIVERED_TO_CONSUMER; - } + void setDeliveredToConsumer(); + + void setExpiration(long expiration); + + void setClientIdentifier(AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier); + + /** + * This is called when all the content has been received. + * @param storeContext + *@param messagePublishInfo + * @param contentHeaderBody @throws org.apache.qpid.AMQException + */ + void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) + throws AMQException; + void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) + throws AMQException; - public AMQMessageHandle getMessageHandle() - { - return _messageHandle; - } + void removeMessage(StoreContext storeContext) throws AMQException; - public long getSize() - { - return _size; + String toString(); - } + String debugIdentity(); - public Object getPublisherClientInstance() - { - return _sessionIdentifier.getSessionInstance(); - } - - public Object getPublisherIdentifier() - { - return _sessionIdentifier.getSessionIdentifier(); - } + // Reference counting methods - public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) - { - _sessionIdentifier = sessionIdentifier; - } + void decrementReference(StoreContext storeContext) throws MessageCleanupException; + boolean incrementReference(int queueCount); - public String toString() - { - // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - // _taken + " by :" + _takenBySubcription; + boolean incrementReference(); - return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; - } + AMQMessage takeReference(); + boolean isReferenced(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index f5853bd303..a08719875d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -353,29 +353,20 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que } } - try + // Create header attributes list + CommonContentHeaderProperties headerProperties = + (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; + String mimeType = null, encoding = null; + if (headerProperties != null) { - // Create header attributes list - CommonContentHeaderProperties headerProperties = - (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) - { - AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); - encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); - } + AMQShortString mimeTypeShortSting = headerProperties.getContentType(); + mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); + encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); + } - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - catch (AMQException e) - { - JMException jme = new JMException("Error creating header attributes list: " + e); - jme.initCause(e); - throw jme; - } + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); } /** @@ -392,27 +383,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que List list = _queue.getMessagesOnTheQueue(); TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - try + // Create the tabular list of message header contents + for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) { - // Create the tabular list of message header contents - for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) - { - QueueEntry queueEntry = list.get(i - 1); - AMQMessage msg = queueEntry.getMessage(); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, - queueEntry.isRedelivered() }; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); - _messageList.put(messageData); - } - } - catch (AMQException e) - { - JMException jme = new JMException("Error creating message contents: " + e); - jme.initCause(e); - throw jme; + QueueEntry queueEntry = list.get(i - 1); + AMQMessage msg = queueEntry.getMessage(); + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + String[] headerAttributes = getMessageHeaderProperties(headerBody); + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, + queueEntry.isRedelivered() }; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + _messageList.put(messageData); } return _messageList; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java deleted file mode 100644 index 1092f67d94..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.Collections; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.StoreContext; - -/** - */ -public class InMemoryMessageHandle implements AMQMessageHandle -{ - - private ContentHeaderBody _contentHeaderBody; - - private MessagePublishInfo _messagePublishInfo; - - private List _contentBodies; - - private boolean _redelivered; - - private long _arrivalTime; - - private final Long _messageId; - - public InMemoryMessageHandle(final Long messageId) - { - _messageId = messageId; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - return _contentHeaderBody; - } - - public Long getMessageId() - { - return _messageId; - } - - public int getBodyCount(StoreContext context) - { - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if(_contentBodies == null) - { - throw new RuntimeException("No ContentBody has been set"); - } - - if (index > _contentBodies.size() - 1 || index < 0) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - return _contentBodies.get(index); - } - - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) - throws AMQException - { - if(_contentBodies == null) - { - if(isLastContentBody) - { - _contentBodies = Collections.singletonList(contentBody); - } - else - { - _contentBodies = new ArrayList(); - _contentBodies.add(contentBody); - } - } - else - { - _contentBodies.add(contentBody); - } - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - return _messagePublishInfo; - } - - public boolean isPersistent() - { - return false; - } - - /** - * This is called when all the content has been received. - * @param messagePublishInfo - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _messagePublishInfo = messagePublishInfo; - _contentHeaderBody = contentHeaderBody; - if(contentHeaderBody.bodySize == 0) - { - _contentBodies = Collections.EMPTY_LIST; - } - _arrivalTime = System.currentTimeMillis(); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - // NO OP - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index b994040131..aad99da6c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -35,7 +35,6 @@ import org.apache.qpid.AMQException; import org.apache.log4j.Logger; import java.util.ArrayList; -import java.util.Collection; public class IncomingMessage implements Filterable { @@ -48,7 +47,7 @@ public class IncomingMessage implements Filterable private final MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; - private AMQMessageHandle _messageHandle; + private AMQMessage _message; private final Long _messageId; private final TransactionalContext _txnContext; @@ -74,7 +73,6 @@ public class IncomingMessage implements Filterable private Exchange _exchange; - public IncomingMessage(final Long messageId, final MessagePublishInfo info, final TransactionalContext txnContext, @@ -124,11 +122,11 @@ public class IncomingMessage implements Filterable } public void routingComplete(final MessageStore store, - final MessageHandleFactory factory) throws AMQException + final MessageFactory factory) throws AMQException { final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(_messageId, store, persistent); + _message = factory.createMessage(_messageId, store, persistent); if (persistent) { _txnContext.beginTranIfNecessary(); @@ -157,21 +155,16 @@ public class IncomingMessage implements Filterable _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); } - AMQMessage message = null; - try { // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), - _messagePublishInfo, getContentHeaderBody()); + _message.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), _messagePublishInfo, getContentHeaderBody()); + - - - message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); - message.setExpiration(_expiration); - message.setClientIdentifier(_publisher.getSessionIdentifier()); + _message.setExpiration(_expiration); + _message.setClientIdentifier(_publisher.getSessionIdentifier()); // we then allow the transactional context to do something with the message content // now that it has all been received, before we attempt delivery @@ -182,7 +175,7 @@ public class IncomingMessage implements Filterable if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) { - throw new UnauthorizedAccessException("Acccess Refused",message); + throw new UnauthorizedAccessException("Acccess Refused", _message); } if ((_destinationQueues == null) || _destinationQueues.size() == 0) @@ -190,26 +183,26 @@ public class IncomingMessage implements Filterable if (isMandatory() || isImmediate()) { - throw new NoRouteException("No Route for message", message); + throw new NoRouteException("No Route for message", _message); } else { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + message); + _logger.warn("MESSAGE DISCARDED: No routes for message - " + _message); } } else { int offset; final int queueCount = _destinationQueues.size(); - message.incrementReference(queueCount); + _message.incrementReference(queueCount); if(queueCount == 1) { offset = 0; } else { - offset = ((int)(message.getMessageId().longValue())) % queueCount; + offset = ((int)(_message.getMessageId().longValue())) % queueCount; if(offset < 0) { offset = -offset; @@ -218,22 +211,21 @@ public class IncomingMessage implements Filterable for (int i = offset; i < queueCount; i++) { // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); + _txnContext.deliver(_destinationQueues.get(i), _message); } for (int i = 0; i < offset; i++) { // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); + _txnContext.deliver(_destinationQueues.get(i), _message); } } - message.clearStoreContext(); - return message; + return _message; } finally { // Remove refence for routing process . Reference count should now == delivered queue count - if(message != null) message.decrementReference(_txnContext.getStoreContext()); + if(_message != null) _message.decrementReference(_txnContext.getStoreContext()); } } @@ -244,7 +236,7 @@ public class IncomingMessage implements Filterable _bodyLengthReceived += contentChunk.getSize(); - _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); + _message.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java new file mode 100644 index 0000000000..e18834874f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +public class MessageFactory +{ + + public AMQMessage createMessage(Long messageId, MessageStore store, boolean persistent) + { + if (persistent) + { + return new PersistentAMQMessage(messageId, store); + } + else + { + return new TransientAMQMessage(messageId); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java deleted file mode 100644 index 7573a629c1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.store.MessageStore; - -/** - * Constructs a message handle based on the publish body, the content header and the queue to which the message - * has been routed. - * - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class MessageHandleFactory -{ - - public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) - { - // just hardcoded for now - if (persistent) - { - return new WeakReferenceMessageHandle(messageId, store); - } - else - { - return new InMemoryMessageHandle(messageId); - } - -// return new AMQMessage(messageId, store, persistent); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 6f9efd3200..e33b0c83c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -47,20 +47,13 @@ public enum NotificationCheck if(maximumMessageSize != 0) { // Check for threshold message size - long messageSize; - try - { - messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - messageSize = 0; - } - + long messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; if (messageSize >= maximumMessageSize) { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold (" + + maximumMessageSize + ") breached. [Message ID=" + + (msg == null ? "null" : msg.getMessageId()) + "]"); return true; } } @@ -110,7 +103,7 @@ public enum NotificationCheck } } return false; - + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java new file mode 100644 index 0000000000..04e3635f92 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +public class PersistentAMQMessage extends TransientAMQMessage +{ + protected MessageStore _messageStore; + + public PersistentAMQMessage(Long messageId, MessageStore store) + { + super(messageId); + _messageStore = store; + } + + @Override + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) + throws AMQException + { + super.addContentBodyFrame(storeContext, contentChunk, isLastContentBody); + _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, + contentChunk, isLastContentBody); + } + + @Override + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + super.setPublishAndContentHeaderBody(storeContext, messagePublishInfo, contentHeaderBody); + MessageMetaData mmd = new MessageMetaData(messagePublishInfo, contentHeaderBody, _contentBodies == null ? 0 : _contentBodies.size(), _arrivalTime); + + _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); + } + + @Override + public void removeMessage(StoreContext storeContext) throws AMQException + { + _messageStore.removeMessage(storeContext, _messageId); + } + + @Override + public boolean isPersistent() + { + return true; + } + + public void recoverFromMessageMetaData(MessageMetaData mmd) + { + _arrivalTime = mmd.getArrivalTime(); + _contentHeaderBody = mmd.getContentHeaderBody(); + _messagePublishInfo = mmd.getMessagePublishInfo(); + } + + public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException + { + super.addContentBodyFrame(null, contentChunk, isLastContentBody); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java index fd46a8a5ff..7be2827e0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -54,25 +54,16 @@ public class PriorityQueueList implements QueueEntryList public QueueEntry add(AMQMessage message) { - try + int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; + if(index >= _priorities) { - int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if(index >= _priorities) - { - index = _priorities-1; - } - else if(index < 0) - { - index = 0; - } - return _priorityLists[index].add(message); + index = _priorities-1; } - catch (AMQException e) + else if(index < 0) { - // TODO - fix AMQ Exception - throw new RuntimeException(e); + index = 0; } - + return _priorityLists[index].add(message); } public QueueEntry next(QueueEntry node) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index fe9686e906..ba14be5580 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -132,7 +132,7 @@ public class QueueEntryImpl implements QueueEntry public boolean expired() throws AMQException { - return getMessage().expired(getQueue()); + return getMessage().expired(); } public boolean isAcquired() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java new file mode 100644 index 0000000000..8c62e046f8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java @@ -0,0 +1,469 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; + +import java.util.Iterator; +import java.util.List; +import java.util.Collections; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A deliverable message. + */ +public class TransientAMQMessage implements AMQMessage +{ + /** Used for debugging purposes. */ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + private final AtomicInteger _referenceCount = new AtomicInteger(1); + + protected ContentHeaderBody _contentHeaderBody; + + protected MessagePublishInfo _messagePublishInfo; + + protected List _contentBodies; + + protected long _arrivalTime; + + protected final Long _messageId; + + + + /** Flag to indicate that this message requires 'immediate' delivery. */ + + private static final byte IMMEDIATE = 0x01; + + /** + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. + */ + + private static final byte DELIVERED_TO_CONSUMER = 0x02; + + private byte _flags = 0; + + private long _expiration; + + private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; + private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); + + /** + * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory + * therefore is memory-efficient. + */ + private class BodyFrameIterator implements Iterator + { + private int _channel; + + private int _index = -1; + private AMQProtocolSession _protocolSession; + + private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + _channel = channel; + _protocolSession = protocolSession; + } + + public boolean hasNext() + { + return _index < (getBodyCount() - 1); + } + + public AMQDataBlock next() + { + AMQBody cb = + getProtocolVersionMethodConverter().convertToBody(getContentChunk(++_index)); + + return new AMQFrame(_channel, cb); + } + + private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() + { + return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + private class BodyContentIterator implements Iterator + { + + private int _index = -1; + + public boolean hasNext() + { + return _index < (getBodyCount() - 1); + } + + public ContentChunk next() + { + return getContentChunk(++_index); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + /** + * Used by SimpleAMQQueueTest, TxAckTest.TestMessage, AbstractHeaderExchangeTestBase.Message + * These all need refactoring to some sort of MockAMQMessageFactory. + */ + @Deprecated + protected TransientAMQMessage(AMQMessage message) throws AMQException + { + _messageId = message.getMessageId(); + _flags = ((TransientAMQMessage)message)._flags; + _contentHeaderBody = message.getContentHeaderBody(); + _messagePublishInfo = message.getMessagePublishInfo(); + } + + + /** + * Normal message creation via the MessageFactory uses this constructor + * Package scope limited as MessageFactory should be used + * @see MessageFactory + * + * @param messageId + */ + TransientAMQMessage(Long messageId) + { + _messageId = messageId; + } + + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; + } + + public void setExpiration(final long expiration) + { + _expiration = expiration; + } + + public boolean isReferenced() + { + return _referenceCount.get() > 0; + } + + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + return new BodyFrameIterator(protocolSession, channel); + } + + public Iterator getContentBodyIterator() + { + return new BodyContentIterator(); + } + + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public Long getMessageId() + { + return _messageId; + } + + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. + */ + public AMQMessage takeReference() + { + incrementReference(); // _referenceCount.incrementAndGet(); + + return this; + } + + public boolean incrementReference() + { + return incrementReference(1); + } + + /* Threadsafe. Increment the reference count on the message. */ + public boolean incrementReference(int count) + { + if(_referenceCount.addAndGet(count) <= 1) + { + _referenceCount.addAndGet(-count); + return false; + } + else + { + return true; + } + + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * @param storeContext + * + * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + public void decrementReference(StoreContext storeContext) throws MessageCleanupException + { + + int count = _referenceCount.decrementAndGet(); + + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (count == 0) + { + // set the reference count way below 0 so that we can detect that the message has been deleted + // this is to guard against the message being spontaneously recreated (from the mgmt console) + // by copying from other queues at the same time as it is being removed. + _referenceCount.set(Integer.MIN_VALUE/2); + + try + { + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + // no need to perform persistent check anymore as TransientAMQM.removeMessage() is a no-op + removeMessage(storeContext); + } + catch (AMQException e) + { + // to maintain consistency, we revert the count + incrementReference(); + throw new MessageCleanupException(getMessageId(), e); + } + } + else + { + if (count < 0) + { + throw new MessageCleanupException("Reference count for message id " + debugIdentity() + + " has gone below 0."); + } + } + } + + + /** + * Called selectors to determin if the message has already been sent + * + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return (_flags & DELIVERED_TO_CONSUMER) != 0; + } + + /** + * Called to enforce the 'immediate' flag. + * + * @returns true if the message is marked for immediate delivery but has not been marked as delivered + * to a consumer + */ + public boolean immediateAndNotDelivered() + { + + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; + + } + + /** + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @return true if the message has expire + * + * @throws AMQException + */ + public boolean expired() throws AMQException + { + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > _expiration); + } + + return false; + } + + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + */ + public void setDeliveredToConsumer() + { + _flags |= DELIVERED_TO_CONSUMER; + } + + + public long getSize() + { + return _contentHeaderBody.bodySize; + } + + public Object getPublisherClientInstance() + { + return _sessionIdentifier.getSessionInstance(); + } + + public Object getPublisherIdentifier() + { + return _sessionIdentifier.getSessionIdentifier(); + } + + public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) + { + _sessionIdentifier = sessionIdentifier; + } + + /** From AMQMessageHandle **/ + + public int getBodyCount() + { + return _contentBodies.size(); + } + + public ContentChunk getContentChunk(int index) + { + if(_contentBodies == null) + { + throw new RuntimeException("No ContentBody has been set"); + } + + if (index > _contentBodies.size() - 1 || index < 0) + { + throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + + (_contentBodies.size() - 1)); + } + return _contentBodies.get(index); + } + + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) + throws AMQException + { + if(_contentBodies == null) + { + if(isLastContentBody) + { + _contentBodies = Collections.singletonList(contentChunk); + } + else + { + _contentBodies = new ArrayList(); + _contentBodies.add(contentChunk); + } + } + else + { + _contentBodies.add(contentChunk); + } + } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public boolean isPersistent() + { + return false; + } + + /** + * This is called when all the content has been received. + * @param storeContext + *@param messagePublishInfo + * @param contentHeaderBody @throws AMQException + */ + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + + if (contentHeaderBody == null) + { + throw new NullPointerException("HeaderBody cannot be null"); + } + + if( messagePublishInfo == null) + { + throw new NullPointerException("PublishInfo cannot be null"); + } + + _messagePublishInfo = messagePublishInfo; + _contentHeaderBody = contentHeaderBody; + + + if( contentHeaderBody.bodySize == 0) + { + _contentBodies = Collections.EMPTY_LIST; + } + + _arrivalTime = System.currentTimeMillis(); + + if(messagePublishInfo.isImmediate()) + { + _flags |= IMMEDIATE; + } + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void removeMessage(StoreContext storeContext) throws AMQException + { + //no-op + } + + + public String toString() + { + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; + + return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java deleted file mode 100644 index 804d2c2131..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class WeakReferenceMessageHandle implements AMQMessageHandle -{ - private WeakReference _contentHeaderBody; - - private WeakReference _messagePublishInfo; - - private List> _contentBodies; - - private boolean _redelivered; - - private final MessageStore _messageStore; - - private final Long _messageId; - private long _arrivalTime; - - public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore) - { - _messageId = messageId; - _messageStore = messageStore; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); - if (chb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - chb = mmd.getContentHeaderBody(); - } - return chb; - } - - public Long getMessageId() - { - return _messageId; - } - - private MessageMetaData loadMessageMetaData(StoreContext context) - throws AMQException - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - populateFromMessageMetaData(mmd); - return mmd; - } - - private void populateFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); - _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); - } - - public int getBodyCount(StoreContext context) throws AMQException - { - if (_contentBodies == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - int chunkCount = mmd.getContentChunkCount(); - _contentBodies = new ArrayList>(chunkCount); - for (int i = 0; i < chunkCount; i++) - { - _contentBodies.add(new WeakReference(null)); - } - } - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if(_contentBodies == null) - { - throw new RuntimeException("No ContentBody has been set"); - } - - if (index > _contentBodies.size() - 1 || index < 0) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - WeakReference wr = _contentBodies.get(index); - ContentChunk cb = wr.get(); - if (cb == null) - { - cb = _messageStore.getContentBodyChunk(context, _messageId, index); - _contentBodies.set(index, new WeakReference(cb)); - } - return cb; - } - - /** - * Content bodies are set before the publish and header frames - * - * @param storeContext - * @param contentChunk - * @param isLastContentBody - * @throws AMQException - */ - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - if (_contentBodies == null && isLastContentBody) - { - _contentBodies = new ArrayList>(1); - } - else - { - if (_contentBodies == null) - { - _contentBodies = new LinkedList>(); - } - } - _contentBodies.add(new WeakReference(contentChunk)); - _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, - contentChunk, isLastContentBody); - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); - if (bpb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - - bpb = mmd.getMessagePublishInfo(); - } - return bpb; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent() - { - return true; - } - - /** - * This is called when all the content has been received. - * - * @param publishBody - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - // if there are no content bodies the list will be null so we must - // create en empty list here - if (contentHeaderBody.bodySize == 0) - { - _contentBodies = new LinkedList>(); - } - - final long arrivalTime = System.currentTimeMillis(); - - MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies == null ? 0 : _contentBodies.size(), arrivalTime); - - _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); - - - populateFromMessageMetaData(mmd); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - _messageStore.removeMessage(storeContext, _messageId); - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index f23983641b..9de2d09b8e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -27,8 +27,8 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.MessageFactory; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; @@ -93,7 +93,7 @@ public class DerbyMessageStore implements MessageStore private String _connectionURL; - + MessageFactory _messageFactory; private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; @@ -167,6 +167,8 @@ public class DerbyMessageStore implements MessageStore // this recovers durable queues and persistent messages + _messageFactory = new MessageFactory(); + recover(); stateTransition(State.RECOVERING, State.STARTED); @@ -1299,7 +1301,7 @@ public class DerbyMessageStore implements MessageStore private void deliverMessages(final StoreContext context, Map queues) throws SQLException, AMQException { - Map msgMap = new HashMap(); + Map msgMap = new HashMap(); List actions = new ArrayList(); Map queueRecoveries = new TreeMap(); @@ -1318,8 +1320,6 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); } - - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); long maxId = 1; TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); @@ -1355,7 +1355,11 @@ public class DerbyMessageStore implements MessageStore } else { - message = new AMQMessage(messageId, this, messageHandleFactory, txnContext); + message = _messageFactory.createMessage(messageId, this, true); + + _logger.error("todo must do message recovery now."); + //todo must do message recovery now. + msgMap.put(messageId,message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index b5a91c8da6..d46ba85069 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -26,7 +26,6 @@ import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.tools.messagestore.MessageStoreTool; @@ -349,32 +348,15 @@ public class Show extends AbstractCommand arrival.add("" + msg.getArrivalTime()); - try - { - ispersitent.add(msg.isPersistent() ? "true" : "false"); - } - catch (AMQException e) - { - ispersitent.add("n/a"); - } + ispersitent.add(msg.isPersistent() ? "true" : "false"); isredelivered.add(entry.isRedelivered() ? "true" : "false"); isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); -// msg.getMessageHandle(); - BasicContentHeaderProperties headers = null; - try - { - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); - } - catch (AMQException e) - { - //ignore -// commandError("Unable to read properties for message: " + e.getMessage(), null); - } + headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); if (headers != null) { @@ -414,15 +396,7 @@ public class Show extends AbstractCommand AMQShortString useridSS = headers.getUserId(); userid.add(useridSS == null ? "null" : useridSS.toString()); - MessagePublishInfo info = null; - try - { - info = msg.getMessagePublishInfo(); - } - catch (AMQException e) - { - //ignore - } + MessagePublishInfo info = msg.getMessagePublishInfo(); if (info != null) { -- cgit v1.2.1 From 448e6bff629c2d8d9b3cbd7c39d8eefd2b33c06e Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 13 Feb 2009 14:00:10 +0000 Subject: QPID-1511 : Adds authentication and ssl encryption capabilities to the RMI based JMXConnectorServer in use, enforces use of the custom MBeanInvocationhandlerImp when using the RMI based JMX, and implements a customised RMI registry to prevent external changes being possible. Updated Management console accordingly. Patch from Robbert Gemmell git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744113 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 312 ++++++++++++++++----- .../server/management/ManagedObjectRegistry.java | 5 +- .../auth/rmi/RMIPasswordAuthenticator.java | 182 ++++++++++++ 3 files changed, 422 insertions(+), 77 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 659f806d58..a0d2c7dc66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.management; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -27,6 +28,7 @@ import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -37,31 +39,45 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.management.remote.rmi.RMIJRMPServerImpl; +import javax.management.remote.rmi.RMIServerImpl; +import javax.rmi.ssl.SslRMIClientSocketFactory; +import javax.rmi.ssl.SslRMIServerSocketFactory; + +import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import java.util.HashMap; import java.util.Map; /** - * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features - * implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env - * variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be - * used, which again doesn't have user authentication. + * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no + * security features implemented like user authentication and authorisation. */ public class JMXManagedObjectRegistry implements ManagedObjectRegistry { private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); + private static final Logger _startupLog = Logger.getLogger("Qpid.Broker"); + + public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; + public static final int MANAGEMENT_PORT_DEFAULT = 8999; + public static final int PORT_EXPORT_OFFSET = 100; private final MBeanServer _mbeanServer; private Registry _rmiRegistry; - private JMXServiceURL _jmxURL; - public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; - public static final int MANAGEMENT_PORT_DEFAULT = 8999; public JMXManagedObjectRegistry() throws AMQException { @@ -77,44 +93,38 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } - public void start() throws IOException + public void start() throws IOException, ConfigurationException { - // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent + //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) { - _log.info("JMX: Using the out of the box JMX Agent"); + _log.warn("JMX: Using the out of the box JMX Agent"); + _startupLog.warn("JMX: Using the out of the box JMX Agent"); return; } IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); + boolean jmxmpSecurity = appRegistry.getConfiguration().getBoolean("management.security-enabled", false); int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT); - if (security) - { - // For SASL using JMXMP - _jmxURL = new JMXServiceURL("jmxmp", null, port); + //retrieve the Principal Database assigned to JMX authentication duties + String jmxDatabaseName = appRegistry.getConfiguration().getString("security.jmx.principal-database"); + Map map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = map.get(jmxDatabaseName); - Map env = new HashMap(); - Map map = appRegistry.getDatabaseManager().getDatabases(); - PrincipalDatabase db = null; + final JMXConnectorServer cs; + HashMap env = new HashMap(); - for (Map.Entry entry : map.entrySet()) - { - if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) - { - db = entry.getValue(); - break; - } - else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) - { - db = entry.getValue(); - } - } + if (jmxmpSecurity) + { + // For SASL using JMXMP + JMXServiceURL jmxURL = new JMXServiceURL("jmxmp", null, port); + String saslType = null; if (db instanceof Base64MD5PasswordFilePrincipalDatabase) { + saslType = "SASL/CRAM-MD5"; env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); initialiser.initialise(db); @@ -122,6 +132,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } else if (db instanceof PlainPasswordFilePrincipalDatabase) { + saslType = "SASL/PLAIN"; PlainInitialiser initialiser = new PlainInitialiser(); initialiser.initialise(db); env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); @@ -131,43 +142,209 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //workaround NPE generated from env map classloader issue when using Eclipse 3.4 to launch env.put("jmx.remote.profile.provider.class.loader", this.getClass().getClassLoader()); - // Enable the SSL security and server authentication - /* - SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); - SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); - env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); - env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); - */ - - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - cs.start(); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL"); - + _log.warn("Starting JMXMP based JMX ConnectorServer on port '" + port + "' with " + saslType); + _startupLog.warn("Starting JMXMP based JMX ConnectorServer on port '" + port + "' with " + saslType); + + cs = JMXConnectorServerFactory.newJMXConnectorServer(jmxURL, env, _mbeanServer); } else - { - startJMXConnectorServer(port); - _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled"); + { + //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration + RMIClientSocketFactory csf; + RMIServerSocketFactory ssf; + + //check ssl enabled option in config, default to true if option is not set + boolean sslEnabled = appRegistry.getConfiguration().getBoolean("management.ssl.enabled", true); + + if (sslEnabled) + { + //set the SSL related system properties used by the SSL RMI socket factories to the values + //given in the configuration file, unless command line settings have already been specified + String keyStorePath; + + if(System.getProperty("javax.net.ssl.keyStore") != null) + { + keyStorePath = System.getProperty("javax.net.ssl.keyStore"); + } + else{ + keyStorePath = appRegistry.getConfiguration().getString("management.ssl.keyStorePath", null); + } + + //check the keystore path value is valid + if (keyStorePath == null) + { + throw new ConfigurationException("JMX management SSL keystore path not defined, " + + "unable to start SSL protected JMX ConnectorServer"); + } + else + { + //ensure the system property is set + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + + //check the file is usable + File ksf = new File(keyStorePath); + + if (!ksf.exists()) + { + throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf); + } + if (!ksf.canRead()) + { + throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " + + ksf + ". Check permissions."); + } + + _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + } + + //check the key store password is set + if (System.getProperty("javax.net.ssl.keyStorePassword") == null) + { + + if (appRegistry.getConfiguration().getString("management.ssl.keyStorePassword") == null) + { + throw new ConfigurationException("JMX management SSL keystore password not defined, " + + "unable to start requested SSL protected JMX server"); + } + else + { + System.setProperty("javax.net.ssl.keyStorePassword", + appRegistry.getConfiguration().getString("management.ssl.keyStorePassword")); + } + } + + //create the SSL RMI socket factories + csf = new SslRMIClientSocketFactory(); + ssf = new SslRMIServerSocketFactory(); + + _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + } + else + { + //Do not specify any specific RMI socket factories, resulting in use of the defaults. + csf = null; + ssf = null; + + _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + } + + //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server + RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); + rmipa.setPrincipalDatabase(db); + env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); + + /* + * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. + * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. + * As a result, only binds made using the object reference will succeed, thus securing it from external change. + */ + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); + + /* + * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls + * to bind the ConnectorServer to the registry, which will now fail as for security we have + * locked it from any RMI based modifications, including our own. Instead, we will manually bind + * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. + * + * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer + * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. + */ + final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); + final String hostname = InetAddress.getLocalHost().getHostName(); + final JMXServiceURL externalUrl = new JMXServiceURL( + "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); + + final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); + cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + { + @Override + public synchronized void start() throws IOException + { + try + { + //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent + _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); + } + catch (AlreadyBoundException abe) + { + //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means. + + //IOExceptions are the only checked type throwable by the method, wrap and rethrow + IOException ioe = new IOException(abe.getMessage()); + ioe.initCause(abe); + throw ioe; + } + + //now do the normal tasks + super.start(); + } + + @Override + public JMXServiceURL getAddress() + { + //must return our pre-crafted url that includes the full details, inc JNDI details + return externalUrl; + } + + }; } + + //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); } - /** - * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it. - * - * @param port - * - * @throws IOException + /* + * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry. + * Supplied to the registry at creation, this will prevent RMI-based operations on the + * registry such as attempting to bind a new object, thereby securing it from tampering. + * This is accomplished by always returning null when attempting to determine the address + * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc + * made using the object reference will not be affected and continue to operate normally. */ - private void startJMXConnectorServer(int port) throws IOException + + private class CustomRMIServerSocketFactory implements RMIServerSocketFactory { - startRMIRegistry(port); - _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); - JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); - cs.start(); + + public ServerSocket createServerSocket(int port) throws IOException + { + return new NoLocalAddressServerSocket(port); + } + + private class NoLocalAddressServerSocket extends ServerSocket + { + NoLocalAddressServerSocket(int port) throws IOException + { + super(port); + } + + @Override + public Socket accept() throws IOException + { + Socket s = new NoLocalAddressSocket(); + super.implAccept(s); + return s; + } + } + + private class NoLocalAddressSocket extends Socket + { + @Override + public InetAddress getInetAddress() + { + return null; + } + } } + public void registerObject(ManagedObject managedObject) throws JMException { _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); @@ -178,11 +355,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer.unregisterMBean(managedObject.getObjectName()); } - /** - * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent. - * - * @return - */ + // checks if the system properties are set which enable the JVM's out-of-the-box JMXAgent. private boolean areOutOfTheBoxJMXOptionsSet() { if (System.getProperty("com.sun.management.jmxremote") != null) @@ -198,19 +371,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry return false; } - /** - * Starts the rmi registry at given port - * - * @param port - * - * @throws RemoteException - */ - private void startRMIRegistry(int port) throws RemoteException - { - System.setProperty("java.rmi.server.randomIDs", "true"); - _rmiRegistry = LocateRegistry.createRegistry(port); - } - // stops the RMIRegistry, if it was running and bound to a port public void close() throws RemoteException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java index d8d87ef881..b58b17ba86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.management; import javax.management.JMException; + +import org.apache.commons.configuration.ConfigurationException; + import java.rmi.RemoteException; import java.io.IOException; @@ -38,7 +41,7 @@ import java.io.IOException; */ public interface ManagedObjectRegistry { - void start() throws IOException; + void start() throws IOException, ConfigurationException; void registerObject(ManagedObject managedObject) throws JMException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java new file mode 100644 index 0000000000..378b17e733 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -0,0 +1,182 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.rmi; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Collections; + +import javax.management.remote.JMXAuthenticator; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; + +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +public class RMIPasswordAuthenticator implements JMXAuthenticator +{ + static final String UNABLE_TO_LOOKUP = "The broker was unable to lookup the user details"; + static final String SHOULD_BE_STRING_ARRAY = "User details should be String[]"; + static final String SHOULD_HAVE_2_ELEMENTS = "User details should have 2 elements, username, password"; + static final String SHOULD_BE_NON_NULL = "Supplied username and password should be non-null"; + static final String INVALID_CREDENTIALS = "Invalid user details supplied"; + static final String CREDENTIALS_REQUIRED = "User details are required. " + + "Please ensure you are using an up to date management console to connect."; + + public static final String DEFAULT_ENCODING = "utf-8"; + private PrincipalDatabase _db = null; + + public RMIPasswordAuthenticator() + { + } + + public void setPrincipalDatabase(PrincipalDatabase pd) + { + this._db = pd; + } + + public Subject authenticate(Object credentials) throws SecurityException + { + // Verify that credential's are of type String[]. + if (!(credentials instanceof String[])) + { + if (credentials == null) + { + throw new SecurityException(CREDENTIALS_REQUIRED); + } + else + { + throw new SecurityException(SHOULD_BE_STRING_ARRAY); + } + } + + // Verify that required number of credential's. + final String[] userCredentials = (String[]) credentials; + if (userCredentials.length != 2) + { + throw new SecurityException(SHOULD_HAVE_2_ELEMENTS); + } + + String username = (String) userCredentials[0]; + String password = (String) userCredentials[1]; + + // Verify that all required credential's are actually present. + if (username == null || password == null) + { + throw new SecurityException(SHOULD_BE_NON_NULL); + } + + boolean authenticated = false; + + // Perform authentication + try + { + PasswordCallback pwCallback = new PasswordCallback("prompt",false); + UsernamePrincipal uname = new UsernamePrincipal(username); + + if (_db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + //retrieve the stored password for the given user + _db.setPassword(uname, pwCallback); + + //compare the MD5Hash of the given password with the stored value + if (Arrays.equals(getMD5Hash(password), pwCallback.getPassword())) + { + authenticated = true; + } + } + else if (_db instanceof PlainPasswordFilePrincipalDatabase) + { + //retrieve the users stored password and compare with given value + _db.setPassword(uname, pwCallback); + + if (password.equals(new String(pwCallback.getPassword()))) + { + authenticated = true; + } + } + else + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + } + catch (AccountNotFoundException e) + { + throw new SecurityException(INVALID_CREDENTIALS); + } + catch (UnsupportedEncodingException e) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + catch (NoSuchAlgorithmException e) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + catch (IOException e) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + + if (authenticated) + { + //credential's check out, return the appropriate JAAS Subject + return new Subject(true, + Collections.singleton(new JMXPrincipal(username)), + Collections.EMPTY_SET, + Collections.EMPTY_SET); + } + else + { + throw new SecurityException(INVALID_CREDENTIALS); + } + } + + public static char[] getMD5Hash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + byte[] data = text.getBytes(DEFAULT_ENCODING); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length ]; + + int index = 0; + for (byte b : digest) + { + hash[index++] = (char) b; + } + + return hash; + } +} \ No newline at end of file -- cgit v1.2.1 From a8874f55a3b17ac94f38e6697bdb4bed72e7ee6c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Feb 2009 15:09:50 +0000 Subject: QPID-1630 : Updated MessageFactory to be responsible for assigning messagIDs. Several tests needed updating as they relied upon specified messageIDs. Added a recovery mode to the MessageFactory where by new messages can have their ids specified but only as long as the new id is larger than the last one. Recovered messages are always persistent. Simplified a interfaces as a result of not requiring the messageID to be passed through. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744140 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 8 +- .../apache/qpid/server/queue/IncomingMessage.java | 34 ++++----- .../apache/qpid/server/queue/MessageFactory.java | 88 +++++++++++++++++++++- .../qpid/server/store/DerbyMessageStore.java | 4 +- .../org/apache/qpid/server/store/MessageStore.java | 7 -- 5 files changed, 104 insertions(+), 37 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 3b290b3d51..341aae2875 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -37,7 +37,6 @@ import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.MessageFactory; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.UnauthorizedAccessException; import org.apache.qpid.server.queue.AMQMessage; @@ -108,8 +107,6 @@ public class AMQChannel private final List _returnMessages = new LinkedList(); - private MessageFactory _messageHandleFactory = new MessageFactory(); - // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; private boolean _closing; @@ -153,8 +150,7 @@ public class AMQChannel public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException { - _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session); - _currentMessage.setMessageStore(_messageStore); + _currentMessage = new IncomingMessage(info, _txnContext, _session, _messageStore); _currentMessage.setExchange(e); } @@ -178,7 +174,7 @@ public class AMQChannel routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + _currentMessage.routingComplete(_messageStore); deliverCurrentMessageIfComplete(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index aad99da6c3..20926b99d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -48,7 +48,6 @@ public class IncomingMessage implements Filterable private final MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; private AMQMessage _message; - private final Long _messageId; private final TransactionalContext _txnContext; private static final boolean MSG_AUTH = @@ -72,22 +71,23 @@ public class IncomingMessage implements Filterable private long _expiration; private Exchange _exchange; + private static MessageFactory MESSAGE_FACTORY = MessageFactory.getInstance(); - public IncomingMessage(final Long messageId, - final MessagePublishInfo info, + public IncomingMessage(final MessagePublishInfo info, final TransactionalContext txnContext, - final AMQProtocolSession publisher) + final AMQProtocolSession publisher, + MessageStore messasgeStore) { - _messageId = messageId; _messagePublishInfo = info; _txnContext = txnContext; _publisher = publisher; - + _messageStore = messasgeStore; } public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException { _contentHeaderBody = contentHeaderBody; + _message = MESSAGE_FACTORY.createMessage(_messageStore, isPersistent()); } public void setExpiration() @@ -121,13 +121,10 @@ public class IncomingMessage implements Filterable } - public void routingComplete(final MessageStore store, - final MessageFactory factory) throws AMQException + public void routingComplete(final MessageStore store) throws AMQException { - final boolean persistent = isPersistent(); - _message = factory.createMessage(_messageId, store, persistent); - if (persistent) + if (isPersistent()) { _txnContext.beginTranIfNecessary(); // enqueuing the messages ensure that if required the destinations are recorded to a @@ -138,7 +135,7 @@ public class IncomingMessage implements Filterable for (int i = 0; i < _destinationQueues.size(); i++) { store.enqueueMessage(_txnContext.getStoreContext(), - _destinationQueues.get(i), _messageId); + _destinationQueues.get(i), getMessageId()); } } } @@ -152,7 +149,7 @@ public class IncomingMessage implements Filterable // transient message data as quickly as possible if (_logger.isDebugEnabled()) { - _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); + _logger.debug("Delivering message " + getMessageId() + " to " + _destinationQueues); } try @@ -284,14 +281,13 @@ public class IncomingMessage implements Filterable return false; } - public void setMessageStore(final MessageStore messageStore) - { - _messageStore = messageStore; - } - + /** + * The message ID will not be assigned until the ContentHeaderBody has arrived. + * @return + */ public Long getMessageId() { - return _messageId; + return _message.getMessageId(); } public void setExchange(final Exchange e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java index e18834874f..2f6e05963c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java @@ -21,12 +21,85 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; + +import java.util.concurrent.atomic.AtomicLong; public class MessageFactory { + private AtomicLong _messageId; + private static MessageFactory INSTANCE; + + private enum State + { + RECOVER, + OPEN + } + + private State _state = State.RECOVER; + + private MessageFactory() + { + _messageId = new AtomicLong(0L); + } + + public void start() + { + _state = State.OPEN; + } + + /** + * Only used by test as test suite is run in a single VM we need to beable to re-enable recovery mode. + */ + protected void enableRecover() + { + _state = State.RECOVER; + } + + + /** + * Normal message creation path + * @param store + * @param persistent + * @return + */ + public AMQMessage createMessage(MessageStore store, boolean persistent) + { + if (_state != State.OPEN) + { + _state = State.OPEN; + } + + return createNextMessage(_messageId.incrementAndGet(), store, persistent); + } + + /** + * Used for message recovery only and so only creates persistent messages. + * @param messageId the id that this message must have + * @param store + * @return + */ + public AMQMessage createMessage(Long messageId, MessageStore store) + { + if (_state != State.RECOVER) + { + throw new RuntimeException("Unable to create message by ID when not recovering"); + } + + long currentID = _messageId.get(); + if (messageId <= currentID) + { + throw new RuntimeException("Message IDs can only increase current id is:" + + currentID + ". Requested:" + messageId); + } + else + { + _messageId.set(messageId); + } + + return createNextMessage(messageId, store, true); + } - public AMQMessage createMessage(Long messageId, MessageStore store, boolean persistent) + private AMQMessage createNextMessage(Long messageId, MessageStore store, boolean persistent) { if (persistent) { @@ -37,5 +110,14 @@ public class MessageFactory return new TransientAMQMessage(messageId); } } - + + public static MessageFactory getInstance() + { + if (INSTANCE == null) + { + INSTANCE = new MessageFactory(); + } + + return INSTANCE; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 9de2d09b8e..425aed43d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -167,7 +167,7 @@ public class DerbyMessageStore implements MessageStore // this recovers durable queues and persistent messages - _messageFactory = new MessageFactory(); + _messageFactory = MessageFactory.getInstance(); recover(); @@ -1355,7 +1355,7 @@ public class DerbyMessageStore implements MessageStore } else { - message = _messageFactory.createMessage(messageId, this, true); + message = _messageFactory.createMessage(messageId, this); _logger.error("todo must do message recovery now."); //todo must do message recovery now. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index f2910acb77..e65dded149 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -209,13 +209,6 @@ public interface MessageStore */ boolean inTran(StoreContext context); - /** - * Return a valid, currently unused message id. - * - * @return A fresh message id. - */ - Long getNewMessageId(); - /** * Stores a chunk of message data. * -- cgit v1.2.1 From 93ce4ab1ba3922db54f031faa8dfc1b62d8bfae1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Feb 2009 17:22:17 +0000 Subject: QPID-1631 : Convert MessageStore to TransactionLog and RoutingTable. Updated all references and provided a test to ensure that whilst we are transitioning the configuration we can use the old MessageStore classes that now implement both interfaces without any config updates. Updates to the configuration can come when the store are renamed *TransactionLog git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@744184 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 18 +- .../java/org/apache/qpid/server/AMQChannel.java | 26 +- .../configuration/VirtualHostConfiguration.java | 9 +- .../server/exchange/DefaultExchangeRegistry.java | 10 +- .../qpid/server/handler/ChannelOpenHandler.java | 2 +- .../qpid/server/handler/QueueDeclareHandler.java | 9 +- .../qpid/server/handler/QueueDeleteHandler.java | 7 +- .../apache/qpid/server/queue/IncomingMessage.java | 10 +- .../apache/qpid/server/queue/MessageFactory.java | 18 +- .../qpid/server/queue/PersistentAMQMessage.java | 14 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 36 +-- .../apache/qpid/server/routing/RoutingTable.java | 123 ++++++++++ .../qpid/server/store/DerbyMessageStore.java | 45 ++-- .../qpid/server/store/MemoryMessageStore.java | 24 +- .../org/apache/qpid/server/store/MessageStore.java | 269 --------------------- .../qpid/server/transactionlog/TransactionLog.java | 205 ++++++++++++++++ .../qpid/server/txn/LocalTransactionalContext.java | 17 +- .../qpid/server/txn/NonTransactionalContext.java | 14 +- .../qpid/server/txn/StoreMessageOperation.java | 12 +- .../qpid/server/virtualhost/VirtualHost.java | 91 +++++-- .../qpid/tools/messagestore/MessageStoreTool.java | 2 +- 21 files changed, 536 insertions(+), 425 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index fc6057afd2..b3c843ebaa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -42,12 +42,8 @@ import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -59,8 +55,9 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.routing.RoutingTable; /** * This MBean implements the broker management interface and exposes the @@ -72,7 +69,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; + private final TransactionLog _tranasctionLog; + private final RoutingTable _routingTable; private final VirtualHost.VirtualHostMBean _virtualHostMBean; @@ -86,8 +84,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr _queueRegistry = virtualHost.getQueueRegistry(); _exchangeRegistry = virtualHost.getExchangeRegistry(); - _messageStore = virtualHost.getMessageStore(); + _tranasctionLog = virtualHost.getTransactionLog(); _exchangeFactory = virtualHost.getExchangeFactory(); + _routingTable = virtualHost.getRoutingTable(); } public String getObjectInstanceName() @@ -180,7 +179,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr null); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue); + _routingTable.createQueue(queue); } _queueRegistry.registerQueue(queue); @@ -215,8 +214,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.removeQueue(queue); - + _routingTable.removeQueue(queue); } catch (AMQException ex) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 341aae2875..2d0589c223 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -44,11 +44,11 @@ import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.transactionlog.TransactionLog; import java.util.Collection; import java.util.LinkedList; @@ -91,7 +91,7 @@ public class AMQChannel /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */ protected final Map _tag2SubscriptionMap = new HashMap(); - private final MessageStore _messageStore; + private final TransactionLog _transactionLog; private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); @@ -109,9 +109,9 @@ public class AMQChannel // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - private boolean _closing; + private boolean _closing; - public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) + public AMQChannel(AMQProtocolSession session, int channelId, TransactionLog transactionLog) throws AMQException { //Set values from configuration @@ -122,10 +122,10 @@ public class AMQChannel _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); - _messageStore = messageStore; + _transactionLog = transactionLog; // by default the session is non-transactional - _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + _txnContext = new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); } /** Sets this channel to be part of a local transaction */ @@ -150,7 +150,7 @@ public class AMQChannel public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException { - _currentMessage = new IncomingMessage(info, _txnContext, _session, _messageStore); + _currentMessage = new IncomingMessage(info, _txnContext, _session, _transactionLog); _currentMessage.setExchange(e); } @@ -174,7 +174,7 @@ public class AMQChannel routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore); + _currentMessage.routingComplete(_transactionLog); deliverCurrentMessageIfComplete(); @@ -474,7 +474,7 @@ public class AMQChannel { deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); } else { @@ -534,7 +534,7 @@ public class AMQChannel { deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); } else @@ -669,7 +669,7 @@ public class AMQChannel { deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); } else { @@ -870,9 +870,9 @@ public class AMQChannel return _returnMessages; } - public MessageStore getMessageStore() + public TransactionLog getTransactionLog() { - return _messageStore; + return _transactionLog; } private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 705e84752b..02fb57c730 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -38,8 +38,9 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.routing.RoutingTable; public class VirtualHostConfiguration { @@ -101,8 +102,6 @@ public class VirtualHostConfiguration exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString)); exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore messageStore = virtualHost.getMessageStore(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); @@ -159,7 +158,7 @@ public class VirtualHostConfiguration queueConfiguration.addConfiguration(configuration.subset("queues")); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore messageStore = virtualHost.getMessageStore(); + RoutingTable routingTable = virtualHost.getRoutingTable(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); @@ -205,7 +204,7 @@ public class VirtualHostConfiguration if (queue.isDurable()) { - messageStore.createQueue(queue); + routingTable.createQueue(queue); } queueRegistry.registerQueue(queue); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index f28ba0d0de..3e930364df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -25,8 +25,8 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.protocol.ExchangeInitialiser; import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.routing.RoutingTable; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; @@ -56,9 +56,9 @@ public class DefaultExchangeRegistry implements ExchangeRegistry new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); } - public MessageStore getMessageStore() + public RoutingTable getRoutingTable() { - return _host.getMessageStore(); + return _host.getRoutingTable(); } public void registerExchange(Exchange exchange) throws AMQException @@ -66,7 +66,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry _exchangeMap.put(exchange.getName(), exchange); if (exchange.isDurable()) { - getMessageStore().createExchange(exchange); + getRoutingTable().createExchange(exchange); } } @@ -93,7 +93,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { if (e.isDurable()) { - getMessageStore().removeExchange(e); + getRoutingTable().removeExchange(e); } e.close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index 054674aed4..0a7d5cfe6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -54,7 +54,7 @@ public class ChannelOpenHandler implements StateAwareMethodListener { @@ -73,7 +70,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -62,7 +61,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener private ArrayList _destinationQueues; private AMQProtocolSession _publisher; - private MessageStore _messageStore; + private TransactionLog _messageStore; private long _expiration; private Exchange _exchange; @@ -76,7 +76,7 @@ public class IncomingMessage implements Filterable public IncomingMessage(final MessagePublishInfo info, final TransactionalContext txnContext, final AMQProtocolSession publisher, - MessageStore messasgeStore) + TransactionLog messasgeStore) { _messagePublishInfo = info; _txnContext = txnContext; @@ -121,7 +121,7 @@ public class IncomingMessage implements Filterable } - public void routingComplete(final MessageStore store) throws AMQException + public void routingComplete(final TransactionLog transactionLog) throws AMQException { if (isPersistent()) @@ -134,7 +134,7 @@ public class IncomingMessage implements Filterable { for (int i = 0; i < _destinationQueues.size(); i++) { - store.enqueueMessage(_txnContext.getStoreContext(), + transactionLog.enqueueMessage(_txnContext.getStoreContext(), _destinationQueues.get(i), getMessageId()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java index 2f6e05963c..e5e0b6e312 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.transactionlog.TransactionLog; import java.util.concurrent.atomic.AtomicLong; @@ -58,27 +58,27 @@ public class MessageFactory /** * Normal message creation path - * @param store + * @param transactionLog * @param persistent * @return */ - public AMQMessage createMessage(MessageStore store, boolean persistent) + public AMQMessage createMessage(TransactionLog transactionLog, boolean persistent) { if (_state != State.OPEN) { _state = State.OPEN; } - return createNextMessage(_messageId.incrementAndGet(), store, persistent); + return createNextMessage(_messageId.incrementAndGet(), transactionLog, persistent); } /** * Used for message recovery only and so only creates persistent messages. * @param messageId the id that this message must have - * @param store + * @param transactionLog * @return */ - public AMQMessage createMessage(Long messageId, MessageStore store) + public AMQMessage createMessage(Long messageId, TransactionLog transactionLog) { if (_state != State.RECOVER) { @@ -96,14 +96,14 @@ public class MessageFactory _messageId.set(messageId); } - return createNextMessage(messageId, store, true); + return createNextMessage(messageId, transactionLog, true); } - private AMQMessage createNextMessage(Long messageId, MessageStore store, boolean persistent) + private AMQMessage createNextMessage(Long messageId, TransactionLog transactionLog, boolean persistent) { if (persistent) { - return new PersistentAMQMessage(messageId, store); + return new PersistentAMQMessage(messageId, transactionLog); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java index 04e3635f92..804bb29ecd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java @@ -24,17 +24,17 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.transactionlog.TransactionLog; public class PersistentAMQMessage extends TransientAMQMessage { - protected MessageStore _messageStore; + protected TransactionLog _transactionLog; - public PersistentAMQMessage(Long messageId, MessageStore store) + public PersistentAMQMessage(Long messageId, TransactionLog transactionLog) { super(messageId); - _messageStore = store; + _transactionLog = transactionLog; } @Override @@ -42,7 +42,7 @@ public class PersistentAMQMessage extends TransientAMQMessage throws AMQException { super.addContentBodyFrame(storeContext, contentChunk, isLastContentBody); - _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, + _transactionLog.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, contentChunk, isLastContentBody); } @@ -54,13 +54,13 @@ public class PersistentAMQMessage extends TransientAMQMessage super.setPublishAndContentHeaderBody(storeContext, messagePublishInfo, contentHeaderBody); MessageMetaData mmd = new MessageMetaData(messagePublishInfo, contentHeaderBody, _contentBodies == null ? 0 : _contentBodies.size(), _arrivalTime); - _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); + _transactionLog.storeMessageMetaData(storeContext, _messageId, mmd); } @Override public void removeMessage(StoreContext storeContext) throws AMQException { - _messageStore.removeMessage(storeContext, _messageId); + _transactionLog.removeMessage(storeContext, _messageId); } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 547df7856d..a08e4e2667 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -6,11 +6,11 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.transactionlog.TransactionLog; import org.apache.qpid.AMQException; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; @@ -210,7 +210,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + _virtualHost.getRoutingTable().bindQueue(exchange, routingKey, this, arguments); } _bindings.addBinding(routingKey, arguments, exchange); @@ -221,7 +221,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + _virtualHost.getRoutingTable().unbindQueue(exchange, routingKey, this, arguments); } boolean removed = _bindings.remove(routingKey, arguments, exchange); @@ -581,7 +581,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener AMQMessage msg = entry.getMessage(); if (msg.isPersistent()) { - _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); + _virtualHost.getTransactionLog().dequeueMessage(storeContext, this, msg.getMessageId()); } //entry.dispose(storeContext); @@ -826,7 +826,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + TransactionLog transactionLog = getVirtualHost().getTransactionLog(); List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -847,16 +847,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener try { - store.beginTran(storeContext); + transactionLog.beginTran(storeContext); - // Move the messages in on the message store. + // Move the messages in on the transaction log. for (QueueEntry entry : entries) { AMQMessage message = entry.getMessage(); if (message.isPersistent() && toQueue.isDurable()) { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + transactionLog.enqueueMessage(storeContext, toQueue, message.getMessageId()); } // dequeue does not decrement the refence count entry.dequeue(storeContext); @@ -865,18 +865,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Commit and flush the move transcations. try { - store.commitTran(storeContext); + transactionLog.commitTran(storeContext); } catch (AMQException e) { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + throw new RuntimeException("Failed to commit transaction whilst moving messages on transaction log.", e); } } catch (AMQException e) { try { - store.abortTran(storeContext); + transactionLog.abortTran(storeContext); } catch (AMQException rollbackEx) { @@ -910,7 +910,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener final StoreContext storeContext) { AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + TransactionLog transactionLog = getVirtualHost().getTransactionLog(); List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -938,34 +938,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener try { - store.beginTran(storeContext); + transactionLog.beginTran(storeContext); - // Move the messages in on the message store. + // Move the messages in on the transaction log. for (QueueEntry entry : entries) { AMQMessage message = entry.getMessage(); if (message.isReferenced() && message.isPersistent() && toQueue.isDurable()) { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + transactionLog.enqueueMessage(storeContext, toQueue, message.getMessageId()); } } // Commit and flush the move transcations. try { - store.commitTran(storeContext); + transactionLog.commitTran(storeContext); } catch (AMQException e) { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + throw new RuntimeException("Failed to commit transaction whilst moving messages on transaction log.", e); } } catch (AMQException e) { try { - store.abortTran(storeContext); + transactionLog.abortTran(storeContext); } catch (AMQException rollbackEx) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java new file mode 100644 index 0000000000..6344127b24 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java @@ -0,0 +1,123 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.routing; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.commons.configuration.Configuration; + +public interface RoutingTable +{ + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param base The base element identifier from which all configuration items are relative. For example, if + * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws Exception If the close fails. + */ + void close() throws Exception; + + + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createExchange(Exchange exchange) throws AMQException; + + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeExchange(Exchange exchange) throws AMQException; + + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * @param arguments The additional arguments to the binding + * + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; + + /** + * Removes the specified queue from the persistent store. + * + * @param queue The queue to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeQueue(final AMQQueue queue) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 425aed43d4..500fd4c7bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -32,6 +32,8 @@ import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -62,7 +64,7 @@ import java.util.HashMap; import java.util.TreeMap; -public class DerbyMessageStore implements MessageStore +public class DerbyMessageStore implements TransactionLog, RoutingTable { private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); @@ -142,37 +144,40 @@ public class DerbyMessageStore implements MessageStore public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception { - stateTransition(State.INITIAL, State.CONFIGURING); + //Only initialise when loaded with the old 'store' confing ignore the new 'RoutingTable' config + if (base.equals("store")) + { + stateTransition(State.INITIAL, State.CONFIGURING); - initialiseDriver(); + initialiseDriver(); - _virtualHost = virtualHost; + _virtualHost = virtualHost; - _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - final String databasePath = config.getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + final String databasePath = config.getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); - File environmentPath = new File(databasePath); - if (!environmentPath.exists()) - { - if (!environmentPath.mkdirs()) + File environmentPath = new File(databasePath); + if (!environmentPath.exists()) { - throw new IllegalArgumentException("Environment path " + environmentPath + " could not be read or created. " - + "Ensure the path is correct and that the permissions are correct."); + if (!environmentPath.mkdirs()) + { + throw new IllegalArgumentException("Environment path " + environmentPath + " could not be read or created. " + + "Ensure the path is correct and that the permissions are correct."); + } } - } - - createOrOpenDatabase(databasePath); - // this recovers durable queues and persistent messages + createOrOpenDatabase(databasePath); - _messageFactory = MessageFactory.getInstance(); + // this recovers durable queues and persistent messages - recover(); + _messageFactory = MessageFactory.getInstance(); - stateTransition(State.RECOVERING, State.STARTED); + recover(); + stateTransition(State.RECOVERING, State.STARTED); + } } private static synchronized void initialiseDriver() throws ClassNotFoundException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 587c85fc12..eee7be7ef6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -30,6 +30,8 @@ import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.routing.RoutingTable; import java.util.ArrayList; import java.util.Collections; @@ -39,8 +41,14 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; 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 +/** A simple message store that stores the messages in a threadsafe structure in memory. + * + * NOTE: Now that we have removed the MessageStore interface and are using a TransactionLog + * + * This class really should have no storage unless we want to do inMemory Recovery. + * + */ +public class MemoryMessageStore implements TransactionLog, RoutingTable { private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -64,10 +72,14 @@ public class MemoryMessageStore implements MessageStore 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); + //Only initialise when called with current 'store' configs i.e. don't reinit when used as a 'RoutingTable' + if (base.equals("store")) + { + 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(VirtualHost virtualHost, String base, Configuration config) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java deleted file mode 100644 index e65dded149..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/** - * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues - * and exchanges in a transactional manner. - * - *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which - * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single - * transaction. - * - *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. - * - *

      - *
      CRC Card
      Responsibilities - *
      Accept transaction boundary demarcations: Begin, Commit, Abort. - *
      Store and remove queues. - *
      Store and remove exchanges. - *
      Store and remove messages. - *
      Bind and unbind queues to exchanges. - *
      Enqueue and dequeue messages to queues. - *
      Generate message identifiers. - *
      - */ -public interface MessageStore -{ - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object. - * - * @throws Exception If any error occurs that means the store is unable to configure itself. - */ - void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws Exception If the close fails. - */ - void close() throws Exception; - - /** - * Removes the specified message from the store in the given transactional store context. - * - * @param storeContext The transactional context to remove the message in. - * @param messageId Identifies the message to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - /** - * Makes the specified exchange persistent. - * - * @param exchange The exchange to persist. - * - * @throws AMQException If the operation fails for any reason. - */ - void createExchange(Exchange exchange) throws AMQException; - - /** - * Removes the specified persistent exchange. - * - * @param exchange The exchange to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeExchange(Exchange exchange) throws AMQException; - - /** - * Binds the specified queue to an exchange with a routing key. - * - * @param exchange The exchange to bind to. - * @param routingKey The routing key to bind by. - * @param queue The queue to bind. - * @param args Additional parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Unbinds the specified from an exchange under a particular routing key. - * - * @param exchange The exchange to unbind from. - * @param routingKey The routing key to unbind. - * @param queue The queue to unbind. - * @param args Additonal parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue) throws AMQException; - - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @param arguments The additional arguments to the binding - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; - - /** - * Removes the specified queue from the persistent store. - * - * @param queue The queue to remove. - * @throws AMQException If the operation fails for any reason. - */ - void removeQueue(final AMQQueue queue) throws AMQException; - - /** - * Places a message onto a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to enqueue. - * @throws AMQException If the operation fails for any reason. - */ - void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to dequeue. - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Begins a transactional context. - * - * @param context The transactional context to begin. - * - * @throws AMQException If the operation fails for any reason. - */ - void beginTran(StoreContext context) throws AMQException; - - /** - * Commits all operations performed within a given transactional context. - * - * @param context The transactional context to commit all operations for. - * - * @throws AMQException If the operation fails for any reason. - */ - void commitTran(StoreContext context) throws AMQException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @param context The transactional context to abandon. - * - * @throws AMQException If the operation fails for any reason. - */ - void abortTran(StoreContext context) throws AMQException; - - /** - * Tests a transactional context to see if it has been begun but not yet committed or aborted. - * - * @param context The transactional context to test. - * - * @return true if the transactional context is live, false otherwise. - */ - boolean inTran(StoreContext context); - - /** - * Stores a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param index The index of the data chunk. - * @param contentBody The content of the data chunk. - * @param lastContentBody Flag to indicate that this is the last such chunk for the message. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, - boolean lastContentBody) throws AMQException; - - /** - * Stores message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param messageMetaData The message meta data to store. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - - /** - * Retrieves message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the meta-data for. - * - * @return The message meta data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - - /** - * Retrieves a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the data chunk for. - * @param index The offset index of the data chunk within the message. - * - * @return A chunk of message data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; - - /** - * Is this store capable of persisting the data - * - * @return true if this store is capable of persisting data - */ - boolean isPersistent(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java new file mode 100644 index 0000000000..c927bb3272 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java @@ -0,0 +1,205 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transactionlog; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.store.StoreContext; + +/** + * TransactionLog defines the interface for performing transactions. + * This is used to preserve the state of messages, queues + * and exchanges in a transactional manner. + * + *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which + * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single + * transaction. + * + *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. + * + *

      + *
      CRC Card
      Responsibilities + *
      Accept transaction boundary demarcations: Begin, Commit, Abort. + *
      Store and remove queues. + *
      Store and remove exchanges. + *
      Store and remove messages. + *
      Bind and unbind queues to exchanges. + *
      Enqueue and dequeue messages to queues. + *
      Generate message identifiers. + *
      + */ +public interface TransactionLog +{ + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param base The base element identifier from which all configuration items are relative. For example, if + * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws Exception If the close fails. + */ + void close() throws Exception; + + /** + * Removes the specified message from the store in the given transactional store context. + * + * @param storeContext The transactional context to remove the message in. + * @param messageId Identifies the message to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + + + + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param queue The queue to place the message on. + * @param messageId The message to enqueue. + * @throws AMQException If the operation fails for any reason. + */ + void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param queue The queue to place the message on. + * @param messageId The message to dequeue. + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + + /** + * Begins a transactional context. + * + * @param context The transactional context to begin. + * + * @throws AMQException If the operation fails for any reason. + */ + void beginTran(StoreContext context) throws AMQException; + + /** + * Commits all operations performed within a given transactional context. + * + * @param context The transactional context to commit all operations for. + * + * @throws AMQException If the operation fails for any reason. + */ + void commitTran(StoreContext context) throws AMQException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @param context The transactional context to abandon. + * + * @throws AMQException If the operation fails for any reason. + */ + void abortTran(StoreContext context) throws AMQException; + + /** + * Tests a transactional context to see if it has been begun but not yet committed or aborted. + * + * @param context The transactional context to test. + * + * @return true if the transactional context is live, false otherwise. + */ + boolean inTran(StoreContext context); + + + /** + * Stores a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param index The index of the data chunk. + * @param contentBody The content of the data chunk. + * @param lastContentBody Flag to indicate that this is the last such chunk for the message. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, + boolean lastContentBody) throws AMQException; + + /** + * Stores message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param messageMetaData The message meta data to store. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; + + /** + * Retrieves message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the meta-data for. + * + * @return The message meta data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; + + /** + * Retrieves a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the data chunk for. + * @param index The offset index of the data chunk within the message. + * + * @return A chunk of message data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; + + /** + * Is this store capable of persisting the data + * + * @return true if this store is capable of persisting data + */ + boolean isPersistent(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 3c71282c57..9bc2e98fe9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -25,11 +25,11 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.transactionlog.TransactionLog; import org.apache.qpid.server.ack.TxAck; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; import java.util.List; @@ -56,7 +56,6 @@ public class LocalTransactionalContext implements TransactionalContext private boolean _messageDelivered = false; private final AMQChannel _channel; - private abstract class DeliveryAction { @@ -125,9 +124,9 @@ public class LocalTransactionalContext implements TransactionalContext return _channel.getReturnMessages(); } - public MessageStore getMessageStore() + public TransactionLog getTransactionLog() { - return _channel.getMessageStore(); + return _channel.getTransactionLog(); } @@ -135,9 +134,9 @@ public class LocalTransactionalContext implements TransactionalContext { _txnBuffer.rollback(getStoreContext()); // Hack to deal with uncommitted non-transactional writes - if (getMessageStore().inTran(getStoreContext())) + if (getTransactionLog().inTran(getStoreContext())) { - getMessageStore().abortTran(getStoreContext()); + getTransactionLog().abortTran(getStoreContext()); _inTran = false; } @@ -224,7 +223,7 @@ public class LocalTransactionalContext implements TransactionalContext _log.debug("Starting transaction on message store: " + this); } - getMessageStore().beginTran(getStoreContext()); + getTransactionLog().beginTran(getStoreContext()); _inTran = true; } } @@ -247,7 +246,7 @@ public class LocalTransactionalContext implements TransactionalContext if (_messageDelivered && _inTran) { - _txnBuffer.enlist(new StoreMessageOperation(getMessageStore())); + _txnBuffer.enlist(new StoreMessageOperation(getTransactionLog())); } // fixme fail commit here ... QPID-440 try @@ -257,7 +256,7 @@ public class LocalTransactionalContext implements TransactionalContext finally { _messageDelivered = false; - _inTran = getMessageStore().inTran(getStoreContext()); + _inTran = getTransactionLog().inTran(getStoreContext()); } try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index acb2e93818..145d7f8b13 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -26,10 +26,10 @@ 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.transactionlog.TransactionLog; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; /** @author Apache Software Foundation */ @@ -45,20 +45,20 @@ public class NonTransactionalContext implements TransactionalContext - private final MessageStore _messageStore; + private final TransactionLog _transactionLog; private final StoreContext _storeContext; /** Whether we are in a transaction */ private boolean _inTran; - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, + public NonTransactionalContext(TransactionLog transactionLog, StoreContext storeContext, AMQChannel channel, List returnMessages) { _channel = channel; _storeContext = storeContext; _returnMessages = returnMessages; - _messageStore = messageStore; + _transactionLog = transactionLog; } @@ -72,7 +72,7 @@ public class NonTransactionalContext implements TransactionalContext { if (!_inTran) { - _messageStore.beginTran(_storeContext); + _transactionLog.beginTran(_storeContext); _inTran = true; } } @@ -191,7 +191,7 @@ public class NonTransactionalContext implements TransactionalContext } if(_inTran) { - _messageStore.commitTran(_storeContext); + _transactionLog.commitTran(_storeContext); _inTran = false; } } @@ -200,7 +200,7 @@ public class NonTransactionalContext implements TransactionalContext { if (persistent) { - _messageStore.commitTran(_storeContext); + _transactionLog.commitTran(_storeContext); _inTran = false; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java index 0e4d6c2030..f1fbca2e28 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java @@ -21,8 +21,8 @@ package org.apache.qpid.server.txn; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.transactionlog.TransactionLog; /** * A transactional operation to store messages in an underlying persistent store. When this operation @@ -31,11 +31,11 @@ import org.apache.qpid.server.store.StoreContext; */ public class StoreMessageOperation implements TxnOp { - private final MessageStore _messsageStore; + private final TransactionLog _transactionLog; - public StoreMessageOperation(MessageStore messageStore) + public StoreMessageOperation(TransactionLog transactionLog) { - _messsageStore = messageStore; + _transactionLog = transactionLog; } public void prepare(StoreContext context) throws AMQException @@ -48,11 +48,11 @@ public class StoreMessageOperation implements TxnOp public void commit(StoreContext context) throws AMQException { - _messsageStore.commitTran(context); + _transactionLog.commitTran(context); } public void rollback(StoreContext context) throws AMQException { - _messsageStore.abortTran(context); + _transactionLog.abortTran(context); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index de4c8ac1ff..1497b4adb8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -30,6 +30,8 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.routing.RoutingTable; +import org.apache.qpid.server.transactionlog.TransactionLog; import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; @@ -45,10 +47,8 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.access.plugins.SimpleXML; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.store.MessageStore; public class VirtualHost implements Accessable { @@ -65,7 +65,9 @@ public class VirtualHost implements Accessable private ExchangeFactory _exchangeFactory; - private MessageStore _messageStore; + private TransactionLog _transactionLog; + + private RoutingTable _routingTable; protected VirtualHostMBean _virtualHostMBean; @@ -96,6 +98,11 @@ public class VirtualHost implements Accessable return _connectionRegistry; } + public RoutingTable getRoutingTable() + { + return _routingTable; + } + /** * 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. @@ -128,12 +135,12 @@ public class VirtualHost implements Accessable /** * Used for testing only * @param name - * @param store + * @param transactionLog * @throws Exception */ - public VirtualHost(String name, MessageStore store) throws Exception + public VirtualHost(String name, TransactionLog transactionLog) throws Exception { - this(name, new PropertiesConfiguration(), store); + this(name, new PropertiesConfiguration(), transactionLog); } /** @@ -147,7 +154,7 @@ public class VirtualHost implements Accessable this(name, hostConfig, null); } - public VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception + public VirtualHost(String name, Configuration hostConfig, TransactionLog transactionLog) throws Exception { if (name == null || name.length() == 0) { @@ -166,19 +173,26 @@ public class VirtualHost implements Accessable _exchangeFactory.initialise(hostConfig); _exchangeRegistry = new DefaultExchangeRegistry(this); - if (store != null) + if (transactionLog != null) { - _messageStore = store; + _transactionLog = transactionLog; + if (_transactionLog instanceof RoutingTable) + { + _routingTable = (RoutingTable) _transactionLog; + } } else { if (hostConfig == null) { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + throw new IllegalAccessException("HostConfig and TransactionLog cannot be null"); } - initialiseMessageStore(hostConfig); + initialiseTransactionLog(hostConfig); + initialiseRoutingTable(hostConfig); } + + _exchangeRegistry.initialise(); _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); @@ -224,23 +238,52 @@ public class VirtualHost implements Accessable period); } } - - private void initialiseMessageStore(Configuration config) throws Exception + + //todo we need to move from store.class to transactionlog.class + private void initialiseTransactionLog(Configuration config) throws Exception { - String messageStoreClass = config.getString("store.class"); + String transactionLogClass = config.getString("store.class"); - Class clazz = Class.forName(messageStoreClass); + Class clazz = Class.forName(transactionLogClass); Object o = clazz.newInstance(); - if (!(o instanceof MessageStore)) + if (!(o instanceof TransactionLog)) { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + throw new ClassCastException("TransactionLog class must implement " + TransactionLog.class + ". Class " + clazz + " does not."); } - _messageStore = (MessageStore) o; - _messageStore.configure(this, "store", config); + _transactionLog = (TransactionLog) o; + _transactionLog.configure(this, "store", config); } + //todo we need to move from store.class to transactionlog.class + private void initialiseRoutingTable(Configuration config) throws Exception + { + String transactionLogClass = config.getString("routingtable.class"); + + if (transactionLogClass != null) + { + Class clazz = Class.forName(transactionLogClass); + Object o = clazz.newInstance(); + + if (!(o instanceof RoutingTable)) + { + throw new ClassCastException("RoutingTable class must implement " + RoutingTable.class + ". Class " + clazz + + " does not."); + } + _routingTable = (RoutingTable) o; + _routingTable.configure(this, "routingtable", config); + } + else + { + if (_transactionLog instanceof RoutingTable) + { + _routingTable = (RoutingTable)_transactionLog; + } + } + } + + public T getConfiguredObject(Class instanceType, Configuration config) { @@ -284,9 +327,9 @@ public class VirtualHost implements Accessable throw new UnsupportedOperationException(); } - public MessageStore getMessageStore() + public TransactionLog getTransactionLog() { - return _messageStore; + return _transactionLog; } public AuthenticationManager getAuthenticationManager() @@ -320,10 +363,10 @@ public class VirtualHost implements Accessable _houseKeepingTimer.cancel(); } - //Close MessageStore - if (_messageStore != null) + //Close TransactionLog + if (_transactionLog != null) { - _messageStore.close(); + _transactionLog.close(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java index faa7b85d58..a6e060e793 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -302,7 +302,7 @@ public class MessageStoreTool boolean warning = false; for (VirtualHost vhost : vhosts) { - if (vhost.getMessageStore() instanceof MemoryMessageStore) + if (vhost.getTransactionLog() instanceof MemoryMessageStore) { _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " + "Changes will not persist."); -- cgit v1.2.1 From d829b858fe0242caa9cf430b108c619360058262 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 19 Feb 2009 10:03:18 +0000 Subject: QPID-1621: add ServerConfiguration, QueueConfiguration and SecurityConfiguration classes. Move almost all uses of o.a.commons.configuration.Configuration behind there. @Configured delenda est git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@745799 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../java/org/apache/qpid/server/AMQChannel.java | 25 +- .../src/main/java/org/apache/qpid/server/Main.java | 158 +++----- .../qpid/server/configuration/Configurator.java | 118 ------ .../configuration/ExchangeConfiguration.java | 58 +++ .../server/configuration/QueueConfiguration.java | 106 ++++++ .../configuration/SecurityConfiguration.java | 41 +++ .../server/configuration/ServerConfiguration.java | 405 +++++++++++++++++++++ .../configuration/VirtualHostConfiguration.java | 287 ++++----------- .../server/exchange/DefaultExchangeFactory.java | 7 +- .../qpid/server/exchange/ExchangeFactory.java | 3 +- .../handler/ConnectionSecureOkMethodHandler.java | 12 +- .../handler/ConnectionStartOkMethodHandler.java | 21 +- .../qpid/server/handler/QueueDeclareHandler.java | 26 +- .../management/JMXManagedObjectRegistry.java | 30 +- .../server/management/ManagementConfiguration.java | 30 -- .../server/protocol/AMQMinaProtocolSession.java | 2 +- .../server/protocol/AMQPFastProtocolHandler.java | 60 +-- .../qpid/server/protocol/HeartbeatConfig.java | 67 ---- .../org/apache/qpid/server/queue/AMQQueue.java | 8 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 58 +-- .../qpid/server/queue/AsyncDeliveryConfig.java | 56 --- .../apache/qpid/server/queue/IncomingMessage.java | 4 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 69 ++-- .../qpid/server/registry/ApplicationRegistry.java | 54 +-- .../ConfigurationFileApplicationRegistry.java | 75 +--- .../qpid/server/registry/IApplicationRegistry.java | 15 +- .../apache/qpid/server/routing/RoutingTable.java | 3 +- .../qpid/server/security/access/ACLManager.java | 14 +- .../ConfigurationFilePrincipalDatabaseManager.java | 33 +- .../auth/database/PrincipalDatabaseManager.java | 3 +- .../PropertiesPrincipalDatabaseManager.java | 6 +- .../PrincipalDatabaseAuthenticationManager.java | 15 +- .../qpid/server/store/DerbyMessageStore.java | 5 +- .../qpid/server/store/MemoryMessageStore.java | 7 +- .../qpid/server/transactionlog/TransactionLog.java | 3 +- .../server/transport/ConnectorConfiguration.java | 118 ------ .../qpid/server/util/NullApplicationRegistry.java | 18 +- .../qpid/server/virtualhost/VirtualHost.java | 165 ++++++--- 39 files changed, 1080 insertions(+), 1107 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index b3c843ebaa..7216841a94 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -52,9 +52,9 @@ import org.apache.qpid.server.management.MBeanConstructor; import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.transactionlog.TransactionLog; import org.apache.qpid.server.routing.RoutingTable; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 2d0589c223..bb7331e5f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,6 +20,14 @@ */ package org.apache.qpid.server; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -29,12 +37,12 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; -import org.apache.qpid.server.configuration.Configurator; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.QueueEntry; @@ -45,19 +53,15 @@ import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; import org.apache.qpid.server.subscription.RecordDeliveryMethod; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.transactionlog.TransactionLog; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.concurrent.atomic.AtomicBoolean; - public class AMQChannel { public static final int DEFAULT_PREFETCH = 5000; @@ -114,9 +118,6 @@ public class AMQChannel public AMQChannel(AMQProtocolSession session, int channelId, TransactionLog transactionLog) throws AMQException { - //Set values from configuration - Configurator.configure(this); - _session = session; _channelId = channelId; _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index f3b54034e7..780a17940e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,6 +20,12 @@ */ package org.apache.qpid.server; +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -27,36 +33,23 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoAcceptor; import org.apache.mina.common.FixedSizeByteBufferAllocator; +import org.apache.mina.common.IoAcceptor; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; -import org.apache.qpid.AMQException; +import org.apache.mina.util.NewThreadExecutor; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; +import org.apache.qpid.server.configuration.ServerConfiguration; 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.transport.ConnectorConfiguration; -import org.apache.qpid.url.URLSyntaxException; - -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.List; /** * Main entry point for AMQPD. @@ -200,13 +193,6 @@ public class Main _brokerLogger.error("Initialisation Error : " + e.getMessage()); shutdown(1); } - catch (ConfigurationException e) - { - System.out.println("Error configuring message broker: " + e); - _brokerLogger.error("Error configuring message broker: " + e); - e.printStackTrace(); - shutdown(1); - } catch (Throwable e) { System.out.println("Error initialising message broker: " + e); @@ -223,7 +209,7 @@ public class Main System.exit(status); } - protected void startup() throws InitException, ConfigurationException, Exception + protected void startup() throws Exception { final String QpidHome = System.getProperty(QPID_HOME); final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE); @@ -259,40 +245,32 @@ public class Main } ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); - - - updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m")); - - + ServerConfiguration serverConfig = config.getConfiguration(); + updateManagementPort(serverConfig, commandLine.getOptionValue("m")); ApplicationRegistry.initialise(config); - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say // Starting Qpid Client _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - ConnectorConfiguration connectorConfig = - ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); - - ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); + ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); // 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) + if (!serverConfig.getEnablePooledAllocator()) { ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); } - - if(connectorConfig.useBiasedWrites) + if(serverConfig.getUseBiasedWrites()) { System.setProperty("org.apache.qpid.use_write_biased_pool","true"); } - int port = connectorConfig.port; + int port = serverConfig.getPort(); String portStr = commandLine.getOptionValue("p"); if (portStr != null) @@ -306,29 +284,8 @@ public class Main throw new InitException("Invalid port: " + portStr, e); } } - - 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); - + + bind(port, serverConfig); } /** @@ -336,86 +293,59 @@ public class Main * @param configuration * @param managementPort The string from the command line */ - private void updateManagementPort(Configuration configuration, String managementPort) + private void updateManagementPort(ServerConfiguration configuration, String managementPort) { if (managementPort != null) { - int mport; - int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH); try { - mport = Integer.parseInt(managementPort); - configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport); + configuration.setJMXManagementPort(Integer.parseInt(managementPort)); } catch (NumberFormatException e) { - _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e); + _logger.warn("Invalid management port: " + managementPort + " will use:" + configuration.getJMXManagementPort(), e); } } } - 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) throws BindException + protected void bind(int port, ServerConfiguration config) throws BindException { String bindAddr = commandLine.getOptionValue("b"); if (bindAddr == null) { - bindAddr = connectorConfig.bindAddress; + bindAddr = config.getBind(); } try { - // IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); - IoAcceptor acceptor = connectorConfig.createAcceptor(); + IoAcceptor acceptor; + + if (ApplicationRegistry.getInstance().getConfiguration().getQpidNIO()) + { + _logger.warn("Using Qpid Multithreaded IO Processing"); + acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(config.getProcessors(), new NewThreadExecutor()); + } + else + { + _logger.warn("Using Mina IO Processing"); + acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(config.getProcessors(), new NewThreadExecutor()); + } + SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); - sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); - sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); - sc.setTcpNoDelay(connectorConfig.tcpNoDelay); + sc.setReceiveBufferSize(config.getReceiveBufferSize()); + sc.setSendBufferSize(config.getWriteBufferSize()); + sc.setTcpNoDelay(config.getTcpNoDelay()); // if we do not use the executor pool threading model we get the default leader follower // implementation provided by MINA - if (connectorConfig.enableExecutorPool) + if (config.getEnableExecutorPool()) { sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } - if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) + if (!config.getEnableSSL() || !config.getSSLOnly()) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); InetSocketAddress bindAddress; @@ -434,16 +364,16 @@ public class Main _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } - if (connectorConfig.enableSSL) + if (config.getEnableSSL()) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); try { - bind(acceptor, new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); + bind(acceptor, new InetSocketAddress(config.getSSLPort()), handler, sconfig); //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); + _brokerLogger.info("Qpid.AMQP listening on SSL port " + config.getSSLPort()); } catch (IOException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java deleted file mode 100644 index 31c1b61a21..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import java.lang.reflect.Field; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.configuration.PropertyException; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.server.registry.ApplicationRegistry; - -/** - * This class contains utilities for populating classes automatically from values pulled from configuration - * files. - */ -public class Configurator -{ - private static final Logger _logger = Logger.getLogger(Configurator.class); - - - /** - * Configure a given instance using the supplied configuration. Note that superclasses are not - * currently configured but this could easily be added if required. - * @param instance the instance to configure - * @param config the configuration to use to configure the object - */ - public static void configure(Object instance, Configuration config) - { - - for (Field f : instance.getClass().getDeclaredFields()) - { - Configured annotation = f.getAnnotation(Configured.class); - if (annotation != null) - { - setValueInField(f, instance, config, annotation); - } - } - } - - - - /** - * Configure a given instance using the application configuration. Note that superclasses are not - * currently configured but this could easily be added if required. - * @param instance the instance to configure - */ - public static void configure(Object instance) - { - configure(instance, ApplicationRegistry.getInstance().getConfiguration()); - } - - private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) - { - Class fieldClass = f.getType(); - String configPath = annotation.path(); - try - { - if (fieldClass == String.class) - { - String val = config.getString(configPath, annotation.defaultValue()); - val = PropertyUtils.replaceProperties(val); - f.set(instance, val); - } - else if (fieldClass == int.class) - { - int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue())); - f.setInt(instance, val); - } - else if (fieldClass == long.class) - { - long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue())); - f.setLong(instance, val); - } - else if (fieldClass == double.class) - { - double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue())); - f.setDouble(instance, val); - } - else if (fieldClass == boolean.class) - { - boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue())); - f.setBoolean(instance, val); - } - else - { - _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value"); - } - } - catch (PropertyException e) - { - _logger.error("Unable to expand property: " + e + " INGORING field " + f, e); - } - catch (IllegalAccessException e) - { - _logger.error("Unable to access field " + f + " IGNORING configured value"); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java new file mode 100644 index 0000000000..c7cf0c0892 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; + + +public class ExchangeConfiguration +{ + + private Configuration _config; + private String _name; + + public ExchangeConfiguration(String exchName, Configuration subset) + { + _name = exchName; + _config = subset; + } + + public String getName() + { + return _name; + } + + public String getType() + { + return _config.getString("type","direct"); + } + + public boolean getDurable() + { + return _config.getBoolean("durable", false); + } + + public boolean getAutoDelete() + { + return _config.getBoolean("autodelete",false); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java new file mode 100644 index 0000000000..90d6caec99 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -0,0 +1,106 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import java.util.List; + +import org.apache.commons.configuration.Configuration; + +public class QueueConfiguration +{ + + // FIXME AIDAN XXX -- deal with defaults + + private Configuration _config; + private String _name; + + public QueueConfiguration(String name, Configuration config) + { + _config = config; + _name = name; + } + + public boolean getDurable() + { + return _config.getBoolean("durable" ,false); + } + + public boolean getAutoDelete() + { + return _config.getBoolean("autodelete", false); + } + + public String getOwner() + { + return _config.getString("owner", null); + } + + public boolean getPriority() + { + return _config.getBoolean("priority", false); + } + + public int getPriorities() + { + return _config.getInt("priorities", -1); + } + + public String getExchange() + { + return _config.getString("exchange", null); + } + + public List getRoutingKeys() + { + return _config.getList("routingKey"); + } + + public String getName() + { + return _name; + } + + public long getMaximumMessageAge() + { + return _config.getLong("maximumMessageAge", 0); + } + + public long getMaximumQueueDepth() + { + return _config.getLong("maximumQueueDepth", 0); + } + + public long getMaximumMessageSize() + { + return _config.getLong("maximumMessageSize", 0); + } + + public long getMaximumMessageCount() + { + return _config.getLong("maximumMessageCount", 0); + } + + public long getMinimumAlertRepeatGap() + { + return _config.getLong("minimumAlertRepeatGap", 0); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java new file mode 100644 index 0000000000..5d080f8df1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; + +public class SecurityConfiguration +{ + + private Configuration _conf; + + public SecurityConfiguration(Configuration configuration) + { + _conf = configuration; + } + + public Configuration getConfiguration() + { + return _conf; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java new file mode 100644 index 0000000000..225042e9ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import 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; + +public class ServerConfiguration +{ + + private static Configuration _config; + + private static final int DEFAULT_FRAME_SIZE = 65536; + private static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; + private static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; + private static final int DEFAULT_PORT = 5672; + private static final int DEFAUL_SSL_PORT = 8672; + private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; + private static final int DEFAULT_JMXPORT = 8999; + + private long _housekeepingExpiredMessageCheckPeriod = DEFAULT_HOUSEKEEPING_PERIOD; + private static int _jmxPort = DEFAULT_JMXPORT; + + private Map _virtualHosts = new HashMap(); + private SecurityConfiguration _securityConfiguration = null; + + public ServerConfiguration(File configurationURL) throws ConfigurationException + { + this(config(configurationURL)); + } + + public ServerConfiguration(Configuration conf) throws ConfigurationException + { + _config = conf; + _jmxPort = _config.getInt("management.jmxport", 8999); + + _securityConfiguration = new SecurityConfiguration(conf.subset("security")); + + List vhosts = conf.getList("virtualhosts"); + Iterator i = vhosts.iterator(); + while (i.hasNext()) + { + Object thing = i.next(); + if (thing instanceof String) + { + XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); + List hosts = vhostConfiguration.getList("virtualhost.name"); + for (int j = 0; j < hosts.size(); j++) + { + String name = (String) hosts.get(j); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(conf.subset("virtualhosts.virtualhost."+name)); + mungedConf.addConfiguration(vhostConfiguration.subset("virtualhost." + name)); + VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, mungedConf); + _virtualHosts.put(vhostConfig.getName(), vhostConfig); + } + } + } + } + + public static String[] objListToStringArray(List objList) + { + String[] networkStrings = new String[objList.size()]; + int i = 0; + for (Object network : objList) + { + networkStrings[i++] = (String) network; + } + return networkStrings; + } + + // 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 final static 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 setJMXManagementPort(int mport) + { + _jmxPort = mport; + } + + public int getJMXManagementPort() + { + return _jmxPort; + } + + public boolean getPlatformMbeanserver() + { + return _config.getBoolean("management.platform-mbeanserver", true); + } + + public String[] getVirtualHosts() + { + return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); + } + + public String getPluginDirectory() + { + return _config.getString("plugin-directory"); + } + + public VirtualHostConfiguration getVirtualHostConfig(String name) + { + return _virtualHosts.get(name); + } + + public List getPrincipalDatabaseNames() + { + return _config.getList("security.principal-databases.principal-database.name"); + } + + public List getPrincipalDatabaseClass() + { + return _config.getList("security.principal-databases.principal-database.class"); + } + + public List getPrincipalDatabaseAttributeNames(int index) + { + String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name"; + return _config.getList(name); + } + + public List getPrincipalDatabaseAttributeValues(int index) + { + String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value"; + return _config.getList(name); + } + + public List getManagementPrincipalDBs() + { + return _config.getList("security.jmx.principal-database"); + } + + public List getManagementAccessList() + { + return _config.getList("security.jmx.access"); + } + + public int getFrameSize() + { + return _config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + } + + public boolean getManagementSecurityEnabled() + { + return _config.getBoolean("management.security-enabled", false); + } + + public boolean getProtectIOEnabled() + { + return _config.getBoolean("broker.connector.protectio.enabled", false); + } + + public int getBufferReadLimit() + { + return _config.getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); + } + + public int getBufferWriteLimit() + { + return _config.getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); + } + + public boolean getSynchedClocks() + { + return _config.getBoolean("advanced.synced-clocks", false); + } + + public boolean getMsgAuth() + { + return _config.getBoolean("security.msg-auth", false); + } + + public String getJMXPrincipalDatabase() + { + return _config.getString("security.jmx.principal-database"); + } + + public String getManagementKeyStorePath() + { + return _config.getString("management.ssl.keyStorePath", null); + } + + public boolean getManagementSSLEnabled() + { + return _config.getBoolean("management.ssl.enabled", true); + } + + public String getManagementKeyStorePassword() + { + return _config.getString("management.ssl.keyStorePassword"); + } + + public SecurityConfiguration getSecurityConfiguration() + { + return _securityConfiguration; + } + + public boolean getQueueAutoRegister() + { + return _config.getBoolean("queue.auto_register", true); + } + + public boolean getManagementEnabled() + { + return _config.getBoolean("management.enabled", true); + } + + public int getHeartBeatDelay() + { + return _config.getInt("heartbeat.delay", 5); + } + + public double getHeartBeatTimeout() + { + return _config.getDouble("heartbeat.timeoutFactor", 2.0); + } + + public int getDeliveryPoolSize() + { + return _config.getInt("delivery.poolsize", 0); + } + + public long getMaximumMessageAge() + { + return _config.getLong("maximumMessageAge", 0); + } + + public long getMaximumMessageCount() + { + return _config.getLong("maximumMessageCount", 0); + } + + public long getMaximumQueueDepth() + { + return _config.getLong("maximumQueueDepth", 0); + } + + public long getMaximumMessageSize() + { + return _config.getLong("maximumMessageSize", 0); + } + + public long getMinimumAlertRepeatGap() + { + return _config.getLong("minimumAlertRepeatGap", 0); + } + + public int getProcessors() + { + return _config.getInt("connector.processors", 4); + } + + public int getPort() + { + return _config.getInt("connector.port", DEFAULT_PORT); + } + + public String getBind() + { + return _config.getString("connector.bind", "wildcard"); + } + + public int getReceiveBufferSize() + { + return _config.getInt("connector.socketReceiveBuffer", 32767); + } + + public int getWriteBufferSize() + { + return _config.getInt("connector.socketWriteBuffer", 32767); + } + + public boolean getTcpNoDelay() + { + return _config.getBoolean("connector.tcpNoDelay", true); + } + + public boolean getEnableExecutorPool() + { + return _config.getBoolean("advanced.filterchain[@enableExecutorPool]", false); + } + + public boolean getEnablePooledAllocator() + { + return _config.getBoolean("advanced.enablePooledAllocator", false); + } + + public boolean getEnableDirectBuffers() + { + return _config.getBoolean("advanced.enableDirectBuffers", false); + } + + public boolean getEnableSSL() + { + return _config.getBoolean("connector.ssl.enabled", false); + } + + public boolean getSSLOnly() + { + return _config.getBoolean("connector.ssl.sslOnly", true); + } + + public int getSSLPort() + { + return _config.getInt("connector.ssl.port", DEFAUL_SSL_PORT); + } + + public String getKeystorePath() + { + return _config.getString("connector.ssl.keystorePath", "none"); + } + + public String getKeystorePassword() + { + return _config.getString("connector.ssl.keystorePassword", "none"); + } + + public String getCertType() + { + return _config.getString("connector.ssl.certType", "SunX509"); + } + + public boolean getQpidNIO() + { + return _config.getBoolean("connector.qpidnio", false); + } + + public boolean getUseBiasedWrites() + { + return _config.getBoolean("advanced.useWriteBiasedPool", false); + } + + public String getDefaultVirtualHost() + { + return _config.getString("virtualhosts.default"); + } + + public void setHousekeepingExpiredMessageCheckPeriod(long _housekeepingExpiredMessageCheckPeriod) + { + this._housekeepingExpiredMessageCheckPeriod = _housekeepingExpiredMessageCheckPeriod; + } + + public long getHousekeepingExpiredMessageCheckPeriod() + { + return _housekeepingExpiredMessageCheckPeriod; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 02fb57c730..91d0b8d8da 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -20,266 +20,111 @@ */ package org.apache.qpid.server.configuration; -import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.routing.RoutingTable; +import org.apache.qpid.server.store.MemoryMessageStore; public class VirtualHostConfiguration { - private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); + private Configuration _config; + private String _name; + private Map _queues = new HashMap(); + private Map _exchanges = new HashMap(); - private static XMLConfiguration _config; - private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost."; - - - public VirtualHostConfiguration(String configFile) throws ConfigurationException + public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException { - _logger.info("Loading Config file:" + configFile); - - _config = new XMLConfiguration(configFile); - - } - - - - private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException - { - _logger.debug("Loding configuration for virtaulhost: "+virtualHostName); - - - VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName); + _config = config; + _name = name; + Iterator i = _config.getList("queues.queue.name").iterator(); - - if(virtualHost == null) - { - throw new ConfigurationException("Unknown virtual host: " + virtualHostName); - } - - List exchangeNames = configuration.getList("exchanges.exchange.name"); - - for(Object exchangeNameObj : exchangeNames) + while (i.hasNext()) { - String exchangeName = String.valueOf(exchangeNameObj); - configureExchange(virtualHost, exchangeName, configuration); + String queueName = (String) i.next(); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); + mungedConf.addConfiguration(_config.subset("queues")); + _queues.put(queueName, new QueueConfiguration(queueName, mungedConf)); } - - List queueNames = configuration.getList("queues.queue.name"); - - for(Object queueNameObj : queueNames) + i = _config.getList("exchanges.exchange.name").iterator(); + int count = 0; + while (i.hasNext()) { - String queueName = String.valueOf(queueNameObj); - configureQueue(virtualHost, queueName, configuration); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); + mungedConf.addConfiguration(_config.subset("exchanges")); + String exchName = (String) i.next(); + _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); } - } - private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) throws AMQException + public String getName() { - - CompositeConfiguration exchangeConfiguration = new CompositeConfiguration(); - - exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString)); - exchangeConfiguration.addConfiguration(configuration.subset("exchanges")); - - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); - - AMQShortString exchangeName = new AMQShortString(exchangeNameString); - - - Exchange exchange; - - - - synchronized (exchangeRegistry) - { - exchange = exchangeRegistry.getExchange(exchangeName); - if(exchange == null) - { - - AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type","direct")); - boolean durable = exchangeConfiguration.getBoolean("durable",false); - boolean autodelete = exchangeConfiguration.getBoolean("autodelete",false); - - Exchange newExchange = exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); - exchangeRegistry.registerExchange(newExchange); - } - - } + return _name; } - public static CompositeConfiguration getDefaultQueueConfiguration(VirtualHost host) + public long getHousekeepingExpiredMessageCheckPeriod() { - CompositeConfiguration queueConfiguration = null; - if (_config == null) - return null; - - Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + host.getName()); - - if (vHostConfiguration == null) - return null; - - Configuration defaultQueueConfiguration = vHostConfiguration.subset("queues"); - if (defaultQueueConfiguration != null) - { - queueConfiguration = new CompositeConfiguration(); - queueConfiguration.addConfiguration(defaultQueueConfiguration); - } - - return queueConfiguration; + return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingExpiredMessageCheckPeriod()); } - private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException + public String getAuthenticationDatabase() { - CompositeConfiguration queueConfiguration = new CompositeConfiguration(); - - queueConfiguration.addConfiguration(configuration.subset("queues.queue."+ queueNameString)); - queueConfiguration.addConfiguration(configuration.subset("queues")); - - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - RoutingTable routingTable = virtualHost.getRoutingTable(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - - - AMQShortString queueName = new AMQShortString(queueNameString); - - AMQQueue queue; - - synchronized (queueRegistry) - { - queue = queueRegistry.getQueue(queueName); - - if (queue == null) - { - _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName()); - - boolean durable = queueConfiguration.getBoolean("durable" ,false); - boolean autodelete = queueConfiguration.getBoolean("autodelete", false); - String owner = queueConfiguration.getString("owner", null); - FieldTable arguments = null; - boolean priority = queueConfiguration.getBoolean("priority", false); - int priorities = queueConfiguration.getInt("priorities", -1); - if(priority || priorities > 0) - { - if(arguments == null) - { - arguments = new FieldTable(); - } - if (priorities < 0) - { - priorities = 10; - } - arguments.put(new AMQShortString("x-qpid-priorities"), priorities); - } - - - queue = AMQQueueFactory.createAMQQueueImpl(queueName, - durable, - owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */, - autodelete /* Therefore autodelete makes no sence */, - virtualHost, - arguments, - queueConfiguration); - - if (queue.isDurable()) - { - routingTable.createQueue(queue); - } - - queueRegistry.registerQueue(queue); - } - else - { - _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating."); - } - - String exchangeName = queueConfiguration.getString("exchange", null); - - Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - - if(exchange == null) - { - exchange = virtualHost.getExchangeRegistry().getDefaultExchange(); - } - - if (exchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); - } - - synchronized (exchange) - { - List routingKeys = queueConfiguration.getList("routingKey"); - if(routingKeys == null || routingKeys.isEmpty()) - { - routingKeys = Collections.singletonList(queue.getName()); - } - - for(Object routingKeyNameObj : routingKeys) - { - AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - - - queue.bind(exchange, routingKey, null); - + return _config.getString("security.authentication.name"); + } - _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); - } + public List getCustomExchanges() + { + return _config.getList("custom-exchanges.class-name"); + } - if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange()) - { - queue.bind(virtualHost.getExchangeRegistry().getDefaultExchange(), queue.getName(), null); - } - } + public SecurityConfiguration getSecurityConfiguration() + { + return new SecurityConfiguration(_config.subset("security")); + } - } + public Configuration getStoreConfiguration() + { + return _config.subset("store"); } + public String getRoutingTableClass() + { + return _config.getString("routingtable.class"); + } - public void performBindings() throws AMQException, ConfigurationException + public String getTransactionLogClass() { - List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name"); - String defaultVirtualHostName = _config.getString("default"); - if(defaultVirtualHostName != null) - { - ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName); - } - _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames); + return _config.getString("store.class", MemoryMessageStore.class.getName()); + } - for(Object nameObject : virtualHostNames) - { - String name = String.valueOf(nameObject); - configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name)); - } + public List getExchanges() + { + return _config.getList("exchanges.exchange.name"); + } - if (virtualHostNames == null || virtualHostNames.isEmpty()) - { - throw new ConfigurationException( - "Virtualhost Configuration document does not contain a valid virtualhost."); - } + public ExchangeConfiguration getExchangeConfiguration(String exchangeName) + { + return _exchanges.get(exchangeName); } + public String[] getQueueNames() + { + return _queues.keySet().toArray(new String[_queues.size()]); + } + public QueueConfiguration getQueueConfiguration(String queueName) + { + return _queues.get(queueName); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 9d4c090971..c04b6c559c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -25,11 +25,11 @@ import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -73,7 +73,8 @@ public class DefaultExchangeFactory implements ExchangeFactory return e; } - public void initialise(Configuration hostConfig) + @Override + public void initialise(VirtualHostConfiguration hostConfig) { if (hostConfig == null) @@ -81,7 +82,7 @@ public class DefaultExchangeFactory implements ExchangeFactory return; } - for(Object className : hostConfig.getList("custom-exchanges.class-name")) + for(Object className : hostConfig.getCustomExchanges()) { try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index 0bcfec7181..2f76d41228 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -26,6 +26,7 @@ import org.apache.commons.configuration.Configuration; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; public interface ExchangeFactory @@ -34,7 +35,7 @@ public interface ExchangeFactory int ticket) throws AMQException; - void initialise(Configuration hostConfig); + void initialise(VirtualHostConfiguration hostConfig); Collection> getRegisteredTypes(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index 621003be90..a2a6faf21b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -25,14 +25,16 @@ import javax.security.sasl.SaslServer; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionSecureOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; +import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; @@ -92,7 +94,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, ConnectionStartOkMethodHandler.getConfiguredFrameSize(), - HeartbeatConfig.getInstance().getDelay()); + ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); disposeSaslServer(session); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index f53e56601b..6698ae888a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -23,18 +23,19 @@ package org.apache.qpid.server.handler; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; -import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionStartOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; +import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; @@ -47,8 +48,6 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler(); - private static final int DEFAULT_FRAME_SIZE = 65536; - public static ConnectionStartOkMethodHandler getInstance() { return _instance; @@ -117,7 +116,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, getConfiguredFrameSize(), - HeartbeatConfig.getInstance().getDelay()); + ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); break; case CONTINUE: @@ -153,8 +152,8 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< static int getConfiguredFrameSize() { - final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - final int framesize = config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + final ServerConfiguration config = ApplicationRegistry.getInstance().getConfiguration(); + final int framesize = config.getFrameSize(); _logger.info("Framesize set to " + framesize); return framesize; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index b1e02aef7a..7f500cfb8a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -20,27 +20,28 @@ */ package org.apache.qpid.server.handler; -import java.util.concurrent.atomic.AtomicInteger; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; - -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.QueueDeclareOkBody; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.routing.RoutingTable; public class QueueDeclareHandler implements StateAwareMethodListener { @@ -53,17 +54,10 @@ public class QueueDeclareHandler implements StateAwareMethodListener map = appRegistry.getDatabaseManager().getDatabases(); PrincipalDatabase db = map.get(jmxDatabaseName); @@ -154,7 +157,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry RMIServerSocketFactory ssf; //check ssl enabled option in config, default to true if option is not set - boolean sslEnabled = appRegistry.getConfiguration().getBoolean("management.ssl.enabled", true); + boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); if (sslEnabled) { @@ -167,7 +170,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry keyStorePath = System.getProperty("javax.net.ssl.keyStore"); } else{ - keyStorePath = appRegistry.getConfiguration().getString("management.ssl.keyStorePath", null); + keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); } //check the keystore path value is valid @@ -202,7 +205,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry if (System.getProperty("javax.net.ssl.keyStorePassword") == null) { - if (appRegistry.getConfiguration().getString("management.ssl.keyStorePassword") == null) + if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) { throw new ConfigurationException("JMX management SSL keystore password not defined, " + "unable to start requested SSL protected JMX server"); @@ -210,7 +213,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry else { System.setProperty("javax.net.ssl.keyStorePassword", - appRegistry.getConfiguration().getString("management.ssl.keyStorePassword")); + appRegistry.getConfiguration().getManagementKeyStorePassword()); } } @@ -379,6 +382,17 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry // Stopping the RMI registry UnicastRemoteObject.unexportObject(_rmiRegistry, true); } + for (ObjectName name : _mbeanServer.queryNames(null, null)) + { + try + { + _mbeanServer.unregisterMBean(name); + } + catch (JMException e) + { + // Really shouldn't happen, but we'll ignore that... + } + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java deleted file mode 100644 index 042f626e8b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.qpid.configuration.Configured; - -public class ManagementConfiguration -{ - @Configured(path = "management.enabled", - defaultValue = "true") - public boolean enabled; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 4b69842c49..205ca73f13 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -582,7 +582,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable if (delay > 0) { _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); - _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); + _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, (int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index d8dbf97e49..0dbefd8798 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -20,6 +20,9 @@ */ package org.apache.qpid.server.protocol; +import java.io.IOException; +import java.net.InetSocketAddress; + import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.IdleStatus; @@ -34,15 +37,19 @@ import org.apache.mina.filter.executor.ExecutorFilter; import org.apache.mina.util.SessionUtil; import org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.transport.ConnectorConfiguration; import org.apache.qpid.ssl.SSLContextFactory; -import java.io.IOException; -import java.net.InetSocketAddress; - /** * The protocol handler handles "protocol events" for all connections. The state * associated with an individual connection is accessed through the protocol session. @@ -56,9 +63,6 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter private final IApplicationRegistry _applicationRegistry; - private static String DEFAULT_BUFFER_READ_LIMIT_SIZE = "262144"; - private static String DEFAULT_BUFFER_WRITE_LIMIT_SIZE = "262144"; - private final int BUFFER_READ_LIMIT_SIZE; private final int BUFFER_WRITE_LIMIT_SIZE; @@ -72,8 +76,8 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _applicationRegistry = applicationRegistry; // Read the configuration from the application registry - BUFFER_READ_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE)); - BUFFER_WRITE_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE)); + BUFFER_READ_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferReadLimit(); + BUFFER_WRITE_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferWriteLimit(); _logger.debug("AMQPFastProtocolHandler created"); } @@ -92,17 +96,22 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory); - - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); - if (connectorConfig.enableExecutorPool) + final ServerConfiguration config = _applicationRegistry.getConfiguration(); + + String keystorePath = config.getKeystorePath(); + String keystorePassword = config.getKeystorePassword(); + String certType = config.getCertType(); + SSLContextFactory sslContextFactory = null; + boolean isSsl = false; + if (config.getEnableSSL() && isSSLClient(config, protocolSession)) { - if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) + sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + isSsl = true; + } + if (config.getEnableExecutorPool()) + { + if (isSsl) { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", new SSLFilter(sslContextFactory.buildServerContext())); } @@ -111,19 +120,14 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter else { protocolSession.getFilterChain().addLast("protocolFilter", pcf); - if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession)) + if (isSsl) { - String keystorePath = connectorConfig.keystorePath; - String keystorePassword = connectorConfig.keystorePassword; - String certType = connectorConfig.certType; - SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", new SSLFilter(sslContextFactory.buildServerContext())); } - } - if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("broker.connector.protectio.enabled", false)) + if (ApplicationRegistry.getInstance().getConfiguration().getProtectIOEnabled()) { try { @@ -271,10 +275,10 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter } } - protected boolean isSSLClient(ConnectorConfiguration connectionConfig, + protected boolean isSSLClient(ServerConfiguration connectionConfig, IoSession protocolSession) { InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); - return addr.getPort() == connectionConfig.sslPort; + return addr.getPort() == connectionConfig.getSSLPort(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java deleted file mode 100644 index 310deaaf55..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class HeartbeatConfig -{ - @Configured(path = "heartbeat.delay", defaultValue = "5") - public int delay = 5;//in secs - @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0") - public double timeoutFactor = 2; - - public double getTimeoutFactor() - { - return timeoutFactor; - } - - public void setTimeoutFactor(double timeoutFactor) - { - this.timeoutFactor = timeoutFactor; - } - - public int getDelay() - { - return delay; - } - - public void setDelay(int delay) - { - this.delay = delay; - } - - int getTimeout(int writeDelay) - { - return (int) (timeoutFactor * writeDelay); - } - - public static HeartbeatConfig getInstance() - { - return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class); - } - - public String toString() - { - return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}"; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 2d4a9c4b40..0838b71c54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,9 +20,10 @@ */ package org.apache.qpid.server.queue; -import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.subscription.Subscription; @@ -141,6 +142,8 @@ public interface AMQQueue extends Managable, Comparable long getMinimumAlertRepeatGap(); + void setMinimumAlertRepeatGap(long value); + void deleteMessageFromTop(StoreContext storeContext) throws AMQException; @@ -162,7 +165,6 @@ public interface AMQQueue extends Managable, Comparable void stop(); - /** * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription * already exists. @@ -210,6 +212,4 @@ public interface AMQQueue extends Managable, Comparable { public void doTask(AMQQueue queue) throws AMQException; } - - void configure(Configuration virtualHostDefaultQueueConfiguration); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index be8c19d18f..eb0a011e93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -20,38 +20,22 @@ */ package org.apache.qpid.server.queue; -import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.AMQException; public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); - public static AMQQueue createAMQQueueImpl(AMQShortString name, - boolean durable, - AMQShortString owner, - boolean autoDelete, - VirtualHost virtualHost, final FieldTable arguments) - - throws AMQException - { - - return createAMQQueueImpl(name, durable, owner, autoDelete, - virtualHost, arguments, - VirtualHostConfiguration.getDefaultQueueConfiguration(virtualHost)); - } - public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, final FieldTable arguments, - Configuration queueConfiguration) + VirtualHost virtualHost, final FieldTable arguments) throws AMQException { @@ -66,13 +50,41 @@ public class AMQQueueFactory { q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); } - if (q != null && queueConfiguration != null) - { - q.configure(queueConfiguration); - } //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); return q; } + + public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException + { + AMQShortString queueName = new AMQShortString(config.getName()); + + boolean durable = config.getDurable(); + boolean autodelete = config.getAutoDelete(); + AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null; + FieldTable arguments = null; + boolean priority = config.getPriority(); + int priorities = config.getPriorities(); + if(priority || priorities > 0) + { + if(arguments == null) + { + arguments = new FieldTable(); + } + if (priorities < 0) + { + priorities = 10; + } + arguments.put(new AMQShortString("x-qpid-priorities"), priorities); + } + + AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); + q.setMaximumMessageAge(config.getMaximumMessageAge()); + q.setMaximumQueueDepth(config.getMaximumQueueDepth()); + q.setMaximumMessageSize(config.getMaximumMessageSize()); + q.setMaximumMessageCount(config.getMaximumMessageCount()); + q.setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); + return q; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java deleted file mode 100644 index 290fedcf7b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class AsyncDeliveryConfig -{ - private Executor _executor; - - @Configured(path = "delivery.poolsize", defaultValue = "0") - public int poolSize; - - public Executor getExecutor() - { - if (_executor == null) - { - if (poolSize > 0) - { - _executor = Executors.newFixedThreadPool(poolSize); - } - else - { - _executor = Executors.newCachedThreadPool(); - } - } - return _executor; - } - - public static Executor getAsyncDeliveryExecutor() - { - return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 94580a00ac..f7ae04c528 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -43,7 +43,7 @@ public class IncomingMessage implements Filterable private static final Logger _logger = Logger.getLogger(IncomingMessage.class); private static final boolean SYNCHED_CLOCKS = - ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false); + ApplicationRegistry.getInstance().getConfiguration().getSynchedClocks(); private final MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; @@ -51,7 +51,7 @@ public class IncomingMessage implements Filterable private final TransactionalContext _txnContext; private static final boolean MSG_AUTH = - ApplicationRegistry.getInstance().getConfiguration().getBoolean("security.msg-auth", false); + ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index a08e4e2667..42f52ce730 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,28 +1,9 @@ package org.apache.qpid.server.queue; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionList; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.AMQException; -import org.apache.qpid.pool.ReadWriteRunnable; -import org.apache.qpid.pool.ReferenceCountingExecutorService; -import org.apache.qpid.configuration.Configured; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; - -import javax.management.JMException; -import java.util.List; -import java.util.Set; import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -30,6 +11,25 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import javax.management.JMException; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.virtualhost.VirtualHost; + /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -91,24 +91,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _totalMessagesReceived = new AtomicLong(); /** max allowed size(KB) of a single message */ - @Configured(path = "maximumMessageSize", defaultValue = "0") - public long _maximumMessageSize; + public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); /** max allowed number of messages on a queue. */ - @Configured(path = "maximumMessageCount", defaultValue = "0") - public long _maximumMessageCount; + public long _maximumMessageCount = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageCount(); /** max queue depth for the queue */ - @Configured(path = "maximumQueueDepth", defaultValue = "0") - public long _maximumQueueDepth; + public long _maximumQueueDepth = ApplicationRegistry.getInstance().getConfiguration().getMaximumQueueDepth(); /** maximum message age before alerts occur */ - @Configured(path = "maximumMessageAge", defaultValue = "0") - public long _maximumMessageAge; + public long _maximumMessageAge = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageAge(); - /** the minimum interval between sending out consequetive alerts of the same type */ - @Configured(path = "minimumAlertRepeatGap", defaultValue = "0") - public long _minimumAlertRepeatGap; + /** the minimum interval between sending out consecutive alerts of the same type */ + public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); private static final int MAX_ASYNC_DELIVERIES = 10; @@ -167,7 +162,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - private void resetNotifications() + public void resetNotifications() { // This ensure that the notification checks for the configured alerts are created. setMaximumMessageAge(_maximumMessageAge); @@ -1590,10 +1585,4 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } return ids; } - - public void configure(Configuration queueConfiguration) - { - Configurator.configure(this, queueConfiguration); - resetNotifications(); - } -} \ No newline at end of file +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 02124a3737..477beeadcb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,24 +20,20 @@ */ package org.apache.qpid.server.registry; -import org.apache.commons.configuration.Configuration; +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.mina.common.IoAcceptor; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.mina.common.IoAcceptor; - -import java.util.HashMap; -import java.util.Map; -import java.net.InetSocketAddress; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; /** * An abstract application registry that provides access to configuration information and handles the @@ -53,7 +49,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private final Map, Object> _configuredObjects = new HashMap, Object>(); - protected final Configuration _configuration; + protected final ServerConfiguration _configuration; public static final int DEFAULT_INSTANCE = 1; public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; @@ -154,7 +150,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } - protected ApplicationRegistry(Configuration configuration) + protected ApplicationRegistry(ServerConfiguration configuration) { _configuration = configuration; } @@ -242,7 +238,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } - public Configuration getConfiguration() + public ServerConfiguration getConfiguration() { return _configuration; } @@ -255,26 +251,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } - 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", e); - } - Configurator.configure(instance); - _configuredObjects.put(instanceType, instance); - } - return instance; - } - public static void setDefaultApplicationRegistry(String clazz) { _APPLICATION_REGISTRY = clazz; @@ -287,7 +263,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public ACLManager getAccessManager() { - return new ACLManager(_configuration, _pluginManager); + return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); } public ManagedObjectRegistry getManagedObjectRegistry() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index c34c4bf80a..39164883f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -21,71 +21,25 @@ package org.apache.qpid.server.registry; import java.io.File; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.management.JMXManagedObjectRegistry; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.ManagementConfiguration; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { 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; + super(new ServerConfiguration(configurationURL)); } public void initialise() throws Exception @@ -94,9 +48,9 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _virtualHostRegistry = new VirtualHostRegistry(); - _pluginManager = new PluginManager(_configuration.getString("plugin-directory")); + _pluginManager = new PluginManager(_configuration.getPluginDirectory()); - _accessManager = new ACLManager(_configuration, _pluginManager); + _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); @@ -111,18 +65,17 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } private void initialiseVirtualHosts() throws Exception - { - for (String name : getVirtualHostNames()) + { + for (String name : _configuration.getVirtualHosts()) { - - _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name))); + _virtualHostRegistry.registerVirtualHost(new VirtualHost(_configuration.getVirtualHostConfig(name))); } + getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } private void initialiseManagedObjectRegistry() throws AMQException { - ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); - if (config.enabled) + if (_configuration.getManagementEnabled()) { _managedObjectRegistry = new JMXManagedObjectRegistry(); } @@ -131,10 +84,4 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _managedObjectRegistry = new NoopManagedObjectRegistry(); } } - - public Collection getVirtualHostNames() - { - return getConfiguration().getList("virtualhosts.virtualhost.name"); - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index e68dca285c..a1f30c6eed 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.net.InetSocketAddress; import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; @@ -48,22 +49,12 @@ public interface IApplicationRegistry */ void close() throws Exception; - /** - * This gets access to a "configured object". A configured object has fields populated from a the configuration - * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields. - * Application registry implementations can choose the refresh strategy or caching approach. - * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only - * have a single object of this type in the system. - * @return the configured object - */ - T 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(); + ServerConfiguration getConfiguration(); ManagedObjectRegistry getManagedObjectRegistry(); @@ -71,8 +62,6 @@ public interface IApplicationRegistry AuthenticationManager getAuthenticationManager(); - Collection getVirtualHostNames(); - VirtualHostRegistry getVirtualHostRegistry(); ACLManager getAccessManager(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java index 6344127b24..0c62638710 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.routing; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -41,7 +42,7 @@ public interface RoutingTable * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; + void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index 356ee815dd..57c6098874 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -30,6 +30,9 @@ import java.util.Map.Entry; import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.SecurityConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -46,12 +49,12 @@ public class ACLManager private Map _globalPlugins = new HashMap(); private Map _hostPlugins = new HashMap(); - public ACLManager(Configuration configuration, PluginManager manager) + public ACLManager(SecurityConfiguration configuration, PluginManager manager) { this(configuration, manager, null); } - public ACLManager(Configuration configuration, PluginManager manager, ACLPluginFactory securityPlugin) + public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) { _pluginManager = manager; @@ -70,14 +73,14 @@ public class ACLManager } - public void configureHostPlugins(Configuration hostConfig) + public void configureHostPlugins(SecurityConfiguration hostConfig) { _hostPlugins = configurePlugins(hostConfig); } - public Map configurePlugins(Configuration configuration) + public Map configurePlugins(SecurityConfiguration hostConfig) { - Configuration securityConfig = configuration.subset("security"); + Configuration securityConfig = hostConfig.getConfiguration(); Map plugins = new HashMap(); Iterator keys = securityConfig.getKeys(); Collection handledTags = new HashSet(); @@ -86,7 +89,6 @@ public class ACLManager // Splitting the string is necessary here because of the way that getKeys() returns only // bottom level children String tag = ((String) keys.next()).split("\\.", 2)[0]; - if (!handledTags.contains(tag)) { for (ACLPluginFactory plugin : _allSecurityPlugins.values()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index fc96776a3a..e0d4c49af1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -34,6 +34,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.configuration.PropertyUtils; import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; @@ -46,20 +47,18 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); - private static final String _base = "security.principal-databases.principal-database"; - Map _databases; - public ConfigurationFilePrincipalDatabaseManager(Configuration configuration) throws Exception + public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception { _logger.info("Initialising PrincipleDatabase authentication manager"); - _databases = initialisePrincipalDatabases(configuration); + _databases = initialisePrincipalDatabases(_configuration); } - private Map initialisePrincipalDatabases(Configuration configuration) throws Exception + private Map initialisePrincipalDatabases(ServerConfiguration _configuration) throws Exception { - List databaseNames = configuration.getList(_base + ".name"); - List databaseClasses = configuration.getList(_base + ".class"); + List databaseNames = _configuration.getPrincipalDatabaseNames(); + List databaseClasses = _configuration.getPrincipalDatabaseClass(); Map databases = new HashMap(); if (databaseNames.size() == 0) @@ -84,7 +83,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab throw new Exception("Principal databases must implement the PrincipalDatabase interface"); } - initialisePrincipalDatabase((PrincipalDatabase) o, configuration, i); + initialisePrincipalDatabase((PrincipalDatabase) o, _configuration, i); String name = databaseNames.get(i); if ((name == null) || (name.length() == 0)) @@ -105,12 +104,11 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab return databases; } - private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, ServerConfiguration _configuration, int index) throws FileNotFoundException, ConfigurationException { - String baseName = _base + "(" + index + ").attributes.attribute."; - List argumentNames = config.getList(baseName + "name"); - List argumentValues = config.getList(baseName + "value"); + List argumentNames = _configuration.getPrincipalDatabaseAttributeNames(index); + List argumentValues = _configuration.getPrincipalDatabaseAttributeValues(index); for (int i = 0; i < argumentNames.size(); i++) { String argName = argumentNames.get(i); @@ -166,18 +164,17 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab return _databases; } - public void initialiseManagement(Configuration config) throws ConfigurationException + public void initialiseManagement(ServerConfiguration config) throws ConfigurationException { try { AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); - String baseSecurity = "security.jmx"; - List principalDBs = config.getList(baseSecurity + ".principal-database"); + List principalDBs = config.getManagementPrincipalDBs(); if (principalDBs.size() == 0) { - throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)"); + throw new ConfigurationException("No principal-database specified for jmx security"); } String databaseName = principalDBs.get(0); @@ -191,11 +188,11 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab _mbean.setPrincipalDatabase(database); - List jmxaccesslist = config.getList(baseSecurity + ".access"); + List jmxaccesslist = config.getManagementAccessList(); if (jmxaccesslist.size() == 0) { - throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)"); + throw new ConfigurationException("No access control files specified for jmx security"); } String jmxaccesssFile = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java index 2c553ae76a..f9882f8810 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.security.auth.database; +import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -30,5 +31,5 @@ public interface PrincipalDatabaseManager { public Map getDatabases(); - public void initialiseManagement(Configuration config) throws ConfigurationException; + public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java index 6b86a46bd2..4efe381a8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -20,7 +20,8 @@ */ package org.apache.qpid.server.security.auth.database; -import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ServerConfiguration; import java.util.Map; import java.util.Properties; @@ -41,7 +42,8 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana return _databases; } - public void initialiseManagement(Configuration config) + @Override + public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException { //todo } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 2cbbdc85ff..98c060599a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.security.auth.manager; import org.apache.log4j.Logger; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; @@ -60,7 +61,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan /** The name for the required SASL Server mechanisms */ public static final String PROVIDER_NAME= "AMQSASLProvider-Server"; - public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception + public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception { _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") + " PrincipleDatabase authentication manager."); @@ -77,7 +78,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan } else { - String databaseName = hostConfig.getString("security.authentication.name"); + String databaseName = hostConfig.getAuthenticationDatabase(); if (databaseName == null) { @@ -121,14 +122,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan private void initialiseAuthenticationMechanisms(Map> providerMap, 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. - - if (databases.size() > 1) { _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); @@ -136,13 +129,11 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan for (Map.Entry entry : databases.entrySet()) { - // fixme As the database now provide the mechanisms they support, they will ... // overwrite each other in the map. There should only be one database per vhost. // But currently we must have authentication before vhost definition. initialiseAuthenticationMechanisms(providerMap, entry.getValue()); } - } private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 500fd4c7bf..35d8d9ea6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.store; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; @@ -142,7 +143,7 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable private State _state = State.INITIAL; - public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { //Only initialise when loaded with the old 'store' confing ignore the new 'RoutingTable' config if (base.equals("store")) @@ -156,7 +157,7 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - final String databasePath = config.getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + final String databasePath = config.getStoreConfiguration().getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index eee7be7ef6..aa7b6e2542 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -27,6 +27,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -70,19 +71,19 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); } - public void configure(String base, Configuration config) + public void configure(String base, VirtualHostConfiguration config) { //Only initialise when called with current 'store' configs i.e. don't reinit when used as a 'RoutingTable' if (base.equals("store")) { - int hashtableCapacity = config.getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); + int hashtableCapacity = config.getStoreConfiguration().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(VirtualHost virtualHost, String base, Configuration config) throws Exception + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { configure(base, config); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java index c927bb3272..4fa85dd6cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java @@ -26,6 +26,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.AMQQueue; @@ -67,7 +68,7 @@ public interface TransactionLog * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception; + void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java deleted file mode 100644 index b67bb98e28..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transport; - -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.util.NewThreadExecutor; -import org.apache.qpid.configuration.Configured; -import org.apache.log4j.Logger; - -public class ConnectorConfiguration -{ - private static final Logger _logger = Logger.getLogger(ConnectorConfiguration.class); - - public static final String DEFAULT_PORT = "5672"; - - public static final String SSL_PORT = "8672"; - - @Configured(path = "connector.processors", - defaultValue = "4") - public int processors; - - @Configured(path = "connector.port", - defaultValue = DEFAULT_PORT) - public int port; - - @Configured(path = "connector.bind", - defaultValue = "wildcard") - public String bindAddress; - - @Configured(path = "connector.socketReceiveBuffer", - defaultValue = "32767") - public int socketReceiveBufferSize; - - @Configured(path = "connector.socketWriteBuffer", - defaultValue = "32767") - public int socketWriteBuferSize; - - @Configured(path = "connector.tcpNoDelay", - defaultValue = "true") - public boolean tcpNoDelay; - - @Configured(path = "advanced.filterchain[@enableExecutorPool]", - defaultValue = "false") - public boolean enableExecutorPool; - - @Configured(path = "advanced.enablePooledAllocator", - defaultValue = "false") - public boolean enablePooledAllocator; - - @Configured(path = "advanced.enableDirectBuffers", - defaultValue = "false") - public boolean enableDirectBuffers; - - @Configured(path = "connector.ssl.enabled", - defaultValue = "false") - public boolean enableSSL; - - @Configured(path = "connector.ssl.sslOnly", - defaultValue = "true") - public boolean sslOnly; - - @Configured(path = "connector.ssl.port", - defaultValue = SSL_PORT) - public int sslPort; - - @Configured(path = "connector.ssl.keystorePath", - defaultValue = "none") - public String keystorePath; - - @Configured(path = "connector.ssl.keystorePassword", - defaultValue = "none") - public String keystorePassword; - - @Configured(path = "connector.ssl.certType", - defaultValue = "SunX509") - public String certType; - - @Configured(path = "connector.qpidnio", - defaultValue = "false") - public boolean _multiThreadNIO; - - @Configured(path = "advanced.useWriteBiasedPool", - defaultValue = "false") - public boolean useBiasedWrites; - - - public IoAcceptor createAcceptor() - { - if (_multiThreadNIO) - { - _logger.warn("Using Qpid Multithreaded IO Processing"); - return new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(processors, new NewThreadExecutor()); - } - else - { - _logger.warn("Using Mina IO Processing"); - return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 88ad87b9c1..eda2d3a94e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -26,7 +26,11 @@ import java.util.HashMap; import java.util.Properties; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.MapConfiguration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -39,17 +43,16 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public class NullApplicationRegistry extends ApplicationRegistry { - public NullApplicationRegistry() + public NullApplicationRegistry() throws ConfigurationException { - super(new MapConfiguration(new HashMap())); + super(new ServerConfiguration(new PropertiesConfiguration())); } public void initialise() throws Exception { _logger.info("Initialising NullApplicationRegistry"); - _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); - _configuration.addProperty("housekeeping.expiredMessageCheckPeriod", "200"); + _configuration.setHousekeepingExpiredMessageCheckPeriod(200); Properties users = new Properties(); @@ -57,17 +60,18 @@ public class NullApplicationRegistry extends ApplicationRegistry _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); - _accessManager = new ACLManager(_configuration, _pluginManager, AllowAll.FACTORY); + _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY); _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); _managedObjectRegistry = new NoopManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - VirtualHost dummyHost = new VirtualHost("test", _configuration); + PropertiesConfiguration vhostProps = new PropertiesConfiguration(); + VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); + VirtualHost dummyHost = new VirtualHost(hostConfig); _virtualHostRegistry.registerVirtualHost(dummyHost); _virtualHostRegistry.setDefaultVirtualHostName("test"); _pluginManager = new PluginManager(""); - _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 1497b4adb8..9a4a4c3286 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,35 +20,41 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Collections; +import java.util.List; import java.util.Timer; import java.util.TimerTask; import javax.management.NotCompliantMBeanException; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.routing.RoutingTable; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.ExchangeConfiguration; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; import org.apache.qpid.server.exchange.DefaultExchangeFactory; import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.transactionlog.TransactionLog; public class VirtualHost implements Accessable { @@ -79,9 +85,6 @@ public class VirtualHost implements Accessable private final Timer _houseKeepingTimer; - private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; - - public void setAccessableName(String name) { _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" @@ -132,47 +135,32 @@ public class VirtualHost implements Accessable } // End of MBean class - /** - * Used for testing only - * @param name - * @param transactionLog - * @throws Exception - */ - public VirtualHost(String name, TransactionLog transactionLog) throws Exception - { - this(name, new PropertiesConfiguration(), transactionLog); - } - /** * Normal Constructor * @param name * @param hostConfig * @throws Exception */ - public VirtualHost(String name, Configuration hostConfig) throws Exception + public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception { - this(name, hostConfig, null); + this(hostConfig, null); } - public VirtualHost(String name, Configuration hostConfig, TransactionLog transactionLog) throws Exception + public VirtualHost(VirtualHostConfiguration hostConfig, TransactionLog transactionLog) throws Exception { - if (name == null || name.length() == 0) + _name = hostConfig.getName(); + + if (_name == null || _name.length() == 0) { - throw new IllegalArgumentException("Illegal name (" + name + ") for virtualhost."); + throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); } - _name = name; - _virtualHostMBean = new VirtualHostMBean(); _connectionRegistry = new ConnectionRegistry(this); - _houseKeepingTimer = new Timer("Queue-housekeeping-"+name, true); - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - _exchangeRegistry = new DefaultExchangeRegistry(this); - + _houseKeepingTimer = new Timer("Queue-housekeeping-"+_name, true); + if (transactionLog != null) { _transactionLog = transactionLog; @@ -183,33 +171,30 @@ public class VirtualHost implements Accessable } else { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and TransactionLog cannot be null"); - } initialiseTransactionLog(hostConfig); initialiseRoutingTable(hostConfig); } - - + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + _exchangeRegistry = new DefaultExchangeRegistry(this); _exchangeRegistry.initialise(); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig); + initialiseModel(hostConfig); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig); + _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); - initialiseHouseKeeping(hostConfig); + initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); } - private void initialiseHouseKeeping(final Configuration hostConfig) + private void initialiseHouseKeeping(long period) { - - long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); - /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ if(period != 0L) { @@ -240,9 +225,9 @@ public class VirtualHost implements Accessable } //todo we need to move from store.class to transactionlog.class - private void initialiseTransactionLog(Configuration config) throws Exception + private void initialiseTransactionLog(VirtualHostConfiguration config) throws Exception { - String transactionLogClass = config.getString("store.class"); + String transactionLogClass = config.getTransactionLogClass(); Class clazz = Class.forName(transactionLogClass); Object o = clazz.newInstance(); @@ -257,9 +242,9 @@ public class VirtualHost implements Accessable } //todo we need to move from store.class to transactionlog.class - private void initialiseRoutingTable(Configuration config) throws Exception + private void initialiseRoutingTable(VirtualHostConfiguration hostConfig) throws Exception { - String transactionLogClass = config.getString("routingtable.class"); + String transactionLogClass = hostConfig.getRoutingTableClass(); if (transactionLogClass != null) { @@ -272,7 +257,7 @@ public class VirtualHost implements Accessable " does not."); } _routingTable = (RoutingTable) o; - _routingTable.configure(this, "routingtable", config); + _routingTable.configure(this, "routingtable", hostConfig); } else { @@ -282,24 +267,86 @@ public class VirtualHost implements Accessable } } } + + private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException + { + _logger.debug("Loading configuration for virtualhost: "+config.getName()); + + List exchangeNames = config.getExchanges(); + + for(Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(config.getExchangeConfiguration(exchangeName)); + } + + String[] queueNames = config.getQueueNames(); + + for(Object queueNameObj : queueNames) + { + String queueName = String.valueOf(queueNameObj); + configureQueue(config.getQueueConfiguration(queueName)); + } + } + + private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException + { + AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); + + Exchange exchange; + exchange = _exchangeRegistry.getExchange(exchangeName); + if(exchange == null) + { + AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); + boolean durable = exchangeConfiguration.getDurable(); + boolean autodelete = exchangeConfiguration.getAutoDelete(); + Exchange newExchange = _exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); + _exchangeRegistry.registerExchange(newExchange); + } + } - public T getConfiguredObject(Class instanceType, Configuration config) + private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException { - T instance; - try + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); + + if (queue.isDurable()) + { + _routingTable.createQueue(queue); + } + + String exchangeName = queueConfiguration.getExchange(); + + Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if(exchange == null) + { + exchange = _exchangeRegistry.getDefaultExchange(); + } + + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } + + List routingKeys = queueConfiguration.getRoutingKeys(); + if(routingKeys == null || routingKeys.isEmpty()) { - instance = instanceType.newInstance(); + routingKeys = Collections.singletonList(queue.getName()); } - catch (Exception e) + + for(Object routingKeyNameObj : routingKeys) { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + queue.bind(exchange, routingKey, null); + _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); } - Configurator.configure(instance); - return instance; + if(exchange != _exchangeRegistry.getDefaultExchange()) + { + queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + } } public String getName() -- cgit v1.2.1 From 0db29114e114d6073494de791785df237cfda475 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Feb 2009 14:48:28 +0000 Subject: QPID-1632 - Initial testing of reference counting and implemntation of TransactionLog based reference counting git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@746259 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 2 +- .../qpid/server/RequiredDeliveryException.java | 3 +- .../java/org/apache/qpid/server/ack/TxAck.java | 2 +- .../org/apache/qpid/server/queue/AMQMessage.java | 4 -- .../apache/qpid/server/queue/IncomingMessage.java | 4 ++ .../apache/qpid/server/queue/MessageFactory.java | 10 +-- .../qpid/server/queue/PersistentAMQMessage.java | 1 + .../apache/qpid/server/queue/QueueEntryImpl.java | 6 ++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 4 +- .../qpid/server/queue/TransientAMQMessage.java | 84 +++++++++------------- .../qpid/server/store/DerbyMessageStore.java | 2 +- .../qpid/server/subscription/SubscriptionImpl.java | 1 + .../qpid/server/txn/LocalTransactionalContext.java | 2 +- .../qpid/server/virtualhost/VirtualHost.java | 11 ++- 14 files changed, 67 insertions(+), 69 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index bb7331e5f7..125518358b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -251,7 +251,7 @@ public class AMQChannel } catch (NoRouteException e) { - //_currentMessage.incrementReference(); + //_currentMessage.takeReference(); _returnMessages.add(e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index 3f1947d65a..415f1fe8be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -61,7 +61,8 @@ public abstract class RequiredDeliveryException extends AMQException // and so will have the ref decremented as routing fails. // we need to keep this message around so we can return it in the // handler. So increment here. - _amqMessage = payload.takeReference(); + payload.incrementReference(1); + _amqMessage = payload; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index db3a05eb52..0f40e00624 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -130,7 +130,7 @@ public class TxAck implements TxnOp //in memory (persistent changes will be rolled back by store) for (QueueEntry msg : _unacked.values()) { - msg.getMessage().takeReference(); + msg.getMessage().incrementReference(1); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 2bd6e612f8..1f56b2ccd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -126,9 +126,5 @@ public interface AMQMessage boolean incrementReference(int queueCount); - boolean incrementReference(); - - AMQMessage takeReference(); - boolean isReferenced(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index f7ae04c528..5d4322c4fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -78,6 +78,10 @@ public class IncomingMessage implements Filterable final AMQProtocolSession publisher, TransactionLog messasgeStore) { + if (publisher == null) + { + throw new NullPointerException("Message Publisher cannot be null"); + } _messagePublishInfo = info; _txnContext = txnContext; _publisher = publisher; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java index e5e0b6e312..9924733178 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java @@ -42,19 +42,19 @@ public class MessageFactory _messageId = new AtomicLong(0L); } - public void start() + public void recoveryComplete() { _state = State.OPEN; } /** - * Only used by test as test suite is run in a single VM we need to beable to re-enable recovery mode. - */ - protected void enableRecover() + * Only to be used by tests as this will cause violate the principal that message IDs should not be reused. + */ + public void reset() { _state = State.RECOVER; + _messageId = new AtomicLong(0L); } - /** * Normal message creation path diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java index 804bb29ecd..ec48a2afb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java @@ -60,6 +60,7 @@ public class PersistentAMQMessage extends TransientAMQMessage @Override public void removeMessage(StoreContext storeContext) throws AMQException { + _log.info("PAMQM : removing message:" + _messageId); _transactionLog.removeMessage(storeContext, _messageId); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index ba14be5580..3eb1636884 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -301,10 +301,16 @@ public class QueueEntryImpl implements QueueEntry public void dispose(final StoreContext storeContext) throws MessageCleanupException { + _log.info("QEI Disposing of message:" + getMessage().getMessageId() + ": state=" + _state); if(delete()) { + _log.info("QEI delete message:" + getMessage().getMessageId()); getMessage().decrementReference(storeContext); } + else + { + _log.info("QEI delete state wrong:" + getMessage().getMessageId()); + } } public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 42f52ce730..a0f21033c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -918,7 +918,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if (!entry.isDeleted()) { - return entry.getMessage().incrementReference(); + return entry.getMessage().incrementReference(1); } } @@ -1418,7 +1418,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - @Override + public void checkMessageStatus() throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java index 8c62e046f8..f3d74fb01c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java @@ -32,19 +32,17 @@ import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.store.StoreContext; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Collections; -import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; -/** - * A deliverable message. - */ +/** A deliverable message. */ public class TransientAMQMessage implements AMQMessage { /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(AMQMessage.class); + protected static final Logger _log = Logger.getLogger(AMQMessage.class); private final AtomicInteger _referenceCount = new AtomicInteger(1); @@ -58,8 +56,6 @@ public class TransientAMQMessage implements AMQMessage protected final Long _messageId; - - /** Flag to indicate that this message requires 'immediate' delivery. */ private static final byte IMMEDIATE = 0x01; @@ -143,23 +139,23 @@ public class TransientAMQMessage implements AMQMessage /** * Used by SimpleAMQQueueTest, TxAckTest.TestMessage, AbstractHeaderExchangeTestBase.Message * These all need refactoring to some sort of MockAMQMessageFactory. - */ + */ @Deprecated protected TransientAMQMessage(AMQMessage message) throws AMQException { _messageId = message.getMessageId(); - _flags = ((TransientAMQMessage)message)._flags; + _flags = ((TransientAMQMessage) message)._flags; _contentHeaderBody = message.getContentHeaderBody(); _messagePublishInfo = message.getMessagePublishInfo(); } - /** * Normal message creation via the MessageFactory uses this constructor * Package scope limited as MessageFactory should be used - * @see MessageFactory * * @param messageId + * + * @see MessageFactory */ TransientAMQMessage(Long messageId) { @@ -191,7 +187,6 @@ public class TransientAMQMessage implements AMQMessage return new BodyContentIterator(); } - public ContentHeaderBody getContentHeaderBody() { return _contentHeaderBody; @@ -202,32 +197,19 @@ public class TransientAMQMessage implements AMQMessage return _messageId; } - /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic - * operation. - */ - public AMQMessage takeReference() - { - incrementReference(); // _referenceCount.incrementAndGet(); - - return this; - } - - public boolean incrementReference() - { - return incrementReference(1); - } - /* Threadsafe. Increment the reference count on the message. */ public boolean incrementReference(int count) { - if(_referenceCount.addAndGet(count) <= 1) + if (_referenceCount.addAndGet(count) <= 1) { - _referenceCount.addAndGet(-count); + int newcount = _referenceCount.addAndGet(-count); + _log.debug("Message(" + _messageId + ") Incremented Ref count by (" + count + ") to :" + newcount); return false; } else { + _log.debug("Message(" + _messageId + ") Incremented Ref count by (" + count + ") but count was <=1(" + + _referenceCount.get() + ")"); return true; } @@ -247,6 +229,8 @@ public class TransientAMQMessage implements AMQMessage int count = _referenceCount.decrementAndGet(); + _log.debug("Message(" + _messageId + ") Decremented Ref count to :" + count); + // 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 @@ -256,10 +240,11 @@ public class TransientAMQMessage implements AMQMessage // set the reference count way below 0 so that we can detect that the message has been deleted // this is to guard against the message being spontaneously recreated (from the mgmt console) // by copying from other queues at the same time as it is being removed. - _referenceCount.set(Integer.MIN_VALUE/2); + _referenceCount.set(Integer.MIN_VALUE / 2); try { + _log.debug("Reference Count hit 0, removing message"); // must check if the handle is null since there may be cases where we decide to throw away a message // and the handle has not yet been constructed // no need to perform persistent check anymore as TransientAMQM.removeMessage() is a no-op @@ -268,7 +253,7 @@ public class TransientAMQMessage implements AMQMessage catch (AMQException e) { // to maintain consistency, we revert the count - incrementReference(); + incrementReference(1); throw new MessageCleanupException(getMessageId(), e); } } @@ -282,7 +267,6 @@ public class TransientAMQMessage implements AMQMessage } } - /** * Called selectors to determin if the message has already been sent * @@ -296,10 +280,10 @@ public class TransientAMQMessage implements AMQMessage /** * Called to enforce the 'immediate' flag. * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer + * @returns true if the message is marked for immediate delivery but has not been marked as delivered + * to a consumer */ - public boolean immediateAndNotDelivered() + public boolean immediateAndNotDelivered() { return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; @@ -335,7 +319,6 @@ public class TransientAMQMessage implements AMQMessage _flags |= DELIVERED_TO_CONSUMER; } - public long getSize() { return _contentHeaderBody.bodySize; @@ -345,7 +328,7 @@ public class TransientAMQMessage implements AMQMessage { return _sessionIdentifier.getSessionInstance(); } - + public Object getPublisherIdentifier() { return _sessionIdentifier.getSessionIdentifier(); @@ -356,7 +339,7 @@ public class TransientAMQMessage implements AMQMessage _sessionIdentifier = sessionIdentifier; } - /** From AMQMessageHandle **/ + /** From AMQMessageHandle * */ public int getBodyCount() { @@ -365,7 +348,7 @@ public class TransientAMQMessage implements AMQMessage public ContentChunk getContentChunk(int index) { - if(_contentBodies == null) + if (_contentBodies == null) { throw new RuntimeException("No ContentBody has been set"); } @@ -381,9 +364,9 @@ public class TransientAMQMessage implements AMQMessage public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException { - if(_contentBodies == null) + if (_contentBodies == null) { - if(isLastContentBody) + if (isLastContentBody) { _contentBodies = Collections.singletonList(contentChunk); } @@ -411,9 +394,10 @@ public class TransientAMQMessage implements AMQMessage /** * This is called when all the content has been received. + * * @param storeContext - *@param messagePublishInfo - * @param contentHeaderBody @throws AMQException + * @param messagePublishInfo + * @param contentHeaderBody @throws AMQException */ public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) @@ -425,7 +409,7 @@ public class TransientAMQMessage implements AMQMessage throw new NullPointerException("HeaderBody cannot be null"); } - if( messagePublishInfo == null) + if (messagePublishInfo == null) { throw new NullPointerException("PublishInfo cannot be null"); } @@ -433,15 +417,14 @@ public class TransientAMQMessage implements AMQMessage _messagePublishInfo = messagePublishInfo; _contentHeaderBody = contentHeaderBody; - - if( contentHeaderBody.bodySize == 0) + if (contentHeaderBody.bodySize == 0) { _contentBodies = Collections.EMPTY_LIST; - } + } _arrivalTime = System.currentTimeMillis(); - if(messagePublishInfo.isImmediate()) + if (messagePublishInfo.isImmediate()) { _flags |= IMMEDIATE; } @@ -457,7 +440,6 @@ public class TransientAMQMessage implements AMQMessage //no-op } - public String toString() { // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 35d8d9ea6c..fe81346c8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -1357,7 +1357,7 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable if(message != null) { - message.incrementReference(); + message.incrementReference(1); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index be11eb7b84..1c58e644e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -594,6 +594,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage protected void sendToClient(final QueueEntry entry, final long deliveryTag) throws AMQException { + _logger.info("Sending Message(" + entry + ") DTag:" + deliveryTag + " to subscription:" + debugIdentity()); _deliveryMethod.deliverToClient(this,entry,deliveryTag); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 9bc2e98fe9..8e63b95f0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -92,7 +92,7 @@ public class LocalTransactionalContext implements TransactionalContext public void process() throws AMQException { - _message.incrementReference(); + _message.incrementReference(1); try { QueueEntry entry = _queue.enqueue(getStoreContext(),_message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9a4a4c3286..1115ed723c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -238,6 +238,13 @@ public class VirtualHost implements Accessable " does not."); } _transactionLog = (TransactionLog) o; + + //Assign RoutingTable as old MessageStores converted to TransactionLog may require the _routingTable. + if (_transactionLog instanceof RoutingTable) + { + _routingTable = (RoutingTable)_transactionLog; + } + _transactionLog.configure(this, "store", config); } @@ -261,9 +268,9 @@ public class VirtualHost implements Accessable } else { - if (_transactionLog instanceof RoutingTable) + if (_routingTable == null) { - _routingTable = (RoutingTable)_transactionLog; + throw new RuntimeException("No Routing Table configured unable to startup."); } } } -- cgit v1.2.1 From 67d5fb5c48b224efea5134c455719670398dd5eb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Feb 2009 14:50:01 +0000 Subject: QPID-1632 - Removal of reference counting and update to tests, TxAckTest was reduced in size as reference counting is now not modified until the transaction completes. Replaced MessageReferenceCoutingTest with PersistentMessageTest and further tests wil be created when DerbyDBMessageStore is also updated. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@746260 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 10 ++- .../qpid/server/ExtractResendAndRequeue.java | 4 +- .../qpid/server/RequiredDeliveryException.java | 8 +-- .../java/org/apache/qpid/server/ack/TxAck.java | 21 +++--- .../server/ack/UnacknowledgedMessageMapImpl.java | 6 +- .../server/handler/BasicRejectMethodHandler.java | 22 +++--- .../org/apache/qpid/server/queue/AMQMessage.java | 9 --- .../org/apache/qpid/server/queue/AMQQueue.java | 7 -- .../apache/qpid/server/queue/IncomingMessage.java | 12 +--- .../qpid/server/queue/PersistentAMQMessage.java | 7 -- .../org/apache/qpid/server/queue/QueueEntry.java | 26 +++---- .../apache/qpid/server/queue/QueueEntryImpl.java | 27 ++------ .../apache/qpid/server/queue/SimpleAMQQueue.java | 44 ++++++++---- .../qpid/server/queue/TransientAMQMessage.java | 80 ---------------------- .../qpid/server/store/DerbyMessageStore.java | 3 +- .../qpid/server/store/MemoryMessageStore.java | 48 ++++++++++--- .../qpid/server/subscription/SubscriptionImpl.java | 8 +-- .../qpid/server/txn/LocalTransactionalContext.java | 8 --- .../qpid/server/txn/NonTransactionalContext.java | 28 ++++---- 19 files changed, 146 insertions(+), 232 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 125518358b..5a01888ccf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -499,7 +499,7 @@ public class AMQChannel } else { - unacked.discard(_storeContext); + unacked.dequeueAndDelete(_storeContext); } } @@ -555,7 +555,7 @@ public class AMQChannel _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - unacked.discard(_storeContext); + unacked.dequeueAndDelete(_storeContext); } } else @@ -712,7 +712,7 @@ public class AMQChannel { try { - message.discard(_storeContext); + message.dequeueAndDelete(_storeContext); message.setQueueDeleted(true); } @@ -831,9 +831,7 @@ public class AMQChannel { AMQMessage message = bouncedMessage.getAMQMessage(); _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); - - message.decrementReference(_storeContext); + new AMQShortString(bouncedMessage.getMessage())); } _returnMessages.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 1723d46ef0..8d41cc58d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -82,13 +82,13 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor } else { - queueEntry.discard(_storeContext); + queueEntry.dequeueAndDelete(_storeContext); _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + queueEntry); } } else { - queueEntry.discard(_storeContext); + queueEntry.dequeueAndDelete(_storeContext); _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + queueEntry); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java index 415f1fe8be..a81b2cc2db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -56,14 +56,10 @@ public abstract class RequiredDeliveryException extends AMQException public void setMessage(final AMQMessage payload) { - - // Increment the reference as this message is in the routing phase - // and so will have the ref decremented as routing fails. // we need to keep this message around so we can return it in the - // handler. So increment here. - payload.incrementReference(1); + // handler. + // Messages are all kept in memory now. Only queues can push messages out of memory. _amqMessage = payload; - } public AMQMessage getAMQMessage() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index 0f40e00624..918fcd8407 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.ack; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.HashMap; @@ -116,22 +115,20 @@ public class TxAck implements TxnOp //make persistent changes, i.e. dequeue and decrementReference for (QueueEntry msg : _unacked.values()) { - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(storeContext); - + //Message has been ack so dequeueAndDelete it. + // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed + // from the transaciton log + msg.dequeueAndDelete(storeContext); } } public void undoPrepare() { - //decrementReference is annoyingly untransactional (due to - //in memory counter) so if we failed in prepare for full - //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for (QueueEntry msg : _unacked.values()) - { - msg.getMessage().incrementReference(1); - } + //As this is transaction the above dequeueAndDelete will only request the message be dequeue from the + // transactionLog. Only when the transaction succesfully completes will it perform any + // update of the internal transactionLog reference counting and any resulting message data deletion. + // The success or failure of the data deletion is not important to this transaction only that the ack has been + // successfully recorded. } public void commit(StoreContext storeContext) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index efdadd4922..ac3b0b5e49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -174,8 +174,10 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); } - //Message has been ack so discard it. This will dequeue and decrement the reference. - unacked.getValue().discard(storeContext); + //Message has been ack so dequeueAndDelete it. + // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed + // from the transaciton log + unacked.getValue().dequeueAndDelete(storeContext); it.remove(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index f3cab10ed7..bd70cd7776 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -65,38 +65,38 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener boolean isDeleted(); - int delete() throws AMQException; - QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; - - boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - - void addQueueDeleteTask(final Task task); - List getMessagesOnTheQueue(); List getMessagesOnTheQueue(long fromMessageId, long toMessageId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 5d4322c4fc..5eafd281c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -156,8 +156,7 @@ public class IncomingMessage implements Filterable _logger.debug("Delivering message " + getMessageId() + " to " + _destinationQueues); } - try - { + // first we allow the handle to know that the message has been fully received. This is useful if it is // maintaining any calculated values based on content chunks _message.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), _messagePublishInfo, getContentHeaderBody()); @@ -196,7 +195,6 @@ public class IncomingMessage implements Filterable { int offset; final int queueCount = _destinationQueues.size(); - _message.incrementReference(queueCount); if(queueCount == 1) { offset = 0; @@ -222,12 +220,8 @@ public class IncomingMessage implements Filterable } return _message; - } - finally - { - // Remove refence for routing process . Reference count should now == delivered queue count - if(_message != null) _message.decrementReference(_txnContext.getStoreContext()); - } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java index ec48a2afb0..92c10b0347 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java @@ -57,13 +57,6 @@ public class PersistentAMQMessage extends TransientAMQMessage _transactionLog.storeMessageMetaData(storeContext, _messageId, mmd); } - @Override - public void removeMessage(StoreContext storeContext) throws AMQException - { - _log.info("PAMQM : removing message:" + _messageId); - _transactionLog.removeMessage(storeContext, _messageId); - } - @Override public boolean isPersistent() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 0df976a620..09600b9d28 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -49,7 +49,6 @@ public interface QueueEntry extends Comparable, Filterable, Filterable, Filterable, Filterable, Filterable, Filterable, Filterable, Filterable 0; - } - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) { return new BodyFrameIterator(protocolSession, channel); @@ -197,76 +192,6 @@ public class TransientAMQMessage implements AMQMessage return _messageId; } - /* Threadsafe. Increment the reference count on the message. */ - public boolean incrementReference(int count) - { - if (_referenceCount.addAndGet(count) <= 1) - { - int newcount = _referenceCount.addAndGet(-count); - _log.debug("Message(" + _messageId + ") Incremented Ref count by (" + count + ") to :" + newcount); - return false; - } - else - { - _log.debug("Message(" + _messageId + ") Incremented Ref count by (" + count + ") but count was <=1(" - + _referenceCount.get() + ")"); - return true; - } - - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @param storeContext - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException - { - - int count = _referenceCount.decrementAndGet(); - - _log.debug("Message(" + _messageId + ") Decremented Ref count to :" + count); - - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (count == 0) - { - // set the reference count way below 0 so that we can detect that the message has been deleted - // this is to guard against the message being spontaneously recreated (from the mgmt console) - // by copying from other queues at the same time as it is being removed. - _referenceCount.set(Integer.MIN_VALUE / 2); - - try - { - _log.debug("Reference Count hit 0, removing message"); - // must check if the handle is null since there may be cases where we decide to throw away a message - // and the handle has not yet been constructed - // no need to perform persistent check anymore as TransientAMQM.removeMessage() is a no-op - removeMessage(storeContext); - } - catch (AMQException e) - { - // to maintain consistency, we revert the count - incrementReference(1); - throw new MessageCleanupException(getMessageId(), e); - } - } - else - { - if (count < 0) - { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() - + " has gone below 0."); - } - } - } - /** * Called selectors to determin if the message has already been sent * @@ -435,11 +360,6 @@ public class TransientAMQMessage implements AMQMessage return _arrivalTime; } - public void removeMessage(StoreContext storeContext) throws AMQException - { - //no-op - } - public String toString() { // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index fe81346c8c..33b3d8608e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -1357,7 +1357,8 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable if(message != null) { - message.incrementReference(1); + //todo must enqueue message to build reference table +// message.incrementReference(1); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index aa7b6e2542..cd0f0c1769 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -30,24 +30,28 @@ import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.routing.RoutingTable; +import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -/** A simple message store that stores the messages in a threadsafe structure in memory. +/** + * A simple message store that stores the messages in a threadsafe structure in memory. * * NOTE: Now that we have removed the MessageStore interface and are using a TransactionLog * * This class really should have no storage unless we want to do inMemory Recovery. - * */ public class MemoryMessageStore implements TransactionLog, RoutingTable { @@ -63,6 +67,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable private final AtomicLong _messageId = new AtomicLong(1); private AtomicBoolean _closed = new AtomicBoolean(false); + protected final Map> _messageEnqueueMap = new HashMap>(); public void configure() { @@ -112,6 +117,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } _metaDataMap.remove(messageId); _contentBodyMap.remove(messageId); + _messageEnqueueMap.remove(messageId); } public void createExchange(Exchange exchange) throws AMQException @@ -134,7 +140,6 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } - public void createQueue(AMQQueue queue) throws AMQException { // Not requred to do anything @@ -152,12 +157,39 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { - // Not required to do anything + synchronized (_messageEnqueueMap) + { + List queues = _messageEnqueueMap.get(messageId); + if (queues == null) + { + queues = new LinkedList(); + _messageEnqueueMap.put(messageId, queues); + } + + queues.add(queue); + } } public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { - // Not required to do anything + synchronized (_messageEnqueueMap) + { + List queues = _messageEnqueueMap.get(messageId); + if (queues == null || !queues.contains(queue)) + { + throw new RuntimeException("Attempt to dequeue messageID:" + messageId + " from queue:" + queue.getName() + + " but it is not enqueued on that queue."); + } + else + { + queues.remove(queue); + if (queues.isEmpty()) + { + removeMessage(context,messageId); + } + } + } + } public void beginTran(StoreContext context) throws AMQException @@ -238,7 +270,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } private void checkNotClosed() throws MessageStoreClosedException - { + { if (_closed.get()) { throw new MessageStoreClosedException(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 1c58e644e9..119a4b1692 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -144,7 +144,8 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage StoreContext storeContext = getChannel().getStoreContext(); try - { // if we do not need to wait for client acknowledgements + { + // 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 @@ -153,7 +154,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage // The send may of course still fail, in which case, as // the message is unacked, it will be lost. - entry.dequeue(storeContext); + entry.dequeueAndDelete(storeContext); synchronized (getChannel()) @@ -163,7 +164,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage sendToClient(entry, deliveryTag); } - entry.dispose(storeContext); } finally { @@ -316,7 +316,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _autoClose = false; } - + _logger.info(debugIdentity()+" Created subscription:"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 8e63b95f0d..abfb60c5bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -92,20 +92,12 @@ public class LocalTransactionalContext implements TransactionalContext public void process() throws AMQException { - _message.incrementReference(1); - try - { QueueEntry entry = _queue.enqueue(getStoreContext(),_message); if(entry.immediateAndNotDelivered()) { getReturnMessages().add(new NoConsumersException(_message)); } - } - finally - { - _message.decrementReference(getStoreContext()); - } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 145d7f8b13..561f998b98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -123,18 +123,18 @@ public class NonTransactionalContext implements TransactionalContext unacknowledgedMessageMap.size()); unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() { - public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException + public boolean callback(final long deliveryTag, QueueEntry queueEntry) throws AMQException { if (debug) { - _log.debug("Discarding message: " + message.getMessage().getMessageId()); + _log.debug("Discarding message: " + queueEntry.getMessage().getMessageId()); } - if(message.getMessage().isPersistent()) + if(queueEntry.getMessage().isPersistent()) { beginTranIfNecessary(); } - //Message has been ack so discard it. This will dequeue and decrement the reference. - message.discard(_storeContext); + //Message has been ack so dequeueAndDelete it. + queueEntry.dequeueAndDelete(_storeContext); return false; } @@ -157,10 +157,10 @@ public class NonTransactionalContext implements TransactionalContext } else { - QueueEntry msg; - msg = unacknowledgedMessageMap.get(deliveryTag); + QueueEntry queueEntry; + queueEntry = unacknowledgedMessageMap.get(deliveryTag); - if (msg == null) + if (queueEntry == null) { _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channel.getChannelId()); @@ -170,15 +170,17 @@ public class NonTransactionalContext implements TransactionalContext if (debug) { - _log.debug("Discarding message: " + msg.getMessage().getMessageId()); + _log.debug("Discarding message: " + queueEntry.getMessage().getMessageId()); } - if(msg.getMessage().isPersistent()) + if(queueEntry.getMessage().isPersistent()) { beginTranIfNecessary(); } - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); + //Message has been ack so dequeueAndDelete it. + // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed + // from the transaciton log + queueEntry.dequeueAndDelete(_storeContext); unacknowledgedMessageMap.remove(deliveryTag); @@ -186,7 +188,7 @@ public class NonTransactionalContext implements TransactionalContext if (debug) { _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - msg.getMessage().getMessageId()); + queueEntry.getMessage().getMessageId()); } } if(_inTran) -- cgit v1.2.1 From 755e6b33b45e4b59a20e94bb1fddf8fdde2d102c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Feb 2009 14:55:26 +0000 Subject: QPID-1621,QPID-1632 : Added a setManagementEnabled option to allow the MC to be disabled. Updates as a result of merging configuration changes. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@746265 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/ServerConfiguration.java | 6 ++++++ .../org/apache/qpid/server/store/MemoryMessageStore.java | 2 +- .../apache/qpid/server/transactionlog/TransactionLog.java | 12 ------------ .../org/apache/qpid/server/txn/NonTransactionalContext.java | 10 +++++----- .../java/org/apache/qpid/server/virtualhost/VirtualHost.java | 9 +++++---- 5 files changed, 17 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 225042e9ec..9a358d9ba7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -263,6 +263,12 @@ public class ServerConfiguration return _config.getBoolean("management.enabled", true); } + public void setManagementEnabled(boolean enabled) + { + _config.setProperty("management.enabled", enabled); + } + + public int getHeartBeatDelay() { return _config.getInt("heartbeat.delay", 5); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index cd0f0c1769..3754b41a3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -108,7 +108,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } } - public void removeMessage(StoreContext context, Long messageId) throws AMQException + private void removeMessage(StoreContext context, Long messageId) throws AMQException { checkNotClosed(); if (_log.isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java index 4fa85dd6cd..97a1ecb38c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java @@ -77,18 +77,6 @@ public interface TransactionLog */ void close() throws Exception; - /** - * Removes the specified message from the store in the given transactional store context. - * - * @param storeContext The transactional context to remove the message in. - * @param messageId Identifies the message to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - - /** * Places a message onto a specified queue, in a given transactional context. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 561f998b98..0ca8135f71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -160,6 +160,11 @@ public class NonTransactionalContext implements TransactionalContext QueueEntry queueEntry; queueEntry = unacknowledgedMessageMap.get(deliveryTag); + if (debug) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag); + } + if (queueEntry == null) { _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + @@ -185,11 +190,6 @@ public class NonTransactionalContext implements TransactionalContext unacknowledgedMessageMap.remove(deliveryTag); - if (debug) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - queueEntry.getMessage().getMessageId()); - } } if(_inTran) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 1115ed723c..e1b770b1d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -160,7 +160,11 @@ public class VirtualHost implements Accessable _connectionRegistry = new ConnectionRegistry(this); _houseKeepingTimer = new Timer("Queue-housekeeping-"+_name, true); - + + _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeRegistry = new DefaultExchangeRegistry(this); + if (transactionLog != null) { _transactionLog = transactionLog; @@ -175,10 +179,7 @@ public class VirtualHost implements Accessable initialiseRoutingTable(hostConfig); } - _queueRegistry = new DefaultQueueRegistry(this); - _exchangeFactory = new DefaultExchangeFactory(this); _exchangeFactory.initialise(hostConfig); - _exchangeRegistry = new DefaultExchangeRegistry(this); _exchangeRegistry.initialise(); initialiseModel(hostConfig); -- cgit v1.2.1 From 18097b7fdb30fe06adfeff3be2146d35fb42e361 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 24 Feb 2009 13:02:30 +0000 Subject: Merge branch 'QPID-1612' git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747363 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 84 ++++++++++++++++++---- 1 file changed, 69 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 9a358d9ba7..af1df13609 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -25,12 +25,18 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import org.apache.commons.configuration.CombinedConfiguration; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConfigurationFactory; +import org.apache.commons.configuration.DefaultConfigurationBuilder; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.configuration.ConfigurationFactory.DigesterConfigurationFactory; +import org.apache.commons.configuration.tree.ExpressionEngine; public class ServerConfiguration { @@ -45,24 +51,57 @@ public class ServerConfiguration private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; private static final int DEFAULT_JMXPORT = 8999; - private long _housekeepingExpiredMessageCheckPeriod = DEFAULT_HOUSEKEEPING_PERIOD; private static int _jmxPort = DEFAULT_JMXPORT; private Map _virtualHosts = new HashMap(); private SecurityConfiguration _securityConfiguration = null; + + // Map of environment variables to config items + private static final Map envVarMap = new HashMap(); + + { + envVarMap.put("QPID_PORT", "connector.port"); + envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers"); + envVarMap.put("QPID_SSLPORT", "connector.ssl.port"); + envVarMap.put("QPID_NIO", "connector.qpidnio"); + envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool"); + envVarMap.put("QPID_JMXPORT", "management.jmxport"); + envVarMap.put("QPID_FRAMESIZE", "advanced.framesize"); + envVarMap.put("QPID_MSGAUTH", "security.msg-auth"); + envVarMap.put("QPID_AUTOREGISTER", "auto_register"); + envVarMap.put("QPID_MANAGEMENTENABLED", "management.enabled"); + envVarMap.put("QPID_HEARTBEATDELAY", "heartbeat.delay"); + envVarMap.put("QPID_HEARTBEATTIMEOUTFACTOR", "heartbeat.timeoutFactor"); + envVarMap.put("QPID_MAXIMUMMESSAGEAGE", "maximumMessageAge"); + envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount"); + envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth"); + envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize"); + envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap"); + envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer"); + envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer"); + envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay"); + envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator"); + } public ServerConfiguration(File configurationURL) throws ConfigurationException { - this(config(configurationURL)); + this(parseConfig(configurationURL)); } public ServerConfiguration(Configuration conf) throws ConfigurationException { _config = conf; + + substituteEnvironmentVariables(); + _jmxPort = _config.getInt("management.jmxport", 8999); - _securityConfiguration = new SecurityConfiguration(conf.subset("security")); + setupVirtualHosts(conf); + } + + private void setupVirtualHosts(Configuration conf) throws ConfigurationException + { List vhosts = conf.getList("virtualhosts"); Iterator i = vhosts.iterator(); while (i.hasNext()) @@ -85,17 +124,32 @@ public class ServerConfiguration } } - public static String[] objListToStringArray(List objList) + private void substituteEnvironmentVariables() { - String[] networkStrings = new String[objList.size()]; - int i = 0; - for (Object network : objList) + for (Entry var : envVarMap.entrySet()) { - networkStrings[i++] = (String) network; + String val = System.getenv(var.getKey()); + if (val != null) + { + _config.setProperty(var.getValue(), val); + } } - return networkStrings; } + private final static Configuration parseConfig(File file) throws ConfigurationException + { + ConfigurationFactory factory = new ConfigurationFactory(); + factory.setConfigurationFileName(file.getAbsolutePath()); + Configuration conf = factory.getConfiguration(); + Iterator keys = conf.getKeys(); + if (!keys.hasNext()) + { + keys = null; + conf = flatConfig(file); + } + return conf; + } + // 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 @@ -105,8 +159,8 @@ public class ServerConfiguration return super.interpolate(obj); } } - - private final static Configuration config(File url) throws ConfigurationException + + private final static Configuration flatConfig(File file) throws ConfigurationException { // We have to override the interpolate methods so that // interpolation takes place accross the entirety of the @@ -121,7 +175,7 @@ public class ServerConfiguration return conf.interpolate(o); } }); - conf.addConfiguration(new XMLConfiguration(url) + conf.addConfiguration(new XMLConfiguration(file) { protected String interpolate(String o) { @@ -399,13 +453,13 @@ public class ServerConfiguration return _config.getString("virtualhosts.default"); } - public void setHousekeepingExpiredMessageCheckPeriod(long _housekeepingExpiredMessageCheckPeriod) + public void setHousekeepingExpiredMessageCheckPeriod(long value) { - this._housekeepingExpiredMessageCheckPeriod = _housekeepingExpiredMessageCheckPeriod; + _config.setProperty("housekeeping.expiredMessageCheckPeriod", value); } public long getHousekeepingExpiredMessageCheckPeriod() { - return _housekeepingExpiredMessageCheckPeriod; + return _config.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); } } -- cgit v1.2.1 From 37d3f0675c0b7f6052c14d104a6b03e78b86965a Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 24 Feb 2009 13:29:59 +0000 Subject: Fix build deps file git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747376 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index af1df13609..b3c08a2a95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -27,16 +27,12 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import org.apache.commons.configuration.CombinedConfiguration; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationFactory; -import org.apache.commons.configuration.DefaultConfigurationBuilder; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.commons.configuration.ConfigurationFactory.DigesterConfigurationFactory; -import org.apache.commons.configuration.tree.ExpressionEngine; public class ServerConfiguration { -- cgit v1.2.1 From 65174361067400b29aae1946457d2fef2ef694e8 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 25 Feb 2009 11:30:04 +0000 Subject: QPID-1632 : Removed commented code git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747751 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 1 - 1 file changed, 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 5a01888ccf..9b29c7b921 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -251,7 +251,6 @@ public class AMQChannel } catch (NoRouteException e) { - //_currentMessage.takeReference(); _returnMessages.add(e); } } -- cgit v1.2.1 From f3d424977961151a0ce4676eb93ecaff9ceb8569 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 25 Feb 2009 11:31:18 +0000 Subject: QPID-1633 : Added new properties to SimpleAMQQueue with appropriate getters/setters from the ServerConfiguration and Management Console. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747753 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/QueueConfiguration.java | 20 +++++- .../server/configuration/ServerConfiguration.java | 7 +- .../configuration/VirtualHostConfiguration.java | 34 ++++++++- .../org/apache/qpid/server/queue/AMQQueue.java | 10 +++ .../apache/qpid/server/queue/AMQQueueFactory.java | 2 + .../apache/qpid/server/queue/AMQQueueMBean.java | 30 ++++++++ .../org/apache/qpid/server/queue/ManagedQueue.java | 57 +++++++++++++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 80 +++++++++++++++++++++- 8 files changed, 234 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 90d6caec99..83fcfad1fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -21,8 +21,10 @@ package org.apache.qpid.server.configuration; import java.util.List; +import java.io.File; import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.registry.ApplicationRegistry; public class QueueConfiguration { @@ -31,13 +33,20 @@ public class QueueConfiguration private Configuration _config; private String _name; + private VirtualHostConfiguration _virtualHostConfiguration; - public QueueConfiguration(String name, Configuration config) + public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) { + _virtualHostConfiguration = virtualHostConfiguration; _config = config; _name = name; } + public VirtualHostConfiguration getVirtualHostConfiguration() + { + return _virtualHostConfiguration; + } + public boolean getDurable() { return _config.getBoolean("durable" ,false); @@ -103,4 +112,13 @@ public class QueueConfiguration return _config.getLong("minimumAlertRepeatGap", 0); } + public long getMemoryUsageMaximum() + { + return _config.getLong("maximumMemoryUsage", 0); + } + + public long getMemoryUsageMinimum() + { + return _config.getLong("minimumMemoryUsage", 0); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index b3c08a2a95..484a241fc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -113,7 +113,7 @@ public class ServerConfiguration CompositeConfiguration mungedConf = new CompositeConfiguration(); mungedConf.addConfiguration(conf.subset("virtualhosts.virtualhost."+name)); mungedConf.addConfiguration(vhostConfiguration.subset("virtualhost." + name)); - VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, mungedConf); + VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, mungedConf, this); _virtualHosts.put(vhostConfig.getName(), vhostConfig); } } @@ -181,6 +181,11 @@ public class ServerConfiguration return conf; } + public String getQpidWork() + { + return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); + } + public void setJMXManagementPort(int mport) { _jmxPort = mport; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 91d0b8d8da..2a235fe9a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -37,10 +37,12 @@ public class VirtualHostConfiguration private String _name; private Map _queues = new HashMap(); private Map _exchanges = new HashMap(); + private ServerConfiguration _serverConfiguration; - - public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException + public VirtualHostConfiguration(String name, Configuration config, + ServerConfiguration serverConfiguration) throws ConfigurationException { + _serverConfiguration = serverConfiguration; _config = config; _name = name; @@ -52,7 +54,7 @@ public class VirtualHostConfiguration CompositeConfiguration mungedConf = new CompositeConfiguration(); mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); mungedConf.addConfiguration(_config.subset("queues")); - _queues.put(queueName, new QueueConfiguration(queueName, mungedConf)); + _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); } i = _config.getList("exchanges.exchange.name").iterator(); @@ -67,6 +69,11 @@ public class VirtualHostConfiguration } } + public VirtualHostConfiguration(String name, Configuration mungedConf) throws ConfigurationException + { + this(name,mungedConf, null); + } + public String getName() { return _name; @@ -127,4 +134,25 @@ public class VirtualHostConfiguration return _queues.get(queueName); } + public long getMemoryUsageMaximum() + { + return _config.getLong("queues.maximumMemoryUsage", 0); + } + + public long getMemoryUsageMinimum() + { + return _config.getLong("queues.minimumMemoryUsage", 0); + } + + public ServerConfiguration getServerConfiguration() + { + return _serverConfiguration; + } + + public static final String FLOW_TO_DISK_PATH = "flowToDiskPath"; + public String getFlowToDiskLocation() + { + return _config.getString(FLOW_TO_DISK_PATH, getServerConfiguration().getQpidWork()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 9fadbb0cdc..43ec6c4d15 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -68,6 +68,8 @@ public interface AMQQueue extends Managable, Comparable boolean isEmpty(); + boolean isFlowed(); + int getMessageCount(); int getUndeliveredMessageCount(); @@ -111,7 +113,15 @@ public interface AMQQueue extends Managable, Comparable void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); + long getMemoryUsageMaximum(); + + void setMemoryUsageMaximum(long maximumMemoryUsage); + + long getMemoryUsageMinimum(); + + void setMemoryUsageMinimum(long minimumMemoryUsage); + long getMemoryUsageCurrent(); long getMaximumMessageSize(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index eb0a011e93..f977dc0449 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -85,6 +85,8 @@ public class AMQQueueFactory q.setMaximumMessageSize(config.getMaximumMessageSize()); q.setMaximumMessageCount(config.getMaximumMessageCount()); q.setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); + q.setMemoryUsageMaximum(config.getMemoryUsageMaximum()); + q.setMemoryUsageMinimum(config.getMemoryUsageMinimum()); return q; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index a08719875d..b077b453cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -233,6 +233,36 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _queue.setMaximumQueueDepth(value); } + public Long getMemoryUsageMaximum() + { + return _queue.getMemoryUsageMaximum(); + } + + public void setMemoryUsageMaximum(Long maximumMemoryUsage) + { + _queue.setMemoryUsageMaximum(maximumMemoryUsage); + } + + public Long getMemoryUsageMinimum() + { + return _queue.getMemoryUsageMinimum(); + } + + public void setMemoryUsageMinimum(Long minimumMemoryUsage) + { + _queue.setMemoryUsageMinimum(minimumMemoryUsage); + } + + public Long getMemoryUsageCurrent() + { + return _queue.getMemoryUsageCurrent(); + } + + public boolean isFlowed() + { + return _queue.isFlowed(); + } + /** * returns the size of messages(KB) in the queue. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 2bc94995e9..21e99034fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -183,6 +183,63 @@ public interface ManagedQueue @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth") void setMaximumQueueDepth(Long value) throws IOException; + //TODO change descriptions + /** + * View the limit on the memory that this queue will utilise. + * + * Used by Flow to Disk. + * + * @return The maximum memory(B) that the queue will occuy. + */ + public Long getMemoryUsageMaximum(); + + /** + * Place a limit on the memory that this queue will utilise. + * + * Used by Flow to Disk + * + * @param maximumMemoryUsage The new maximum memory(B) to be used by this queue + */ + @MBeanAttribute(name="MemoryUsageMaximum", description="The maximum memory(B) that the queue will occupy.") + public void setMemoryUsageMaximum(Long maximumMemoryUsage); + + /** + * View the minimum amount of memory that has been defined for this queue. + * + * Used by Flow to Disk + * + * @return The minimum amount of queue data(B) that the queue will attempt to keep in memory + */ + public Long getMemoryUsageMinimum(); + + /** + * Set the minimum amount of memory that has been defined for this queue. + * + * Used by Flow to Disk + * + * @param minimumMemoryUsage The new minimum memory(B) level to be used by this queue + */ + @MBeanAttribute(name="MemoryUsageMinimum", description="The minimum memory(B) that the queue will occupy.") + public void setMemoryUsageMinimum(Long minimumMemoryUsage); + + /** + * View the amount of memory(B) that this queue is using. + * + * @return The current memory(B) usage of this queue. + */ + @MBeanAttribute(name="MemoryUsageCurrent", description="The current amount of memory(B) used by this queue.") + public Long getMemoryUsageCurrent(); + + /** + * When a queue exceeds its MemoryUsageMaximum value then the Queue will start flowing to disk. + * + * This boolean is used to show that change in state. + * + * @return true if the Queue is currently flowing to disk + */ + @MBeanAttribute(name="isFlowed", description="true if the queue is currently flowing to disk.") + public boolean isFlowed(); + //********** Operations *****************// diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 501e90b4d7..a4945bc11a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -19,7 +19,6 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; -import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -77,6 +76,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _atomicQueueSize = new AtomicLong(0L); + private final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); + private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); protected final SubscriptionList _subscriptionList = new SubscriptionList(this); @@ -105,6 +106,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener /** the minimum interval between sending out consecutive alerts of the same type */ public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); + /** The maximum amount of memory that is allocated to this queue. Beyond this the queue will flow to disk. */ + private long _memoryUsageMaximum = 0; + + /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ + private long _memoryUsageMinimum = 0; + private static final int MAX_ASYNC_DELIVERIES = 10; private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); @@ -113,6 +120,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private AtomicReference _asynchronousRunner = new AtomicReference(null); private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); + /** Control to determin if this queue is flowed or not. */ + protected AtomicBoolean _flowed = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -159,7 +168,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } resetNotifications(); + resetFlowToDisk(); + } + public void resetFlowToDisk() + { + setMemoryUsageMaximum(_memoryUsageMaximum); + setMemoryUsageMinimum(_memoryUsageMinimum); } public void resetNotifications() @@ -188,6 +203,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _autoDelete; } + public boolean isFlowed() + { + return _flowed.get(); + } + public AMQShortString getOwner() { return _owner; @@ -468,6 +488,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void incrementQueueSize(final AMQMessage message) { getAtomicQueueSize().addAndGet(message.getSize()); + getAtomicQueueInMemory().addAndGet(message.getSize()); } private void incrementQueueCount() @@ -607,6 +628,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void decrementQueueSize(final QueueEntry entry) { getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); + getAtomicQueueInMemory().addAndGet(-entry.getMessage().getSize()); } void decrementQueueCount() @@ -658,6 +680,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return getMessageCount() == 0; } + public long getMemoryUsageCurrent() + { + return getAtomicQueueInMemory().get(); + } + public int getMessageCount() { return getAtomicQueueCount().get(); @@ -751,6 +778,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _atomicQueueSize; } + public AtomicLong getAtomicQueueInMemory() + { + return _atomicQueueInMemory; + } + + private boolean isExclusiveSubscriber() { return _exclusiveSubscriber != null; @@ -1457,6 +1490,51 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + + public long getMemoryUsageMaximum() + { + return _memoryUsageMaximum; + } + + public void setMemoryUsageMaximum(long maximumMemoryUsage) + { + _memoryUsageMaximum = maximumMemoryUsage; + + // Don't attempt to start the inhaler/purger unless we have a minimum value specified. + if (_memoryUsageMaximum > 0) + { + // If we've increased the max memory above what we have in memory then we can inhale more + if (_memoryUsageMaximum > _atomicQueueInMemory.get()) + { + //TODO start inhaler + } + else // if we have now have to much memory in use we need to purge. + { + //TODO start purger + } + } + } + + public long getMemoryUsageMinimum() + { + return _memoryUsageMinimum; + } + + public void setMemoryUsageMinimum(long minimumMemoryUsage) + { + _memoryUsageMinimum = minimumMemoryUsage; + + // Don't attempt to start the inhaler unless we have a minimum value specified. + if (_memoryUsageMinimum > 0) + { + // If we've increased the minimum memory above what we have in memory then we need to inhale more + if (_memoryUsageMinimum >= _atomicQueueInMemory.get()) + { + //TODO start inhaler + } + } + } + public long getMinimumAlertRepeatGap() { return _minimumAlertRepeatGap; -- cgit v1.2.1 From 357424abb8b425a1c1b1d8ac24d1d480d9c41bb3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 25 Feb 2009 11:32:24 +0000 Subject: QPID-1634 : Created QueueBackingStore interface and implementation FileQueueBackingStore. Tested by FileQueueBackingStoreTest. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747754 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 3 +- .../org/apache/qpid/server/queue/AMQMessage.java | 3 + .../qpid/server/queue/FileQueueBackingStore.java | 419 +++++++++++++++++++++ .../qpid/server/queue/PersistentAMQMessage.java | 11 +- .../qpid/server/queue/QueueBackingStore.java | 36 ++ .../qpid/server/queue/TransientAMQMessage.java | 35 +- .../server/queue/UnableToFlowMessageException.java | 29 ++ .../queue/UnableToRecoverMessageException.java | 29 ++ .../qpid/server/virtualhost/VirtualHost.java | 11 +- 9 files changed, 558 insertions(+), 18 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 2a235fe9a2..1077306eac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -28,6 +28,7 @@ import java.util.Map; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; @@ -71,7 +72,7 @@ public class VirtualHostConfiguration public VirtualHostConfiguration(String name, Configuration mungedConf) throws ConfigurationException { - this(name,mungedConf, null); + this(name,mungedConf, new ServerConfiguration(new PropertiesConfiguration())); } public String getName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index e96d2ba874..5bde27dba5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -113,6 +113,9 @@ public interface AMQMessage void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException; + void recoverFromMessageMetaData(MessageMetaData mmd); + + void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException; String toString(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java new file mode 100644 index 0000000000..7acb683e3b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -0,0 +1,419 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.AMQProtocolVersionException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.util.FileUtils; +import org.apache.qpid.AMQException; +import org.apache.commons.configuration.ConfigurationException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class FileQueueBackingStore implements QueueBackingStore +{ + private static final Logger _log = Logger.getLogger(FileQueueBackingStore.class); + + private AtomicBoolean _closed = new AtomicBoolean(false); + private String _flowToDiskLocation; + private static final String QUEUE_BACKING_DIR = "queueBacking"; + + public void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException + { + setFlowToDisk(virtualHost.getName(), config.getFlowToDiskLocation()); + } + + private void setFlowToDisk(String vHostName, String location) throws ConfigurationException + { + if (vHostName == null) + { + throw new ConfigurationException("Unable to setup to Flow to Disk as Virtualhost name was not specified"); + } + + if (location == null) + { + throw new ConfigurationException("Unable to setup to Flow to Disk as location was not specified."); + } + + _flowToDiskLocation = location; + + _flowToDiskLocation += File.separator + QUEUE_BACKING_DIR + File.separator + vHostName; + + File root = new File(location); + if (!root.exists()) + { + throw new ConfigurationException("Specified Flow to Disk root does not exist:" + root.getAbsolutePath()); + } + else + { + + if (root.isFile()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified root is a file:"+ + root.getAbsolutePath()); + } + + if(!root.canWrite()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to specified root:"+ + root.getAbsolutePath()); + } + + } + + + File store = new File(_flowToDiskLocation); + if (store.exists()) + { + if (!FileUtils.delete(store, true)) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store as directory already exsits:" + + store.getAbsolutePath()); + } + + if (store.isFile()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified location is a file:"+ + store.getAbsolutePath()); + } + + } + else + { + if (!store.getParentFile().getParentFile().canWrite()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to parent location:"+ + store.getParentFile().getParentFile().getAbsolutePath()); + } + } + + + _log.info("Creating Flow to Disk Store : " + store.getAbsolutePath()); + store.deleteOnExit(); + if (!store.mkdirs()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store:" + store.getAbsolutePath()); + } + } + + + public AMQMessage recover(Long messageId) + { + MessageMetaData mmd; + List contentBodies = new LinkedList(); + + File handle = getFileHandle(messageId); + handle.deleteOnExit(); + + ObjectInputStream input = null; + + Exception error = null; + try + { + input = new ObjectInputStream(new FileInputStream(handle)); + + long arrivaltime = input.readLong(); + + final AMQShortString exchange = new AMQShortString(input.readUTF()); + final AMQShortString routingKey = new AMQShortString(input.readUTF()); + final boolean mandatory = input.readBoolean(); + final boolean immediate = input.readBoolean(); + + int bodySize = input.readInt(); + byte[] underlying = new byte[bodySize]; + + input.readFully(underlying, 0, bodySize); + + ByteBuffer buf = ByteBuffer.wrap(underlying); + + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, bodySize); + + int chunkCount = input.readInt(); + + // There are WAY to many annonymous MPIs in the code this should be made concrete. + MessagePublishInfo info = new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public void setExchange(AMQShortString exchange) + { + + } + + public boolean isImmediate() + { + return immediate; + } + + public boolean isMandatory() + { + return mandatory; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + }; + + mmd = new MessageMetaData(info, chb, chunkCount); + mmd.setArrivalTime(arrivaltime); + + AMQMessage message; + if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2) + { + message = new PersistentAMQMessage(messageId, null); + } + else + { + message = new TransientAMQMessage(messageId); + } + + message.recoverFromMessageMetaData(mmd); + + for (int chunk = 0; chunk < chunkCount; chunk++) + { + int length = input.readInt(); + + byte[] data = new byte[length]; + + input.readFully(data, 0, length); + + // There are WAY to many annonymous CCs in the code this should be made concrete. + try + { + message.recoverContentBodyFrame(new RecoverDataBuffer(length, data), (chunk + 1 == chunkCount)); + } + catch (AMQException e) + { + //ignore as this will not occur. + // It is thrown by the _transactionLog method in recover on PersistentAMQMessage + // but we have created the message with a null log and will never call that method. + } + } + + return message; + } + catch (Exception e) + { + error = e; + } + finally + { + try + { + input.close(); + } + catch (IOException e) + { + _log.info("Unable to close input on message("+messageId+") recovery due to:"+e.getMessage()); + } + } + + throw new UnableToRecoverMessageException(error); + } + + + public void flow(AMQMessage message) throws UnableToFlowMessageException + { + long messageId = message.getMessageId(); + + File handle = getFileHandle(messageId); + + //If we have written the data once then we don't need to do it again. + if (handle.exists()) + { + _log.debug("Message(" + messageId + ") already flowed to disk."); + return; + } + + handle.deleteOnExit(); + + ObjectOutputStream writer = null; + Exception error = null; + + try + { + writer = new ObjectOutputStream(new FileOutputStream(handle)); + + writer.writeLong(message.getArrivalTime()); + + MessagePublishInfo mpi = message.getMessagePublishInfo(); + writer.writeUTF(String.valueOf(mpi.getExchange())); + writer.writeUTF(String.valueOf(mpi.getRoutingKey())); + writer.writeBoolean(mpi.isMandatory()); + writer.writeBoolean(mpi.isImmediate()); + ContentHeaderBody chb = message.getContentHeaderBody(); + + // write out the content header body + final int bodySize = chb.getSize(); + byte[] underlying = new byte[bodySize]; + ByteBuffer buf = ByteBuffer.wrap(underlying); + chb.writePayload(buf); + + writer.writeInt(bodySize); + writer.write(underlying, 0, bodySize); + + int bodyCount = message.getBodyCount(); + writer.writeInt(bodyCount); + + //WriteContentBody + for (int index = 0; index < bodyCount; index++) + { + ContentChunk chunk = message.getContentChunk(index); + chunk.reduceToFit(); + + byte[] chunkData = chunk.getData().array(); + + int length = chunk.getSize(); + writer.writeInt(length); + writer.write(chunkData, 0, length); + } + } + catch (FileNotFoundException e) + { + error = e; + } + catch (IOException e) + { + error = e; + } + finally + { + try + { + writer.flush(); + writer.close(); + } + catch (IOException e) + { + error = e; + } + } + + if (error != null) + { + _log.error("Unable to flow message(" + messageId + ") to disk, restoring state."); + handle.delete(); + throw new UnableToFlowMessageException(messageId, error); + } + } + + /** + * Use the messageId to calculate the file path on disk. + * + * Current implementation will give us 256 bins. + * Therefore the maximum messages that can be flowed before error/platform is: + * ext3 : 256 bins * 32000 = 8192000 + * FAT32 : 256 bins * 65534 = 16776704 + * Other FS have much greater limits than we need to worry about. + * + * @param messageId the Message we need a file Handle for. + * + * @return the File handle + */ + private File getFileHandle(long messageId) + { + // grab the 8 LSB to give us 256 bins + long bin = messageId & 0xFFL; + + String bin_path =_flowToDiskLocation + File.separator + bin; + File bin_dir = new File(bin_path); + + if (!bin_dir.exists()) + { + bin_dir.mkdirs(); + bin_dir.deleteOnExit(); + } + + String id = bin_path + File.separator + messageId; + + return new File(id); + } + + public void delete(Long messageId) + { + String id = String.valueOf(messageId); + File handle = new File(_flowToDiskLocation, id); + + if (handle.exists()) + { + _log.debug("Message(" + messageId + ") delete flowToDisk."); + if (!handle.delete()) + { + throw new RuntimeException("Unable to delete flowToDisk data"); + } + } + } + + private class RecoverDataBuffer implements ContentChunk + { + private int _length; + private ByteBuffer _dataBuffer; + + public RecoverDataBuffer(int length, byte[] data) + { + _length = length; + _dataBuffer = ByteBuffer.wrap(data); + } + + public int getSize() + { + return _length; + } + + public ByteBuffer getData() + { + return _dataBuffer; + } + + public void reduceToFit() + { + + } + + } + +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java index 92c10b0347..9c644cc010 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java @@ -52,7 +52,8 @@ public class PersistentAMQMessage extends TransientAMQMessage throws AMQException { super.setPublishAndContentHeaderBody(storeContext, messagePublishInfo, contentHeaderBody); - MessageMetaData mmd = new MessageMetaData(messagePublishInfo, contentHeaderBody, _contentBodies == null ? 0 : _contentBodies.size(), _arrivalTime); + MessageMetaData mmd = new MessageMetaData(messagePublishInfo, contentHeaderBody, + _contentBodies == null ? 0 : _contentBodies.size(), _arrivalTime); _transactionLog.storeMessageMetaData(storeContext, _messageId, mmd); } @@ -63,13 +64,7 @@ public class PersistentAMQMessage extends TransientAMQMessage return true; } - public void recoverFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = mmd.getContentHeaderBody(); - _messagePublishInfo = mmd.getMessagePublishInfo(); - } - + @Override public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException { super.addContentBodyFrame(null, contentChunk, isLastContentBody); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java new file mode 100644 index 0000000000..376e6f1b57 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.commons.configuration.ConfigurationException; + +public interface QueueBackingStore +{ + void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException; + + AMQMessage recover(Long messageId); + + void flow(AMQMessage message) throws UnableToFlowMessageException; + + void delete(Long messageId); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java index fa4e85a043..bea10cef53 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java @@ -339,27 +339,48 @@ public class TransientAMQMessage implements AMQMessage throw new NullPointerException("PublishInfo cannot be null"); } - _messagePublishInfo = messagePublishInfo; + _arrivalTime = System.currentTimeMillis(); + + _contentHeaderBody = contentHeaderBody; + _messagePublishInfo = messagePublishInfo; + + updateHeaderAndFlags(); + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void recoverFromMessageMetaData(MessageMetaData mmd) + { + _arrivalTime = mmd.getArrivalTime(); + _contentHeaderBody = mmd.getContentHeaderBody(); + _messagePublishInfo = mmd.getMessagePublishInfo(); - if (contentHeaderBody.bodySize == 0) + updateHeaderAndFlags(); + } + + private void updateHeaderAndFlags() + { + if (_contentHeaderBody.bodySize == 0) { _contentBodies = Collections.EMPTY_LIST; } - _arrivalTime = System.currentTimeMillis(); - - if (messagePublishInfo.isImmediate()) + if (_messagePublishInfo.isImmediate()) { _flags |= IMMEDIATE; } } - public long getArrivalTime() + public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException { - return _arrivalTime; + addContentBodyFrame(null, contentChunk, isLastContentBody); } + public String toString() { // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java new file mode 100644 index 0000000000..03cfed8533 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +public class UnableToFlowMessageException extends Exception +{ + public UnableToFlowMessageException(long messageId, Exception error) + { + super("Unable to Flow Message:"+messageId, error); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java new file mode 100644 index 0000000000..cae5bc6327 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +public class UnableToRecoverMessageException extends RuntimeException +{ + public UnableToRecoverMessageException(Exception error) + { + super(error); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e1b770b1d3..e10697f580 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -84,7 +84,9 @@ public class VirtualHost implements Accessable private ACLManager _accessManager; private final Timer _houseKeepingTimer; - + + private VirtualHostConfiguration _configuration; + public void setAccessableName(String name) { _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" @@ -106,6 +108,11 @@ public class VirtualHost implements Accessable return _routingTable; } + public VirtualHostConfiguration getConfiguration() + { + return _configuration ; + } + /** * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any * implementaion of an Exchange MBean should extend this class. @@ -137,7 +144,6 @@ public class VirtualHost implements Accessable /** * Normal Constructor - * @param name * @param hostConfig * @throws Exception */ @@ -148,6 +154,7 @@ public class VirtualHost implements Accessable public VirtualHost(VirtualHostConfiguration hostConfig, TransactionLog transactionLog) throws Exception { + _configuration = hostConfig; _name = hostConfig.getName(); if (_name == null || _name.length() == 0) -- cgit v1.2.1 From c96d23b520c2df7e377532ba027e6ddb29d4710a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 25 Feb 2009 11:32:56 +0000 Subject: QPID-1686 - Had to had another AR.getInstance() call as alternative is to complete this JIRA. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747755 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/VirtualHostConfiguration.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 1077306eac..650f6722f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -70,9 +70,19 @@ public class VirtualHostConfiguration } } + /** + * All future usages should use the constructor that takes the ServerConfiguration. + * + * This can be removed after QPID-1696 has been resolved. + * + * @param name + * @param mungedConf + * @throws ConfigurationException + */ + @Deprecated public VirtualHostConfiguration(String name, Configuration mungedConf) throws ConfigurationException { - this(name,mungedConf, new ServerConfiguration(new PropertiesConfiguration())); + this(name,mungedConf, ApplicationRegistry.getInstance().getConfiguration()); } public String getName() @@ -82,7 +92,7 @@ public class VirtualHostConfiguration public long getHousekeepingExpiredMessageCheckPeriod() { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingExpiredMessageCheckPeriod()); + return _config.getLong("housekeeping.expiredMessageCheckPeriod", _serverConfiguration.getHousekeepingExpiredMessageCheckPeriod()); } public String getAuthenticationDatabase() -- cgit v1.2.1 From 50b29ef8901b40d9880c1758b2329309cf837873 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 25 Feb 2009 17:47:10 +0000 Subject: QPID-1537: Version MBeans. Patch from Robbie Gemmell git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747868 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../org/apache/qpid/server/exchange/AbstractExchange.java | 6 +----- .../java/org/apache/qpid/server/exchange/ManagedExchange.java | 1 + .../org/apache/qpid/server/management/AMQManagedObject.java | 4 ++-- .../apache/qpid/server/management/DefaultManagedObject.java | 11 ++++++++++- .../java/org/apache/qpid/server/management/ManagedBroker.java | 4 ++-- .../apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 4 +--- .../org/apache/qpid/server/protocol/ManagedConnection.java | 1 + .../main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../main/java/org/apache/qpid/server/queue/ManagedQueue.java | 1 + .../security/access/management/AMQUserManagementMBean.java | 2 +- .../server/security/access/management/UserManagement.java | 3 +++ .../apache/qpid/server/virtualhost/ManagedVirtualHost.java | 1 + .../java/org/apache/qpid/server/virtualhost/VirtualHost.java | 2 +- 14 files changed, 27 insertions(+), 17 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 7216841a94..22bdae8267 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -77,7 +77,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { - super(ManagedBroker.class, ManagedBroker.TYPE); + super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); _virtualHostMBean = virtualHostMBean; VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 8d24626b73..b6c741bbec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -38,13 +38,9 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.List; -import java.util.Map; - public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; @@ -81,7 +77,7 @@ public abstract class AbstractExchange implements Exchange, Managable public ExchangeMBean() throws NotCompliantMBeanException { - super(ManagedExchange.class, ManagedExchange.TYPE); + super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); } protected void init() throws OpenDataException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java index 5d6d68b3c8..317ff385ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -40,6 +40,7 @@ import org.apache.qpid.server.queue.ManagedQueue; public interface ManagedExchange { static final String TYPE = "Exchange"; + static final int VERSION = 1; /** * Returns the name of the managed exchange. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java index a2c2bd62a2..c6e07f6f48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -50,10 +50,10 @@ public abstract class AMQManagedObject extends DefaultManagedObject protected MBeanInfo _mbeanInfo; - protected AMQManagedObject(Class managementInterface, String typeName) + protected AMQManagedObject(Class managementInterface, String typeName, int version) throws NotCompliantMBeanException { - super(managementInterface, typeName); + super(managementInterface, typeName, version); buildMBeanInfo(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 84526dbc11..67aee90ba4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -39,13 +39,15 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana private Class _managementInterface; private String _typeName; + private int _version; - protected DefaultManagedObject(Class managementInterface, String typeName) + protected DefaultManagedObject(Class managementInterface, String typeName, int version) throws NotCompliantMBeanException { super(managementInterface); _managementInterface = managementInterface; _typeName = typeName; + _version = version; } public String getType() @@ -115,6 +117,10 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(getHierarchicalName(this)); objectName.append("name=").append(name); + objectName.append(","); + objectName.append("version=").append(_version); + + return new ObjectName(objectName.toString()); } @@ -132,6 +138,9 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); } + objectName.append(","); + objectName.append("version=").append(_version); + return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index 45e2e91ed7..c18417fc43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -40,12 +40,13 @@ public interface ManagedBroker { static final String TYPE = "VirtualHostManager"; + static final int VERSION = 1 ; + /** * Creates a new Exchange. * @param name * @param type * @param durable - * @param passive * @throws IOException * @throws JMException */ @@ -73,7 +74,6 @@ public interface ManagedBroker * @param queueName * @param durable * @param owner - * @param autoDelete * @throws IOException * @throws JMException */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index bd072985c4..5dd3cc075a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,7 +37,6 @@ */ package org.apache.qpid.server.protocol; -import java.security.Principal; import java.util.Date; import java.util.List; @@ -58,7 +57,6 @@ import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.MethodRegistry; @@ -93,7 +91,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException { - super(ManagedConnection.class, ManagedConnection.TYPE); + super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); _session = session; String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index e6e713ac6d..e75b09a0cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -41,6 +41,7 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedConnection { static final String TYPE = "Connection"; + static final int VERSION = 1; @MBeanAttribute(name = "ClientId", description = "Client Id") String getClientId(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index b077b453cb..6c44d70847 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -100,7 +100,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException { - super(ManagedQueue.class, ManagedQueue.TYPE); + super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); _queue = queue; _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 21e99034fc..48fae57134 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -41,6 +41,7 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedQueue { static final String TYPE = "Queue"; + static final int VERSION = 1; /** * Returns the Name of the ManagedQueue. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index f04aecd0a5..e127e7a9d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -104,7 +104,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public AMQUserManagementMBean() throws JMException { - super(UserManagement.class, UserManagement.TYPE); + super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); } public String getObjectInstanceName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java index 658d7ebbd3..9fcdd4cd17 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java @@ -33,7 +33,9 @@ import java.io.IOException; public interface UserManagement { + String TYPE = "UserManagement"; + int VERSION = 2; //********** Operations *****************// /** @@ -115,4 +117,5 @@ public interface UserManagement impact = MBeanOperationInfo.INFO) TabularData viewUsers(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 85d804457e..f4c81fbbb8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.management.MBeanAttribute; public interface ManagedVirtualHost { static final String TYPE = "VirtualHost"; + static final int VERSION = 1; /** * Returns the name of the managed virtualHost. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e10697f580..b4b392c91d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -121,7 +121,7 @@ public class VirtualHost implements Accessable { public VirtualHostMBean() throws NotCompliantMBeanException { - super(ManagedVirtualHost.class, "VirtualHost"); + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); } public String getObjectInstanceName() -- cgit v1.2.1 From c58c862dec600fa99de317c25020f2f5d30405e8 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 25 Feb 2009 17:49:05 +0000 Subject: QPID-1568: make isInstanceOf and isRegistered read only methods. Fix code style issue with field name. Patch from Robbie Gemmell git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747869 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/MBeanInvocationHandlerImpl.java | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index a0ecc2bd85..6a81646cae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -53,7 +53,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler public final static String READWRITE = "readwrite"; public final static String READONLY = "readonly"; private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; - private MBeanServer mbs; + private MBeanServer _mbs; private static Properties _userRoles = new Properties(); public static MBeanServerForwarder newProxyInstance() @@ -71,7 +71,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler if (methodName.equals("getMBeanServer")) { - return mbs; + return _mbs; } if (methodName.equals("setMBeanServer")) @@ -80,11 +80,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler { throw new IllegalArgumentException("Null MBeanServer"); } - if (mbs != null) + if (_mbs != null) { throw new IllegalArgumentException("MBeanServer object already initialized"); } - mbs = (MBeanServer) args[0]; + _mbs = (MBeanServer) args[0]; return null; } @@ -95,12 +95,12 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler // Allow operations performed locally on behalf of the connector server itself if (subject == null) { - return method.invoke(mbs, args); + return method.invoke(_mbs, args); } if (args == null || DELEGATE.equals(args[0])) { - return method.invoke(mbs, args); + return method.invoke(_mbs, args); } // Restrict access to "createMBean" and "unregisterMBean" to any user @@ -124,7 +124,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler { if (isAdmin(identity)) { - return method.invoke(mbs, args); + return method.invoke(_mbs, args); } else { @@ -135,14 +135,14 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler // Following users can perform any operation other than "createMBean" and "unregisterMBean" if (isAllowedToModify(identity)) { - return method.invoke(mbs, args); + return method.invoke(_mbs, args); } // These users can only call "getAttribute" on the MBeanServerDelegate MBean // Here we can add other fine grained permissions like specific method for a particular mbean if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) { - return method.invoke(mbs, args); + return method.invoke(_mbs, args); } throw new SecurityException("Access denied"); @@ -196,7 +196,10 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler private boolean isReadOnlyMethod(Method method, Object[] args) { String methodName = method.getName(); - if (methodName.startsWith("query") || methodName.startsWith("get")) + + //handle standard get/set/query and select 'is' methods from MBeanServer + if (methodName.startsWith("query") || methodName.startsWith("get") + ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) { return true; } @@ -205,8 +208,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler return false; } + //handle invocation of other methods on mbeans if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) { + + //get invoked method name String mbeanMethod = (args.length > 1) ? (String) args[1] : null; if (mbeanMethod == null) { @@ -215,7 +221,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler try { - MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); + //check if the given method is tagged with an INFO impact attribute + MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); if (mbeanInfo != null) { MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); -- cgit v1.2.1 From c1fdf76a434a011f190c322d458f66a7e4e8fd04 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 25 Feb 2009 17:53:09 +0000 Subject: QPID-1648: Add LoggingManagement and associated MBean to enable dynamic reloading of log4j file. Update sample log4js so that they aren't arbitrarily rewritten. Patch from Robbie Gemmell git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747870 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 51 +- .../logging/management/LoggingManagement.java | 258 ++++ .../logging/management/LoggingManagementMBean.java | 1334 ++++++++++++++++++++ .../management/MBeanInvocationHandlerImpl.java | 8 +- 4 files changed, 1634 insertions(+), 17 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 780a17940e..0e5facfefe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -42,10 +42,12 @@ import org.apache.mina.common.IoAcceptor; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; import org.apache.mina.util.NewThreadExecutor; +import org.apache.qpid.AMQException; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -232,16 +234,29 @@ public class Main String logConfig = commandLine.getOptionValue("l"); String logWatchConfig = commandLine.getOptionValue("w", "0"); + + int logWatchTime = 0; + try + { + logWatchTime = Integer.parseInt(logWatchConfig); + } + catch (NumberFormatException e) + { + System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + + "a non-negative integer. Using default of zero (no watching configured"); + } + + File logConfigFile; if (logConfig != null) { - File logConfigFile = new File(logConfig); - configureLogging(logConfigFile, logWatchConfig); + logConfigFile = new File(logConfig); + configureLogging(logConfigFile, logWatchTime); } else { File configFileDirectory = configFile.getParentFile(); - File logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); - configureLogging(logConfigFile, logWatchConfig); + logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); + configureLogging(logConfigFile, logWatchTime); } ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); @@ -249,6 +264,8 @@ public class Main updateManagementPort(serverConfig, commandLine.getOptionValue("m")); ApplicationRegistry.initialise(config); + + configureLoggingManagementMBean(logConfigFile, logWatchTime); //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say @@ -445,19 +462,8 @@ public class Main return ip; } - private void configureLogging(File logConfigFile, String logWatchConfig) + private void configureLogging(File logConfigFile, int logWatchTime) { - 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()); @@ -481,4 +487,17 @@ public class Main } } + private void configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception + { + LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); + + try + { + blm.register(); + } + catch (AMQException e) + { + throw new InitException("Unable to initialise the Logging Management MBean: ", e); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java new file mode 100644 index 0000000000..d60b9c304a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +public interface LoggingManagement +{ + String TYPE = "LoggingManagement"; + int VERSION = 1; + + //TabularType and contained CompositeType key/description information + String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; + String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; + String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; + + /** + * Attribute to represent the log4j xml configuration file's LogWatch interval. + * @return The logwatch interval in seconds. + */ + @MBeanAttribute(name="Log4jLogWatchInterval", + description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") + Integer getLog4jLogWatchInterval(); + + + //****** log4j runtime operations ****** // + + /** + * Sets the level of an active Log4J logger + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Retrieves a TabularData set of the active log4j loggers and their levels + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + */ + @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + + "for active log4j logger's.", impact = MBeanOperationInfo.INFO) + TabularData viewEffectiveRuntimeLoggerLevels(); + + /** + * Sets the level of the active Log4J RootLogger + * @param level The level to set the RootLogger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Attribute to represent the level of the active Log4J RootLogger + * @return The level of the RootLogger. + */ + @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") + String getRuntimeRootLoggerLevel(); + + + //****** log4j XML configuration file operations ****** // + + /** + * Updates the level of an existing Log4J logger within the xml configuration file + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + + "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) + TabularData viewConfigFileLoggerLevels() throws IOException; + + /** + * Updates the level of the Log4J RootLogger within the xml configuration file if it is present + * @param level The level to set the logger to + * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Attribute to represent the level of the Log4J RootLogger within the xml configuration file + * @return The level of the RootLogger, or null if it is not present + */ + @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + + "in the log4j xml configuration file.") + String getConfigFileRootLoggerLevel() throws IOException; +} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +public interface LoggingManagement +{ + String TYPE = "LoggingManagement"; + int VERSION = 1; + + //TabularType and contained CompositeType key/description information + String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; + String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; + String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; + + /** + * Attribute to represent the log4j xml configuration file's LogWatch interval. + * @return The logwatch interval in seconds. + */ + @MBeanAttribute(name="Log4jLogWatchInterval", + description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") + Integer getLog4jLogWatchInterval(); + + + //****** log4j runtime operations ****** // + + /** + * Sets the level of an active Log4J logger + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Retrieves a TabularData set of the active log4j loggers and their levels + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + */ + @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + + "for active log4j logger's.", impact = MBeanOperationInfo.INFO) + TabularData viewEffectiveRuntimeLoggerLevels(); + + /** + * Sets the level of the active Log4J RootLogger + * @param level The level to set the RootLogger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Attribute to represent the level of the active Log4J RootLogger + * @return The level of the RootLogger. + */ + @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") + String getRuntimeRootLoggerLevel(); + + + //****** log4j XML configuration file operations ****** // + + /** + * Updates the level of an existing Log4J logger within the xml configuration file + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + + "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) + TabularData viewConfigFileLoggerLevels() throws IOException; + + /** + * Updates the level of the Log4J RootLogger within the xml configuration file if it is present + * @param level The level to set the logger to + * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Attribute to represent the level of the Log4J RootLogger within the xml configuration file + * @return The level of the RootLogger, or null if it is not present + */ + @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + + "in the log4j xml configuration file.") + String getConfigFileRootLoggerLevel() throws IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java new file mode 100644 index 0000000000..e35292c4b0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -0,0 +1,1334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.Log4jEntityResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + + +/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ +@MBeanDescription("Logging Management Interface") +public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement +{ + + private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); + private String _log4jConfigFileName; + private int _log4jLogWatchInterval; + + static TabularType _loggerLevelTabularType; + static CompositeType _loggerLevelCompositeType; + + static + { + try + { + OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; + + _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); + + _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", + _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing logger levels was incorrect."); + _loggerLevelTabularType = null; + } + } + + public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException + { + super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); + _log4jConfigFileName = log4jConfigFileName; + _log4jLogWatchInterval = log4jLogWatchInterval; + } + + public String getObjectInstanceName() + { + return LoggingManagement.TYPE; + } + + public Integer getLog4jLogWatchInterval() + { + return _log4jLogWatchInterval; + } + + @SuppressWarnings("unchecked") + public synchronized boolean setRuntimeLoggerLevel(String logger, String level) + { + //check specified level is valid + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + //check specified logger exists + Enumeration loggers = LogManager.getCurrentLoggers(); + Boolean loggerExists = false; + + while(loggers.hasMoreElements()) + { + Logger log = (Logger) loggers.nextElement(); + if (log.getName().equals(logger)) + { + loggerExists = true; + break; + } + } + + if(!loggerExists) + { + return false; + } + + //set the logger to the new level + _logger.info("Setting level to " + level + " for logger: " + logger); + + Logger log = Logger.getLogger(logger); + log.setLevel(newLevel); + + return true; + } + + @SuppressWarnings("unchecked") + public synchronized TabularData viewEffectiveRuntimeLoggerLevels() + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting levels for currently active log4j loggers"); + + Enumeration loggers = LogManager.getCurrentLoggers(); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Logger logger; + String loggerName; + String level; + + try + { + while(loggers.hasMoreElements()){ + logger = (Logger) loggers.nextElement(); + + loggerName = logger.getName(); + level = logger.getEffectiveLevel().toString(); + + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + + return loggerLevelList; + + } + + public synchronized String getRuntimeRootLoggerLevel() + { + Logger rootLogger = Logger.getRootLogger(); + + return rootLogger.getLevel().toString(); + } + + public synchronized boolean setRuntimeRootLoggerLevel(String level) + { + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + _logger.info("Setting RootLogger level to " + level); + + Logger log = Logger.getRootLogger(); + log.setLevel(newLevel); + + return true; + } + + //method to convert from a string to a log4j Level, throws exception if the given value is invalid + private Level getLevel(String level) throws Exception + { + Level newLevel = Level.toLevel(level); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new Exception("Invalid level name"); + } + + return newLevel; + } + + //handler to catch errors signalled by the JAXP parser and throw an appropriate exception + private class SaxErrorHandler implements ErrorHandler + { + + public void error(SAXParseException e) throws SAXException + { + throw new SAXException("Error parsing XML file: " + e.getMessage()); + } + + public void fatalError(SAXParseException e) throws SAXException + { + throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + } + + public void warning(SAXParseException e) throws SAXException + { + throw new SAXException("Warning parsing XML file: " + e.getMessage()); + } + } + + //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. + private synchronized Document parseConfigFile(String fileName) throws IOException + { + //check file was specified, exists, and is readable + if(fileName == null) + { + _logger.warn("No log4j XML configuration file has been set"); + throw new IOException("No log4j XML configuration file has been set"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); + throw new IOException("Specified log4j XML configuration file does not exist"); + } + else if (!configFile.canRead()) + { + _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); + throw new IOException("Specified log4j XML configuration file is not readable"); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document doc; + + ErrorHandler errHandler = new SaxErrorHandler(); + try + { + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + doc = docBuilder.parse(fileName); + } + catch (ParserConfigurationException e) + { + _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); + //recommended that MBeans should use java.* and javax.* exceptions only + throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); + } + catch (SAXException e) + { + _logger.warn("The specified log4j XML file is invalid: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); + } + catch (IOException e) + { + _logger.warn("Unable to parse the specified log4j XML file" + e); + throw new IOException("Unable to parse the specified log4j XML file", e); + } + + return doc; + } + + + private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + { + File log4jConfigFile = new File(log4jConfigFileName); + + if (!log4jConfigFile.canWrite()) + { + _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); + throw new IOException("Specified log4j XML configuration file is not writable"); + } + + Transformer transformer = null; + try + { + transformer = TransformerFactory.newInstance().newTransformer(); + } + catch (Exception e) + { + _logger.warn("Could not create an XML transformer: " +e); + return false; + } + + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); + DOMSource source = new DOMSource(doc); + + File tmp; + try + { + tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); + tmp.deleteOnExit(); + StreamResult result = new StreamResult(tmp); + transformer.transform(source, result); + } + catch (TransformerException e) + { + _logger.warn("Could not transform the XML into new file: " +e); + return false; + } + catch (IOException e) + { + _logger.warn("Could not create the new file: " +e); + return false; + } + + // Swap temp file in to replace existing configuration file. + File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + log4jConfigFile.renameTo(old); + return tmp.renameTo(log4jConfigFile); + } + + + /* The log4j XML configuration file DTD defines three possible element + * combinations for specifying optional logger+level settings. + * Must account for the following: + * + * OR + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + //retrieve the 'category' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + + String categoryName; + String priority = null; + + for (int i = 0; i < categoryElements.getLength(); i++) + { + Element categoryElement = (Element) categoryElements.item(i); + categoryName = categoryElement.getAttribute("name"); + + //retrieve the category's mandatory 'priority' or 'level' element's value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = categoryElement.getElementsByTagName("priority"); + NodeList levelElements = categoryElement.getElementsByTagName("level"); + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value").toUpperCase(); + } + else if (levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value").toUpperCase(); + } + else + { + //there is no exiting priority or level to view, move onto next category/logger + continue; + } + + try + { + Object[] itemData = {categoryName, priority}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + //retrieve the 'logger' element nodes + NodeList loggerElements = doc.getElementsByTagName("logger"); + + String loggerName; + String level; + + for (int i = 0; i < loggerElements.getLength(); i++) + { + Element loggerElement = (Element) loggerElements.item(i); + loggerName = loggerElement.getAttribute("name"); + + //retrieve the logger's mandatory 'level' element's value + //It may not be the only child node, so request by tag name. + NodeList levelElements = loggerElement.getElementsByTagName("level"); + + Element levelElement = (Element) levelElements.item(0); + level = levelElement.getAttribute("value").toUpperCase(); + + try + { + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + return loggerLevelList; + } + + public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for logger '" + logger + + "' in log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the 'category' and 'logger' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + NodeList loggerElements = doc.getElementsByTagName("logger"); + + //collect them into a single elements list + List logElements = new ArrayList(); + + for (int i = 0; i < categoryElements.getLength(); i++) + { + logElements.add((Element) categoryElements.item(i)); + } + for (int i = 0; i < loggerElements.getLength(); i++) + { + logElements.add((Element) loggerElements.item(i)); + } + + //try to locate the specified logger/category in the elements retrieved + Element logElement = null; + for (Element e : logElements) + { + if (e.getAttribute("name").equals(logger)) + { + logElement = e; + break; + } + } + + if (logElement == null) + { + //no loggers/categories with given name found, does not exist to update + _logger.warn("Specified logger does not exist in the configuration file: " +logger); + return false; + } + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = logElement.getElementsByTagName("priority"); + NodeList levelElements = logElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority or level element to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } + + + /* The log4j XML configuration file DTD defines 2 possible element + * combinations for specifying the optional root logger level settings + * Must account for the following: + * + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + _logger.info("Getting root logger level from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + //there is not root logger definition + return null; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + String priority = null; + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value"); + } + else if(levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value"); + } + + if(priority != null) + { + return priority.toUpperCase(); + } + else + { + return null; + } + } + + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for the Root logger in " + + "log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + return false; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority/level to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } +} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.Log4jEntityResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + + +/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ +@MBeanDescription("Logging Management Interface") +public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement +{ + + private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); + private String _log4jConfigFileName; + private int _log4jLogWatchInterval; + + static TabularType _loggerLevelTabularType; + static CompositeType _loggerLevelCompositeType; + + static + { + try + { + OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; + + _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); + + _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", + _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing logger levels was incorrect."); + _loggerLevelTabularType = null; + } + } + + public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException + { + super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); + _log4jConfigFileName = log4jConfigFileName; + _log4jLogWatchInterval = log4jLogWatchInterval; + } + + public String getObjectInstanceName() + { + return LoggingManagement.TYPE; + } + + public Integer getLog4jLogWatchInterval() + { + return _log4jLogWatchInterval; + } + + @SuppressWarnings("unchecked") + public synchronized boolean setRuntimeLoggerLevel(String logger, String level) + { + //check specified level is valid + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + //check specified logger exists + Enumeration loggers = LogManager.getCurrentLoggers(); + Boolean loggerExists = false; + + while(loggers.hasMoreElements()) + { + Logger log = (Logger) loggers.nextElement(); + if (log.getName().equals(logger)) + { + loggerExists = true; + break; + } + } + + if(!loggerExists) + { + return false; + } + + //set the logger to the new level + _logger.info("Setting level to " + level + " for logger: " + logger); + + Logger log = Logger.getLogger(logger); + log.setLevel(newLevel); + + return true; + } + + @SuppressWarnings("unchecked") + public synchronized TabularData viewEffectiveRuntimeLoggerLevels() + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting levels for currently active log4j loggers"); + + Enumeration loggers = LogManager.getCurrentLoggers(); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Logger logger; + String loggerName; + String level; + + try + { + while(loggers.hasMoreElements()){ + logger = (Logger) loggers.nextElement(); + + loggerName = logger.getName(); + level = logger.getEffectiveLevel().toString(); + + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + + return loggerLevelList; + + } + + public synchronized String getRuntimeRootLoggerLevel() + { + Logger rootLogger = Logger.getRootLogger(); + + return rootLogger.getLevel().toString(); + } + + public synchronized boolean setRuntimeRootLoggerLevel(String level) + { + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + _logger.info("Setting RootLogger level to " + level); + + Logger log = Logger.getRootLogger(); + log.setLevel(newLevel); + + return true; + } + + //method to convert from a string to a log4j Level, throws exception if the given value is invalid + private Level getLevel(String level) throws Exception + { + Level newLevel = Level.toLevel(level); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new Exception("Invalid level name"); + } + + return newLevel; + } + + //handler to catch errors signalled by the JAXP parser and throw an appropriate exception + private class SaxErrorHandler implements ErrorHandler + { + + public void error(SAXParseException e) throws SAXException + { + throw new SAXException("Error parsing XML file: " + e.getMessage()); + } + + public void fatalError(SAXParseException e) throws SAXException + { + throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + } + + public void warning(SAXParseException e) throws SAXException + { + throw new SAXException("Warning parsing XML file: " + e.getMessage()); + } + } + + //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. + private synchronized Document parseConfigFile(String fileName) throws IOException + { + //check file was specified, exists, and is readable + if(fileName == null) + { + _logger.warn("No log4j XML configuration file has been set"); + throw new IOException("No log4j XML configuration file has been set"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); + throw new IOException("Specified log4j XML configuration file does not exist"); + } + else if (!configFile.canRead()) + { + _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); + throw new IOException("Specified log4j XML configuration file is not readable"); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document doc; + + ErrorHandler errHandler = new SaxErrorHandler(); + try + { + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + doc = docBuilder.parse(fileName); + } + catch (ParserConfigurationException e) + { + _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); + //recommended that MBeans should use java.* and javax.* exceptions only + throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); + } + catch (SAXException e) + { + _logger.warn("The specified log4j XML file is invalid: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); + } + catch (IOException e) + { + _logger.warn("Unable to parse the specified log4j XML file" + e); + throw new IOException("Unable to parse the specified log4j XML file", e); + } + + return doc; + } + + + private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + { + File log4jConfigFile = new File(log4jConfigFileName); + + if (!log4jConfigFile.canWrite()) + { + _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); + throw new IOException("Specified log4j XML configuration file is not writable"); + } + + Transformer transformer = null; + try + { + transformer = TransformerFactory.newInstance().newTransformer(); + } + catch (Exception e) + { + _logger.warn("Could not create an XML transformer: " +e); + return false; + } + + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); + DOMSource source = new DOMSource(doc); + + File tmp; + try + { + tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); + tmp.deleteOnExit(); + StreamResult result = new StreamResult(tmp); + transformer.transform(source, result); + } + catch (TransformerException e) + { + _logger.warn("Could not transform the XML into new file: " +e); + return false; + } + catch (IOException e) + { + _logger.warn("Could not create the new file: " +e); + return false; + } + + // Swap temp file in to replace existing configuration file. + File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + log4jConfigFile.renameTo(old); + return tmp.renameTo(log4jConfigFile); + } + + + /* The log4j XML configuration file DTD defines three possible element + * combinations for specifying optional logger+level settings. + * Must account for the following: + * + * OR + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + //retrieve the 'category' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + + String categoryName; + String priority = null; + + for (int i = 0; i < categoryElements.getLength(); i++) + { + Element categoryElement = (Element) categoryElements.item(i); + categoryName = categoryElement.getAttribute("name"); + + //retrieve the category's mandatory 'priority' or 'level' element's value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = categoryElement.getElementsByTagName("priority"); + NodeList levelElements = categoryElement.getElementsByTagName("level"); + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value").toUpperCase(); + } + else if (levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value").toUpperCase(); + } + else + { + //there is no exiting priority or level to view, move onto next category/logger + continue; + } + + try + { + Object[] itemData = {categoryName, priority}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + //retrieve the 'logger' element nodes + NodeList loggerElements = doc.getElementsByTagName("logger"); + + String loggerName; + String level; + + for (int i = 0; i < loggerElements.getLength(); i++) + { + Element loggerElement = (Element) loggerElements.item(i); + loggerName = loggerElement.getAttribute("name"); + + //retrieve the logger's mandatory 'level' element's value + //It may not be the only child node, so request by tag name. + NodeList levelElements = loggerElement.getElementsByTagName("level"); + + Element levelElement = (Element) levelElements.item(0); + level = levelElement.getAttribute("value").toUpperCase(); + + try + { + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + return loggerLevelList; + } + + public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for logger '" + logger + + "' in log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the 'category' and 'logger' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + NodeList loggerElements = doc.getElementsByTagName("logger"); + + //collect them into a single elements list + List logElements = new ArrayList(); + + for (int i = 0; i < categoryElements.getLength(); i++) + { + logElements.add((Element) categoryElements.item(i)); + } + for (int i = 0; i < loggerElements.getLength(); i++) + { + logElements.add((Element) loggerElements.item(i)); + } + + //try to locate the specified logger/category in the elements retrieved + Element logElement = null; + for (Element e : logElements) + { + if (e.getAttribute("name").equals(logger)) + { + logElement = e; + break; + } + } + + if (logElement == null) + { + //no loggers/categories with given name found, does not exist to update + _logger.warn("Specified logger does not exist in the configuration file: " +logger); + return false; + } + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = logElement.getElementsByTagName("priority"); + NodeList levelElements = logElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority or level element to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } + + + /* The log4j XML configuration file DTD defines 2 possible element + * combinations for specifying the optional root logger level settings + * Must account for the following: + * + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + _logger.info("Getting root logger level from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + //there is not root logger definition + return null; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + String priority = null; + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value"); + } + else if(levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value"); + } + + if(priority != null) + { + return priority.toUpperCase(); + } + else + { + return null; + } + } + + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for the Root logger in " + + "log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + return false; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority/level to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 6a81646cae..fccd91ffdb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.management; +import org.apache.qpid.server.logging.management.LoggingManagement; import org.apache.qpid.server.security.access.management.UserManagement; import org.apache.log4j.Logger; @@ -153,7 +154,12 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler if (args[0] instanceof ObjectName) { ObjectName object = (ObjectName) args[0]; - return UserManagement.TYPE.equals(object.getKeyProperty("type")); + + if (UserManagement.TYPE.equals(object.getKeyProperty("type")) + || LoggingManagement.TYPE.equals(object.getKeyProperty("type"))) + { + return true; + } } return false; -- cgit v1.2.1 From 2b90c663875cc035d1e058f52707152601a89fab Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 25 Feb 2009 18:09:04 +0000 Subject: QPID-1648: Remove doubling of new classes. Stoopid patch(1). PEBKAC. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@747875 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/management/LoggingManagement.java | 129 ---- .../logging/management/LoggingManagementMBean.java | 667 --------------------- 2 files changed, 796 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java index d60b9c304a..79d60a6df0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java @@ -86,135 +86,6 @@ public interface LoggingManagement String getRuntimeRootLoggerLevel(); - //****** log4j XML configuration file operations ****** // - - /** - * Updates the level of an existing Log4J logger within the xml configuration file - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + - "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) - TabularData viewConfigFileLoggerLevels() throws IOException; - - /** - * Updates the level of the Log4J RootLogger within the xml configuration file if it is present - * @param level The level to set the logger to - * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Attribute to represent the level of the Log4J RootLogger within the xml configuration file - * @return The level of the RootLogger, or null if it is not present - */ - @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + - "in the log4j xml configuration file.") - String getConfigFileRootLoggerLevel() throws IOException; -} -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.management; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -public interface LoggingManagement -{ - String TYPE = "LoggingManagement"; - int VERSION = 1; - - //TabularType and contained CompositeType key/description information - String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; - String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; - String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; - - /** - * Attribute to represent the log4j xml configuration file's LogWatch interval. - * @return The logwatch interval in seconds. - */ - @MBeanAttribute(name="Log4jLogWatchInterval", - description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") - Integer getLog4jLogWatchInterval(); - - - //****** log4j runtime operations ****** // - - /** - * Sets the level of an active Log4J logger - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Retrieves a TabularData set of the active log4j loggers and their levels - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - */ - @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + - "for active log4j logger's.", impact = MBeanOperationInfo.INFO) - TabularData viewEffectiveRuntimeLoggerLevels(); - - /** - * Sets the level of the active Log4J RootLogger - * @param level The level to set the RootLogger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Attribute to represent the level of the active Log4J RootLogger - * @return The level of the RootLogger. - */ - @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") - String getRuntimeRootLoggerLevel(); - - //****** log4j XML configuration file operations ****** // /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index e35292c4b0..f84cbbd786 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -61,673 +61,6 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ -@MBeanDescription("Logging Management Interface") -public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement -{ - - private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); - private String _log4jConfigFileName; - private int _log4jLogWatchInterval; - - static TabularType _loggerLevelTabularType; - static CompositeType _loggerLevelCompositeType; - - static - { - try - { - OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; - - _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); - - _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", - _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); - } - catch (OpenDataException e) - { - _logger.error("Tabular data setup for viewing logger levels was incorrect."); - _loggerLevelTabularType = null; - } - } - - public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException - { - super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); - _log4jConfigFileName = log4jConfigFileName; - _log4jLogWatchInterval = log4jLogWatchInterval; - } - - public String getObjectInstanceName() - { - return LoggingManagement.TYPE; - } - - public Integer getLog4jLogWatchInterval() - { - return _log4jLogWatchInterval; - } - - @SuppressWarnings("unchecked") - public synchronized boolean setRuntimeLoggerLevel(String logger, String level) - { - //check specified level is valid - Level newLevel; - try - { - newLevel = getLevel(level); - } - catch (Exception e) - { - return false; - } - - //check specified logger exists - Enumeration loggers = LogManager.getCurrentLoggers(); - Boolean loggerExists = false; - - while(loggers.hasMoreElements()) - { - Logger log = (Logger) loggers.nextElement(); - if (log.getName().equals(logger)) - { - loggerExists = true; - break; - } - } - - if(!loggerExists) - { - return false; - } - - //set the logger to the new level - _logger.info("Setting level to " + level + " for logger: " + logger); - - Logger log = Logger.getLogger(logger); - log.setLevel(newLevel); - - return true; - } - - @SuppressWarnings("unchecked") - public synchronized TabularData viewEffectiveRuntimeLoggerLevels() - { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting levels for currently active log4j loggers"); - - Enumeration loggers = LogManager.getCurrentLoggers(); - - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); - - Logger logger; - String loggerName; - String level; - - try - { - while(loggers.hasMoreElements()){ - logger = (Logger) loggers.nextElement(); - - loggerName = logger.getName(); - level = logger.getEffectiveLevel().toString(); - - Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - - return loggerLevelList; - - } - - public synchronized String getRuntimeRootLoggerLevel() - { - Logger rootLogger = Logger.getRootLogger(); - - return rootLogger.getLevel().toString(); - } - - public synchronized boolean setRuntimeRootLoggerLevel(String level) - { - Level newLevel; - try - { - newLevel = getLevel(level); - } - catch (Exception e) - { - return false; - } - - _logger.info("Setting RootLogger level to " + level); - - Logger log = Logger.getRootLogger(); - log.setLevel(newLevel); - - return true; - } - - //method to convert from a string to a log4j Level, throws exception if the given value is invalid - private Level getLevel(String level) throws Exception - { - Level newLevel = Level.toLevel(level); - - //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. - if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug"))) - { - //received DEBUG but we did not ask for it, the Level request failed. - throw new Exception("Invalid level name"); - } - - return newLevel; - } - - //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - private class SaxErrorHandler implements ErrorHandler - { - - public void error(SAXParseException e) throws SAXException - { - throw new SAXException("Error parsing XML file: " + e.getMessage()); - } - - public void fatalError(SAXParseException e) throws SAXException - { - throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); - } - - public void warning(SAXParseException e) throws SAXException - { - throw new SAXException("Warning parsing XML file: " + e.getMessage()); - } - } - - //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private synchronized Document parseConfigFile(String fileName) throws IOException - { - //check file was specified, exists, and is readable - if(fileName == null) - { - _logger.warn("No log4j XML configuration file has been set"); - throw new IOException("No log4j XML configuration file has been set"); - } - - File configFile = new File(fileName); - - if (!configFile.exists()) - { - _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); - throw new IOException("Specified log4j XML configuration file does not exist"); - } - else if (!configFile.canRead()) - { - _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); - throw new IOException("Specified log4j XML configuration file is not readable"); - } - - //parse it - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder; - Document doc; - - ErrorHandler errHandler = new SaxErrorHandler(); - try - { - docFactory.setValidating(true); - docBuilder = docFactory.newDocumentBuilder(); - docBuilder.setErrorHandler(errHandler); - docBuilder.setEntityResolver(new Log4jEntityResolver()); - doc = docBuilder.parse(fileName); - } - catch (ParserConfigurationException e) - { - _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); - //recommended that MBeans should use java.* and javax.* exceptions only - throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); - } - catch (SAXException e) - { - _logger.warn("The specified log4j XML file is invalid: " + e); - //recommended that MBeans should use standard java.* and javax.* exceptions only - throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); - } - catch (IOException e) - { - _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file", e); - } - - return doc; - } - - - private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException - { - File log4jConfigFile = new File(log4jConfigFileName); - - if (!log4jConfigFile.canWrite()) - { - _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); - throw new IOException("Specified log4j XML configuration file is not writable"); - } - - Transformer transformer = null; - try - { - transformer = TransformerFactory.newInstance().newTransformer(); - } - catch (Exception e) - { - _logger.warn("Could not create an XML transformer: " +e); - return false; - } - - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); - DOMSource source = new DOMSource(doc); - - File tmp; - try - { - tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); - tmp.deleteOnExit(); - StreamResult result = new StreamResult(tmp); - transformer.transform(source, result); - } - catch (TransformerException e) - { - _logger.warn("Could not transform the XML into new file: " +e); - return false; - } - catch (IOException e) - { - _logger.warn("Could not create the new file: " +e); - return false; - } - - // Swap temp file in to replace existing configuration file. - File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - log4jConfigFile.renameTo(old); - return tmp.renameTo(log4jConfigFile); - } - - - /* The log4j XML configuration file DTD defines three possible element - * combinations for specifying optional logger+level settings. - * Must account for the following: - * - * OR - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - - - public synchronized TabularData viewConfigFileLoggerLevels() throws IOException - { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); - - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); - - //retrieve the 'category' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - - String categoryName; - String priority = null; - - for (int i = 0; i < categoryElements.getLength(); i++) - { - Element categoryElement = (Element) categoryElements.item(i); - categoryName = categoryElement.getAttribute("name"); - - //retrieve the category's mandatory 'priority' or 'level' element's value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = categoryElement.getElementsByTagName("priority"); - NodeList levelElements = categoryElement.getElementsByTagName("level"); - - if (priorityElements.getLength() != 0) - { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value").toUpperCase(); - } - else if (levelElements.getLength() != 0) - { - Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value").toUpperCase(); - } - else - { - //there is no exiting priority or level to view, move onto next category/logger - continue; - } - - try - { - Object[] itemData = {categoryName, priority}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - } - - //retrieve the 'logger' element nodes - NodeList loggerElements = doc.getElementsByTagName("logger"); - - String loggerName; - String level; - - for (int i = 0; i < loggerElements.getLength(); i++) - { - Element loggerElement = (Element) loggerElements.item(i); - loggerName = loggerElement.getAttribute("name"); - - //retrieve the logger's mandatory 'level' element's value - //It may not be the only child node, so request by tag name. - NodeList levelElements = loggerElement.getElementsByTagName("level"); - - Element levelElement = (Element) levelElements.item(0); - level = levelElement.getAttribute("value").toUpperCase(); - - try - { - Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - } - - return loggerLevelList; - } - - public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException - { - //check that the specified level is a valid log4j Level - try - { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for logger '" + logger - + "' in log4j xml configuration file: " + _log4jConfigFileName); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the 'category' and 'logger' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - NodeList loggerElements = doc.getElementsByTagName("logger"); - - //collect them into a single elements list - List logElements = new ArrayList(); - - for (int i = 0; i < categoryElements.getLength(); i++) - { - logElements.add((Element) categoryElements.item(i)); - } - for (int i = 0; i < loggerElements.getLength(); i++) - { - logElements.add((Element) loggerElements.item(i)); - } - - //try to locate the specified logger/category in the elements retrieved - Element logElement = null; - for (Element e : logElements) - { - if (e.getAttribute("name").equals(logger)) - { - logElement = e; - break; - } - } - - if (logElement == null) - { - //no loggers/categories with given name found, does not exist to update - _logger.warn("Specified logger does not exist in the configuration file: " +logger); - return false; - } - - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = logElement.getElementsByTagName("priority"); - NodeList levelElements = logElement.getElementsByTagName("level"); - - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); - } - else - { - //there is no exiting priority or level element to update - return false; - } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); - } - - - /* The log4j XML configuration file DTD defines 2 possible element - * combinations for specifying the optional root logger level settings - * Must account for the following: - * - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - - public synchronized String getConfigFileRootLoggerLevel() throws IOException - { - _logger.info("Getting root logger level from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - //there is not root logger definition - return null; - } - - Element rootElement = (Element) rootElements.item(0); - - //retrieve the optional 'priority' or 'level' element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); - String priority = null; - - if (priorityElements.getLength() != 0) - { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value"); - } - else if(levelElements.getLength() != 0) - { - Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value"); - } - - if(priority != null) - { - return priority.toUpperCase(); - } - else - { - return null; - } - } - - public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException - { - //check that the specified level is a valid log4j Level - try - { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for the Root logger in " + - "log4j xml configuration file: " + _log4jConfigFileName); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - return false; - } - - Element rootElement = (Element) rootElements.item(0); - - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); - - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); - } - else - { - //there is no exiting priority/level to update - return false; - } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); - } -} -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.management; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.Log4jEntityResolver; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - - /** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ @MBeanDescription("Logging Management Interface") public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement -- cgit v1.2.1 From 36cd5c60669afbd8d59d7303a03f7f2cf9a11bea Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Feb 2009 13:33:56 +0000 Subject: QPID-1629 : Forgot to delete AMQMessageHandle.java git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748513 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/AMQMessageHandle.java | 75 ---------------------- 1 file changed, 75 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java deleted file mode 100644 index 93ac21fc7c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * A pluggable way of getting message data. Implementations can provide intelligent caching for example or - * even no caching at all to minimise the broker memory footprint. - */ -public interface AMQMessageHandle -{ - ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException; - - /** - * - * @return the messageId for the message associated with this handle - */ - Long getMessageId(); - - - /** - * @return the number of body frames associated with this message - */ - int getBodyCount(StoreContext context) throws AMQException; - - /** - * @return the size of the body - */ - long getBodySize(StoreContext context) throws AMQException; - - /** - * Get a particular content body - * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 - * @return a content body - * @throws IllegalArgumentException if the index is invalid - */ - ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException; - - void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - - MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; - - boolean isPersistent(); - - void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException; - - void removeMessage(StoreContext storeContext) throws AMQException; - - long getArrivalTime(); -} -- cgit v1.2.1 From 7e7297001cb450dbf67454d9d4b759e6221439c8 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Feb 2009 13:34:40 +0000 Subject: QPID-1632 : Tidied up old referenceCount variable that was still in use in logging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748514 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/TransientAMQMessage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java index bea10cef53..0334a54fab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java @@ -44,8 +44,6 @@ public class TransientAMQMessage implements AMQMessage /** Used for debugging purposes. */ protected static final Logger _log = Logger.getLogger(AMQMessage.class); - private final AtomicInteger _referenceCount = new AtomicInteger(1); - protected ContentHeaderBody _contentHeaderBody; protected MessagePublishInfo _messagePublishInfo; @@ -164,7 +162,7 @@ public class TransientAMQMessage implements AMQMessage public String debugIdentity() { - return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() +")"; } public void setExpiration(final long expiration) @@ -386,7 +384,7 @@ public class TransientAMQMessage implements AMQMessage // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + // _taken + " by :" + _takenBySubcription; - return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; + return "Message[" + debugIdentity() + "]: " + getMessageId() ; } } -- cgit v1.2.1 From 5ea9fa4baa5219c7666ccddb04703289e56cbd6f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Feb 2009 13:35:38 +0000 Subject: QPID-1635,QPID-1636 : Moved additional properties from AMQMessage up to QueueEntry to allow processing whilst messasge has been flowed. Moved : _flags (for Immediate and delivered status), expiry, messageID. Created base class to maintain counts of data and objects in queue. Removed this responsibility from the AMQQueues and on to the QueueEntryLists. This will more easily allow the QEL structure to be flowed to disk at a later stage. Updated tests as a result of moves. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748516 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQMessage.java | 35 +--- .../apache/qpid/server/queue/AMQPriorityQueue.java | 4 +- .../server/queue/FlowableBaseQueueEntryList.java | 185 +++++++++++++++++++++ .../qpid/server/queue/FlowableQueueEntryList.java | 42 +++++ .../qpid/server/queue/PriorityQueueEntryList.java | 182 ++++++++++++++++++++ .../qpid/server/queue/PriorityQueueList.java | 160 ------------------ .../org/apache/qpid/server/queue/QueueEntry.java | 47 +++++- .../apache/qpid/server/queue/QueueEntryImpl.java | 97 +++++++++-- .../apache/qpid/server/queue/QueueEntryList.java | 2 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 102 ++---------- .../qpid/server/queue/SimpleQueueEntryList.java | 20 ++- .../qpid/server/queue/TransientAMQMessage.java | 82 ++------- .../qpid/server/virtualhost/VirtualHost.java | 11 ++ .../qpid/tools/messagestore/commands/Show.java | 2 +- 14 files changed, 602 insertions(+), 369 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index 5bde27dba5..8dac12fe24 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -60,30 +60,6 @@ public interface AMQMessage //Check the status of this message - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - boolean getDeliveredToConsumer(); - - /** - * Called to enforce the 'immediate' flag. - * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer - */ - boolean immediateAndNotDelivered(); - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @return true if the message has expire - * - * @throws org.apache.qpid.AMQException - */ - boolean expired() throws AMQException; - /** Is this a persistent message * * @return true if the message is persistent @@ -91,13 +67,8 @@ public interface AMQMessage boolean isPersistent(); - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - */ - void setDeliveredToConsumer(); + boolean isImmediate(); - void setExpiration(long expiration); void setClientIdentifier(AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier); @@ -121,4 +92,8 @@ public interface AMQMessage String toString(); String debugIdentity(); + + void setExpiration(long expiration); + + long getExpiration(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index 34a70c6969..ade780d0bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -36,12 +36,12 @@ public class AMQPriorityQueue extends SimpleAMQQueue int priorities) throws AMQException { - super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); + super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueEntryList.Factory(priorities)); } public int getPriorities() { - return ((PriorityQueueList) _entries).getPriorities(); + return ((PriorityQueueEntryList) _entries).getPriorities(); } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java new file mode 100644 index 0000000000..72ea5f2667 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -0,0 +1,185 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * This is an abstract base class to handle + */ +public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryList +{ + private static final Logger _log = Logger.getLogger(FlowableBaseQueueEntryList.class); + + private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); + private final AtomicLong _atomicQueueSize = new AtomicLong(0L); + private final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); + /** The maximum amount of memory that is allocated to this queue. Beyond this the queue will flow to disk. */ + + private long _memoryUsageMaximum = 0; + + /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ + private long _memoryUsageMinimum = 0; + private AtomicBoolean _flowed; + private QueueBackingStore _backingStore; + protected AMQQueue _queue; + + FlowableBaseQueueEntryList(AMQQueue queue) + { + _queue = queue; + _flowed = new AtomicBoolean(false); + VirtualHost vhost = queue.getVirtualHost(); + if (vhost != null) + { + _backingStore = vhost.getQueueBackingStore(); + } + } + + public void setFlowed(boolean flowed) + { + if (_flowed.get() != flowed) + { + _log.info("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); + _flowed.set(flowed); + } + } + + public boolean isFlowed() + { + return _flowed.get(); + } + + public int size() + { + return _atomicQueueCount.get(); + } + + public long dataSize() + { + return _atomicQueueSize.get(); + } + + public long memoryUsed() + { + return _atomicQueueInMemory.get(); + } + + public void setMemoryUsageMaximum(long maximumMemoryUsage) + { + _memoryUsageMaximum = maximumMemoryUsage; + + // Don't attempt to start the inhaler/purger unless we have a minimum value specified. + if (_memoryUsageMaximum > 0) + { + // If we've increased the max memory above what we have in memory then we can inhale more + if (_memoryUsageMaximum > _atomicQueueInMemory.get()) + { + //TODO start inhaler + } + else // if we have now have to much memory in use we need to purge. + { + //TODO start purger + } + } + } + + public long getMemoryUsageMaximum() + { + return _memoryUsageMaximum; + } + + public void setMemoryUsageMinimum(long minimumMemoryUsage) + { + _memoryUsageMinimum = minimumMemoryUsage; + + // Don't attempt to start the inhaler unless we have a minimum value specified. + if (_memoryUsageMinimum > 0) + { + // If we've increased the minimum memory above what we have in memory then we need to inhale more + if (_memoryUsageMinimum >= _atomicQueueInMemory.get()) + { + //TODO start inhaler + } + } + } + + public long getMemoryUsageMinimum() + { + return _memoryUsageMinimum; + } + + protected boolean willCauseFlowToDisk(QueueEntryImpl queueEntry) + { + return _memoryUsageMaximum != 0 && memoryUsed() + queueEntry.getSize() > _memoryUsageMaximum; + } + + protected void incrementCounters(final QueueEntryImpl queueEntry) + { + _atomicQueueCount.incrementAndGet(); + _atomicQueueSize.addAndGet(queueEntry.getSize()); + if (!willCauseFlowToDisk(queueEntry)) + { + _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + } + else + { + setFlowed(true); + flowingToDisk(queueEntry); + } + } + + /** + * Called when we are now flowing to disk + * @param queueEntry the entry that is being flowed to disk + */ + protected void flowingToDisk(QueueEntryImpl queueEntry) + { + try + { + queueEntry.flow(); + } + catch (UnableToFlowMessageException e) + { + _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + } + } + + protected void dequeued(QueueEntryImpl queueEntry) + { + _atomicQueueCount.decrementAndGet(); + _atomicQueueSize.addAndGet(-queueEntry.getSize()); + if (!queueEntry.isFlowed()) + { + _atomicQueueInMemory.addAndGet(-queueEntry.getSize()); + } + } + + public QueueBackingStore getBackingStore() + { + return _backingStore; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java new file mode 100644 index 0000000000..4e95978bf8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +public interface FlowableQueueEntryList +{ + void setFlowed(boolean flowed); + + boolean isFlowed(); + + int size(); + + long dataSize(); + + long memoryUsed(); + + void setMemoryUsageMaximum(long maximumMemoryUsage); + + long getMemoryUsageMaximum(); + + void setMemoryUsageMinimum(long minimumMemoryUsage); + + long getMemoryUsageMinimum(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java new file mode 100644 index 0000000000..d812b8ceca --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -0,0 +1,182 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.CommonContentHeaderProperties; + +public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList +{ + private final AMQQueue _queue; + private final QueueEntryList[] _priorityLists; + private final int _priorities; + private final int _priorityOffset; + + public PriorityQueueEntryList(AMQQueue queue, int priorities) + { + super(queue); + _queue = queue; + _priorityLists = new QueueEntryList[priorities]; + _priorities = priorities; + _priorityOffset = 5-((priorities + 1)/2); + for(int i = 0; i < priorities; i++) + { + _priorityLists[i] = new SimpleQueueEntryList(queue); + } + } + + public int getPriorities() + { + return _priorities; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public QueueEntry add(AMQMessage message) + { + int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; + if(index >= _priorities) + { + index = _priorities-1; + } + else if(index < 0) + { + index = 0; + } + return _priorityLists[index].add(message); + } + + public QueueEntry next(QueueEntry node) + { + QueueEntryImpl nodeImpl = (QueueEntryImpl)node; + QueueEntry next = nodeImpl.getNext(); + + if(next == null) + { + QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); + int index; + for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--); + + while(next == null && index != 0) + { + index--; + next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext(); + } + + } + return next; + } + + private final class PriorityQueueEntryListIterator implements QueueEntryIterator + { + private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; + private QueueEntry _lastNode; + + PriorityQueueEntryListIterator() + { + for(int i = 0; i < _priorityLists.length; i++) + { + _iterators[i] = _priorityLists[i].iterator(); + } + _lastNode = _iterators[_iterators.length - 1].getNode(); + } + + + public boolean atTail() + { + for(int i = 0; i < _iterators.length; i++) + { + if(!_iterators[i].atTail()) + { + return false; + } + } + return true; + } + + public QueueEntry getNode() + { + return _lastNode; + } + + public boolean advance() + { + for(int i = _iterators.length-1; i >= 0; i--) + { + if(_iterators[i].advance()) + { + _lastNode = _iterators[i].getNode(); + return true; + } + } + return false; + } + } + + public QueueEntryIterator iterator() + { + return new PriorityQueueEntryListIterator(); + } + + public QueueEntry getHead() + { + return _priorityLists[_priorities-1].getHead(); + } + + static class Factory implements QueueEntryListFactory + { + private final int _priorities; + + Factory(int priorities) + { + _priorities = priorities; + } + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new PriorityQueueEntryList(queue, _priorities); + } + } + + @Override + public int size() + { + int size=0; + for (QueueEntryList queueEntryList : _priorityLists) + { + size += queueEntryList.size(); + } + + return size; + } + + + @Override + protected void flowingToDisk(QueueEntryImpl queueEntry) + { + //TODO this disables FTD for priority queues + // As the incomming message isn't always the one to purge. + // More logic is required up in the add() method here to determine if the + // incomming message is at the 'front' or not. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java deleted file mode 100644 index 7be2827e0f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ /dev/null @@ -1,160 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.AMQException; - -public class PriorityQueueList implements QueueEntryList -{ - private final AMQQueue _queue; - private final QueueEntryList[] _priorityLists; - private final int _priorities; - private final int _priorityOffset; - - public PriorityQueueList(AMQQueue queue, int priorities) - { - _queue = queue; - _priorityLists = new QueueEntryList[priorities]; - _priorities = priorities; - _priorityOffset = 5-((priorities + 1)/2); - for(int i = 0; i < priorities; i++) - { - _priorityLists[i] = new SimpleQueueEntryList(queue); - } - } - - public int getPriorities() - { - return _priorities; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public QueueEntry add(AMQMessage message) - { - int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if(index >= _priorities) - { - index = _priorities-1; - } - else if(index < 0) - { - index = 0; - } - return _priorityLists[index].add(message); - } - - public QueueEntry next(QueueEntry node) - { - QueueEntryImpl nodeImpl = (QueueEntryImpl)node; - QueueEntry next = nodeImpl.getNext(); - - if(next == null) - { - QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); - int index; - for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--); - - while(next == null && index != 0) - { - index--; - next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext(); - } - - } - return next; - } - - private final class PriorityQueueEntryListIterator implements QueueEntryIterator - { - private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; - private QueueEntry _lastNode; - - PriorityQueueEntryListIterator() - { - for(int i = 0; i < _priorityLists.length; i++) - { - _iterators[i] = _priorityLists[i].iterator(); - } - _lastNode = _iterators[_iterators.length - 1].getNode(); - } - - - public boolean atTail() - { - for(int i = 0; i < _iterators.length; i++) - { - if(!_iterators[i].atTail()) - { - return false; - } - } - return true; - } - - public QueueEntry getNode() - { - return _lastNode; - } - - public boolean advance() - { - for(int i = _iterators.length-1; i >= 0; i--) - { - if(_iterators[i].advance()) - { - _lastNode = _iterators[i].getNode(); - return true; - } - } - return false; - } - } - - public QueueEntryIterator iterator() - { - return new PriorityQueueEntryListIterator(); - } - - public QueueEntry getHead() - { - return _priorityLists[_priorities-1].getHead(); - } - - static class Factory implements QueueEntryListFactory - { - private final int _priorities; - - Factory(int priorities) - { - _priorities = priorities; - } - - public QueueEntryList createQueueEntryList(AMQQueue queue) - { - return new PriorityQueueList(queue, _priorities); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 09600b9d28..25d41c8203 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -119,16 +119,42 @@ public interface QueueEntry extends Comparable, Filterable, Filterable, Filterable _expiration); + } + + return false; + } + + public void setExpiration(final long expiration) + { + _expiration = expiration; } public boolean isAcquired() @@ -169,7 +210,7 @@ public class QueueEntryImpl implements QueueEntry public void setDeliveredToSubscription() { - getMessage().setDeliveredToConsumer(); + _flags |= DELIVERED_TO_CONSUMER; } public void release() @@ -185,7 +226,7 @@ public class QueueEntryImpl implements QueueEntry public boolean immediateAndNotDelivered() { - return _message.immediateAndNotDelivered(); + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; } public ContentHeaderBody getContentHeaderBody() throws AMQException @@ -206,8 +247,8 @@ public class QueueEntryImpl implements QueueEntry public void setRedelivered(boolean redelivered) { _redelivered = redelivered; - // todo - here we could mark this message as redelivered so we don't have to mark - // all messages on recover as redelivered. + // todo - here we could record this message as redelivered on this queue in the transactionLog + // so we don't have to mark all messages on recover as redelivered. } public Subscription getDeliveredSubscription() @@ -281,6 +322,8 @@ public class QueueEntryImpl implements QueueEntry s.restoreCredit(this); } + _queueEntryList.dequeued(this); + getQueue().dequeue(storeContext, this); if (_stateChangeListeners != null) @@ -337,6 +380,34 @@ public class QueueEntryImpl implements QueueEntry return false; } + public void flow() throws UnableToFlowMessageException + { + if (_message != null && _backingStore != null) + { + if(_log.isDebugEnabled()) + { + _log.debug("Flowing message:" + _message.debugIdentity()); + } + _backingStore.flow(_message); + _message = null; + _flowed.getAndSet(true); + } + } + + public void recover() + { + if (_messageId != null && _backingStore != null) + { + _message = _backingStore.recover(_messageId); + _flowed.getAndSet(false); + } + } + + public boolean isFlowed() + { + return _flowed.get(); + } + public int compareTo(final QueueEntry o) { @@ -382,7 +453,11 @@ public class QueueEntryImpl implements QueueEntry if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) { - _queueEntryList.advanceHead(); + _queueEntryList.advanceHead(); + if (_backingStore != null) + { + _backingStore.delete(_messageId); + } return true; } else @@ -395,4 +470,6 @@ public class QueueEntryImpl implements QueueEntry { return _queueEntryList; } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index 313e076f61..72783e3f78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.queue; -public interface QueueEntryList +public interface QueueEntryList extends FlowableQueueEntryList { AMQQueue getQueue(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index a4945bc11a..7f46a6063a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -72,12 +72,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final List _deleteTaskList = new CopyOnWriteArrayList(); - private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); - - private final AtomicLong _atomicQueueSize = new AtomicLong(0L); - - private final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); - private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); protected final SubscriptionList _subscriptionList = new SubscriptionList(this); @@ -106,11 +100,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener /** the minimum interval between sending out consecutive alerts of the same type */ public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); - /** The maximum amount of memory that is allocated to this queue. Beyond this the queue will flow to disk. */ - private long _memoryUsageMaximum = 0; - - /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ - private long _memoryUsageMinimum = 0; private static final int MAX_ASYNC_DELIVERIES = 10; @@ -120,8 +109,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private AtomicReference _asynchronousRunner = new AtomicReference(null); private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); - /** Control to determin if this queue is flowed or not. */ - protected AtomicBoolean _flowed = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -168,13 +155,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } resetNotifications(); - resetFlowToDisk(); - } - - public void resetFlowToDisk() - { - setMemoryUsageMaximum(_memoryUsageMaximum); - setMemoryUsageMinimum(_memoryUsageMinimum); } public void resetNotifications() @@ -205,7 +185,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean isFlowed() { - return _flowed.get(); + return _entries.isFlowed(); } public AMQShortString getOwner() @@ -341,10 +321,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException { - - incrementQueueCount(); - incrementQueueSize(message); - _totalMessagesReceived.incrementAndGet(); QueueEntry entry; @@ -485,17 +461,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Simple Queues don't :-) } - private void incrementQueueSize(final AMQMessage message) - { - getAtomicQueueSize().addAndGet(message.getSize()); - getAtomicQueueInMemory().addAndGet(message.getSize()); - } - - private void incrementQueueCount() - { - getAtomicQueueCount().incrementAndGet(); - } - private void deliverMessage(final Subscription sub, final QueueEntry entry) throws AMQException { @@ -594,8 +559,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener */ public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException { - decrementQueueCount(); - decrementQueueSize(entry); if (entry.acquiredBySubscription()) { _deliveredMessages.decrementAndGet(); @@ -625,16 +588,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - private void decrementQueueSize(final QueueEntry entry) - { - getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); - getAtomicQueueInMemory().addAndGet(-entry.getMessage().getSize()); - } - - void decrementQueueCount() - { - getAtomicQueueCount().decrementAndGet(); - } public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException { @@ -682,17 +635,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public long getMemoryUsageCurrent() { - return getAtomicQueueInMemory().get(); + return getQueueInMemory(); } public int getMessageCount() { - return getAtomicQueueCount().get(); + return getQueueCount(); } public long getQueueDepth() { - return getAtomicQueueSize().get(); + return getQueueSize(); } public int getUndeliveredMessageCount() @@ -768,21 +721,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _name.compareTo(o.getName()); } - public AtomicInteger getAtomicQueueCount() + public int getQueueCount() { - return _atomicQueueCount; + return _entries.size(); } - public AtomicLong getAtomicQueueSize() + public long getQueueSize() { - return _atomicQueueSize; + return _entries.dataSize(); } - public AtomicLong getAtomicQueueInMemory() + public long getQueueInMemory() { - return _atomicQueueInMemory; - } - + return _entries.memoryUsed(); + } private boolean isExclusiveSubscriber() { @@ -1493,46 +1445,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public long getMemoryUsageMaximum() { - return _memoryUsageMaximum; + return _entries.getMemoryUsageMaximum(); } public void setMemoryUsageMaximum(long maximumMemoryUsage) { - _memoryUsageMaximum = maximumMemoryUsage; - - // Don't attempt to start the inhaler/purger unless we have a minimum value specified. - if (_memoryUsageMaximum > 0) - { - // If we've increased the max memory above what we have in memory then we can inhale more - if (_memoryUsageMaximum > _atomicQueueInMemory.get()) - { - //TODO start inhaler - } - else // if we have now have to much memory in use we need to purge. - { - //TODO start purger - } - } + _entries.setMemoryUsageMaximum(maximumMemoryUsage); } public long getMemoryUsageMinimum() { - return _memoryUsageMinimum; + return _entries.getMemoryUsageMinimum(); } public void setMemoryUsageMinimum(long minimumMemoryUsage) { - _memoryUsageMinimum = minimumMemoryUsage; - - // Don't attempt to start the inhaler unless we have a minimum value specified. - if (_memoryUsageMinimum > 0) - { - // If we've increased the minimum memory above what we have in memory then we need to inhale more - if (_memoryUsageMinimum >= _atomicQueueInMemory.get()) - { - //TODO start inhaler - } - } + _entries.setMemoryUsageMinimum(minimumMemoryUsage); } public long getMinimumAlertRepeatGap() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index a46c5ae2e8..10abdd8318 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -1,6 +1,9 @@ package org.apache.qpid.server.queue; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /* * @@ -22,8 +25,9 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; * under the License. * */ -public class SimpleQueueEntryList implements QueueEntryList +public class SimpleQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList { + private final QueueEntryImpl _head; private volatile QueueEntryImpl _tail; @@ -41,12 +45,9 @@ public class SimpleQueueEntryList implements QueueEntryList AtomicReferenceFieldUpdater.newUpdater (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); - - - - public SimpleQueueEntryList(AMQQueue queue) { + super(queue); _queue = queue; _head = new QueueEntryImpl(this); _tail = _head; @@ -77,6 +78,9 @@ public class SimpleQueueEntryList implements QueueEntryList public QueueEntry add(AMQMessage message) { QueueEntryImpl node = new QueueEntryImpl(this, message); + + incrementCounters(node); + for (;;) { QueueEntryImpl tail = _tail; @@ -101,12 +105,12 @@ public class SimpleQueueEntryList implements QueueEntryList } } + public QueueEntry next(QueueEntry node) { return ((QueueEntryImpl)node).getNext(); } - public class QueueEntryIteratorImpl implements QueueEntryIterator { @@ -172,7 +176,9 @@ public class SimpleQueueEntryList implements QueueEntryList { return new SimpleQueueEntryList(queue); } + } - + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java index 0334a54fab..4c9fe81439 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java @@ -54,23 +54,11 @@ public class TransientAMQMessage implements AMQMessage protected final Long _messageId; - /** Flag to indicate that this message requires 'immediate' delivery. */ - - private static final byte IMMEDIATE = 0x01; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - - private static final byte DELIVERED_TO_CONSUMER = 0x02; private byte _flags = 0; - private long _expiration; - private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; - private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); + private long _expiration; /** * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory @@ -165,11 +153,16 @@ public class TransientAMQMessage implements AMQMessage return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() +")"; } - public void setExpiration(final long expiration) + public void setExpiration(long expiration) { _expiration = expiration; } + public long getExpiration() + { + return _expiration; + } + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) { return new BodyFrameIterator(protocolSession, channel); @@ -190,57 +183,6 @@ public class TransientAMQMessage implements AMQMessage return _messageId; } - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - public boolean getDeliveredToConsumer() - { - return (_flags & DELIVERED_TO_CONSUMER) != 0; - } - - /** - * Called to enforce the 'immediate' flag. - * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer - */ - public boolean immediateAndNotDelivered() - { - - return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; - - } - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @return true if the message has expire - * - * @throws AMQException - */ - public boolean expired() throws AMQException - { - - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } - - return false; - } - - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - */ - public void setDeliveredToConsumer() - { - _flags |= DELIVERED_TO_CONSUMER; - } public long getSize() { @@ -315,6 +257,11 @@ public class TransientAMQMessage implements AMQMessage return false; } + public boolean isImmediate() + { + return _messagePublishInfo.isImmediate(); + } + /** * This is called when all the content has been received. * @@ -366,11 +313,6 @@ public class TransientAMQMessage implements AMQMessage { _contentBodies = Collections.EMPTY_LIST; } - - if (_messagePublishInfo.isImmediate()) - { - _flags |= IMMEDIATE; - } } public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index b4b392c91d..c5b6eeca3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -48,6 +48,8 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.QueueBackingStore; +import org.apache.qpid.server.queue.FileQueueBackingStore; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.server.security.access.ACLManager; @@ -86,6 +88,7 @@ public class VirtualHost implements Accessable private final Timer _houseKeepingTimer; private VirtualHostConfiguration _configuration; + private QueueBackingStore _queueBackingStore; public void setAccessableName(String name) { @@ -113,6 +116,11 @@ public class VirtualHost implements Accessable return _configuration ; } + public QueueBackingStore getQueueBackingStore() + { + return _queueBackingStore; + } + /** * 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. @@ -186,6 +194,9 @@ public class VirtualHost implements Accessable initialiseRoutingTable(hostConfig); } + _queueBackingStore = new FileQueueBackingStore(); + _queueBackingStore.configure(this,hostConfig); + _exchangeFactory.initialise(hostConfig); _exchangeRegistry.initialise(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index d46ba85069..49afcb1340 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -352,7 +352,7 @@ public class Show extends AbstractCommand isredelivered.add(entry.isRedelivered() ? "true" : "false"); - isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false"); BasicContentHeaderProperties headers = null; -- cgit v1.2.1 From e96bf6ebc67cc1a0e3421b82c0ce497771882fcf Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Feb 2009 13:37:03 +0000 Subject: QPID-1635,QPID-1636,QPID-1638 : Updated QueueEntries to contain additional values from AMQMessage, _flags and expiry this allows the checking of immediate delivery and expiry on unloaded messages. Updated nomenclature to use load/unload rather than the overloaded flow/recover. Created new FileQueueBackingStoreFactory to ensure that validates and creates initial flowToDiskLocation and creates a new BackingStore. Responsibility for FlowToDisk has been added to the QueueEntryLists. This will allow the easy unloading of the structure in the future. Inorder to do this the size,count and memory count properties had to be moved from the SimpleAMQQueue to the QueueEntryList. An Inhaler thread was created in addition to the synchronous loading of messages. This is initiated as a result of a flowed QEL dropping below the minimumMemory value. A test to ensure that the queue never exceeds its set memory usage and that the count does not go negative has been added to SimpleAMQQueueTest. The SimpleAMQQueue is responsible for deciding when a message can be unloaded after delivery takes place. The QEL cannot decide this as there is no state for a message being marked as sent to a consumer. Only Aquired and Dequeued. The unloaded message is only deleted after the QueueEntry is deleted from the QEL. This negates the need to recreated the data on disk if the message needs to be unloaded again. All files/directories relating to FtD are created as deleteOnExit files so that under clean shutdown the VM will ensure that the files are deleted. On startup the flowToDiskLocation is also purged to ensure a clean starting point. SAMQQueueThreadPoolTest was augmented to take in to account the new inhaler executor reference. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748519 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/FileQueueBackingStore.java | 305 ++++++++------------- .../server/queue/FileQueueBackingStoreFactory.java | 166 +++++++++++ .../server/queue/FlowableBaseQueueEntryList.java | 168 ++++++++++-- .../qpid/server/queue/FlowableQueueEntryList.java | 20 +- .../qpid/server/queue/PriorityQueueEntryList.java | 17 +- .../qpid/server/queue/QueueBackingStore.java | 6 +- .../server/queue/QueueBackingStoreFactory.java | 32 +++ .../org/apache/qpid/server/queue/QueueEntry.java | 6 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 32 ++- .../apache/qpid/server/queue/QueueEntryList.java | 2 +- .../qpid/server/queue/QueueEntryListFactory.java | 2 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 16 +- .../qpid/server/queue/SimpleQueueEntryList.java | 4 +- .../qpid/server/virtualhost/VirtualHost.java | 13 +- 14 files changed, 547 insertions(+), 242 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index 7acb683e3b..4e3b2298d1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -22,19 +22,12 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.AMQProtocolVersionException; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.AMQException; -import org.apache.commons.configuration.ConfigurationException; import java.io.File; import java.io.FileInputStream; @@ -43,219 +36,142 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; public class FileQueueBackingStore implements QueueBackingStore { private static final Logger _log = Logger.getLogger(FileQueueBackingStore.class); - private AtomicBoolean _closed = new AtomicBoolean(false); private String _flowToDiskLocation; - private static final String QUEUE_BACKING_DIR = "queueBacking"; - public void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException + public FileQueueBackingStore(String location) { - setFlowToDisk(virtualHost.getName(), config.getFlowToDiskLocation()); + _flowToDiskLocation = location; } - private void setFlowToDisk(String vHostName, String location) throws ConfigurationException + public AMQMessage load(Long messageId) { - if (vHostName == null) - { - throw new ConfigurationException("Unable to setup to Flow to Disk as Virtualhost name was not specified"); - } + _log.info("Loading Message (ID:" + messageId + ")"); - if (location == null) - { - throw new ConfigurationException("Unable to setup to Flow to Disk as location was not specified."); - } + MessageMetaData mmd; - _flowToDiskLocation = location; + File handle = getFileHandle(messageId); + handle.deleteOnExit(); - _flowToDiskLocation += File.separator + QUEUE_BACKING_DIR + File.separator + vHostName; + ObjectInputStream input = null; - File root = new File(location); - if (!root.exists()) - { - throw new ConfigurationException("Specified Flow to Disk root does not exist:" + root.getAbsolutePath()); - } - else + Exception error = null; + try { + input = new ObjectInputStream(new FileInputStream(handle)); - if (root.isFile()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified root is a file:"+ - root.getAbsolutePath()); - } + long arrivaltime = input.readLong(); + + final AMQShortString exchange = new AMQShortString(input.readUTF()); + final AMQShortString routingKey = new AMQShortString(input.readUTF()); + final boolean mandatory = input.readBoolean(); + final boolean immediate = input.readBoolean(); + + int bodySize = input.readInt(); + byte[] underlying = new byte[bodySize]; + + input.readFully(underlying, 0, bodySize); + + ByteBuffer buf = ByteBuffer.wrap(underlying); - if(!root.canWrite()) + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, bodySize); + + int chunkCount = input.readInt(); + + // There are WAY to many annonymous MPIs in the code this should be made concrete. + MessagePublishInfo info = new MessagePublishInfo() { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to specified root:"+ - root.getAbsolutePath()); - } - } + public AMQShortString getExchange() + { + return exchange; + } + public void setExchange(AMQShortString exchange) + { - File store = new File(_flowToDiskLocation); - if (store.exists()) - { - if (!FileUtils.delete(store, true)) + } + + public boolean isImmediate() + { + return immediate; + } + + public boolean isMandatory() + { + return mandatory; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + }; + + mmd = new MessageMetaData(info, chb, chunkCount); + mmd.setArrivalTime(arrivaltime); + + AMQMessage message; + if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2) + { + message = new PersistentAMQMessage(messageId, null); + } + else { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store as directory already exsits:" - + store.getAbsolutePath()); + message = new TransientAMQMessage(messageId); } - if (store.isFile()) + message.recoverFromMessageMetaData(mmd); + + for (int chunk = 0; chunk < chunkCount; chunk++) { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified location is a file:"+ - store.getAbsolutePath()); + int length = input.readInt(); + + byte[] data = new byte[length]; + + input.readFully(data, 0, length); + + try + { + message.recoverContentBodyFrame(new RecoverDataBuffer(length, data), (chunk + 1 == chunkCount)); + } + catch (AMQException e) + { + //ignore as this will not occur. + // It is thrown by the _transactionLog method in load on PersistentAMQMessage + // but we have created the message with a null log and will never call that method. + } } + return message; } - else + catch (Exception e) { - if (!store.getParentFile().getParentFile().canWrite()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to parent location:"+ - store.getParentFile().getParentFile().getAbsolutePath()); - } + error = e; } - - - _log.info("Creating Flow to Disk Store : " + store.getAbsolutePath()); - store.deleteOnExit(); - if (!store.mkdirs()) + finally { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store:" + store.getAbsolutePath()); + try + { + input.close(); + // We can purge the message here then reflow it if required but I believe it to be cleaner to leave it + // on disk until it has been deleted from the queue at that point we can be sure we won't need the data + //handle.delete(); + } + catch (IOException e) + { + _log.info("Unable to close input on message(" + messageId + ") recovery due to:" + e.getMessage()); + } } - } - - - public AMQMessage recover(Long messageId) - { - MessageMetaData mmd; - List contentBodies = new LinkedList(); - - File handle = getFileHandle(messageId); - handle.deleteOnExit(); - - ObjectInputStream input = null; - - Exception error = null; - try - { - input = new ObjectInputStream(new FileInputStream(handle)); - - long arrivaltime = input.readLong(); - - final AMQShortString exchange = new AMQShortString(input.readUTF()); - final AMQShortString routingKey = new AMQShortString(input.readUTF()); - final boolean mandatory = input.readBoolean(); - final boolean immediate = input.readBoolean(); - - int bodySize = input.readInt(); - byte[] underlying = new byte[bodySize]; - - input.readFully(underlying, 0, bodySize); - - ByteBuffer buf = ByteBuffer.wrap(underlying); - - ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, bodySize); - - int chunkCount = input.readInt(); - - // There are WAY to many annonymous MPIs in the code this should be made concrete. - MessagePublishInfo info = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return exchange; - } - - public void setExchange(AMQShortString exchange) - { - - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return mandatory; - } - - public AMQShortString getRoutingKey() - { - return routingKey; - } - }; - - mmd = new MessageMetaData(info, chb, chunkCount); - mmd.setArrivalTime(arrivaltime); - - AMQMessage message; - if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2) - { - message = new PersistentAMQMessage(messageId, null); - } - else - { - message = new TransientAMQMessage(messageId); - } - - message.recoverFromMessageMetaData(mmd); - - for (int chunk = 0; chunk < chunkCount; chunk++) - { - int length = input.readInt(); - - byte[] data = new byte[length]; - - input.readFully(data, 0, length); - - // There are WAY to many annonymous CCs in the code this should be made concrete. - try - { - message.recoverContentBodyFrame(new RecoverDataBuffer(length, data), (chunk + 1 == chunkCount)); - } - catch (AMQException e) - { - //ignore as this will not occur. - // It is thrown by the _transactionLog method in recover on PersistentAMQMessage - // but we have created the message with a null log and will never call that method. - } - } - - return message; - } - catch (Exception e) - { - error = e; - } - finally - { - try - { - input.close(); - } - catch (IOException e) - { - _log.info("Unable to close input on message("+messageId+") recovery due to:"+e.getMessage()); - } - } throw new UnableToRecoverMessageException(error); } - - public void flow(AMQMessage message) throws UnableToFlowMessageException + public void unload(AMQMessage message) throws UnableToFlowMessageException { long messageId = message.getMessageId(); @@ -264,10 +180,18 @@ public class FileQueueBackingStore implements QueueBackingStore //If we have written the data once then we don't need to do it again. if (handle.exists()) { - _log.debug("Message(" + messageId + ") already flowed to disk."); + if (_log.isDebugEnabled()) + { + _log.debug("Message(ID:" + messageId + ") already unloaded."); + } return; } + if (_log.isInfoEnabled()) + { + _log.info("Unloading Message (ID:" + messageId + ")"); + } + handle.deleteOnExit(); ObjectOutputStream writer = null; @@ -334,7 +258,7 @@ public class FileQueueBackingStore implements QueueBackingStore if (error != null) { - _log.error("Unable to flow message(" + messageId + ") to disk, restoring state."); + _log.error("Unable to unload message(" + messageId + ") to disk, restoring state."); handle.delete(); throw new UnableToFlowMessageException(messageId, error); } @@ -358,7 +282,7 @@ public class FileQueueBackingStore implements QueueBackingStore // grab the 8 LSB to give us 256 bins long bin = messageId & 0xFFL; - String bin_path =_flowToDiskLocation + File.separator + bin; + String bin_path = _flowToDiskLocation + File.separator + bin; File bin_dir = new File(bin_path); if (!bin_dir.exists()) @@ -379,7 +303,10 @@ public class FileQueueBackingStore implements QueueBackingStore if (handle.exists()) { - _log.debug("Message(" + messageId + ") delete flowToDisk."); + if (_log.isInfoEnabled()) + { + _log.info("Message(" + messageId + ") delete flowToDisk."); + } if (!handle.delete()) { throw new RuntimeException("Unable to delete flowToDisk data"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java new file mode 100644 index 0000000000..0cfa9d6b32 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java @@ -0,0 +1,166 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.util.FileUtils; + +import java.io.File; + +public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory +{ + private static final Logger _log = Logger.getLogger(FileQueueBackingStoreFactory.class); + + private String _flowToDiskLocation; + private static final String QUEUE_BACKING_DIR = "queueBacking"; + + public void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException + { + setFlowToDisk(virtualHost.getName(), config.getFlowToDiskLocation()); + } + + private void setFlowToDisk(String vHostName, String location) throws ConfigurationException + { + if (vHostName == null) + { + throw new ConfigurationException("Unable to setup to Flow to Disk as Virtualhost name was not specified"); + } + + if (location == null) + { + throw new ConfigurationException("Unable to setup to Flow to Disk as location was not specified."); + } + + _flowToDiskLocation = location; + + _flowToDiskLocation += File.separator + QUEUE_BACKING_DIR + File.separator + vHostName; + + File root = new File(location); + if (!root.exists()) + { + throw new ConfigurationException("Specified Flow to Disk root does not exist:" + root.getAbsolutePath()); + } + else + { + + if (root.isFile()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified root is a file:" + + root.getAbsolutePath()); + } + + if (!root.canWrite()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to specified root:" + + root.getAbsolutePath()); + } + + } + + // if we don't mark QUEUE_BAKCING_DIR as a deleteOnExit it will remain. + File backingDir = new File(location + File.separator + QUEUE_BACKING_DIR); + if (backingDir.exists()) + { + if (!FileUtils.delete(backingDir, true)) + { + throw new ConfigurationException("Unable to delete existing Flow to Disk root at:" + + backingDir.getAbsolutePath()); + } + + if (backingDir.isFile()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk root as specified location is a file:" + + backingDir.getAbsolutePath()); + } + } + + backingDir.deleteOnExit(); + if (!backingDir.mkdirs()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk root:" + location + File.separator + QUEUE_BACKING_DIR); + } + + + File store = new File(_flowToDiskLocation); + if (store.exists()) + { + if (!FileUtils.delete(store, true)) + { + throw new ConfigurationException("Unable to delete existing Flow to Disk store at:" + + store.getAbsolutePath()); + } + + if (store.isFile()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified location is a file:" + + store.getAbsolutePath()); + } + + } + + _log.info("Creating Flow to Disk Store : " + store.getAbsolutePath()); + store.deleteOnExit(); + + if(!store.mkdir()) + { + throw new ConfigurationException("Unable to create Temporary Flow to Disk store:" + store.getAbsolutePath()); + } + } + + public QueueBackingStore createBacking(AMQQueue queue) + { + return new FileQueueBackingStore(createStore(queue.getName().toString())); + } + + private String createStore(String name) + { + return createStore(name, 0); + } + + private String createStore(String name, int index) + { + + String store = _flowToDiskLocation + File.separator + name; + if (index > 0) + { + store += "-" + index; + } + + //TODO ensure store is safe for the OS + + File storeFile = new File(store); + + if (storeFile.exists()) + { + return createStore(name, index + 1); + } + + storeFile.mkdirs(); + + storeFile.deleteOnExit(); + + return store; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 72ea5f2667..a4f80a44b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -20,16 +20,18 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.log4j.Logger; +import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; -/** - * This is an abstract base class to handle - */ +/** This is an abstract base class to handle */ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryList { private static final Logger _log = Logger.getLogger(FlowableBaseQueueEntryList.class); @@ -43,9 +45,12 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ private long _memoryUsageMinimum = 0; - private AtomicBoolean _flowed; + private volatile AtomicBoolean _flowed; private QueueBackingStore _backingStore; protected AMQQueue _queue; + private Executor _inhaler; + private AtomicBoolean _stopped; + private AtomicReference _asynchronousInhaler = new AtomicReference(null); FlowableBaseQueueEntryList(AMQQueue queue) { @@ -54,15 +59,18 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi VirtualHost vhost = queue.getVirtualHost(); if (vhost != null) { - _backingStore = vhost.getQueueBackingStore(); + _backingStore = vhost.getQueueBackingStoreFactory().createBacking(queue); } + + _stopped = new AtomicBoolean(false); + _inhaler = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); } public void setFlowed(boolean flowed) { if (_flowed.get() != flowed) { - _log.info("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); + _log.warn("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); _flowed.set(flowed); } } @@ -94,14 +102,15 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi // Don't attempt to start the inhaler/purger unless we have a minimum value specified. if (_memoryUsageMaximum > 0) { - // If we've increased the max memory above what we have in memory then we can inhale more - if (_memoryUsageMaximum > _atomicQueueInMemory.get()) + if (_memoryUsageMinimum == 0) { - //TODO start inhaler + setMemoryUsageMinimum(_memoryUsageMaximum / 2); } - else // if we have now have to much memory in use we need to purge. + + // if we have now have to much memory in use we need to purge. + if (_memoryUsageMaximum < _atomicQueueInMemory.get()) { - //TODO start purger + startPurger(); } } } @@ -118,19 +127,78 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi // Don't attempt to start the inhaler unless we have a minimum value specified. if (_memoryUsageMinimum > 0) { - // If we've increased the minimum memory above what we have in memory then we need to inhale more - if (_memoryUsageMinimum >= _atomicQueueInMemory.get()) + checkAndStartLoader(); + } + } + + private void checkAndStartLoader() + { + // If we've increased the minimum memory above what we have in memory then we need to inhale more + if (_atomicQueueInMemory.get() <= _memoryUsageMinimum) + { + startInhaler(); + } + } + + private void startInhaler() + { + if (_flowed.get()) + { + MessageInhaler inhaler = new MessageInhaler(); + + if (_asynchronousInhaler.compareAndSet(null, inhaler)) { - //TODO start inhaler + _inhaler.execute(inhaler); } } } + private void startPurger() + { + //TODO create purger, used when maxMemory is reduced creating over memory situation. + _log.warn("Requested Purger Start.. purger TBC."); + //_purger.execute(new MessagePurger(this)); + } + public long getMemoryUsageMinimum() { return _memoryUsageMinimum; } + public void unloadEntry(QueueEntry queueEntry) + { + try + { + queueEntry.unload(); + _atomicQueueInMemory.addAndGet(-queueEntry.getSize()); + checkAndStartLoader(); + } + catch (UnableToFlowMessageException e) + { + _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + } + } + + public void loadEntry(QueueEntry queueEntry) + { + queueEntry.load(); + if( _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + { + _log.error("Loaded to much data!:"+_atomicQueueInMemory.get()+"/"+_memoryUsageMaximum); + } + } + + public void stop() + { + if (!_stopped.getAndSet(true)) + { + // The SimpleAMQQueue keeps running when stopped so we should just release the services + // rather than actively shutdown our threads. + //Shutdown thread for inhaler. + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + } + } + protected boolean willCauseFlowToDisk(QueueEntryImpl queueEntry) { return _memoryUsageMaximum != 0 && memoryUsed() + queueEntry.getSize() > _memoryUsageMaximum; @@ -153,13 +221,14 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi /** * Called when we are now flowing to disk + * * @param queueEntry the entry that is being flowed to disk */ protected void flowingToDisk(QueueEntryImpl queueEntry) { try { - queueEntry.flow(); + queueEntry.unload(); } catch (UnableToFlowMessageException e) { @@ -182,4 +251,71 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi return _backingStore; } + private class MessageInhaler implements Runnable + { + public void run() + { + String threadName = Thread.currentThread().getName(); + Thread.currentThread().setName("Inhaler-" + _queue.getVirtualHost().getName() + "-" + _queue.getName()); + try + { + inhaleList(this); + } + finally + { + Thread.currentThread().setName(threadName); + } + } + } + + private void inhaleList(MessageInhaler messageInhaler) + { + _log.info("Inhaler Running"); + // If in memory count is at or over max then we can't inhale + if (_atomicQueueInMemory.get() >= _memoryUsageMaximum) + { + _log.debug("Unable to start inhaling as we are already over quota:" + + _atomicQueueInMemory.get() + ">=" + _memoryUsageMaximum); + return; + } + + _asynchronousInhaler.compareAndSet(messageInhaler, null); + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && _asynchronousInhaler.compareAndSet(null, messageInhaler)) + { + QueueEntryIterator iterator = iterator(); + + while (!iterator.getNode().isAvailable() && iterator.advance()) + { + //Find first AVAILABLE node + } + + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && !iterator.atTail()) + { + QueueEntry entry = iterator.getNode(); + + if (entry.isAvailable() && entry.isFlowed()) + { + loadEntry(entry); + } + + iterator.advance(); + } + + if (iterator.atTail()) + { + setFlowed(false); + } + + _asynchronousInhaler.set(null); + } + + //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. + if (_flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) + { + _inhaler.execute(messageInhaler); + + } + + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java index 4e95978bf8..b547a41047 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java @@ -20,7 +20,9 @@ */ package org.apache.qpid.server.queue; -public interface FlowableQueueEntryList +import java.util.concurrent.atomic.AtomicLong; + +public interface FlowableQueueEntryList extends QueueEntryList { void setFlowed(boolean flowed); @@ -38,5 +40,19 @@ public interface FlowableQueueEntryList void setMemoryUsageMinimum(long minimumMemoryUsage); - long getMemoryUsageMinimum(); + long getMemoryUsageMinimum(); + + /** + * Immediately unload Entry + * @param queueEntry the entry to unload + */ + public void unloadEntry(QueueEntry queueEntry); + + /** + * Immediately load Entry + * @param queueEntry the entry to load + */ + public void loadEntry(QueueEntry queueEntry); + + void stop(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index d812b8ceca..23307d8acf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -22,10 +22,10 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.CommonContentHeaderProperties; -public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList +public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList { private final AMQQueue _queue; - private final QueueEntryList[] _priorityLists; + private final FlowableQueueEntryList[] _priorityLists; private final int _priorities; private final int _priorityOffset; @@ -33,7 +33,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement { super(queue); _queue = queue; - _priorityLists = new QueueEntryList[priorities]; + _priorityLists = new FlowableQueueEntryList[priorities]; _priorities = priorities; _priorityOffset = 5-((priorities + 1)/2); for(int i = 0; i < priorities; i++) @@ -53,7 +53,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement } public QueueEntry add(AMQMessage message) - { + { int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; if(index >= _priorities) { @@ -152,7 +152,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement _priorities = priorities; } - public QueueEntryList createQueueEntryList(AMQQueue queue) + public FlowableQueueEntryList createQueueEntryList(AMQQueue queue) { return new PriorityQueueEntryList(queue, _priorities); } @@ -162,7 +162,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement public int size() { int size=0; - for (QueueEntryList queueEntryList : _priorityLists) + for (FlowableQueueEntryList queueEntryList : _priorityLists) { size += queueEntryList.size(); } @@ -174,9 +174,6 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement @Override protected void flowingToDisk(QueueEntryImpl queueEntry) { - //TODO this disables FTD for priority queues - // As the incomming message isn't always the one to purge. - // More logic is required up in the add() method here to determine if the - // incomming message is at the 'front' or not. + //This class doesn't maintain it's own sizes it delegates to the sub FlowableQueueEntryLists } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java index 376e6f1b57..1f575d1e05 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java @@ -26,11 +26,9 @@ import org.apache.commons.configuration.ConfigurationException; public interface QueueBackingStore { - void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException; + AMQMessage load(Long messageId); - AMQMessage recover(Long messageId); - - void flow(AMQMessage message) throws UnableToFlowMessageException; + void unload(AMQMessage message) throws UnableToFlowMessageException; void delete(Long messageId); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java new file mode 100644 index 0000000000..3dd23a2f40 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java @@ -0,0 +1,32 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.commons.configuration.ConfigurationException; + +public interface QueueBackingStoreFactory +{ + void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException; + + public QueueBackingStore createBacking(AMQQueue queue); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 25d41c8203..7e41cf53a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -157,6 +157,8 @@ public interface QueueEntry extends Comparable, Filterable, Filterable Date: Fri, 27 Feb 2009 15:40:56 +0000 Subject: QPID-1699: reload the config file sections that we can when we receive SIGHUP. Add jmx method to do so. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748561 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 6 +++ .../server/configuration/ServerConfiguration.java | 51 +++++++++++++++++++++- .../management/ConfigurationManagement.java | 40 +++++++++++++++++ .../management/ConfigurationManagementMBean.java | 49 +++++++++++++++++++++ .../management/MBeanInvocationHandlerImpl.java | 17 +++++--- 5 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 0e5facfefe..49619ac5b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -26,6 +26,8 @@ import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; +import javax.management.NotCompliantMBeanException; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -47,6 +49,7 @@ import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; @@ -267,6 +270,9 @@ public class Main configureLoggingManagementMBean(logConfigFile, logWatchTime); + ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); + configMBean.register(); + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say // Starting Qpid Client diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 484a241fc0..cbb044b7e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -27,14 +27,23 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import javax.management.NotCompliantMBeanException; + import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationFactory; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +import sun.misc.Signal; +import sun.misc.SignalHandler; -public class ServerConfiguration +public class ServerConfiguration implements SignalHandler { private static Configuration _config; @@ -52,6 +61,10 @@ public class ServerConfiguration private Map _virtualHosts = new HashMap(); private SecurityConfiguration _securityConfiguration = null; + private File _configFile; + + private ConfigurationManagementMBean _mbean; + // Map of environment variables to config items private static final Map envVarMap = new HashMap(); @@ -82,6 +95,8 @@ public class ServerConfiguration public ServerConfiguration(File configurationURL) throws ConfigurationException { this(parseConfig(configurationURL)); + _configFile = configurationURL; + sun.misc.Signal.handle(new sun.misc.Signal("HUP"), this); } public ServerConfiguration(Configuration conf) throws ConfigurationException @@ -94,8 +109,9 @@ public class ServerConfiguration _securityConfiguration = new SecurityConfiguration(conf.subset("security")); setupVirtualHosts(conf); + } - + private void setupVirtualHosts(Configuration conf) throws ConfigurationException { List vhosts = conf.getList("virtualhosts"); @@ -181,6 +197,37 @@ public class ServerConfiguration return conf; } + @Override + public void handle(Signal arg0) + { + try + { + reparseConfigFile(); + } + catch (ConfigurationException e) + { + // Not much we can do about it really. + } + } + + public void reparseConfigFile() throws ConfigurationException + { + if (_configFile != null) + { + Configuration newConfig = parseConfig(_configFile); + _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); + ApplicationRegistry.getInstance().getAccessManager().configurePlugins(_securityConfiguration); + + VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); + for (String hostname : _virtualHosts.keySet()) + { + VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); + SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security")); + vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); + } + } + } + public String getQpidWork() { return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java new file mode 100644 index 0000000000..161434bdea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.management; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.management.MBeanAttribute; + +public interface ConfigurationManagement +{ + + String TYPE = "ConfigurationManagement"; + int VERSION = 1; + + /** + * Reload the + * @throws ConfigurationException + */ + @MBeanAttribute(name="reloadSecurityConfiguration", + description = "Force a reload of the security configuration sections") + void reloadSecurityConfiguration() throws ConfigurationException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java new file mode 100644 index 0000000000..ead6053d70 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.management; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement +{ + + public ConfigurationManagementMBean() throws NotCompliantMBeanException + { + super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION); + } + + @Override + public String getObjectInstanceName() + { + return ConfigurationManagement.TYPE; + } + + @Override + public void reloadSecurityConfiguration() throws ConfigurationException + { + ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index fccd91ffdb..e9b4d85e66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.management; +import org.apache.qpid.server.configuration.management.ConfigurationManagement; import org.apache.qpid.server.logging.management.LoggingManagement; import org.apache.qpid.server.security.access.management.UserManagement; import org.apache.log4j.Logger; @@ -38,6 +39,8 @@ import java.lang.reflect.Method; import java.security.AccessController; import java.security.Principal; import java.security.AccessControlContext; +import java.util.ArrayList; +import java.util.HashSet; import java.util.Set; import java.util.Properties; @@ -57,6 +60,13 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler private MBeanServer _mbs; private static Properties _userRoles = new Properties(); + private static HashSet _adminOnlyMethods = new HashSet(); + { + _adminOnlyMethods.add(UserManagement.TYPE); + _adminOnlyMethods.add(LoggingManagement.TYPE); + _adminOnlyMethods.add(ConfigurationManagement.TYPE); + } + public static MBeanServerForwarder newProxyInstance() { final InvocationHandler handler = new MBeanInvocationHandlerImpl(); @@ -155,13 +165,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler { ObjectName object = (ObjectName) args[0]; - if (UserManagement.TYPE.equals(object.getKeyProperty("type")) - || LoggingManagement.TYPE.equals(object.getKeyProperty("type"))) - { - return true; - } + return _adminOnlyMethods.contains(object.getKeyProperty("type")); } - return false; } -- cgit v1.2.1 From 7bd1ee1b36e401aaa64440bc6c3cc029c66365b1 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 27 Feb 2009 16:57:22 +0000 Subject: QPID-1699: fix mbean annotation, log failure to reload file. Address review comments from robbie. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748591 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/ServerConfiguration.java | 10 +++++++--- .../configuration/management/ConfigurationManagement.java | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index cbb044b7e6..0cb31c1b14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -27,8 +27,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import javax.management.NotCompliantMBeanException; - import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -39,6 +37,9 @@ import org.apache.qpid.server.configuration.management.ConfigurationManagementMB import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sun.misc.Signal; import sun.misc.SignalHandler; @@ -62,8 +63,11 @@ public class ServerConfiguration implements SignalHandler private SecurityConfiguration _securityConfiguration = null; private File _configFile; + + private Logger _log = LoggerFactory.getLogger(this.getClass()); private ConfigurationManagementMBean _mbean; + // Map of environment variables to config items private static final Map envVarMap = new HashMap(); @@ -206,7 +210,7 @@ public class ServerConfiguration implements SignalHandler } catch (ConfigurationException e) { - // Not much we can do about it really. + _log.error("Could not reload configuration file", e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java index 161434bdea..8e4bf01c6a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java @@ -20,8 +20,10 @@ */ package org.apache.qpid.server.configuration.management; +import javax.management.MBeanOperationInfo; + import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; public interface ConfigurationManagement { @@ -33,8 +35,9 @@ public interface ConfigurationManagement * Reload the * @throws ConfigurationException */ - @MBeanAttribute(name="reloadSecurityConfiguration", - description = "Force a reload of the security configuration sections") + @MBeanOperation(name="reloadSecurityConfiguration", + description = "Force a reload of the security configuration sections", + impact = MBeanOperationInfo.ACTION) void reloadSecurityConfiguration() throws ConfigurationException; } -- cgit v1.2.1 From 88757d40e7fbe19ae00ff0ef9859690959ab2cee Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Feb 2009 18:56:40 +0000 Subject: QPID-1502: Update the PlainPasswordFilePrincipalDatabase to be manipulatable by the management console and cached in memory like the B64MD5 PD. Add unit tests for the PlainPD git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748641 13f79535-47bb-0310-9956-ffa450edef68 --- .../PlainPasswordFilePrincipalDatabase.java | 334 ++++++++++++++++++--- .../server/security/auth/database/PlainUser.java | 106 +++++++ 2 files changed, 396 insertions(+), 44 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 9da954d74f..5e4678a63b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -34,11 +34,13 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.io.PrintStream; import java.security.Principal; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; /** @@ -50,13 +52,18 @@ import java.util.regex.Pattern; */ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase { + public static final String DEFAULT_ENCODING = "utf-8"; + private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); - protected File _passwordFile; + private File _passwordFile; - protected Pattern _regexp = Pattern.compile(":"); + private Pattern _regexp = Pattern.compile(":"); - protected Map _saslServers; + private Map _saslServers; + + private Map _users = new HashMap(); + private ReentrantLock _userUpdate = new ReentrantLock(); public PlainPasswordFilePrincipalDatabase() { @@ -83,7 +90,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase _saslServers.put(cram.getMechanismName(), cram); } - public void setPasswordFile(String passwordFile) throws FileNotFoundException + public void setPasswordFile(String passwordFile) throws IOException { File f = new File(passwordFile); _logger.info("PlainPasswordFile using file " + f.getAbsolutePath()); @@ -97,10 +104,20 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase throw new FileNotFoundException("Cannot read password file " + f + ". Check permissions."); } + + loadPasswordFile(); } - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, - AccountNotFoundException + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * If you want to change the password for a user, use updatePassword instead. + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannot be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException { if (_passwordFile == null) { @@ -111,6 +128,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase throw new IllegalArgumentException("principal must not be null"); } char[] pwd = lookupPassword(principal.getName()); + if (pwd != null) { callback.setPassword(pwd); @@ -121,33 +139,151 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The plaintext password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException { - try - { - char[] pwd = lookupPassword(principal); - return compareCharArray(pwd, password); - } - catch (IOException e) + char[] pwd = lookupPassword(principal); + + if (pwd == null) { - return false; + throw new AccountNotFoundException("Unable to lookup the specfied users password"); } + + return compareCharArray(pwd, password); + } + /** + * Changes the password for the specified user + * + * @param principal to change the password for + * @param password plaintext password to set the password too + */ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException { - return false; // updates denied + PlainUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + try + { + _userUpdate.lock(); + char[] orig = user.getPassword(); + user.setPassword(password); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user '" + principal + "' discarded"); + //revert the password change + user.setPassword(orig); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (Exception e) + { + return false; + } } public boolean createPrincipal(Principal principal, char[] password) { - return false; // updates denied + if (_users.get(principal.getName()) != null) + { + return false; + } + + PlainUser user = new PlainUser(principal.getName(), password); + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + //remove the use on failure. + _users.remove(user.getName()); + _logger.warn("Unable to create user '" + user.getName()); + return false; + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } } public boolean deletePrincipal(Principal principal) throws AccountNotFoundException { - return false; // updates denied + PlainUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; } public Map getMechanisms() @@ -157,21 +293,14 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase public List getUsers() { - return new LinkedList(); //todo + return new LinkedList(_users.values()); } public Principal getUser(String username) { - try - { - if (lookupPassword(username) != null) - { - return new UsernamePrincipal(username); - } - } - catch (IOException e) + if (_users.containsKey(username)) { - //fall through to null return + return new UsernamePrincipal(username); } return null; } @@ -197,49 +326,166 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase * 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 the name of the principal to lookup - * - * @return char[] of the password + * @param name The principal name to lookup * - * @throws java.io.IOException whilst accessing the file + * @return a char[] for use in SASL. */ - private char[] lookupPassword(String name) throws IOException + private char[] lookupPassword(String name) + { + PlainUser user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + 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 || result[0].startsWith("#")) + { + continue; + } + + PlainUser user = new PlainUser(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException { - BufferedReader reader = null; try { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); - while ((line = reader.readLine()) != null) + try { - if (!line.startsWith("#")) + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) { String[] result = _regexp.split(line); - if (result == null || result.length < 2) + if (result == null || result.length < 2 || result[0].startsWith("#")) { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); continue; } - if (name.equals(result[0])) + PlainUser user = _users.get(result[0]); + + if (user == null) { - return result[1].toCharArray(); + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + byte[] password = user.getPasswordBytes(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(password); + writer.println(); + + user.saved(); + } + } + } + + for (PlainUser user : _users.values()) + { + if (user.isModified()) + { + byte[] password; + password = user.getPasswordBytes(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(password); + writer.println(); + user.saved(); } } } - return null; + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } } finally { - if (reader != null) + if (_userUpdate.isHeldByCurrentThread()) { - reader.close(); + _userUpdate.unlock(); } } } - + public void reload() throws IOException { - //This PD is not cached, so do nothing. + loadPasswordFile(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java new file mode 100644 index 0000000000..46a78a55aa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java @@ -0,0 +1,106 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; + +import java.security.Principal; + +public class PlainUser implements Principal +{ + private String _name; + private char[] _password; + private boolean _modified = false; + private boolean _deleted = false; + + PlainUser(String[] data) + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + _password = data[1].toCharArray(); + + } + + public PlainUser(String name, char[] password) + { + _name = name; + _password = password; + _modified = true; + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + byte[] getPasswordBytes() + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + return byteArray; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} -- cgit v1.2.1 From a2f199031454fcc52db512776c75e5518636ba13 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Feb 2009 20:14:07 +0000 Subject: QPID-1536: modify the B64MD5 PD to take plain text input and perform the required hashing itself in order to present a consistent interface for user management. Alter management console to use mbean versioning to detect this and send plaintext to v2+ user management mbeans. Update RMIPasswordAuthenticator to make use of the new PD input consistency git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748680 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 49 +++++++++++-- .../server/security/auth/database/HashedUser.java | 43 ++++++++++-- .../auth/rmi/RMIPasswordAuthenticator.java | 81 +++------------------- 3 files changed, 93 insertions(+), 80 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 69ad9014db..3c211746e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -152,8 +152,39 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException { char[] pwd = lookupPassword(principal); + + if (pwd == null) + { + throw new AccountNotFoundException("Unable to lookup the specfied users password"); + } + + byte[] byteArray = new byte[password.length]; + int index = 0; + for (char c : password) + { + byteArray[index++] = (byte) c; + } + + byte[] MD5byteArray; + try + { + MD5byteArray = HashedUser.getMD5(byteArray); + } + catch (Exception e1) + { + _logger.warn("Unable to hash password for user '" + principal + "' for comparison"); + return false; + } + + char[] hashedPassword = new char[MD5byteArray.length]; - return compareCharArray(pwd, password); + index = 0; + for (byte c : MD5byteArray) + { + hashedPassword[index++] = (char) c; + } + + return compareCharArray(pwd, hashedPassword); } private boolean compareCharArray(char[] a, char[] b) @@ -193,7 +224,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { _userUpdate.lock(); char[] orig = user.getPassword(); - user.setPassword(password); + user.setPassword(password,false); try { @@ -204,7 +235,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase _logger.error("Unable to save password file, password change for user'" + principal + "' will revert at restart"); //revert the password change - user.setPassword(orig); + user.setPassword(orig,true); return false; } return true; @@ -230,7 +261,17 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return false; } - HashedUser user = new HashedUser(principal.getName(), password); + HashedUser user; + try + { + user = new HashedUser(principal.getName(), password); + } + catch (Exception e1) + { + _logger.warn("Unable to create new user '" + principal.getName() + "'"); + return false; + } + try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java index 4d92e3fb4c..3690e7f92a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -25,6 +25,7 @@ import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -63,10 +64,22 @@ public class HashedUser implements Principal } } - public HashedUser(String name, char[] password) + public HashedUser(String name, char[] password) throws UnsupportedEncodingException, NoSuchAlgorithmException { _name = name; - setPassword(password); + setPassword(password,false); + } + + public static byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + return md.digest(); } public String getName() @@ -84,9 +97,31 @@ public class HashedUser implements Principal return _password; } - void setPassword(char[] password) + void setPassword(char[] password, boolean alreadyHashed) throws UnsupportedEncodingException, NoSuchAlgorithmException { - _password = password; + if(alreadyHashed){ + _password = password; + } + else + { + byte[] byteArray = new byte[password.length]; + int index = 0; + for (char c : password) + { + byteArray[index++] = (byte) c; + } + + byte[] MD5byteArray = getMD5(byteArray); + + _password = new char[MD5byteArray.length]; + + index = 0; + for (byte c : MD5byteArray) + { + _password[index++] = (char) c; + } + } + _modified = true; _encodedPassword = null; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java index 378b17e733..77040e896c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -20,23 +20,14 @@ */ package org.apache.qpid.server.security.auth.rmi; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import java.util.Collections; import javax.management.remote.JMXAuthenticator; import javax.management.remote.JMXPrincipal; import javax.security.auth.Subject; -import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; public class RMIPasswordAuthenticator implements JMXAuthenticator { @@ -48,7 +39,6 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator static final String CREDENTIALS_REQUIRED = "User details are required. " + "Please ensure you are using an up to date management console to connect."; - public static final String DEFAULT_ENCODING = "utf-8"; private PrincipalDatabase _db = null; public RMIPasswordAuthenticator() @@ -91,56 +81,26 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator throw new SecurityException(SHOULD_BE_NON_NULL); } + // Verify that a PD has been set. + if (_db == null) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + boolean authenticated = false; // Perform authentication try { - PasswordCallback pwCallback = new PasswordCallback("prompt",false); - UsernamePrincipal uname = new UsernamePrincipal(username); - - if (_db instanceof Base64MD5PasswordFilePrincipalDatabase) - { - //retrieve the stored password for the given user - _db.setPassword(uname, pwCallback); - - //compare the MD5Hash of the given password with the stored value - if (Arrays.equals(getMD5Hash(password), pwCallback.getPassword())) - { - authenticated = true; - } - } - else if (_db instanceof PlainPasswordFilePrincipalDatabase) - { - //retrieve the users stored password and compare with given value - _db.setPassword(uname, pwCallback); - - if (password.equals(new String(pwCallback.getPassword()))) - { - authenticated = true; - } - } - else - { - throw new SecurityException(UNABLE_TO_LOOKUP); + if (_db.verifyPassword(username, password.toCharArray())) + { + authenticated = true; } } catch (AccountNotFoundException e) { throw new SecurityException(INVALID_CREDENTIALS); } - catch (UnsupportedEncodingException e) - { - throw new SecurityException(UNABLE_TO_LOOKUP); - } - catch (NoSuchAlgorithmException e) - { - throw new SecurityException(UNABLE_TO_LOOKUP); - } - catch (IOException e) - { - throw new SecurityException(UNABLE_TO_LOOKUP); - } if (authenticated) { @@ -155,28 +115,5 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator throw new SecurityException(INVALID_CREDENTIALS); } } - - public static char[] getMD5Hash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException - { - byte[] data = text.getBytes(DEFAULT_ENCODING); - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - char[] hash = new char[digest.length ]; - - int index = 0; - for (byte b : digest) - { - hash[index++] = (char) b; - } - - return hash; - } } \ No newline at end of file -- cgit v1.2.1 From fc3a2cc0e08cb7943793fcf6fa15295bf1c73a25 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Feb 2009 20:30:10 +0000 Subject: QPID-1655: use a File object to hold reference to access file instead of a String to fix issue with createTempFile and absolute paths. Stop catching IOExceptions in saveAccessFile() and make calling methods catch them to check for and report failure and act accordingly to reverse actions in memory. Add additional unit tests to cover access rights file manipulation. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@748686 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/management/AMQUserManagementMBean.java | 168 +++++++++++++-------- 1 file changed, 106 insertions(+), 62 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index e127e7a9d4..121f571abe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -64,9 +64,9 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); private PrincipalDatabase _principalDatabase; - private String _accessFileName; private Properties _accessRights; - // private File _accessFile; + private File _accessFile; + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); // Setup for the TabularType @@ -129,9 +129,10 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public boolean setRights(String username, boolean read, boolean write, boolean admin) { - if (_accessRights.get(username) == null) + Object oldRights = null; + if ((oldRights =_accessRights.get(username)) == null) { - // If the user doesn't exist in the user rights file check that they at least have an account. + // If the user doesn't exist in the access rights file check that they at least have an account. if (_principalDatabase.getUser(username) == null) { return false; @@ -140,7 +141,6 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana try { - _accessRightsUpdate.lock(); // Update the access rights @@ -166,8 +166,29 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRights.remove(username); } } + + //save the rights file + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - saveAccessFile(); + //the rights file was not successfully saved, restore user rights to previous value + _logger.warn("Reverting attempted rights update for user'" + username + "'"); + if (oldRights != null) + { + _accessRights.put(username, oldRights); + } + else + { + _accessRights.remove(username); + } + + return false; + } } finally { @@ -184,9 +205,23 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana { if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) { - _accessRights.put(username, ""); - - return setRights(username, read, write, admin); + if (!setRights(username, read, write, admin)) + { + //unable to set rights for user, remove account + try + { + _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); + } + catch (AccountNotFoundException e) + { + //ignore + } + return false; + } + else + { + return true; + } } return false; @@ -194,7 +229,6 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public boolean deleteUser(String username) { - try { if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) @@ -204,7 +238,16 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.lock(); _accessRights.remove(username); - saveAccessFile(); + + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); + return false; + } } finally { @@ -213,15 +256,15 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.unlock(); } } - return true; } } catch (AccountNotFoundException e) { _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + return false; } - return false; + return true; } public boolean reloadData() @@ -233,12 +276,12 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } catch (ConfigurationException e) { - _logger.info("Reload failed due to:" + e); + _logger.warn("Reload failed due to:" + e); return false; } catch (IOException e) { - _logger.info("Reload failed due to:" + e); + _logger.warn("Reload failed due to:" + e); return false; } // Reload successful @@ -320,10 +363,24 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana */ public void setAccessFile(String accessFile) throws IOException, ConfigurationException { - _accessFileName = accessFile; - - if (_accessFileName != null) + if (accessFile != null) { + _accessFile = new File(accessFile); + if (!_accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFile + "' does not exist"); + } + + if (!_accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFile + "'."); + } + + if (!_accessFile.canWrite()) + { + _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); + } + loadAccessFile(); } else @@ -334,39 +391,34 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana private void loadAccessFile() throws IOException, ConfigurationException { - try + if(_accessFile == null) { - _accessRightsUpdate.lock(); - - Properties accessRights = new Properties(); - - File accessFile = new File(_accessFileName); - - if (!accessFile.exists()) + _logger.error("No jmx access rights file has been specified."); + return; + } + + if(_accessFile.exists()) + { + try { - throw new ConfigurationException("'" + _accessFileName + "' does not exist"); - } + _accessRightsUpdate.lock(); - if (!accessFile.canRead()) - { - throw new ConfigurationException("Cannot read '" + _accessFileName + "'."); + Properties accessRights = new Properties(); + accessRights.load(new FileInputStream(_accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); } - - if (!accessFile.canWrite()) + finally { - _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved."); + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } } - - accessRights.load(new FileInputStream(accessFile)); - checkAccessRights(accessRights); - setAccessRights(accessRights); } - finally + else { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } + _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); } } @@ -385,33 +437,24 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } } - private void saveAccessFile() + private void saveAccessFile() throws IOException { try { _accessRightsUpdate.lock(); - try - { - // Create temporary file - File tmp = File.createTempFile(_accessFileName, ".tmp"); - // Rename current file - File rights = new File(_accessFileName); + // Create temporary file + File tmp = File.createTempFile(_accessFile.getName(), ".tmp"); - FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); - output.close(); + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); + output.close(); - // Rename new file to main file - tmp.renameTo(rights); + // Rename new file to main file + tmp.renameTo(_accessFile); - // delete tmp - tmp.delete(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e); - } + // delete tmp + tmp.delete(); } finally { @@ -420,6 +463,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.unlock(); } } + } private String getCurrentJMXUser() -- cgit v1.2.1 From 57467edca63f41be1ce777ccc11d1911a750c384 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 2 Mar 2009 01:57:40 +0000 Subject: QPID-1492: make the broker return the current queue depth and maximum queue depth in bytes rather than kilbytes, matching their respective setter methods. Augment the management console's navigation queue selection list to show the appropriate numbers git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749149 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/AMQQueueMBean.java | 13 ++++++------- .../java/org/apache/qpid/server/queue/ManagedQueue.java | 6 +++--- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 6c44d70847..36da1c4cb1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -221,11 +221,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _queue.setMaximumMessageCount(value); } + /** + * returns the maximum total size of messages(bytes) in the queue. + */ public Long getMaximumQueueDepth() { - long queueDepthInBytes = _queue.getMaximumQueueDepth(); - - return queueDepthInBytes >> 10; + return _queue.getMaximumQueueDepth(); } public void setMaximumQueueDepth(Long value) @@ -264,13 +265,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que } /** - * returns the size of messages(KB) in the queue. + * returns the total size of messages(bytes) in the queue. */ public Long getQueueDepth() throws JMException { - long queueBytesSize = _queue.getQueueDepth(); - - return queueBytesSize >> 10; + return _queue.getQueueDepth(); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 48fae57134..d2cf90b42d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -41,7 +41,7 @@ import org.apache.qpid.server.management.MBeanOperationParameter; public interface ManagedQueue { static final String TYPE = "Queue"; - static final int VERSION = 1; + static final int VERSION = 2; /** * Returns the Name of the ManagedQueue. @@ -72,7 +72,7 @@ public interface ManagedQueue * @return * @throws IOException */ - @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue") + @MBeanAttribute(name="QueueDepth", description="The total size(Bytes) of messages in the queue") Long getQueueDepth() throws IOException, JMException; /** @@ -181,7 +181,7 @@ public interface ManagedQueue * @param value * @throws IOException */ - @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth") + @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth") void setMaximumQueueDepth(Long value) throws IOException; //TODO change descriptions -- cgit v1.2.1 From bba0a2edd69dfc5282ae6908255b9428507648d7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 2 Mar 2009 11:55:22 +0000 Subject: QPID-1704: remove JMXMP ConnectorServer usage from the brokers JMX management capabilities git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749282 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 5 - .../management/JMXManagedObjectRegistry.java | 280 +++++++++------------ 2 files changed, 123 insertions(+), 162 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 0cb31c1b14..3ff44da281 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -304,11 +304,6 @@ public class ServerConfiguration implements SignalHandler return _config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); } - public boolean getManagementSecurityEnabled() - { - return _config.getBoolean("management.security-enabled", false); - } - public boolean getProtectIOEnabled() { return _config.getBoolean("broker.connector.protectio.enabled", false); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index aea2f9d872..f02e858250 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -107,8 +107,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - - boolean jmxmpSecurity = appRegistry.getConfiguration().getManagementSecurityEnabled(); int port = appRegistry.getConfiguration().getJMXManagementPort(); //retrieve the Principal Database assigned to JMX authentication duties @@ -119,184 +117,152 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry final JMXConnectorServer cs; HashMap env = new HashMap(); - if (jmxmpSecurity) + //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration + RMIClientSocketFactory csf; + RMIServerSocketFactory ssf; + + //check ssl enabled option in config, default to true if option is not set + boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); + + if (sslEnabled) { - // For SASL using JMXMP - JMXServiceURL jmxURL = new JMXServiceURL("jmxmp", null, port); + //set the SSL related system properties used by the SSL RMI socket factories to the values + //given in the configuration file, unless command line settings have already been specified + String keyStorePath; - String saslType = null; - if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + if(System.getProperty("javax.net.ssl.keyStore") != null) { - saslType = "SASL/CRAM-MD5"; - env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); - CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); - initialiser.initialise(db); - env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + keyStorePath = System.getProperty("javax.net.ssl.keyStore"); } - else if (db instanceof PlainPasswordFilePrincipalDatabase) + else { - saslType = "SASL/PLAIN"; - PlainInitialiser initialiser = new PlainInitialiser(); - initialiser.initialise(db); - env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); - env.put("jmx.remote.profiles", "SASL/PLAIN"); + keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); } - //workaround NPE generated from env map classloader issue when using Eclipse 3.4 to launch - env.put("jmx.remote.profile.provider.class.loader", this.getClass().getClassLoader()); - - _log.warn("Starting JMXMP based JMX ConnectorServer on port '" + port + "' with " + saslType); - _startupLog.warn("Starting JMXMP based JMX ConnectorServer on port '" + port + "' with " + saslType); - - cs = JMXConnectorServerFactory.newJMXConnectorServer(jmxURL, env, _mbeanServer); - } - else - { - //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration - RMIClientSocketFactory csf; - RMIServerSocketFactory ssf; - - //check ssl enabled option in config, default to true if option is not set - boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); - - if (sslEnabled) + //check the keystore path value is valid + if (keyStorePath == null) { - //set the SSL related system properties used by the SSL RMI socket factories to the values - //given in the configuration file, unless command line settings have already been specified - String keyStorePath; - - if(System.getProperty("javax.net.ssl.keyStore") != null) + throw new ConfigurationException("JMX management SSL keystore path not defined, " + + "unable to start SSL protected JMX ConnectorServer"); + } + else + { + //ensure the system property is set + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + + //check the file is usable + File ksf = new File(keyStorePath); + + if (!ksf.exists()) { - keyStorePath = System.getProperty("javax.net.ssl.keyStore"); + throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf); } - else{ - keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); + if (!ksf.canRead()) + { + throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " + + ksf + ". Check permissions."); } - //check the keystore path value is valid - if (keyStorePath == null) + _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + } + + //check the key store password is set + if (System.getProperty("javax.net.ssl.keyStorePassword") == null) + { + + if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) { - throw new ConfigurationException("JMX management SSL keystore path not defined, " + - "unable to start SSL protected JMX ConnectorServer"); + throw new ConfigurationException("JMX management SSL keystore password not defined, " + + "unable to start requested SSL protected JMX server"); } else { - //ensure the system property is set - System.setProperty("javax.net.ssl.keyStore", keyStorePath); - - //check the file is usable - File ksf = new File(keyStorePath); - - if (!ksf.exists()) - { - throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf); - } - if (!ksf.canRead()) - { - throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " - + ksf + ". Check permissions."); - } - - _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + System.setProperty("javax.net.ssl.keyStorePassword", + appRegistry.getConfiguration().getManagementKeyStorePassword()); } + } - //check the key store password is set - if (System.getProperty("javax.net.ssl.keyStorePassword") == null) - { - - if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) - { - throw new ConfigurationException("JMX management SSL keystore password not defined, " + - "unable to start requested SSL protected JMX server"); - } - else - { - System.setProperty("javax.net.ssl.keyStorePassword", - appRegistry.getConfiguration().getManagementKeyStorePassword()); - } - } + //create the SSL RMI socket factories + csf = new SslRMIClientSocketFactory(); + ssf = new SslRMIServerSocketFactory(); - //create the SSL RMI socket factories - csf = new SslRMIClientSocketFactory(); - ssf = new SslRMIServerSocketFactory(); + _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + } + else + { + //Do not specify any specific RMI socket factories, resulting in use of the defaults. + csf = null; + ssf = null; - _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - } - else - { - //Do not specify any specific RMI socket factories, resulting in use of the defaults. - csf = null; - ssf = null; - - _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - } - - //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server - RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); - rmipa.setPrincipalDatabase(db); - env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); - - /* - * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. - * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. - * As a result, only binds made using the object reference will succeed, thus securing it from external change. - */ - System.setProperty("java.rmi.server.randomIDs", "true"); - _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); - - /* - * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls - * to bind the ConnectorServer to the registry, which will now fail as for security we have - * locked it from any RMI based modifications, including our own. Instead, we will manually bind - * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. - * - * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer - * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. - */ - final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); - final String hostname = InetAddress.getLocalHost().getHostName(); - final JMXServiceURL externalUrl = new JMXServiceURL( - "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); - - final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); - cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + } + + //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server + RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); + rmipa.setPrincipalDatabase(db); + env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); + + /* + * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. + * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. + * As a result, only binds made using the object reference will succeed, thus securing it from external change. + */ + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); + + /* + * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls + * to bind the ConnectorServer to the registry, which will now fail as for security we have + * locked it from any RMI based modifications, including our own. Instead, we will manually bind + * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. + * + * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer + * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. + */ + final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); + final String hostname = InetAddress.getLocalHost().getHostName(); + final JMXServiceURL externalUrl = new JMXServiceURL( + "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); + + final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); + cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + { + @Override + public synchronized void start() throws IOException { - @Override - public synchronized void start() throws IOException + try { - try - { - //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent - _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); - } - catch (AlreadyBoundException abe) - { - //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means. - - //IOExceptions are the only checked type throwable by the method, wrap and rethrow - IOException ioe = new IOException(abe.getMessage()); - ioe.initCause(abe); - throw ioe; - } - - //now do the normal tasks - super.start(); - } - - @Override - public JMXServiceURL getAddress() - { - //must return our pre-crafted url that includes the full details, inc JNDI details - return externalUrl; - } + //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent + _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); + } + catch (AlreadyBoundException abe) + { + //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means. - }; - } + //IOExceptions are the only checked type throwable by the method, wrap and rethrow + IOException ioe = new IOException(abe.getMessage()); + ioe.initCause(abe); + throw ioe; + } + + //now do the normal tasks + super.start(); + } + + @Override + public JMXServiceURL getAddress() + { + //must return our pre-crafted url that includes the full details, inc JNDI details + return externalUrl; + } + + }; + //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); -- cgit v1.2.1 From 6457256413d8d7360bca260dafe1975962dd6cbc Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 2 Mar 2009 14:30:25 +0000 Subject: QPID-1583: Add test for reloading external firewall rules, fix buglets this test exposed. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749315 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 2 ++ .../qpid/server/registry/ApplicationRegistry.java | 3 +- .../qpid/server/registry/IApplicationRegistry.java | 3 +- .../qpid/server/security/access/ACLManager.java | 9 ++--- .../qpid/server/security/access/ACLPlugin.java | 3 +- .../server/security/access/ACLPluginFactory.java | 3 +- .../access/plugins/network/FirewallFactory.java | 3 +- .../access/plugins/network/FirewallPlugin.java | 39 ++++++++++++++++++---- 8 files changed, 50 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 1b7919e8b7..5d8fa3e9d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -35,6 +35,7 @@ import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.util.tracker.ServiceTracker; @@ -165,6 +166,7 @@ public class PluginManager _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); + _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); } return _securityPlugins; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 477beeadcb..22b4623ae1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -24,6 +24,7 @@ import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.mina.common.IoAcceptor; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -261,7 +262,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _virtualHostRegistry; } - public ACLManager getAccessManager() + public ACLManager getAccessManager() throws ConfigurationException { return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index a1f30c6eed..bbfda3addc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.net.InetSocketAddress; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -64,7 +65,7 @@ public interface IApplicationRegistry VirtualHostRegistry getVirtualHostRegistry(); - ACLManager getAccessManager(); + ACLManager getAccessManager() throws ConfigurationException; PluginManager getPluginManager(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index 57c6098874..6f7f66fad2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Map.Entry; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.SecurityConfiguration; @@ -49,12 +50,12 @@ public class ACLManager private Map _globalPlugins = new HashMap(); private Map _hostPlugins = new HashMap(); - public ACLManager(SecurityConfiguration configuration, PluginManager manager) + public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException { this(configuration, manager, null); } - public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) + public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException { _pluginManager = manager; @@ -73,12 +74,12 @@ public class ACLManager } - public void configureHostPlugins(SecurityConfiguration hostConfig) + public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException { _hostPlugins = configurePlugins(hostConfig); } - public Map configurePlugins(SecurityConfiguration hostConfig) + public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException { Configuration securityConfig = hostConfig.getConfiguration(); Map plugins = new HashMap(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java index ca760f3360..032184ec39 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -36,7 +37,7 @@ public interface ACLPlugin ABSTAIN } - void setConfiguration(Configuration config); + void setConfiguration(Configuration config) throws ConfigurationException; // These return true if the plugin thinks the action should be allowed, and false if not. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java index aee6af93d0..256f093477 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java @@ -21,12 +21,13 @@ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; public interface ACLPluginFactory { public boolean supportsTag(String name); - public ACLPlugin newInstance(Configuration config); + public ACLPlugin newInstance(Configuration config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java index 7fcf4a0494..a1a399e5bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.access.plugins.network; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; @@ -28,7 +29,7 @@ public class FirewallFactory implements ACLPluginFactory { @Override - public ACLPlugin newInstance(Configuration config) + public ACLPlugin newInstance(Configuration config) throws ConfigurationException { FirewallPlugin plugin = new FirewallPlugin(); plugin.setConfiguration(config); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index cb8b6f6fed..39397966f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -23,12 +23,18 @@ package org.apache.qpid.server.security.access.plugins.network; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; +import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.util.NetMatcher; @@ -36,6 +42,21 @@ import org.apache.qpid.util.NetMatcher; public class FirewallPlugin extends AbstractACLPlugin { + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return name.startsWith("firewall"); + } + + public ACLPlugin newInstance(Configuration config) throws ConfigurationException + { + FirewallPlugin plugin = new FirewallPlugin(); + plugin.setConfiguration(config); + return plugin; + } + }; + public class FirewallRule { @@ -149,7 +170,7 @@ public class FirewallPlugin extends AbstractACLPlugin } @Override - public void setConfiguration(Configuration config) + public void setConfiguration(Configuration config) throws ConfigurationException { // Get default action String defaultAction = config.getString("[@default-action]"); @@ -165,15 +186,21 @@ public class FirewallPlugin extends AbstractACLPlugin { _default = AuthzResult.DENIED; } + CompositeConfiguration finalConfig = new CompositeConfiguration(config); + + List subFiles = config.getList("firewall.xml[@fileName]"); + for (Object subFile : subFiles) + { + finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); + } - int numRules = config.getList("rule[@access]").size(); // all rules must - // have an access - // attribute + // all rules must have an access attribute + int numRules = finalConfig.getList("rule[@access]").size(); _rules = new FirewallRule[numRules]; for (int i = 0; i < numRules; i++) { - FirewallRule rule = new FirewallRule(config.getString("rule(" + i + ")[@access]"), config.getList("rule(" - + i + ")[@network]"), config.getList("rule(" + i + ")[@hostname]")); + FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), finalConfig.getList("rule(" + + i + ")[@network]"), finalConfig.getList("rule(" + i + ")[@hostname]")); _rules[i] = rule; } } -- cgit v1.2.1 From 36d2a03f183eecc1ccb7be9e89a56f4aec3dd945 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 2 Mar 2009 15:13:57 +0000 Subject: QPID-1637 : Added Purger thread for Priority Queues and when threasholds are adjusted. QueueEntries are now the point of entry to load/unload rather than the List. This is because it is only the QueueEntryList that the QueueEntry that is attached to that can correctly account for the inMemory usage. In the Priority Queue case the priority queue does not know which sub list the QueueEntry is on. As the QEI knows it makes sence to request load/unload through the entry. Set the default Maximum InMemory to -1, disabled. Removed the FlowableQueueEntryList interface, merged with QueueEntryList git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749331 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/QueueConfiguration.java | 2 +- .../server/queue/FlowableBaseQueueEntryList.java | 268 ++++++++++++++------ .../qpid/server/queue/FlowableQueueEntryList.java | 58 ----- .../qpid/server/queue/PriorityQueueEntryList.java | 269 +++++++++++++++++++-- .../org/apache/qpid/server/queue/QueueEntry.java | 2 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 39 ++- .../apache/qpid/server/queue/QueueEntryList.java | 70 ++++-- .../qpid/server/queue/QueueEntryListFactory.java | 2 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 7 +- .../qpid/server/queue/SimpleQueueEntryList.java | 5 +- 10 files changed, 532 insertions(+), 190 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 83fcfad1fd..30bf8aba5d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -114,7 +114,7 @@ public class QueueConfiguration public long getMemoryUsageMaximum() { - return _config.getLong("maximumMemoryUsage", 0); + return _config.getLong("maximumMemoryUsage", -1); } public long getMemoryUsageMinimum() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index a4f80a44b4..599f0a8ca4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -24,7 +24,6 @@ import org.apache.log4j.Logger; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -32,25 +31,29 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** This is an abstract base class to handle */ -public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryList +public abstract class FlowableBaseQueueEntryList implements QueueEntryList { - private static final Logger _log = Logger.getLogger(FlowableBaseQueueEntryList.class); + protected static final Logger _log = Logger.getLogger(FlowableBaseQueueEntryList.class); private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); private final AtomicLong _atomicQueueSize = new AtomicLong(0L); - private final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); + protected final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); /** The maximum amount of memory that is allocated to this queue. Beyond this the queue will flow to disk. */ - private long _memoryUsageMaximum = 0; + protected long _memoryUsageMaximum = -1L; /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ - private long _memoryUsageMinimum = 0; + protected long _memoryUsageMinimum = 0; private volatile AtomicBoolean _flowed; private QueueBackingStore _backingStore; protected AMQQueue _queue; private Executor _inhaler; + private Executor _purger; private AtomicBoolean _stopped; private AtomicReference _asynchronousInhaler = new AtomicReference(null); + protected boolean _disabled; + private AtomicReference _asynchronousPurger = new AtomicReference(null); + private static final int BATCH_INHALE_COUNT = 100; FlowableBaseQueueEntryList(AMQQueue queue) { @@ -64,6 +67,8 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi _stopped = new AtomicBoolean(false); _inhaler = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); + _purger = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); + _disabled = true; } public void setFlowed(boolean flowed) @@ -71,10 +76,26 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi if (_flowed.get() != flowed) { _log.warn("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); + showUsage(); _flowed.set(flowed); } } + protected void showUsage() + { + showUsage(""); + } + + protected void showUsage(String prefix) + { + if (_log.isDebugEnabled()) + { + _log.debug(prefix + " Queue(" + _queue + ":" + _queue.getName() + ") usage:" + memoryUsed() + + "/" + getMemoryUsageMinimum() + "<>" + getMemoryUsageMaximum() + + "/" + dataSize()); + } + } + public boolean isFlowed() { return _flowed.get(); @@ -99,13 +120,15 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi { _memoryUsageMaximum = maximumMemoryUsage; + if (maximumMemoryUsage >= 0) + { + _disabled = false; + } + // Don't attempt to start the inhaler/purger unless we have a minimum value specified. if (_memoryUsageMaximum > 0) { - if (_memoryUsageMinimum == 0) - { - setMemoryUsageMinimum(_memoryUsageMaximum / 2); - } + setMemoryUsageMinimum(_memoryUsageMaximum / 2); // if we have now have to much memory in use we need to purge. if (_memoryUsageMaximum < _atomicQueueInMemory.get()) @@ -113,6 +136,21 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi startPurger(); } } + else if (_memoryUsageMaximum == 0) + { + if (_atomicQueueInMemory.get() > 0) + { + startPurger(); + } + } + else + { + if (_log.isInfoEnabled()) + { + _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); + } + _disabled = true; + } } public long getMemoryUsageMaximum() @@ -134,7 +172,9 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi private void checkAndStartLoader() { // If we've increased the minimum memory above what we have in memory then we need to inhale more - if (_atomicQueueInMemory.get() <= _memoryUsageMinimum) + long inMemory = _atomicQueueInMemory.get(); + // Can't check if inMemory == 0 or we will cause the inhaler thread to continually run. + if (inMemory < _memoryUsageMinimum || _memoryUsageMinimum == 0) { startInhaler(); } @@ -142,22 +182,22 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi private void startInhaler() { - if (_flowed.get()) - { - MessageInhaler inhaler = new MessageInhaler(); + MessageInhaler inhaler = new MessageInhaler(); - if (_asynchronousInhaler.compareAndSet(null, inhaler)) - { - _inhaler.execute(inhaler); - } + if (_asynchronousInhaler.compareAndSet(null, inhaler)) + { + _inhaler.execute(inhaler); } } private void startPurger() { - //TODO create purger, used when maxMemory is reduced creating over memory situation. - _log.warn("Requested Purger Start.. purger TBC."); - //_purger.execute(new MessagePurger(this)); + MessagePurger purger = new MessagePurger(); + + if (_asynchronousPurger.compareAndSet(null, purger)) + { + _purger.execute(purger); + } } public long getMemoryUsageMinimum() @@ -165,26 +205,30 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi return _memoryUsageMinimum; } + /** + * Only to be called by the QueueEntry + * + * @param queueEntry the entry to unload + */ public void unloadEntry(QueueEntry queueEntry) { - try - { - queueEntry.unload(); - _atomicQueueInMemory.addAndGet(-queueEntry.getSize()); - checkAndStartLoader(); - } - catch (UnableToFlowMessageException e) + if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) { - _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); } + checkAndStartLoader(); } + /** + * Only to be called from the QueueEntry + * + * @param queueEntry the entry to load + */ public void loadEntry(QueueEntry queueEntry) { - queueEntry.load(); - if( _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + if (_atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) { - _log.error("Loaded to much data!:"+_atomicQueueInMemory.get()+"/"+_memoryUsageMaximum); + _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); } } @@ -196,44 +240,21 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi // rather than actively shutdown our threads. //Shutdown thread for inhaler. ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); } } - protected boolean willCauseFlowToDisk(QueueEntryImpl queueEntry) - { - return _memoryUsageMaximum != 0 && memoryUsed() + queueEntry.getSize() > _memoryUsageMaximum; - } - protected void incrementCounters(final QueueEntryImpl queueEntry) { _atomicQueueCount.incrementAndGet(); _atomicQueueSize.addAndGet(queueEntry.getSize()); - if (!willCauseFlowToDisk(queueEntry)) - { - _atomicQueueInMemory.addAndGet(queueEntry.getSize()); - } - else - { - setFlowed(true); - flowingToDisk(queueEntry); - } - } + long inUseMemory = _atomicQueueInMemory.addAndGet(queueEntry.getSize()); - /** - * Called when we are now flowing to disk - * - * @param queueEntry the entry that is being flowed to disk - */ - protected void flowingToDisk(QueueEntryImpl queueEntry) - { - try + if (!_disabled && inUseMemory > _memoryUsageMaximum) { + setFlowed(true); queueEntry.unload(); } - catch (UnableToFlowMessageException e) - { - _atomicQueueInMemory.addAndGet(queueEntry.getSize()); - } } protected void dequeued(QueueEntryImpl queueEntry) @@ -242,7 +263,10 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi _atomicQueueSize.addAndGet(-queueEntry.getSize()); if (!queueEntry.isFlowed()) { - _atomicQueueInMemory.addAndGet(-queueEntry.getSize()); + if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + { + _log.error("InMemory Count just went below 0 on dequeue."); + } } } @@ -270,32 +294,53 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi private void inhaleList(MessageInhaler messageInhaler) { - _log.info("Inhaler Running"); + if (_log.isInfoEnabled()) + { + _log.info("Inhaler Running:" + _queue.getName()); + showUsage("Inhaler Running:" + _queue.getName()); + } // If in memory count is at or over max then we can't inhale if (_atomicQueueInMemory.get() >= _memoryUsageMaximum) { - _log.debug("Unable to start inhaling as we are already over quota:" + - _atomicQueueInMemory.get() + ">=" + _memoryUsageMaximum); + if (_log.isDebugEnabled()) + { + _log.debug("Unable to start inhaling as we are already over quota:" + + _atomicQueueInMemory.get() + ">=" + _memoryUsageMaximum); + } return; } _asynchronousInhaler.compareAndSet(messageInhaler, null); - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && _asynchronousInhaler.compareAndSet(null, messageInhaler)) + int inhaled = 0; + + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && (inhaled < BATCH_INHALE_COUNT) + && _asynchronousInhaler.compareAndSet(null, messageInhaler)) { QueueEntryIterator iterator = iterator(); - while (!iterator.getNode().isAvailable() && iterator.advance()) + // If the inhaler is running and delivery rate picks up ensure that we just don't chase the delivery thread. + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) + && !iterator.getNode().isAvailable() && iterator.advance()) { //Find first AVAILABLE node } - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && !iterator.atTail()) + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && (inhaled < BATCH_INHALE_COUNT) && !iterator.atTail()) { QueueEntry entry = iterator.getNode(); if (entry.isAvailable() && entry.isFlowed()) { - loadEntry(entry); + if (_atomicQueueInMemory.get() + entry.getSize() > _memoryUsageMaximum) + { + // We don't have space for this message so we need to stop inhaling. + inhaled = BATCH_INHALE_COUNT; + } + else + { + loadEntry(entry); + inhaled++; + } } iterator.advance(); @@ -309,13 +354,100 @@ public abstract class FlowableBaseQueueEntryList implements FlowableQueueEntryLi _asynchronousInhaler.set(null); } + if (_log.isInfoEnabled()) + { + _log.info("Inhaler Stopping:" + _queue.getName()); + showUsage("Inhaler Stopping:" + _queue.getName()); + } + //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. if (_flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) { + if (_log.isInfoEnabled()) + { + _log.info("Rescheduling Inhaler:" + _queue.getName()); + } _inhaler.execute(messageInhaler); - } } + private class MessagePurger implements Runnable + { + public void run() + { + String threadName = Thread.currentThread().getName(); + Thread.currentThread().setName("Purger-" + _queue.getVirtualHost().getName() + "-" + _queue.getName()); + try + { + purgeList(this); + } + finally + { + Thread.currentThread().setName(threadName); + } + } + } + + private void purgeList(MessagePurger messagePurger) + { + // If in memory count is at or over max then we can't inhale + if (_atomicQueueInMemory.get() <= _memoryUsageMinimum) + { + if (_log.isDebugEnabled()) + { + _log.debug("Unable to start purging as we are already below our minimum cache level:" + + _atomicQueueInMemory.get() + "<=" + _memoryUsageMinimum); + } + return; + } + + _asynchronousPurger.compareAndSet(messagePurger, null); + + while ((_atomicQueueInMemory.get() >= _memoryUsageMinimum) && _asynchronousPurger.compareAndSet(null, messagePurger)) + { + QueueEntryIterator iterator = iterator(); + + while (!iterator.getNode().isAvailable() && iterator.advance()) + { + //Find first AVAILABLE node + } + + // Count up the memory usage + long memoryUsage = 0; + while ((memoryUsage < _memoryUsageMaximum) && !iterator.atTail()) + { + QueueEntry entry = iterator.getNode(); + + if (entry.isAvailable() && !entry.isFlowed()) + { + memoryUsage += entry.getSize(); + } + + iterator.advance(); + } + + //Purge remainging mesages on queue + while (!iterator.atTail()) + { + QueueEntry entry = iterator.getNode(); + + if (entry.isAvailable() && !entry.isFlowed()) + { + entry.unload(); + } + + iterator.advance(); + } + + _asynchronousInhaler.set(null); + } + + //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. + if (_flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) + { + _inhaler.execute(messagePurger); + + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java deleted file mode 100644 index b547a41047..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableQueueEntryList.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.concurrent.atomic.AtomicLong; - -public interface FlowableQueueEntryList extends QueueEntryList -{ - void setFlowed(boolean flowed); - - boolean isFlowed(); - - int size(); - - long dataSize(); - - long memoryUsed(); - - void setMemoryUsageMaximum(long maximumMemoryUsage); - - long getMemoryUsageMaximum(); - - void setMemoryUsageMinimum(long minimumMemoryUsage); - - long getMemoryUsageMinimum(); - - /** - * Immediately unload Entry - * @param queueEntry the entry to unload - */ - public void unloadEntry(QueueEntry queueEntry); - - /** - * Immediately load Entry - * @param queueEntry the entry to load - */ - public void loadEntry(QueueEntry queueEntry); - - void stop(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index 23307d8acf..61a3c45c49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -25,7 +25,7 @@ import org.apache.qpid.framing.CommonContentHeaderProperties; public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList { private final AMQQueue _queue; - private final FlowableQueueEntryList[] _priorityLists; + private final QueueEntryList[] _priorityLists; private final int _priorities; private final int _priorityOffset; @@ -33,13 +33,15 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement { super(queue); _queue = queue; - _priorityLists = new FlowableQueueEntryList[priorities]; + _priorityLists = new QueueEntryList[priorities]; _priorities = priorities; - _priorityOffset = 5-((priorities + 1)/2); - for(int i = 0; i < priorities; i++) + _priorityOffset = 5 - ((priorities + 1) / 2); + for (int i = 0; i < priorities; i++) { _priorityLists[i] = new SimpleQueueEntryList(queue); } + + showUsage("Created:" + _queue.getName()); } public int getPriorities() @@ -54,33 +56,149 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement public QueueEntry add(AMQMessage message) { - int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if(index >= _priorities) + int index = ((CommonContentHeaderProperties) ((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; + if (index >= _priorities) { - index = _priorities-1; + index = _priorities - 1; } - else if(index < 0) + else if (index < 0) { index = 0; } + + long requriedSize = message.getSize(); + // Check and see if list would flow on adding message + if (!_disabled && !isFlowed() && _priorityLists[index].memoryUsed() + requriedSize > _priorityLists[index].getMemoryUsageMaximum()) + { + if (_log.isDebugEnabled()) + { + _log.debug("Message(" + message.debugIdentity() + ") Add of size (" + + requriedSize + ") will cause flow. Searching for space"); + } + + long reclaimed = 0; + + //work down the priorities looking for memory + int scavangeIndex = _priorities - 1; + + //First: Don't take all the memory. So look for a queue that has more than 50% free + + long currentMax; + + while (scavangeIndex >= 0 && reclaimed <= requriedSize) + { + currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); + long used = _priorityLists[scavangeIndex].memoryUsed(); + + if (used < currentMax / 2) + { + long newMax = currentMax / 2; + + _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); + + reclaimed += currentMax - newMax; + if (_log.isDebugEnabled()) + { + _log.debug("Reclaiming(1) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); + } + break; + } + else + { + scavangeIndex--; + } + } + + //Second: Just take the memory we need + if (scavangeIndex == -1) + { + scavangeIndex = _priorities - 1; + while (scavangeIndex >= 0 && reclaimed <= requriedSize) + { + currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); + long used = _priorityLists[scavangeIndex].memoryUsed(); + + if (used < currentMax) + { + long newMax = currentMax - used; + + // if there are no messages at this priority just take it all + if (newMax == currentMax) + { + newMax = 0; + } + + _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); + + reclaimed += currentMax - newMax; + if (_log.isDebugEnabled()) + { + _log.debug("Reclaiming(2) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); + } + break; + } + else + { + scavangeIndex--; + } + } + } + + //Increment Maximum + if (reclaimed > 0) + { + if (_log.isDebugEnabled()) + { + _log.debug("Increasing queue(" + index + ") maximum by " + reclaimed + + " to " + (_priorityLists[index].getMemoryUsageMaximum() + reclaimed)); + } + _priorityLists[index].setMemoryUsageMaximum(_priorityLists[index].getMemoryUsageMaximum() + reclaimed); + } + else + { + _log.debug("No space found."); + } + + showUsage(); + } + return _priorityLists[index].add(message); } + @Override + protected void showUsage(String prefix) + { + if (_log.isDebugEnabled()) + { + _log.debug(prefix); + for (int index = 0; index < _priorities; index++) + { + QueueEntryList queueEntryList = _priorityLists[index]; + _log.debug("Queue (" + _queue + ":" + _queue.getName() + ")[" + index + "] usage:" + queueEntryList.memoryUsed() + + "/" + queueEntryList.getMemoryUsageMaximum() + + "/" + queueEntryList.dataSize()); + } + } + } + public QueueEntry next(QueueEntry node) { - QueueEntryImpl nodeImpl = (QueueEntryImpl)node; + QueueEntryImpl nodeImpl = (QueueEntryImpl) node; QueueEntry next = nodeImpl.getNext(); - if(next == null) + if (next == null) { QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); int index; - for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--); + for (index = _priorityLists.length - 1; _priorityLists[index] != nodeEntryList; index--) + { + ; + } - while(next == null && index != 0) + while (next == null && index != 0) { index--; - next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext(); + next = ((QueueEntryImpl) _priorityLists[index].getHead()).getNext(); } } @@ -89,24 +207,23 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement private final class PriorityQueueEntryListIterator implements QueueEntryIterator { - private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; + private final QueueEntryIterator[] _iterators = new QueueEntryIterator[_priorityLists.length]; private QueueEntry _lastNode; PriorityQueueEntryListIterator() { - for(int i = 0; i < _priorityLists.length; i++) + for (int i = 0; i < _priorityLists.length; i++) { _iterators[i] = _priorityLists[i].iterator(); } _lastNode = _iterators[_iterators.length - 1].getNode(); } - public boolean atTail() { - for(int i = 0; i < _iterators.length; i++) + for (int i = 0; i < _iterators.length; i++) { - if(!_iterators[i].atTail()) + if (!_iterators[i].atTail()) { return false; } @@ -121,9 +238,9 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement public boolean advance() { - for(int i = _iterators.length-1; i >= 0; i--) + for (int i = _iterators.length - 1; i >= 0; i--) { - if(_iterators[i].advance()) + if (_iterators[i].advance()) { _lastNode = _iterators[i].getNode(); return true; @@ -140,7 +257,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement public QueueEntry getHead() { - return _priorityLists[_priorities-1].getHead(); + return _priorityLists[_priorities - 1].getHead(); } static class Factory implements QueueEntryListFactory @@ -152,17 +269,31 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement _priorities = priorities; } - public FlowableQueueEntryList createQueueEntryList(AMQQueue queue) + public QueueEntryList createQueueEntryList(AMQQueue queue) { return new PriorityQueueEntryList(queue, _priorities); } } + @Override + public boolean isFlowed() + { + boolean flowed = false; + boolean full = true; + showUsage(); + for (QueueEntryList queueEntryList : _priorityLists) + { + full = full && queueEntryList.getMemoryUsageMaximum() == queueEntryList.memoryUsed(); + flowed = flowed || (queueEntryList.isFlowed()); + } + return flowed && full; + } + @Override public int size() { - int size=0; - for (FlowableQueueEntryList queueEntryList : _priorityLists) + int size = 0; + for (QueueEntryList queueEntryList : _priorityLists) { size += queueEntryList.size(); } @@ -170,10 +301,96 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement return size; } + @Override + public long dataSize() + { + int dataSize = 0; + for (QueueEntryList queueEntryList : _priorityLists) + { + dataSize += queueEntryList.dataSize(); + } + + return dataSize; + } + + @Override + public long memoryUsed() + { + int memoryUsed = 0; + for (QueueEntryList queueEntryList : _priorityLists) + { + memoryUsed += queueEntryList.memoryUsed(); + } + + return memoryUsed; + } + + @Override + public void setMemoryUsageMaximum(long maximumMemoryUsage) + { + _memoryUsageMaximum = maximumMemoryUsage; + + if (maximumMemoryUsage >= 0) + { + _disabled = false; + } + + long share = maximumMemoryUsage / _priorities; + + //Apply a share of the maximum To each prioirty quue + for (QueueEntryList queueEntryList : _priorityLists) + { + queueEntryList.setMemoryUsageMaximum(share); + } + + if (maximumMemoryUsage < 0) + { + if (_log.isInfoEnabled()) + { + _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); + } + _disabled = true; + return; + } + + //ensure we use the full allocation of memory + long remainder = maximumMemoryUsage - (share * _priorities); + if (remainder > 0) + { + _priorityLists[_priorities - 1].setMemoryUsageMaximum(share + remainder); + } + } + + @Override + public long getMemoryUsageMaximum() + { + return _memoryUsageMaximum; + } + + @Override + public void setMemoryUsageMinimum(long minimumMemoryUsage) + { + _memoryUsageMinimum = minimumMemoryUsage; + + //Apply a share of the minimum To each prioirty quue + for (QueueEntryList queueEntryList : _priorityLists) + { + queueEntryList.setMemoryUsageMaximum(minimumMemoryUsage / _priorities); + } + } @Override - protected void flowingToDisk(QueueEntryImpl queueEntry) + public long getMemoryUsageMinimum() { - //This class doesn't maintain it's own sizes it delegates to the sub FlowableQueueEntryLists + return _memoryUsageMinimum; + } + + @Override + public void stop() + { + for (QueueEntryList queueEntryList : _priorityLists) + { + queueEntryList.stop(); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 7e41cf53a2..2cb1493a8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -221,7 +221,7 @@ public interface QueueEntry extends Comparable, Filterable Date: Tue, 3 Mar 2009 09:48:47 +0000 Subject: QPID-430: Change configuration variable name in line with review remarks. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749572 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 6 ++++-- .../apache/qpid/server/configuration/VirtualHostConfiguration.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 3ff44da281..c0fe42c5c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -505,8 +505,10 @@ public class ServerConfiguration implements SignalHandler _config.setProperty("housekeeping.expiredMessageCheckPeriod", value); } - public long getHousekeepingExpiredMessageCheckPeriod() + public long getHousekeepingCheckPeriod() { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD); + return _config.getLong("housekeeping.checkPeriod", + _config.getLong("housekeeping.expiredMessageCheckPeriod", + DEFAULT_HOUSEKEEPING_PERIOD)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 650f6722f2..343abe4b5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -92,7 +92,7 @@ public class VirtualHostConfiguration public long getHousekeepingExpiredMessageCheckPeriod() { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", _serverConfiguration.getHousekeepingExpiredMessageCheckPeriod()); + return _config.getLong("housekeeping.expiredMessageCheckPeriod", _serverConfiguration.getHousekeepingCheckPeriod()); } public String getAuthenticationDatabase() -- cgit v1.2.1 From 1541ef71942d0b86cb180100548825a42113c711 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 3 Mar 2009 18:59:04 +0000 Subject: Prevent NullPointerException when backing store file is deleted externally git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749697 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/FileQueueBackingStore.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index 4e3b2298d1..bce06fad14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -245,14 +245,18 @@ public class FileQueueBackingStore implements QueueBackingStore } finally { - try + // In a FileNotFound situation writer will be null. + if (writer != null) { - writer.flush(); - writer.close(); - } - catch (IOException e) - { - error = e; + try + { + writer.flush(); + writer.close(); + } + catch (IOException e) + { + error = e; + } } } -- cgit v1.2.1 From 09217aadcac77f2211dd9c36279dd0417fe2b79f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 3 Mar 2009 19:00:02 +0000 Subject: QPID-1637 : Update to test to correctly use priority queues in test. Fixed big in inhaler/purger to ensure priority data is correctly reloaded. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@749699 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/queue/FlowableBaseQueueEntryList.java | 102 +++++++++++++-------- .../qpid/server/queue/PriorityQueueEntryList.java | 97 +++++++++++++++++--- .../apache/qpid/server/queue/QueueEntryImpl.java | 4 +- .../apache/qpid/server/queue/QueueEntryList.java | 4 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 4 + 5 files changed, 157 insertions(+), 54 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 599f0a8ca4..d25c096337 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -53,7 +53,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList private AtomicReference _asynchronousInhaler = new AtomicReference(null); protected boolean _disabled; private AtomicReference _asynchronousPurger = new AtomicReference(null); - private static final int BATCH_INHALE_COUNT = 100; + private static final int BATCH_PROCESS_COUNT = 100; FlowableBaseQueueEntryList(AMQQueue queue) { @@ -76,7 +76,6 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList if (_flowed.get() != flowed) { _log.warn("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); - showUsage(); _flowed.set(flowed); } } @@ -126,20 +125,14 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } // Don't attempt to start the inhaler/purger unless we have a minimum value specified. - if (_memoryUsageMaximum > 0) + if (_memoryUsageMaximum >= 0) { setMemoryUsageMinimum(_memoryUsageMaximum / 2); // if we have now have to much memory in use we need to purge. if (_memoryUsageMaximum < _atomicQueueInMemory.get()) { - startPurger(); - } - } - else if (_memoryUsageMaximum == 0) - { - if (_atomicQueueInMemory.get() > 0) - { + setFlowed(true); startPurger(); } } @@ -165,16 +158,15 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList // Don't attempt to start the inhaler unless we have a minimum value specified. if (_memoryUsageMinimum > 0) { - checkAndStartLoader(); + checkAndStartInhaler(); } } - private void checkAndStartLoader() + private void checkAndStartInhaler() { - // If we've increased the minimum memory above what we have in memory then we need to inhale more - long inMemory = _atomicQueueInMemory.get(); - // Can't check if inMemory == 0 or we will cause the inhaler thread to continually run. - if (inMemory < _memoryUsageMinimum || _memoryUsageMinimum == 0) + // If we've increased the minimum memory above what we have in memory then + // we need to inhale more if there is more + if (_atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) { startInhaler(); } @@ -210,13 +202,14 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList * * @param queueEntry the entry to unload */ - public void unloadEntry(QueueEntry queueEntry) + public void entryUnloadedUpdateMemory(QueueEntry queueEntry) { if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) { _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); } - checkAndStartLoader(); + + checkAndStartInhaler(); } /** @@ -224,11 +217,13 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList * * @param queueEntry the entry to load */ - public void loadEntry(QueueEntry queueEntry) + public void entryLoadedUpdateMemory(QueueEntry queueEntry) { if (_atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) { _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); + setFlowed(true); + startPurger(); } } @@ -311,11 +306,15 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } _asynchronousInhaler.compareAndSet(messageInhaler, null); - int inhaled = 0; + int inhaled = 1; - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && (inhaled < BATCH_INHALE_COUNT) - && _asynchronousInhaler.compareAndSet(null, messageInhaler)) + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) // we havn't filled our max memory + && (_atomicQueueInMemory.get() < _atomicQueueSize.get()) // we haven't loaded all that is available + && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do + && (inhaled > 0) // ensure we could inhale something + && _asynchronousInhaler.compareAndSet(null, messageInhaler)) // Ensure we are the running inhaler { + inhaled = 0; QueueEntryIterator iterator = iterator(); // If the inhaler is running and delivery rate picks up ensure that we just don't chase the delivery thread. @@ -325,7 +324,13 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList //Find first AVAILABLE node } - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) && (inhaled < BATCH_INHALE_COUNT) && !iterator.atTail()) + // Because the above loop checks then moves on to the next entry a check for atTail will return true but + // we won't have checked the last entry to see if we can load it. So create atEndofList and update it based + // on the return from advance() which returns true if it can advance. + boolean atEndofList = false; + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) // we havn't filled our max memory + && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do + && !atEndofList) // We have reached end of list QueueEntries { QueueEntry entry = iterator.getNode(); @@ -334,16 +339,20 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList if (_atomicQueueInMemory.get() + entry.getSize() > _memoryUsageMaximum) { // We don't have space for this message so we need to stop inhaling. - inhaled = BATCH_INHALE_COUNT; + if (_log.isDebugEnabled()) + { + _log.debug("Entry won't fit in memory stopping inhaler:" + entry.debugIdentity()); + } + inhaled = BATCH_PROCESS_COUNT; } else { - loadEntry(entry); + entry.load(); inhaled++; } } - iterator.advance(); + atEndofList = !iterator.advance(); } if (iterator.atTail()) @@ -402,20 +411,34 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList return; } + if (_log.isInfoEnabled()) + { + _log.info("Purger Running:" + _queue.getName()); + showUsage("Purger Running:" + _queue.getName()); + } + _asynchronousPurger.compareAndSet(messagePurger, null); + int purged = 0; - while ((_atomicQueueInMemory.get() >= _memoryUsageMinimum) && _asynchronousPurger.compareAndSet(null, messagePurger)) + while ((_atomicQueueInMemory.get() > _memoryUsageMinimum) + && purged < BATCH_PROCESS_COUNT + && _asynchronousPurger.compareAndSet(null, messagePurger)) { QueueEntryIterator iterator = iterator(); + //There are potentially AQUIRED messages that can be purged but we can't purge the last AQUIRED message + // as it may have just become AQUIRED and not yet delivered. + + //To be safe only purge available messages. This should be fine as long as we have a small prefetch. while (!iterator.getNode().isAvailable() && iterator.advance()) { //Find first AVAILABLE node } - // Count up the memory usage + // Count up the memory usage to find our minimum point long memoryUsage = 0; - while ((memoryUsage < _memoryUsageMaximum) && !iterator.atTail()) + boolean atTail = false; + while ((memoryUsage < _memoryUsageMaximum) && !atTail) { QueueEntry entry = iterator.getNode(); @@ -424,30 +447,37 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList memoryUsage += entry.getSize(); } - iterator.advance(); + atTail = !iterator.advance(); } //Purge remainging mesages on queue - while (!iterator.atTail()) + while (!atTail && (purged < BATCH_PROCESS_COUNT)) { QueueEntry entry = iterator.getNode(); if (entry.isAvailable() && !entry.isFlowed()) { entry.unload(); + purged++; } - iterator.advance(); + atTail = !iterator.advance(); } - _asynchronousInhaler.set(null); + _asynchronousPurger.set(null); } - //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. - if (_flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) + if (_log.isInfoEnabled()) { - _inhaler.execute(messagePurger); + _log.info("Purger Stopping:" + _queue.getName()); + showUsage("Purger Stopping:" + _queue.getName()); + } + //If we are still flowed and are over the minimum value then schedule to run again. + if (_flowed.get() && _atomicQueueInMemory.get() > _memoryUsageMinimum) + { + _log.info("Rescheduling Purger:" + _queue.getName()); + _purger.execute(messagePurger); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index 61a3c45c49..89f6e6378b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -79,13 +79,17 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement long reclaimed = 0; //work down the priorities looking for memory - int scavangeIndex = _priorities - 1; //First: Don't take all the memory. So look for a queue that has more than 50% free - long currentMax; + int scavangeIndex = 0; + + if (scavangeIndex == index) + { + scavangeIndex++; + } - while (scavangeIndex >= 0 && reclaimed <= requriedSize) + while (scavangeIndex < _priorities && reclaimed <= requriedSize) { currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); long used = _priorityLists[scavangeIndex].memoryUsed(); @@ -105,15 +109,24 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement } else { - scavangeIndex--; + scavangeIndex++; + if (scavangeIndex == index) + { + scavangeIndex++; + } } - } + } - //Second: Just take the memory we need - if (scavangeIndex == -1) + //Second: Just take the free memory we need + if (scavangeIndex == _priorities) { - scavangeIndex = _priorities - 1; - while (scavangeIndex >= 0 && reclaimed <= requriedSize) + scavangeIndex = 0; + if (scavangeIndex == index) + { + scavangeIndex++; + } + + while (scavangeIndex < _priorities && reclaimed <= requriedSize) { currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); long used = _priorityLists[scavangeIndex].memoryUsed(); @@ -139,7 +152,51 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement } else { - scavangeIndex--; + scavangeIndex++; + if (scavangeIndex == index) + { + scavangeIndex++; + } + } + } + + //Third: Take required memory + if (scavangeIndex == _priorities) + { + scavangeIndex = 0; + if (scavangeIndex == index) + { + scavangeIndex++; + } + while (scavangeIndex < _priorities && reclaimed <= requriedSize) + { + currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); + + if (currentMax > 0 ) + { + long newMax = currentMax; + // Just take the amount of space required for this message. + if (newMax > requriedSize) + { + newMax = requriedSize; + } + _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); + + reclaimed += currentMax - newMax; + if (_log.isDebugEnabled()) + { + _log.debug("Reclaiming(3) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); + } + break; + } + else + { + scavangeIndex++; + if (scavangeIndex == index) + { + scavangeIndex++; + } + } } } } @@ -159,7 +216,10 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement _log.debug("No space found."); } - showUsage(); + if (_log.isTraceEnabled()) + { + showUsage("Add"); + } } return _priorityLists[index].add(message); @@ -170,7 +230,10 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement { if (_log.isDebugEnabled()) { - _log.debug(prefix); + if (prefix.length() != 0) + { + _log.debug(prefix); + } for (int index = 0; index < _priorities; index++) { QueueEntryList queueEntryList = _priorityLists[index]; @@ -280,10 +343,16 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement { boolean flowed = false; boolean full = true; - showUsage(); + + if (_log.isTraceEnabled()) + { + showUsage("isFlowed"); + } + for (QueueEntryList queueEntryList : _priorityLists) { - full = full && queueEntryList.getMemoryUsageMaximum() == queueEntryList.memoryUsed(); + //full = full && queueEntryList.getMemoryUsageMaximum() == queueEntryList.memoryUsed(); + full = full && queueEntryList.getMemoryUsageMaximum() <= queueEntryList.dataSize(); flowed = flowed || (queueEntryList.isFlowed()); } return flowed && full; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 2a579b83c6..32abe3e1cf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -411,7 +411,7 @@ public class QueueEntryImpl implements QueueEntry //Update the memoryState if this load call resulted in the message being purged from memory if (!_flowed.getAndSet(true)) { - _queueEntryList.unloadEntry(this); + _queueEntryList.entryUnloadedUpdateMemory(this); } } catch (UnableToFlowMessageException utfme) { @@ -438,7 +438,7 @@ public class QueueEntryImpl implements QueueEntry //Update the memoryState if this load call resulted in the message comming in to memory if (_flowed.getAndSet(false)) { - _queueEntryList.loadEntry(this); + _queueEntryList.entryLoadedUpdateMemory(this); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index 706f10dca1..a58c6eaf7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -54,13 +54,13 @@ public interface QueueEntryList * Immediately update memory usage based on the unload of this queueEntry, potentially start inhaler. * @param queueEntry the entry that has been unloaded */ - void unloadEntry(QueueEntry queueEntry); + void entryUnloadedUpdateMemory(QueueEntry queueEntry); /** * Immediately update memory usage based on the load of this queueEntry * @param queueEntry the entry that has been loaded */ - void loadEntry(QueueEntry queueEntry); + void entryLoadedUpdateMemory(QueueEntry queueEntry); void stop(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 9f1472439c..5730e419d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -468,6 +468,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (entry.isFlowed()) { + if(_logger.isDebugEnabled()) + { + _logger.debug("Synchoronus load of entry:" + entry.debugIdentity()); + } entry.load(); } -- cgit v1.2.1 From c2b1a4b4bd28439686585b1e510a70afc15b38da Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Mar 2009 12:25:04 +0000 Subject: QPID-1639 : Added test to ensure that properties passed on QueueDeclare are applied to queue. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750867 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/AMQQueueFactory.java | 64 ++++++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index f977dc0449..a2b514af68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -23,13 +23,17 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; - public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + public static final AMQShortString QPID_MAX_COUNT = new AMQShortString("qpid.max_count"); + public static final AMQShortString QPID_MAX_SIZE = new AMQShortString("qpid.max_size"); + public static final AMQShortString QPID_POLICY_TYPE = new AMQShortString("qpid.policy_type"); + public static final String QPID_FLOW_TO_DISK = "flow_to_disk"; public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, @@ -39,10 +43,26 @@ public class AMQQueueFactory throws AMQException { - final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + int priorities = 1; + + if (arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) + { + Integer priority = arguments.getInteger(X_QPID_PRIORITIES); + + if (priority != null) + { + priorities = priority.intValue(); + } + else + { + throw new AMQException(AMQConstant.INVALID_ARGUMENT, + "Queue create request with non integer value for :" + X_QPID_PRIORITIES + "=" + arguments.get(X_QPID_PRIORITIES), null); + } + + } AMQQueue q = null; - if(priorities > 1) + if (priorities > 1) { q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); } @@ -51,6 +71,40 @@ public class AMQQueueFactory q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); } + final String queuePolicyType = arguments == null ? null : + arguments.containsKey(QPID_POLICY_TYPE) ? arguments.getString(QPID_POLICY_TYPE) : null; + + if (queuePolicyType != null) + { + if (queuePolicyType.equals(QPID_FLOW_TO_DISK)) + { + if (arguments.containsKey(QPID_MAX_SIZE)) + { + + final long queueSize = arguments.getInteger(QPID_MAX_SIZE); + + if (queueSize < 0) + { + throw new AMQException(AMQConstant.INVALID_ARGUMENT, + "Queue create request with negative size:" + queueSize, null); + } + + q.setMaximumMessageSize(queueSize); + } + else + { + throw new AMQException(AMQConstant.INVALID_ARGUMENT, + "Queue create request with no qpid.max_size value,", null); + } + } + else + { + throw new AMQException(AMQConstant.NOT_IMPLEMENTED, + "Queue create request with unknown Policy Type:" + queuePolicyType, null); + } + + } + //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); return q; @@ -66,9 +120,9 @@ public class AMQQueueFactory FieldTable arguments = null; boolean priority = config.getPriority(); int priorities = config.getPriorities(); - if(priority || priorities > 0) + if (priority || priorities > 0) { - if(arguments == null) + if (arguments == null) { arguments = new FieldTable(); } -- cgit v1.2.1 From fff143ba920066a1f127c4e69ed5f3c145f73443 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Mar 2009 12:27:49 +0000 Subject: Style Changes git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750871 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/QueueEntryImpl.java | 119 ++++++++++----------- 1 file changed, 55 insertions(+), 64 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 32abe3e1cf..c510ec3374 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -20,26 +20,23 @@ */ package org.apache.qpid.server.queue; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; -import org.apache.log4j.Logger; -import java.util.Set; import java.util.HashSet; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; - +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class QueueEntryImpl implements QueueEntry { - /** - * Used for debugging purposes. - */ + /** Used for debugging purposes. */ private static final Logger _log = Logger.getLogger(QueueEntryImpl.class); private final SimpleQueueEntryList _queueEntryList; @@ -53,27 +50,24 @@ public class QueueEntryImpl implements QueueEntry private volatile EntryState _state = AVAILABLE_STATE; private static final - AtomicReferenceFieldUpdater + AtomicReferenceFieldUpdater _stateUpdater = - AtomicReferenceFieldUpdater.newUpdater - (QueueEntryImpl.class, EntryState.class, "_state"); - + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, EntryState.class, "_state"); private volatile Set _stateChangeListeners; private static final - AtomicReferenceFieldUpdater - _listenersUpdater = - AtomicReferenceFieldUpdater.newUpdater - (QueueEntryImpl.class, Set.class, "_stateChangeListeners"); - + AtomicReferenceFieldUpdater + _listenersUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, Set.class, "_stateChangeListeners"); private static final - AtomicLongFieldUpdater + AtomicLongFieldUpdater _entryIdUpdater = - AtomicLongFieldUpdater.newUpdater - (QueueEntryImpl.class, "_entryId"); - + AtomicLongFieldUpdater.newUpdater + (QueueEntryImpl.class, "_entryId"); private volatile long _entryId; @@ -90,17 +84,15 @@ public class QueueEntryImpl implements QueueEntry private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - QueueEntryImpl(SimpleQueueEntryList queueEntryList) { - this(queueEntryList,null,Long.MIN_VALUE); + this(queueEntryList, null, Long.MIN_VALUE); _state = DELETED_STATE; } - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) { - this(queueEntryList,message); + this(queueEntryList, message); _entryIdUpdater.set(this, entryId); } @@ -113,8 +105,8 @@ public class QueueEntryImpl implements QueueEntry { _messageId = message.getMessageId(); _messageSize = message.getSize(); - - if(message.isImmediate()) + + if (message.isImmediate()) { _flags |= IMMEDIATE; } @@ -193,8 +185,8 @@ public class QueueEntryImpl implements QueueEntry private boolean acquire(final EntryState state) { - boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state); - if(acquired && _stateChangeListeners != null) + boolean acquired = _stateUpdater.compareAndSet(this, AVAILABLE_STATE, state); + if (acquired && _stateChangeListeners != null) { notifyStateChange(State.AVAILABLE, State.ACQUIRED); } @@ -220,24 +212,23 @@ public class QueueEntryImpl implements QueueEntry public void release() { - _stateUpdater.set(this,AVAILABLE_STATE); + _stateUpdater.set(this, AVAILABLE_STATE); } public String debugIdentity() { - String entry="[State:"+_state.getState().name()+"]"; + String entry = "[State:" + _state.getState().name() + "]"; if (_message == null) { - return entry+"(Message Unloaded ID:" + _messageId +")"; + return entry + "(Message Unloaded ID:" + _messageId + ")"; } else { - return entry+_message.debugIdentity(); + return entry + _message.debugIdentity(); } } - - public boolean immediateAndNotDelivered() + public boolean immediateAndNotDelivered() { return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; } @@ -266,15 +257,15 @@ public class QueueEntryImpl implements QueueEntry public Subscription getDeliveredSubscription() { - EntryState state = _state; - if (state instanceof SubscriptionAcquiredState) - { - return ((SubscriptionAcquiredState) state).getSubscription(); - } - else - { - return null; - } + EntryState state = _state; + if (state instanceof SubscriptionAcquiredState) + { + return ((SubscriptionAcquiredState) state).getSubscription(); + } + else + { + return null; + } } @@ -301,7 +292,7 @@ public class QueueEntryImpl implements QueueEntry } public boolean isRejectedBy(Subscription subscription) - { + { if (_rejectedBy != null) // We have subscriptions that rejected this message { @@ -313,11 +304,10 @@ public class QueueEntryImpl implements QueueEntry } } - public void requeue(final StoreContext storeContext) throws AMQException { getQueue().requeue(storeContext, this); - if(_stateChangeListeners != null) + if (_stateChangeListeners != null) { notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); } @@ -327,7 +317,7 @@ public class QueueEntryImpl implements QueueEntry { EntryState state = _state; - if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) + if ((state.getState() == State.ACQUIRED) && _stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) { if (state instanceof SubscriptionAcquiredState) { @@ -348,7 +338,7 @@ public class QueueEntryImpl implements QueueEntry private void notifyStateChange(final State oldState, final State newState) { - for(StateChangeListener l : _stateChangeListeners) + for (StateChangeListener l : _stateChangeListeners) { l.stateChanged(this, oldState, newState); } @@ -373,7 +363,7 @@ public class QueueEntryImpl implements QueueEntry public void addStateChangeListener(StateChangeListener listener) { Set listeners = _stateChangeListeners; - if(listeners == null) + if (listeners == null) { _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet()); listeners = _stateChangeListeners; @@ -385,7 +375,7 @@ public class QueueEntryImpl implements QueueEntry public boolean removeStateChangeListener(StateChangeListener listener) { Set listeners = _stateChangeListeners; - if(listeners != null) + if (listeners != null) { return listeners.remove(listener); } @@ -402,21 +392,23 @@ public class QueueEntryImpl implements QueueEntry { _backingStore.unload(_message); - if(_log.isDebugEnabled()) + if (_log.isDebugEnabled()) { _log.debug("Unloaded:" + debugIdentity()); } - _message = null; - //Update the memoryState if this load call resulted in the message being purged from memory + + //Update the memoryState if this load call resulted in the message being purged from memory if (!_flowed.getAndSet(true)) { _queueEntryList.entryUnloadedUpdateMemory(this); } - } catch (UnableToFlowMessageException utfme) { + } + catch (UnableToFlowMessageException utfme) + { // There is no recovery needed as the memory states remain unchanged. - if(_log.isDebugEnabled()) + if (_log.isDebugEnabled()) { _log.debug("Unable to Flow message:" + debugIdentity() + ", due to:" + utfme.getMessage()); } @@ -430,7 +422,7 @@ public class QueueEntryImpl implements QueueEntry { _message = _backingStore.load(_messageId); - if(_log.isDebugEnabled()) + if (_log.isDebugEnabled()) { _log.debug("Loaded:" + debugIdentity()); } @@ -448,10 +440,9 @@ public class QueueEntryImpl implements QueueEntry return _flowed.get(); } - public int compareTo(final QueueEntry o) { - QueueEntryImpl other = (QueueEntryImpl)o; + QueueEntryImpl other = (QueueEntryImpl) o; return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0; } @@ -459,13 +450,13 @@ public class QueueEntryImpl implements QueueEntry { QueueEntryImpl next = nextNode(); - while(next != null && next.isDeleted()) + while (next != null && next.isDeleted()) { final QueueEntryImpl newNext = next.nextNode(); - if(newNext != null) + if (newNext != null) { - SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext); + SimpleQueueEntryList._nextUpdater.compareAndSet(this, next, newNext); next = nextNode(); } else @@ -491,7 +482,7 @@ public class QueueEntryImpl implements QueueEntry { EntryState state = _state; - if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) + if (state != DELETED_STATE && _stateUpdater.compareAndSet(this, state, DELETED_STATE)) { _queueEntryList.advanceHead(); if (_backingStore != null) -- cgit v1.2.1 From 5728d63f9bbfbc7919dbed0b79d6781a083d7f67 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Mar 2009 12:28:33 +0000 Subject: QPID-1628 : Ensured all getSize() calls are done on the QueueEntry to prevent the inadvertent loading of a flowed message with a call to getMessage() git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750873 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java | 6 +++--- .../org/apache/qpid/server/flow/BytesOnlyCreditManager.java | 6 +++--- .../java/org/apache/qpid/server/flow/FlowCreditManager.java | 3 ++- .../org/apache/qpid/server/flow/LimitlessCreditManager.java | 4 ++-- .../qpid/server/flow/MessageAndBytesCreditManager.java | 6 +++--- .../apache/qpid/server/flow/MessageOnlyCreditManager.java | 4 ++-- .../org/apache/qpid/server/flow/Pre0_10CreditManager.java | 12 ++++++------ .../apache/qpid/server/handler/BasicGetMethodHandler.java | 6 +++--- .../apache/qpid/server/subscription/SubscriptionImpl.java | 4 ++-- 9 files changed, 26 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index ac3b0b5e49..5c38185696 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -89,7 +89,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap QueueEntry message = _map.remove(deliveryTag); if(message != null) { - _unackedSize -= message.getMessage().getSize(); + _unackedSize -= message.getSize(); } @@ -115,7 +115,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap synchronized (_lock) { _map.put(deliveryTag, message); - _unackedSize += message.getMessage().getSize(); + _unackedSize += message.getSize(); _lastDeliveryTag = deliveryTag; } } @@ -181,7 +181,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap it.remove(); - _unackedSize -= unacked.getValue().getMessage().getSize(); + _unackedSize -= unacked.getValue().getSize(); if (unacked.getKey() == deliveryTag) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java index 0743e4bb8d..0bb428cd8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import java.util.concurrent.atomic.AtomicLong; @@ -49,9 +49,9 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager return _bytesCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(QueueEntry queueEntry) { - final long msgSize = msg.getSize(); + final long msgSize = queueEntry.getSize(); if(hasCredit()) { if(_bytesCredit.addAndGet(-msgSize) >= 0) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java index a249a6e63a..297e5a4826 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java @@ -1,6 +1,7 @@ package org.apache.qpid.server.flow; import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; /* * @@ -40,5 +41,5 @@ public interface FlowCreditManager public boolean hasCredit(); - public boolean useCreditForMessage(AMQMessage msg); + public boolean useCreditForMessage(QueueEntry queueEntry); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java index d63431c3eb..437b7b0469 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; /* * @@ -37,7 +37,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements return true; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(QueueEntry queueEntry) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java index 5f0acec03f..15ecb5f292 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; /* * @@ -52,7 +52,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl return (_messageCredit > 0L) && ( _bytesCredit > 0L ); } - public synchronized boolean useCreditForMessage(AMQMessage msg) + public synchronized boolean useCreditForMessage(QueueEntry queueEntry) { if(_messageCredit == 0L) { @@ -61,7 +61,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl } else { - final long msgSize = msg.getSize(); + final long msgSize = queueEntry.getSize(); if(msgSize > _bytesCredit) { setSuspended(true); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java index c1b3a09006..3e28d779b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import java.util.concurrent.atomic.AtomicLong; @@ -50,7 +50,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen return _messageCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(QueueEntry queueEntry) { if(hasCredit()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java index be0300f2c1..5cdd3a0328 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager { @@ -123,7 +123,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F && (_messageCreditLimit == 0L || _messageCredit > 0); } - public synchronized boolean useCreditForMessage(final AMQMessage msg) + public synchronized boolean useCreditForMessage(final QueueEntry queueEntry) { if(_messageCreditLimit != 0L) { @@ -137,10 +137,10 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F } else { - if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + if((_bytesCredit >= queueEntry.getSize()) || (_bytesCredit == _bytesCreditLimit)) { _messageCredit--; - _bytesCredit -= msg.getSize(); + _bytesCredit -= queueEntry.getSize(); return true; } @@ -166,9 +166,9 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F } else { - if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + if((_bytesCredit >= queueEntry.getSize()) || (_bytesCredit == _bytesCreditLimit)) { - _bytesCredit -= msg.getSize(); + _bytesCredit -= queueEntry.getSize(); return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 0f492a21bb..a626114792 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -129,7 +129,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener Date: Fri, 6 Mar 2009 12:29:27 +0000 Subject: QPID-1635 : Feed back from review, ensure that getMessage() never returns null. Used setDeliveredToConsumers() on QEI to know when it is safe to unload message so SAMQQueue does not need to have anything to do with message un/loading. So the FtD work is fully encapuslated by the QEI which delegates memory accounting to its list. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750874 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/QueueEntryImpl.java | 10 ++++++++++ .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 15 --------------- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index c510ec3374..5114529419 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -133,6 +133,10 @@ public class QueueEntryImpl implements QueueEntry public AMQMessage getMessage() { + if (_message == null) + { + return _backingStore.load(_messageId); + } return _message; } @@ -149,6 +153,12 @@ public class QueueEntryImpl implements QueueEntry public void setDeliveredToConsumer() { _flags |= DELIVERED_TO_CONSUMER; + + // We have delivered this message so we can unload it if we are flowed. + if (_queueEntryList.isFlowed()) + { + unload(); + } } public boolean expired() throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 5730e419d5..9e9895c53b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -466,23 +466,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _deliveredMessages.incrementAndGet(); - if (entry.isFlowed()) - { - if(_logger.isDebugEnabled()) - { - _logger.debug("Synchoronus load of entry:" + entry.debugIdentity()); - } - entry.load(); - } - sub.send(entry); - // We have delivered this message so we can unload it. - if (_entries.isFlowed() && entry.isAcquired() && entry.getDeliveredToConsumer()) - { - entry.unload(); - } - } private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) -- cgit v1.2.1 From ba042a2ceb03fb1edb2dab8273070c07af63bacd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Mar 2009 12:30:20 +0000 Subject: QPID-949, QPID-1633 : Set default Maximum Memory Usage for a queue to 100Meg. Future work would be to have the broker split Xmx between VirtualHost and for the Vhost then to use its housekeeping thread to spread the memory between the current queues. It could of course be clever and give more memory to queues in high use. Mistype in AMQQueueFactory resulted in it setting the Max Queue Size alert rather than the Max Memory value git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750875 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/QueueConfiguration.java | 2 +- .../src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 30bf8aba5d..e6c5dee90d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -114,7 +114,7 @@ public class QueueConfiguration public long getMemoryUsageMaximum() { - return _config.getLong("maximumMemoryUsage", -1); + return _config.getLong("maximumMemoryUsage", 100 * 1024 * 1024); //100Meg } public long getMemoryUsageMinimum() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index a2b514af68..6ba22321f1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -89,7 +89,7 @@ public class AMQQueueFactory "Queue create request with negative size:" + queueSize, null); } - q.setMaximumMessageSize(queueSize); + q.setMemoryUsageMaximum(queueSize); } else { -- cgit v1.2.1 From 2c5b19111b7ab9bca45f4f5797a6834d3b7d136d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 6 Mar 2009 12:30:58 +0000 Subject: QPID-1634 : FileQueueBackingStore had two issues. Delete wasn't using the getFileHandle() method so it was attempting to delete a bin rather than the message data. Our Broker Unit tests don't create the right type of ByteBuffer so whilst they passed the buffer.getData().array() failed as array() is not supported in the ByteBuffer types we actually use at runtime. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@750876 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/FileQueueBackingStore.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index bce06fad14..7c83788883 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -226,13 +226,16 @@ public class FileQueueBackingStore implements QueueBackingStore for (int index = 0; index < bodyCount; index++) { ContentChunk chunk = message.getContentChunk(index); - chunk.reduceToFit(); + int length = chunk.getSize(); - byte[] chunkData = chunk.getData().array(); + byte[] chunk_underlying = new byte[length]; + + ByteBuffer chunk_buf = chunk.getData(); + + chunk_buf.duplicate().rewind().get(chunk_underlying); - int length = chunk.getSize(); writer.writeInt(length); - writer.write(chunkData, 0, length); + writer.write(chunk_underlying, 0, length); } } catch (FileNotFoundException e) @@ -301,9 +304,8 @@ public class FileQueueBackingStore implements QueueBackingStore } public void delete(Long messageId) - { - String id = String.valueOf(messageId); - File handle = new File(_flowToDiskLocation, id); + { + File handle = getFileHandle(messageId); if (handle.exists()) { -- cgit v1.2.1 From bf6b5856c7abb109f958bd07000cdc0ebd133656 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 9 Mar 2009 15:53:50 +0000 Subject: Added test to ensure ThreadPool is references are correctly removed for Priority queues. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@751714 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index 89f6e6378b..5dd76a5299 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -457,6 +457,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement @Override public void stop() { + super.stop(); for (QueueEntryList queueEntryList : _priorityLists) { queueEntryList.stop(); -- cgit v1.2.1 From 038d1727cc37edfc9f22ebb71e28f35122366c57 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 9 Mar 2009 15:57:33 +0000 Subject: QPID-949 : Removed all getMessage() calls as this will cause a flowed message to be read in to memory from disk. In all instances the reason was to perform methods that exist on the the QueueEntry. Added accessor to MessageID on QueueEntry. Outstanding getMessage() calls have been left in to perform NO_LOCAL work. Moving Publisher and PublisherClient identifer to the QEI would remove this need. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@751718 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 4 +-- .../java/org/apache/qpid/server/ack/TxAck.java | 2 +- .../server/handler/BasicRejectMethodHandler.java | 2 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 5 +-- .../qpid/server/queue/NotificationCheck.java | 16 +++++----- .../org/apache/qpid/server/queue/QueueEntry.java | 2 ++ .../apache/qpid/server/queue/QueueEntryImpl.java | 11 +++++-- .../apache/qpid/server/queue/SimpleAMQQueue.java | 36 ++++++++++------------ .../qpid/server/subscription/SubscriptionImpl.java | 2 ++ .../qpid/server/txn/NonTransactionalContext.java | 8 ++--- .../qpid/tools/messagestore/commands/Move.java | 2 +- 11 files changed, 49 insertions(+), 41 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 9b29c7b921..72a2780c32 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -431,7 +431,7 @@ public class AMQChannel { if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + _log.debug(debugIdentity() + " Adding unacked message(" + entry.toString() + " DT:" + deliveryTag + ") with a queue(" + entry.getQueue() + ") for " + subscription); } } @@ -551,7 +551,7 @@ public class AMQChannel } else { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.debugIdentity() + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); unacked.dequeueAndDelete(_storeContext); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java index 918fcd8407..95de0dc8c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -102,7 +102,7 @@ public class TxAck implements TxnOp //buffer must be marked as persistent: for (QueueEntry msg : _unacked.values()) { - if (msg.getMessage().isPersistent()) + if (msg.isPersistent()) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index bd70cd7776..8b04315d33 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -96,7 +96,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener notificationChecks = _queue.getNotificationChecks(); @@ -289,7 +290,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) { - if (check.notifyIfNecessary(msg, _queue, this)) + if (check.notifyIfNecessary(queueEntry, _queue, this)) { _lastNotificationTimes[check.ordinal()] = currentTime; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index e33b0c83c7..a83d661de2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -20,14 +20,12 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.AMQException; - public enum NotificationCheck { MESSAGE_COUNT_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) { int msgCount; final long maximumMessageCount = queue.getMaximumMessageCount(); @@ -41,19 +39,19 @@ public enum NotificationCheck }, MESSAGE_SIZE_ALERT(true) { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) { final long maximumMessageSize = queue.getMaximumMessageSize(); if(maximumMessageSize != 0) { // Check for threshold message size - long messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + long messageSize = (queueEntry == null) ? 0 : queueEntry.getSize(); if (messageSize >= maximumMessageSize) { listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold (" + maximumMessageSize + ") breached. [Message ID=" + - (msg == null ? "null" : msg.getMessageId()) + "]"); + (queueEntry == null ? "null" : queueEntry.getMessageId()) + "]"); return true; } } @@ -63,7 +61,7 @@ public enum NotificationCheck }, QUEUE_DEPTH_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) { // Check for threshold queue depth in bytes final long maximumQueueDepth = queue.getMaximumQueueDepth(); @@ -84,7 +82,7 @@ public enum NotificationCheck }, MESSAGE_AGE_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) { final long maxMessageAge = queue.getMaximumMessageAge(); @@ -126,6 +124,6 @@ public enum NotificationCheck return _messageSpecific; } - abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + abstract boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 2cb1493a8f..7fc5df4e9e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -135,6 +135,8 @@ public interface QueueEntry extends Comparable, Filterable= fromMessageId && messageId <= toMessageId; } @@ -780,7 +779,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - _complete = entry.getMessage().getMessageId() == messageId; + _complete = entry.getMessageId() == messageId; return _complete; } @@ -829,7 +828,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessageId(); return (messageId >= fromMessageId) && (messageId <= toMessageId) && entry.acquire(); @@ -848,11 +847,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Move the messages in the transaction log. for (QueueEntry entry : entries) { - AMQMessage message = entry.getMessage(); - - if (message.isPersistent() && toQueue.isDurable()) + if (entry.isPersistent() && toQueue.isDurable()) { - transactionLog.enqueueMessage(storeContext, toQueue, message.getMessageId()); + transactionLog.enqueueMessage(storeContext, toQueue, entry.getMessageId()); } // dequeue will remove the messages from the queue entry.dequeue(storeContext); @@ -887,6 +884,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for (QueueEntry entry : entries) { toQueue.enqueue(storeContext, entry.getMessage()); + // As we only did a dequeue above now that we have moved the message we should perform a delete. + // We cannot do this earlier as the message will be lost if flowed. + //entry.delete(); } } catch (MessageCleanupException e) @@ -913,7 +913,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessageId(); if ((messageId >= fromMessageId) && (messageId <= toMessageId)) { @@ -939,11 +939,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Move the messages in on the transaction log. for (QueueEntry entry : entries) { - AMQMessage message = entry.getMessage(); - - if (!entry.isDeleted() && message.isPersistent() && toQueue.isDurable()) + if (!entry.isDeleted() && entry.isPersistent() && toQueue.isDurable()) { - transactionLog.enqueueMessage(storeContext, toQueue, message.getMessageId()); + transactionLog.enqueueMessage(storeContext, toQueue, entry.getMessageId()); } } @@ -1002,7 +1000,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { QueueEntry node = queueListIterator.getNode(); - final long messageId = node.getMessage().getMessageId(); + final long messageId = node.getMessageId(); if ((messageId >= fromMessageId) && (messageId <= toMessageId) @@ -1438,7 +1436,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } else { - _managedObject.checkForNotification(node.getMessage()); + _managedObject.checkForNotification(node); } } @@ -1605,7 +1603,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for (int i = 0; i < num && !it.atTail(); i++) { it.advance(); - ids.add(it.getNode().getMessage().getMessageId()); + ids.add(it.getNode().getMessageId()); } return ids; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index d3e69fc1fa..bc1f56fee1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -387,6 +387,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage //todo - client id should be recoreded and this test removed but handled below if (_noLocal) { + //todo getPublisherClientInstance should be moved to QueueEntryImpl final Object publisherId = entry.getMessage().getPublisherClientInstance(); // We don't want local messages so check to see if message is one we sent @@ -407,6 +408,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage //todo - client id should be recoreded and this test removed but handled here + //todo getPublisherIdentifier should be moved to QueueEntryImpl if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) { return false; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 0ca8135f71..2f27e1405a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -127,9 +127,9 @@ public class NonTransactionalContext implements TransactionalContext { if (debug) { - _log.debug("Discarding message: " + queueEntry.getMessage().getMessageId()); + _log.debug("Discarding message: " + queueEntry.getMessageId()); } - if(queueEntry.getMessage().isPersistent()) + if(queueEntry.isPersistent()) { beginTranIfNecessary(); } @@ -175,9 +175,9 @@ public class NonTransactionalContext implements TransactionalContext if (debug) { - _log.debug("Discarding message: " + queueEntry.getMessage().getMessageId()); + _log.debug("Discarding message: " + queueEntry.getMessageId()); } - if(queueEntry.getMessage().isPersistent()) + if(queueEntry.isPersistent()) { beginTranIfNecessary(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index a8dd58ca83..7fe16062fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -172,7 +172,7 @@ public class Move extends AbstractCommand { for (QueueEntry msg : messages) { - ids.add(msg.getMessage().getMessageId()); + ids.add(msg.getMessageId()); } } } -- cgit v1.2.1 From 856792f17634b9c43a100408bf8c50988b3c14ee Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 9 Mar 2009 16:03:45 +0000 Subject: QPID-949 : Removed the deleteOnExit calls on all flowed entries, as this will increase our memory usage. Instead add a close method on the BackingStore that is called when the queue closes and clean up the backing then. Also moved the QueueHousekeeping thread stop to before we do any queue closing in the VHost. This will ensure that we are not causing any operations that might inadvertadly load a message, and so prevent the backing file from being deleted. This should of course now not occur as all getMessage() calls have been removed. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@751722 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/FileQueueBackingStore.java | 16 +++++++++++----- .../qpid/server/queue/FileQueueBackingStoreFactory.java | 4 ++-- .../qpid/server/queue/FlowableBaseQueueEntryList.java | 2 ++ .../org/apache/qpid/server/queue/QueueBackingStore.java | 2 ++ .../org/apache/qpid/server/virtualhost/VirtualHost.java | 14 +++++++------- 5 files changed, 24 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index 7c83788883..0e5a4efba6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -28,6 +28,7 @@ import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.util.FileUtils; import java.io.File; import java.io.FileInputStream; @@ -55,7 +56,6 @@ public class FileQueueBackingStore implements QueueBackingStore MessageMetaData mmd; File handle = getFileHandle(messageId); - handle.deleteOnExit(); ObjectInputStream input = null; @@ -192,8 +192,6 @@ public class FileQueueBackingStore implements QueueBackingStore _log.info("Unloading Message (ID:" + messageId + ")"); } - handle.deleteOnExit(); - ObjectOutputStream writer = null; Exception error = null; @@ -295,7 +293,6 @@ public class FileQueueBackingStore implements QueueBackingStore if (!bin_dir.exists()) { bin_dir.mkdirs(); - bin_dir.deleteOnExit(); } String id = bin_path + File.separator + messageId; @@ -304,7 +301,7 @@ public class FileQueueBackingStore implements QueueBackingStore } public void delete(Long messageId) - { + { File handle = getFileHandle(messageId); if (handle.exists()) @@ -320,6 +317,15 @@ public class FileQueueBackingStore implements QueueBackingStore } } + public void close() + { + _log.info("Closing Backing store at:" + _flowToDiskLocation); + if (!FileUtils.delete(new File(_flowToDiskLocation), true)) + { + _log.error("Unable to fully delete backing store location"); + } + } + private class RecoverDataBuffer implements ContentChunk { private int _length; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java index 0cfa9d6b32..21073c22ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java @@ -56,6 +56,7 @@ public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory _flowToDiskLocation += File.separator + QUEUE_BACKING_DIR + File.separator + vHostName; + //Check the location we will create QUEUE_BACKING_DIR in. File root = new File(location); if (!root.exists()) { @@ -121,8 +122,7 @@ public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory _log.info("Creating Flow to Disk Store : " + store.getAbsolutePath()); store.deleteOnExit(); - - if(!store.mkdir()) + if (!store.mkdir()) { throw new ConfigurationException("Unable to create Temporary Flow to Disk store:" + store.getAbsolutePath()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index d25c096337..0c4b8a0b42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -236,6 +236,8 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList //Shutdown thread for inhaler. ReferenceCountingExecutorService.getInstance().releaseExecutorService(); ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + + _backingStore.close(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java index 1f575d1e05..5efb95d0c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java @@ -31,4 +31,6 @@ public interface QueueBackingStore void unload(AMQMessage message) throws UnableToFlowMessageException; void delete(Long messageId); + + void close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index db05c7b299..5d2a31b80d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -422,6 +422,12 @@ public class VirtualHost implements Accessable //Stop Connections _connectionRegistry.close(); + //Stop Housekeeping + if (_houseKeepingTimer != null) + { + _houseKeepingTimer.cancel(); + } + //Stop the Queues processing if (_queueRegistry != null) { @@ -429,13 +435,7 @@ public class VirtualHost implements Accessable { queue.stop(); } - } - - //Stop Housekeeping - if (_houseKeepingTimer != null) - { - _houseKeepingTimer.cancel(); - } + } //Close TransactionLog if (_transactionLog != null) -- cgit v1.2.1 From 04edf83c4c5b7ea62c36109483bf75fe53345ca1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Mar 2009 12:22:23 +0000 Subject: QPID-1730 : Update the order in which we initialise. We now load the config file from disk then recover from the persistent strore. This approach applies the vhost configuration and then applies the persistent state from the store to those objects rather than recreating them. The new inner classes on VirtualHost are to be removed once we have fully extracted the RoutingTable from the legacy MessageStores as this is the root of the problem. The Store needs to be open to create new durable objects but the current stores must recover their state before new entries are added. So now the persistent state is being loaded on to a broker in a consistent state after it has configured a) its default exchanges and b) loaded the queue config from the config file. Eventually we will only have one location for queue config and all will be right in the world. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@753219 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHost.java | 203 ++++++++++++++++----- 1 file changed, 162 insertions(+), 41 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 5d2a31b80d..8a8cbd23cf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,17 +20,11 @@ */ package org.apache.qpid.server.virtualhost; -import java.util.Collections; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import javax.management.NotCompliantMBeanException; - import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; import org.apache.qpid.server.configuration.ExchangeConfiguration; import org.apache.qpid.server.configuration.QueueConfiguration; @@ -47,10 +41,9 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.QueueBackingStore; import org.apache.qpid.server.queue.FileQueueBackingStoreFactory; import org.apache.qpid.server.queue.QueueBackingStoreFactory; +import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.server.security.access.ACLManager; @@ -59,11 +52,17 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.transactionlog.TransactionLog; +import javax.management.NotCompliantMBeanException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + public class VirtualHost implements Accessable { private static final Logger _logger = Logger.getLogger(VirtualHost.class); - private final String _name; private ConnectionRegistry _connectionRegistry; @@ -87,7 +86,7 @@ public class VirtualHost implements Accessable private ACLManager _accessManager; private final Timer _houseKeepingTimer; - + private VirtualHostConfiguration _configuration; private QueueBackingStoreFactory _queueBackingStoreFactory; @@ -114,7 +113,7 @@ public class VirtualHost implements Accessable public VirtualHostConfiguration getConfiguration() { - return _configuration ; + return _configuration; } public QueueBackingStoreFactory getQueueBackingStoreFactory() @@ -148,12 +147,13 @@ public class VirtualHost implements Accessable return VirtualHost.this; } - } // End of MBean class /** * Normal Constructor + * * @param hostConfig + * * @throws Exception */ public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception @@ -165,7 +165,7 @@ public class VirtualHost implements Accessable { _configuration = hostConfig; _name = hostConfig.getName(); - + if (_name == null || _name.length() == 0) { throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); @@ -175,12 +175,30 @@ public class VirtualHost implements Accessable _connectionRegistry = new ConnectionRegistry(this); - _houseKeepingTimer = new Timer("Queue-housekeeping-"+_name, true); + _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); _queueRegistry = new DefaultQueueRegistry(this); + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + _exchangeRegistry = new DefaultExchangeRegistry(this); + _queueBackingStoreFactory = new FileQueueBackingStoreFactory(); + _queueBackingStoreFactory.configure(this, hostConfig); + + //Create a temporary RT to store the durable entries from the config file + // so we can replay them in to the real _RT after it has been loaded. + /// This should be removed after the _RT has been fully split from the the TL + + StartupRoutingTable configFileRT = new StartupRoutingTable(); + + _routingTable = configFileRT; + + // This needs to be after the RT has been defined as it creates the default durable exchanges. + _exchangeRegistry.initialise(); + initialiseModel(hostConfig); + if (transactionLog != null) { _transactionLog = transactionLog; @@ -195,19 +213,28 @@ public class VirtualHost implements Accessable initialiseRoutingTable(hostConfig); } - _queueBackingStoreFactory = new FileQueueBackingStoreFactory(); - _queueBackingStoreFactory.configure(this, hostConfig); + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config + // file and write them in to the new routing Table. + for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) + { + _routingTable.createQueue(cqt.queue, cqt.arguments); + } - _exchangeFactory.initialise(hostConfig); - _exchangeRegistry.initialise(); + for (Exchange exchange : configFileRT.exchange) + { + _routingTable.createExchange(exchange); + } + + for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) + { + _routingTable.bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); + } - initialiseModel(hostConfig); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); _accessManager = ApplicationRegistry.getInstance().getAccessManager(); _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); - + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); @@ -216,13 +243,13 @@ public class VirtualHost implements Accessable private void initialiseHouseKeeping(long period) { /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if(period != 0L) + if (period != 0L) { class RemoveExpiredMessagesTask extends TimerTask { public void run() { - for(AMQQueue q : _queueRegistry.getQueues()) + for (AMQQueue q : _queueRegistry.getQueues()) { try @@ -231,7 +258,7 @@ public class VirtualHost implements Accessable } catch (AMQException e) { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e); + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); throw new RuntimeException(e); } } @@ -239,8 +266,8 @@ public class VirtualHost implements Accessable } _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period/2, - period); + period / 2, + period); } } @@ -259,10 +286,10 @@ public class VirtualHost implements Accessable } _transactionLog = (TransactionLog) o; - //Assign RoutingTable as old MessageStores converted to TransactionLog may require the _routingTable. + //Assign RoutingTable as old MessageStores converted to TransactionLog will require the _routingTable. if (_transactionLog instanceof RoutingTable) { - _routingTable = (RoutingTable)_transactionLog; + _routingTable = (RoutingTable) _transactionLog; } _transactionLog.configure(this, "store", config); @@ -294,14 +321,14 @@ public class VirtualHost implements Accessable } } } - + private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException { - _logger.debug("Loading configuration for virtualhost: "+config.getName()); + _logger.debug("Loading configuration for virtualhost: " + config.getName()); List exchangeNames = config.getExchanges(); - for(Object exchangeNameObj : exchangeNames) + for (Object exchangeNameObj : exchangeNames) { String exchangeName = String.valueOf(exchangeNameObj); configureExchange(config.getExchangeConfiguration(exchangeName)); @@ -309,7 +336,7 @@ public class VirtualHost implements Accessable String[] queueNames = config.getQueueNames(); - for(Object queueNameObj : queueNames) + for (Object queueNameObj : queueNames) { String queueName = String.valueOf(queueNameObj); configureQueue(config.getQueueConfiguration(queueName)); @@ -322,14 +349,14 @@ public class VirtualHost implements Accessable Exchange exchange; exchange = _exchangeRegistry.getExchange(exchangeName); - if(exchange == null) + if (exchange == null) { AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); boolean durable = exchangeConfiguration.getDurable(); boolean autodelete = exchangeConfiguration.getAutoDelete(); - Exchange newExchange = _exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0); + Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); _exchangeRegistry.registerExchange(newExchange); } } @@ -347,7 +374,7 @@ public class VirtualHost implements Accessable Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - if(exchange == null) + if (exchange == null) { exchange = _exchangeRegistry.getDefaultExchange(); } @@ -358,19 +385,22 @@ public class VirtualHost implements Accessable } List routingKeys = queueConfiguration.getRoutingKeys(); - if(routingKeys == null || routingKeys.isEmpty()) + if (routingKeys == null || routingKeys.isEmpty()) { routingKeys = Collections.singletonList(queue.getName()); } - for(Object routingKeyNameObj : routingKeys) + for (Object routingKeyNameObj : routingKeys) { AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); + } queue.bind(exchange, routingKey, null); - _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'"); } - if(exchange != _exchangeRegistry.getDefaultExchange()) + if (exchange != _exchangeRegistry.getDefaultExchange()) { queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); } @@ -414,7 +444,7 @@ public class VirtualHost implements Accessable public ACLManager getAccessManager() { return _accessManager; - } + } public void close() throws Exception { @@ -453,4 +483,95 @@ public class VirtualHost implements Accessable { return _virtualHostMBean; } + + /** + * Temporary Startup RT class to record the creation of persistent queues / exchanges. + * + * + * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. + * This should be removed after the _RT has been fully split from the the TL + */ + private class StartupRoutingTable implements RoutingTable + { + public List exchange = new LinkedList(); + public List queue = new LinkedList(); + public List bindings = new LinkedList(); + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + } + + public void close() throws Exception + { + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (exchange.isDurable()) + { + this.exchange.add(exchange); + } + } + + public void removeExchange(Exchange exchange) throws AMQException + { + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + if (exchange.isDurable() && queue.isDurable()) + { + bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); + } + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + } + + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + if (queue.isDurable()) + { + this.queue.add(new CreateQueueTuple(queue, arguments)); + } + } + + public void removeQueue(AMQQueue queue) throws AMQException + { + } + + private class CreateQueueTuple + { + public AMQQueue queue; + public FieldTable arguments; + + public CreateQueueTuple(AMQQueue queue, FieldTable arguments) + { + this.queue = queue; + this.arguments = arguments; + } + } + + private class CreateBindingTuple + { + public AMQQueue queue; + public FieldTable arguments; + public Exchange exchange; + public AMQShortString routingKey; + + public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + { + this.exchange = exchange; + this.routingKey = routingKey; + this.queue = queue; + arguments = args; + } + } + } } -- cgit v1.2.1 From 4409ca8f8585fa2e2f7c530be3dd8c1c733e03bb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Mar 2009 12:23:12 +0000 Subject: QPID-1730 : Improve the logging so we can see what is going one during persistent recovery as we do not have a working persistent module. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@753220 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/AbstractExchange.java | 2 +- .../java/org/apache/qpid/server/exchange/DirectExchange.java | 6 ++---- .../java/org/apache/qpid/server/queue/AMQPriorityQueue.java | 6 ++++++ .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 11 +++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index b6c741bbec..30af09ce4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -191,7 +191,7 @@ public abstract class AbstractExchange implements Exchange, Managable public String toString() { - return getClass().getName() + "[" + getName() +"]"; + return getClass().getSimpleName() + "[" + getName() +"]"; } public ManagedObject getManagedObject() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index e39c005750..e9af92bad8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -168,16 +168,14 @@ public class DirectExchange extends AbstractExchange { if (_logger.isDebugEnabled()) { - _logger.debug("Queue (" + queue.getName() + ")" + queue + " is already registered with routing key " + routingKey); + _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey); } } else { if (_logger.isDebugEnabled()) { - _logger.debug("Binding queue(" + queue.getName() + ") " + queue + " with routing key " + routingKey - + (args == null ? "" : " and arguments " + args.toString()) - + " to exchange " + this); + _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index ade780d0bb..f5cc694e86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -68,4 +68,10 @@ public class AMQPriorityQueue extends SimpleAMQQueue } } + @Override + public String getType() + { + return getClass().getName() + "[" + getName() + "][Priorities:" + getPriorities() + "]"; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 63ec56c1af..ed9b1eb8d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1607,4 +1607,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } return ids; } + + + public String getType() + { + return getClass().getSimpleName() + "[" + getName() +"]"; + } + + public String toString() + { + return getType() + "[Owner:" + _owner + "][Durable:" + _durable + "]"; + } } -- cgit v1.2.1 From 6591fd7807daa14dc710503cbfacaed4b96251fb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 13 Mar 2009 13:59:25 +0000 Subject: QPID-1730 : Logging update highlighted that we were printing the queue before we had fully initialised it. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@753253 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java | 2 +- .../main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index f5cc694e86..00dec57ed5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -71,7 +71,7 @@ public class AMQPriorityQueue extends SimpleAMQQueue @Override public String getType() { - return getClass().getName() + "[" + getName() + "][Priorities:" + getPriorities() + "]"; + return getClass().getSimpleName() + "[" + getName() + "][Priorities:" + getPriorities() + "]"; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index 5dd76a5299..d5271295dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -237,7 +237,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement for (int index = 0; index < _priorities; index++) { QueueEntryList queueEntryList = _priorityLists[index]; - _log.debug("Queue (" + _queue + ":" + _queue.getName() + ")[" + index + "] usage:" + queueEntryList.memoryUsed() + _log.debug("Queue (" + _queue.getName() + ")[" + index + "] usage:" + queueEntryList.memoryUsed() + "/" + queueEntryList.getMemoryUsageMaximum() + "/" + queueEntryList.dataSize()); } -- cgit v1.2.1 From e579e5791a20d45eb99e671f0d4ebfa188377859 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 16 Mar 2009 16:32:50 +0000 Subject: QPID-1736: Timeout DNS lookups if they take more than 30 seconds. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@754934 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/plugins/network/FirewallPlugin.java | 63 ++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 39397966f0..85026121ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -25,6 +25,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Iterator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import org.apache.commons.configuration.CompositeConfiguration; @@ -42,6 +43,8 @@ import org.apache.qpid.util.NetMatcher; public class FirewallPlugin extends AbstractACLPlugin { + public class FirewallPluginException extends Exception {} + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() { public boolean supportsTag(String name) @@ -60,6 +63,7 @@ public class FirewallPlugin extends AbstractACLPlugin public class FirewallRule { + private static final long DNS_TIMEOUT = 30000; private AuthzResult _access; private NetMatcher _network; private Pattern[] _hostnamePatterns; @@ -97,11 +101,15 @@ public class FirewallPlugin extends AbstractACLPlugin return networkStrings; } - public boolean match(InetAddress remote) + public boolean match(InetAddress remote) throws FirewallPluginException { if (_hostnamePatterns != null) { - String hostname = remote.getCanonicalHostName(); + String hostname = getHostname(remote); + if (hostname == null) + { + throw new FirewallPluginException(); + } for (Pattern pattern : _hostnamePatterns) { if (pattern.matcher(hostname).matches()) @@ -117,6 +125,48 @@ public class FirewallPlugin extends AbstractACLPlugin } } + /** + * @param remote the InetAddress to look up + * @return the hostname, null if not found or takes longer than 30s to find + */ + private String getHostname(final InetAddress remote) + { + final String[] hostname = new String[]{null}; + final AtomicBoolean done = new AtomicBoolean(false); + // Spawn thread + Thread thread = new Thread(new Runnable() + { + public void run() + { + hostname[0] = remote.getCanonicalHostName(); + done.getAndSet(true); + synchronized (done) + { + done.notifyAll(); + } + } + }); + + thread.run(); + long endTime = System.currentTimeMillis() + DNS_TIMEOUT; + + while (System.currentTimeMillis() < endTime && !done.get()) + { + try + { + synchronized (done) + { + done.wait(endTime - System.currentTimeMillis()); + } + } + catch (InterruptedException e) + { + // Check the time and if necessary sleep for a bit longer + } + } + return hostname[0]; + } + public AuthzResult getAccess() { return _access; @@ -146,7 +196,14 @@ public class FirewallPlugin extends AbstractACLPlugin boolean match = false; for (FirewallRule rule : _rules) { - match = rule.match(addr); + try + { + match = rule.match(addr); + } + catch (FirewallPluginException e) + { + return AuthzResult.DENIED; + } if (match) { return rule.getAccess(); -- cgit v1.2.1 From d58864360fa7c0a47f9d4686f35bac09c32e6ff5 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 16 Mar 2009 16:53:59 +0000 Subject: QPID-1626: handle legacy config file a bit more gracefully. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@754958 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 2 + .../access/plugins/LegacyAccessPlugin.java | 71 ++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 5d8fa3e9d7..dbfcefb6ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; +import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; import org.apache.qpid.server.security.access.plugins.SimpleXML; import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; import org.osgi.framework.BundleActivator; @@ -166,6 +167,7 @@ public class PluginManager _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); + _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); } return _securityPlugins; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java new file mode 100644 index 0000000000..fc1bc048d4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import java.util.Collection; +import java.util.HashSet; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; + +/** + * + * Used to suppress warnings in legacy config files that have things in which aren't handled by a plugin directly. + * + */ +public class LegacyAccessPlugin extends BasicACLPlugin +{ + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + private Collection maskedTags = new HashSet(); + { + maskedTags.add("principal-databases"); + maskedTags.add("access"); + maskedTags.add("msg-auth"); + maskedTags.add("false"); + maskedTags.add("jmx"); + } + + public boolean supportsTag(String name) + { + return maskedTags .contains(name); + } + + public ACLPlugin newInstance(Configuration config) + { + return new LegacyAccessPlugin(); + } + }; + + public String getPluginName() + { + return getClass().getSimpleName(); + } + + @Override + protected AuthzResult getResult() + { + // Always abstain + return AuthzResult.ABSTAIN; + } + +} -- cgit v1.2.1 From 7db47b7b5af603379d67f056be5fe625f5bc71f7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 17 Mar 2009 14:01:23 +0000 Subject: QPID-1743: change maxMessageSize description to indicate it is in Bytes not KBytes, make size descriptions in other methods consistent git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@755256 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/ManagedQueue.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index d2cf90b42d..53e249f210 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -131,7 +131,7 @@ public interface ManagedQueue void setMaximumMessageAge(Long age) throws IOException; /** - * Returns the maximum size of a message (in kbytes) allowed to be accepted by the + * Returns the maximum size of a message (in Bytes) allowed to be accepted by the * ManagedQueue. This is useful in setting notifications or taking * appropriate action, if the size of the message received is more than * the allowed size. @@ -142,12 +142,12 @@ public interface ManagedQueue Long getMaximumMessageSize() throws IOException; /** - * Sets the maximum size of the message (in kbytes) that is allowed to be + * Sets the maximum size of the message (in Bytes) that is allowed to be * accepted by the Queue. * @param size maximum size of message. * @throws IOException */ - @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(KB) for a message size") + @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(Bytes) for a message size") void setMaximumMessageSize(Long size) throws IOException; /** @@ -184,7 +184,6 @@ public interface ManagedQueue @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth") void setMaximumQueueDepth(Long value) throws IOException; - //TODO change descriptions /** * View the limit on the memory that this queue will utilise. * @@ -201,7 +200,7 @@ public interface ManagedQueue * * @param maximumMemoryUsage The new maximum memory(B) to be used by this queue */ - @MBeanAttribute(name="MemoryUsageMaximum", description="The maximum memory(B) that the queue will occupy.") + @MBeanAttribute(name="MemoryUsageMaximum", description="The maximum memory(Bytes) that the queue will occupy.") public void setMemoryUsageMaximum(Long maximumMemoryUsage); /** @@ -220,7 +219,7 @@ public interface ManagedQueue * * @param minimumMemoryUsage The new minimum memory(B) level to be used by this queue */ - @MBeanAttribute(name="MemoryUsageMinimum", description="The minimum memory(B) that the queue will occupy.") + @MBeanAttribute(name="MemoryUsageMinimum", description="The minimum memory(Bytes) that the queue will occupy.") public void setMemoryUsageMinimum(Long minimumMemoryUsage); /** @@ -228,7 +227,7 @@ public interface ManagedQueue * * @return The current memory(B) usage of this queue. */ - @MBeanAttribute(name="MemoryUsageCurrent", description="The current amount of memory(B) used by this queue.") + @MBeanAttribute(name="MemoryUsageCurrent", description="The current amount of memory(Bytes) used by this queue.") public Long getMemoryUsageCurrent(); /** -- cgit v1.2.1 From ce7b4ca4077e6463db212d467a848f27fe3b039e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 20 Mar 2009 15:16:13 +0000 Subject: QPID-1763 : Fixed slow down due to fs lookup for unloaded message introduced in r748516 Merged from branches/0.5-release : r756506 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@756518 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/QueueEntryImpl.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index fceaf75a9e..715dd0c385 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -84,6 +84,7 @@ public class QueueEntryImpl implements QueueEntry private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); private boolean _persistent; + private boolean _hasBeenUnloaded = false; QueueEntryImpl(SimpleQueueEntryList queueEntryList) { @@ -407,11 +408,16 @@ public class QueueEntryImpl implements QueueEntry try { - _backingStore.unload(_message); - - if (_log.isDebugEnabled()) + if (!_hasBeenUnloaded) { - _log.debug("Unloaded:" + debugIdentity()); + _hasBeenUnloaded = true; + + _backingStore.unload(_message); + + if (_log.isDebugEnabled()) + { + _log.debug("Unloaded:" + debugIdentity()); + } } _message = null; @@ -502,7 +508,7 @@ public class QueueEntryImpl implements QueueEntry if (state != DELETED_STATE && _stateUpdater.compareAndSet(this, state, DELETED_STATE)) { _queueEntryList.advanceHead(); - if (_backingStore != null) + if (_backingStore != null && _hasBeenUnloaded) { _backingStore.delete(_messageId); } -- cgit v1.2.1 From e09aa59ff09fb86b15a6ab0402e5c73e37ffaed9 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 22 Mar 2009 21:24:00 +0000 Subject: QPID-1767: add units to message age attribute description Merged from branches/0.5-release : r757257 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@757258 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/ManagedQueue.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java index 53e249f210..d91d45a446 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -116,18 +116,18 @@ public interface ManagedQueue boolean isAutoDelete() throws IOException; /** - * Returns the maximum age of a message (expiration time) + * Returns the maximum age of a message (expiration time) in milliseconds * @return the maximum age * @throws IOException */ Long getMaximumMessageAge() throws IOException; /** - * Sets the maximum age of a message + * Sets the maximum age of a message in milliseconds * @param age maximum age of message. * @throws IOException */ - @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on the broker") + @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value(milliseconds) for message age") void setMaximumMessageAge(Long age) throws IOException; /** -- cgit v1.2.1 From d11f94a9fc743d4c49443dad3ea46cce5171e931 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 22 Mar 2009 22:42:07 +0000 Subject: QPID-1511: add scripts to generate example ssl stores, and add refrence in the relevant exception message Merged from branches/0.5-release : r757268 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@757270 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/management/JMXManagedObjectRegistry.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index f02e858250..3fc460b325 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -155,7 +155,9 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry if (!ksf.exists()) { - throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf); + throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf + "\n" + + "Check broker configuration, or see create-example-ssl-stores script" + + "in the bin/ directory if you need to generate an example store."); } if (!ksf.canRead()) { -- cgit v1.2.1 From 19de7a84b5fae3b977593f0fb81095c1c2c78f55 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 25 Mar 2009 18:36:47 +0000 Subject: QPID-1735 : Removed duplicated methods with differing functionality that was causing FtD to fail. Annoyingly the tests work as they used the method with the extra functionality. Commit from 0.5-release : r758382 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@758395 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/QueueEntry.java | 9 +++++---- .../main/java/org/apache/qpid/server/queue/QueueEntryImpl.java | 7 +------ 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 7fc5df4e9e..f22220ada9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -170,14 +170,15 @@ public interface QueueEntry extends Comparable, Filterable Date: Wed, 25 Mar 2009 18:39:25 +0000 Subject: QPID-1735 : Added Documentation to QueueBackingStore around thread safety of load/unload, Updated FQBS to adhere to the thread safety specified by the interface. QueueEntry was updated to return the AMQMessage from the load() to complete the getMessage() interface. As in a flowed state the message may be purged before a reference can be taken. Added new Test QueueEntryImplThreadingTest that should later be run for longer but aims to show that load always returns the message even when unloads are occuring asynchronously. Commit from 0.5-release : r758388 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@758397 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/FileQueueBackingStore.java | 170 ++++++++++++--------- .../server/queue/FlowableBaseQueueEntryList.java | 6 +- .../qpid/server/queue/QueueBackingStore.java | 28 ++++ .../org/apache/qpid/server/queue/QueueEntry.java | 2 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 98 ++++++++---- 5 files changed, 196 insertions(+), 108 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index 0e5a4efba6..a22eea2b5e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -157,10 +157,10 @@ public class FileQueueBackingStore implements QueueBackingStore { try { - input.close(); - // We can purge the message here then reflow it if required but I believe it to be cleaner to leave it - // on disk until it has been deleted from the queue at that point we can be sure we won't need the data - //handle.delete(); + if (input != null) + { + input.close(); + } } catch (IOException e) { @@ -171,101 +171,123 @@ public class FileQueueBackingStore implements QueueBackingStore throw new UnableToRecoverMessageException(error); } + /** + * Thread safety is ensured here by synchronizing on the message object. + * + * This is safe as load() calls will fail until the first thread through here has created the file on disk + * and fully written the content. + * + * After this point new AMQMessages can exist that reference the same data thus breaking the synchronisation. + * + * Thread safety is maintained here as the existence of the file is checked allowing then subsequent unload() calls + * to skip the writing. + * + * Multiple unload() calls will initially be blocked using the synchronization until the data exists on disk thus + * safely allowing any reference to the message to be cleared prompting a load call. + * + * @param message the message to unload + * @throws UnableToFlowMessageException + */ public void unload(AMQMessage message) throws UnableToFlowMessageException { - long messageId = message.getMessageId(); + //Synchorize on the message to ensure that one only thread can unload at a time. + // If a second unload is attempted then it will block until the unload has completed. + synchronized (message) + { + long messageId = message.getMessageId(); - File handle = getFileHandle(messageId); + File handle = getFileHandle(messageId); - //If we have written the data once then we don't need to do it again. - if (handle.exists()) - { - if (_log.isDebugEnabled()) + //If we have written the data once then we don't need to do it again. + if (handle.exists()) { - _log.debug("Message(ID:" + messageId + ") already unloaded."); + if (_log.isDebugEnabled()) + { + _log.debug("Message(ID:" + messageId + ") already unloaded."); + } + return; } - return; - } - if (_log.isInfoEnabled()) - { - _log.info("Unloading Message (ID:" + messageId + ")"); - } + if (_log.isInfoEnabled()) + { + _log.info("Unloading Message (ID:" + messageId + ")"); + } - ObjectOutputStream writer = null; - Exception error = null; + ObjectOutputStream writer = null; + Exception error = null; - try - { - writer = new ObjectOutputStream(new FileOutputStream(handle)); + try + { + writer = new ObjectOutputStream(new FileOutputStream(handle)); - writer.writeLong(message.getArrivalTime()); + writer.writeLong(message.getArrivalTime()); - MessagePublishInfo mpi = message.getMessagePublishInfo(); - writer.writeUTF(String.valueOf(mpi.getExchange())); - writer.writeUTF(String.valueOf(mpi.getRoutingKey())); - writer.writeBoolean(mpi.isMandatory()); - writer.writeBoolean(mpi.isImmediate()); - ContentHeaderBody chb = message.getContentHeaderBody(); + MessagePublishInfo mpi = message.getMessagePublishInfo(); + writer.writeUTF(String.valueOf(mpi.getExchange())); + writer.writeUTF(String.valueOf(mpi.getRoutingKey())); + writer.writeBoolean(mpi.isMandatory()); + writer.writeBoolean(mpi.isImmediate()); + ContentHeaderBody chb = message.getContentHeaderBody(); - // write out the content header body - final int bodySize = chb.getSize(); - byte[] underlying = new byte[bodySize]; - ByteBuffer buf = ByteBuffer.wrap(underlying); - chb.writePayload(buf); + // write out the content header body + final int bodySize = chb.getSize(); + byte[] underlying = new byte[bodySize]; + ByteBuffer buf = ByteBuffer.wrap(underlying); + chb.writePayload(buf); - writer.writeInt(bodySize); - writer.write(underlying, 0, bodySize); + writer.writeInt(bodySize); + writer.write(underlying, 0, bodySize); - int bodyCount = message.getBodyCount(); - writer.writeInt(bodyCount); + int bodyCount = message.getBodyCount(); + writer.writeInt(bodyCount); - //WriteContentBody - for (int index = 0; index < bodyCount; index++) - { - ContentChunk chunk = message.getContentChunk(index); - int length = chunk.getSize(); + //WriteContentBody + for (int index = 0; index < bodyCount; index++) + { + ContentChunk chunk = message.getContentChunk(index); + int length = chunk.getSize(); - byte[] chunk_underlying = new byte[length]; + byte[] chunk_underlying = new byte[length]; - ByteBuffer chunk_buf = chunk.getData(); + ByteBuffer chunk_buf = chunk.getData(); - chunk_buf.duplicate().rewind().get(chunk_underlying); + chunk_buf.duplicate().rewind().get(chunk_underlying); - writer.writeInt(length); - writer.write(chunk_underlying, 0, length); + writer.writeInt(length); + writer.write(chunk_underlying, 0, length); + } } - } - catch (FileNotFoundException e) - { - error = e; - } - catch (IOException e) - { - error = e; - } - finally - { - // In a FileNotFound situation writer will be null. - if (writer != null) + catch (FileNotFoundException e) { - try - { - writer.flush(); - writer.close(); - } - catch (IOException e) + error = e; + } + catch (IOException e) + { + error = e; + } + finally + { + // In a FileNotFound situation writer will be null. + if (writer != null) { - error = e; + try + { + writer.flush(); + writer.close(); + } + catch (IOException e) + { + error = e; + } } } - } - if (error != null) - { - _log.error("Unable to unload message(" + messageId + ") to disk, restoring state."); - handle.delete(); - throw new UnableToFlowMessageException(messageId, error); + if (error != null) + { + _log.error("Unable to unload message(" + messageId + ") to disk, restoring state."); + handle.delete(); + throw new UnableToFlowMessageException(messageId, error); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 0c4b8a0b42..5e5901bcd7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -166,7 +166,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList { // If we've increased the minimum memory above what we have in memory then // we need to inhale more if there is more - if (_atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) + if (!_disabled && _atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) { startInhaler(); } @@ -204,7 +204,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryUnloadedUpdateMemory(QueueEntry queueEntry) { - if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + if (!_disabled && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) { _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); } @@ -219,7 +219,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryLoadedUpdateMemory(QueueEntry queueEntry) { - if (_atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + if (!_disabled && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) { _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); setFlowed(true); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java index 5efb95d0c0..5c65cb6424 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java @@ -26,8 +26,36 @@ import org.apache.commons.configuration.ConfigurationException; public interface QueueBackingStore { + /** + * Retrieve the message with a given ID + * + * This method must be thread safe. + * + * Multiple calls to load with a given messageId DO NOT need to return the same object. + * + * @param messageId the id of the message to retreive. + * @return + */ AMQMessage load(Long messageId); + /** + * Store a message in the BackingStore. + * + * This method must be thread safe understanding that multiple message objects may be the same data. + * + * Allowing a thread to return from this method means that it is safe to call load() + * + * Implementer guide: + * Until the message has been loaded the message references will all be the same object. + * + * One appraoch as taken by the @see FileQueueBackingStore is to block aimulataneous calls to this method + * until the message is fully on disk. This can be done by synchronising on message as initially it is always the + * same object. Only after a load has taken place will there be a discrepency. + * + * + * @param message the message to unload + * @throws UnableToFlowMessageException + */ void unload(AMQMessage message) throws UnableToFlowMessageException; void delete(Long messageId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index f22220ada9..fb23edb3c5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -226,7 +226,7 @@ public interface QueueEntry extends Comparable, Filterable _messageRef; private boolean _redelivered; @@ -102,7 +103,7 @@ public class QueueEntryImpl implements QueueEntry public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) { _queueEntryList = queueEntryList; - _message = message; + _messageRef = new AtomicReference(message); if (message != null) { _messageId = message.getMessageId(); @@ -136,11 +137,7 @@ public class QueueEntryImpl implements QueueEntry public AMQMessage getMessage() { - if (_message == null) - { - return _backingStore.load(_messageId); - } - return _message; + return load(); } public Long getMessageId() @@ -231,13 +228,17 @@ public class QueueEntryImpl implements QueueEntry public String debugIdentity() { String entry = "[State:" + _state.getState().name() + "]"; - if (_message == null) + + AMQMessage message = _messageRef.get(); + + if (message == null) { return entry + "(Message Unloaded ID:" + _messageId + ")"; } else { - return entry + _message.debugIdentity(); + + return entry + message.debugIdentity(); } } @@ -398,23 +399,27 @@ public class QueueEntryImpl implements QueueEntry public void unload() { - if (_message != null && _backingStore != null) - { + //Get the currently loaded message + AMQMessage message = _messageRef.get(); + // If we have a message in memory and we have a valid backingStore attempt to unload + if (message != null && _backingStore != null) + { try { - if (!_hasBeenUnloaded) + // The backingStore will now handle concurrent calls to unload and safely synchronize to ensure + // multiple initial unloads are unloads + _backingStore.unload(message); + _hasBeenUnloaded = true; + _messageRef.set(null); + + if (_log.isDebugEnabled()) { - _hasBeenUnloaded = true; + _log.debug("Unloaded:" + debugIdentity()); + } - _backingStore.unload(_message); - if (_log.isDebugEnabled()) - { - _log.debug("Unloaded:" + debugIdentity()); - } - } - _message = null; + // Clear the message reference if the loaded message is still the one we are processing. //Update the memoryState if this load call resulted in the message being purged from memory if (!_flowed.getAndSet(true)) @@ -434,23 +439,56 @@ public class QueueEntryImpl implements QueueEntry } } - public void load() + public AMQMessage load() { + // MessageId and Backing store are null in test scenarios, normally this is not the case. if (_messageId != null && _backingStore != null) { - _message = _backingStore.load(_messageId); - - if (_log.isDebugEnabled()) + // See if we have the message currently in memory to return + AMQMessage message = _messageRef.get(); + // if we don't then we need to start a load process. + if (message == null) { - _log.debug("Loaded:" + debugIdentity()); - } + //Synchronize here to ensure only the first thread that attempts to load will perform the load from the + // backing store. + synchronized (this) + { + // Check again to see if someone else ahead of us loaded the message + message = _messageRef.get(); + // if we still don't have the message then we need to start a load process. + if (message == null) + { + // Load the message and keep a reference to it + message = _backingStore.load(_messageId); + // Set the message reference + _messageRef.set(message); + } + else + { + // If someone else loaded the message then we can jump out here as the Memory Updates will + // have been performed by the loading thread + return message; + } + } - //Update the memoryState if this load call resulted in the message comming in to memory - if (_flowed.getAndSet(false)) - { - _queueEntryList.entryLoadedUpdateMemory(this); + if (_log.isDebugEnabled()) + { + _log.debug("Loaded:" + debugIdentity()); + } + + //Update the memoryState if this load call resulted in the message comming in to memory + if (_flowed.getAndSet(false)) + { + _queueEntryList.entryLoadedUpdateMemory(this); + } } + + // Return the message that was either already in memory or the value we just loaded. + return message; } + // This can be null but only in the case where we have no messageId + // in the case where we have no backingStore then we will never have unloaded the message + return _messageRef.get(); } public boolean isFlowed() -- cgit v1.2.1 From a4b8dd527de88d1882bdc3fa27a13530b508e003 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 26 Mar 2009 16:38:29 +0000 Subject: QPID-1776: fix interpolation of variables. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@758730 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/ServerConfiguration.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index c0fe42c5c2..ea8b29c76b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -130,10 +130,16 @@ public class ServerConfiguration implements SignalHandler for (int j = 0; j < hosts.size(); j++) { String name = (String) hosts.get(j); - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(conf.subset("virtualhosts.virtualhost."+name)); - mungedConf.addConfiguration(vhostConfiguration.subset("virtualhost." + name)); - VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, mungedConf, this); + // Add the keys of the virtual host to the main config then bail out + + Configuration myConf = vhostConfiguration.subset("virtualhost." + name); + Iterator k = myConf.getKeys(); + while (k.hasNext()) + { + String key = (String) k.next(); + conf.setProperty("virtualhosts.virtualhost."+name+"."+key, myConf.getProperty(key)); + } + VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name), this); _virtualHosts.put(vhostConfig.getName(), vhostConfig); } } -- cgit v1.2.1 From cf20542cdb2e1b851cf771ed1693209fd76489e1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 26 Mar 2009 16:44:06 +0000 Subject: QPID-949 : renamed _disabled to _disableFlowtoDisk based on review feedback git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@758733 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/FlowableBaseQueueEntryList.java | 16 ++++++++-------- .../apache/qpid/server/queue/PriorityQueueEntryList.java | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 5e5901bcd7..4b387eac53 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -51,7 +51,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList private Executor _purger; private AtomicBoolean _stopped; private AtomicReference _asynchronousInhaler = new AtomicReference(null); - protected boolean _disabled; + protected boolean _disableFlowToDisk; private AtomicReference _asynchronousPurger = new AtomicReference(null); private static final int BATCH_PROCESS_COUNT = 100; @@ -68,7 +68,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList _stopped = new AtomicBoolean(false); _inhaler = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); _purger = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); - _disabled = true; + _disableFlowToDisk = true; } public void setFlowed(boolean flowed) @@ -121,7 +121,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList if (maximumMemoryUsage >= 0) { - _disabled = false; + _disableFlowToDisk = false; } // Don't attempt to start the inhaler/purger unless we have a minimum value specified. @@ -142,7 +142,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList { _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); } - _disabled = true; + _disableFlowToDisk = true; } } @@ -166,7 +166,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList { // If we've increased the minimum memory above what we have in memory then // we need to inhale more if there is more - if (!_disabled && _atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) + if (!_disableFlowToDisk && _atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) { startInhaler(); } @@ -204,7 +204,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryUnloadedUpdateMemory(QueueEntry queueEntry) { - if (!_disabled && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) { _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); } @@ -219,7 +219,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryLoadedUpdateMemory(QueueEntry queueEntry) { - if (!_disabled && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) { _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); setFlowed(true); @@ -247,7 +247,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList _atomicQueueSize.addAndGet(queueEntry.getSize()); long inUseMemory = _atomicQueueInMemory.addAndGet(queueEntry.getSize()); - if (!_disabled && inUseMemory > _memoryUsageMaximum) + if (!_disableFlowToDisk && inUseMemory > _memoryUsageMaximum) { setFlowed(true); queueEntry.unload(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index d5271295dd..fc11dd888a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -68,7 +68,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement long requriedSize = message.getSize(); // Check and see if list would flow on adding message - if (!_disabled && !isFlowed() && _priorityLists[index].memoryUsed() + requriedSize > _priorityLists[index].getMemoryUsageMaximum()) + if (!_disableFlowToDisk && !isFlowed() && _priorityLists[index].memoryUsed() + requriedSize > _priorityLists[index].getMemoryUsageMaximum()) { if (_log.isDebugEnabled()) { @@ -401,7 +401,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement if (maximumMemoryUsage >= 0) { - _disabled = false; + _disableFlowToDisk = false; } long share = maximumMemoryUsage / _priorities; @@ -418,7 +418,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement { _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); } - _disabled = true; + _disableFlowToDisk = true; return; } -- cgit v1.2.1 From 6677aff468f3f209c680413ac31c7d1ad28b6597 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 26 Mar 2009 16:57:21 +0000 Subject: QPID-1768 : Removed all the special priority queue code. Added the ability for a FlowableBaseQueueEntryList to delegate its accounting to a parent QueueEntryList. This results in the PriorityQueueEntryList using the same FtD algorithm as SimpleQELs. - New Messages on a flowed queue are pushed optimistically pushed to disk, this should potentially be removed and just rely on the purger to flush the correct message which in the Priority case may not be the last message in. - When space is available messages are loaded in queue order, so in this case Priority order. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@758742 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/queue/FlowableBaseQueueEntryList.java | 91 +++++-- .../qpid/server/queue/PriorityQueueEntryList.java | 292 +-------------------- .../apache/qpid/server/queue/QueueEntryImpl.java | 7 + .../apache/qpid/server/queue/QueueEntryList.java | 10 + 4 files changed, 89 insertions(+), 311 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 4b387eac53..ca7fc5abf6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -54,6 +54,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList protected boolean _disableFlowToDisk; private AtomicReference _asynchronousPurger = new AtomicReference(null); private static final int BATCH_PROCESS_COUNT = 100; + protected FlowableBaseQueueEntryList _parentQueue; FlowableBaseQueueEntryList(AMQQueue queue) { @@ -89,7 +90,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList { if (_log.isDebugEnabled()) { - _log.debug(prefix + " Queue(" + _queue + ":" + _queue.getName() + ") usage:" + memoryUsed() + _log.debug(prefix + " Queue(" + _queue.getName() + ") usage:" + memoryUsed() + "/" + getMemoryUsageMinimum() + "<>" + getMemoryUsageMaximum() + "/" + dataSize()); } @@ -97,7 +98,14 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList public boolean isFlowed() { - return _flowed.get(); + if (_parentQueue != null) + { + return _parentQueue.isFlowed(); + } + else + { + return _flowed.get(); + } } public int size() @@ -204,12 +212,19 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryUnloadedUpdateMemory(QueueEntry queueEntry) { - if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + if (_parentQueue != null) { - _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); + _parentQueue.entryUnloadedUpdateMemory(queueEntry); } + else + { + if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + { + _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); + } - checkAndStartInhaler(); + checkAndStartInhaler(); + } } /** @@ -219,11 +234,18 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList */ public void entryLoadedUpdateMemory(QueueEntry queueEntry) { - if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + if (_parentQueue != null) { - _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); - setFlowed(true); - startPurger(); + _parentQueue.entryLoadedUpdateMemory(queueEntry); + } + else + { + if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) + { + _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); + setFlowed(true); + startPurger(); + } } } @@ -241,28 +263,55 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } } - protected void incrementCounters(final QueueEntryImpl queueEntry) + /** + * Mark this queue as part of another QueueEntryList for accounting purposes. + * + * All Calls from the QueueEntry to the QueueEntryList need to check if there is + * a parent QueueEntrylist upon which the action should take place. + * + * @param queueEntryList The parent queue that is performing accounting. + */ + public void setParentQueueEntryList(FlowableBaseQueueEntryList queueEntryList) { - _atomicQueueCount.incrementAndGet(); - _atomicQueueSize.addAndGet(queueEntry.getSize()); - long inUseMemory = _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + _parentQueue = queueEntryList; + } - if (!_disableFlowToDisk && inUseMemory > _memoryUsageMaximum) + protected void incrementCounters(final QueueEntryImpl queueEntry) + { + if (_parentQueue != null) + { + _parentQueue.incrementCounters(queueEntry); + } + else { - setFlowed(true); - queueEntry.unload(); + _atomicQueueCount.incrementAndGet(); + _atomicQueueSize.addAndGet(queueEntry.getSize()); + long inUseMemory = _atomicQueueInMemory.addAndGet(queueEntry.getSize()); + + if (!_disableFlowToDisk && inUseMemory > _memoryUsageMaximum) + { + setFlowed(true); + queueEntry.unload(); + } } } protected void dequeued(QueueEntryImpl queueEntry) { - _atomicQueueCount.decrementAndGet(); - _atomicQueueSize.addAndGet(-queueEntry.getSize()); - if (!queueEntry.isFlowed()) + if (_parentQueue != null) { - if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + _parentQueue.dequeued(queueEntry); + } + else + { + _atomicQueueCount.decrementAndGet(); + _atomicQueueSize.addAndGet(-queueEntry.getSize()); + if (!queueEntry.isFlowed()) { - _log.error("InMemory Count just went below 0 on dequeue."); + if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) + { + _log.error("InMemory Count just went below 0 on dequeue."); + } } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java index fc11dd888a..83c7ebb4f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java @@ -39,6 +39,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement for (int i = 0; i < priorities; i++) { _priorityLists[i] = new SimpleQueueEntryList(queue); + _priorityLists[i].setParentQueueEntryList(this); } showUsage("Created:" + _queue.getName()); @@ -66,183 +67,9 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement index = 0; } - long requriedSize = message.getSize(); - // Check and see if list would flow on adding message - if (!_disableFlowToDisk && !isFlowed() && _priorityLists[index].memoryUsed() + requriedSize > _priorityLists[index].getMemoryUsageMaximum()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Message(" + message.debugIdentity() + ") Add of size (" - + requriedSize + ") will cause flow. Searching for space"); - } - - long reclaimed = 0; - - //work down the priorities looking for memory - - //First: Don't take all the memory. So look for a queue that has more than 50% free - long currentMax; - int scavangeIndex = 0; - - if (scavangeIndex == index) - { - scavangeIndex++; - } - - while (scavangeIndex < _priorities && reclaimed <= requriedSize) - { - currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); - long used = _priorityLists[scavangeIndex].memoryUsed(); - - if (used < currentMax / 2) - { - long newMax = currentMax / 2; - - _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); - - reclaimed += currentMax - newMax; - if (_log.isDebugEnabled()) - { - _log.debug("Reclaiming(1) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); - } - break; - } - else - { - scavangeIndex++; - if (scavangeIndex == index) - { - scavangeIndex++; - } - } - } - - //Second: Just take the free memory we need - if (scavangeIndex == _priorities) - { - scavangeIndex = 0; - if (scavangeIndex == index) - { - scavangeIndex++; - } - - while (scavangeIndex < _priorities && reclaimed <= requriedSize) - { - currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); - long used = _priorityLists[scavangeIndex].memoryUsed(); - - if (used < currentMax) - { - long newMax = currentMax - used; - - // if there are no messages at this priority just take it all - if (newMax == currentMax) - { - newMax = 0; - } - - _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); - - reclaimed += currentMax - newMax; - if (_log.isDebugEnabled()) - { - _log.debug("Reclaiming(2) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); - } - break; - } - else - { - scavangeIndex++; - if (scavangeIndex == index) - { - scavangeIndex++; - } - } - } - - //Third: Take required memory - if (scavangeIndex == _priorities) - { - scavangeIndex = 0; - if (scavangeIndex == index) - { - scavangeIndex++; - } - while (scavangeIndex < _priorities && reclaimed <= requriedSize) - { - currentMax = _priorityLists[scavangeIndex].getMemoryUsageMaximum(); - - if (currentMax > 0 ) - { - long newMax = currentMax; - // Just take the amount of space required for this message. - if (newMax > requriedSize) - { - newMax = requriedSize; - } - _priorityLists[scavangeIndex].setMemoryUsageMaximum(newMax); - - reclaimed += currentMax - newMax; - if (_log.isDebugEnabled()) - { - _log.debug("Reclaiming(3) :" + (currentMax - newMax) + "(" + reclaimed + "/" + requriedSize + ") from queue:" + scavangeIndex); - } - break; - } - else - { - scavangeIndex++; - if (scavangeIndex == index) - { - scavangeIndex++; - } - } - } - } - } - - //Increment Maximum - if (reclaimed > 0) - { - if (_log.isDebugEnabled()) - { - _log.debug("Increasing queue(" + index + ") maximum by " + reclaimed - + " to " + (_priorityLists[index].getMemoryUsageMaximum() + reclaimed)); - } - _priorityLists[index].setMemoryUsageMaximum(_priorityLists[index].getMemoryUsageMaximum() + reclaimed); - } - else - { - _log.debug("No space found."); - } - - if (_log.isTraceEnabled()) - { - showUsage("Add"); - } - } - return _priorityLists[index].add(message); } - @Override - protected void showUsage(String prefix) - { - if (_log.isDebugEnabled()) - { - if (prefix.length() != 0) - { - _log.debug(prefix); - } - for (int index = 0; index < _priorities; index++) - { - QueueEntryList queueEntryList = _priorityLists[index]; - _log.debug("Queue (" + _queue.getName() + ")[" + index + "] usage:" + queueEntryList.memoryUsed() - + "/" + queueEntryList.getMemoryUsageMaximum() - + "/" + queueEntryList.dataSize()); - } - } - } public QueueEntry next(QueueEntry node) { @@ -338,122 +165,7 @@ public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implement } } - @Override - public boolean isFlowed() - { - boolean flowed = false; - boolean full = true; - - if (_log.isTraceEnabled()) - { - showUsage("isFlowed"); - } - - for (QueueEntryList queueEntryList : _priorityLists) - { - //full = full && queueEntryList.getMemoryUsageMaximum() == queueEntryList.memoryUsed(); - full = full && queueEntryList.getMemoryUsageMaximum() <= queueEntryList.dataSize(); - flowed = flowed || (queueEntryList.isFlowed()); - } - return flowed && full; - } - - @Override - public int size() - { - int size = 0; - for (QueueEntryList queueEntryList : _priorityLists) - { - size += queueEntryList.size(); - } - - return size; - } - - @Override - public long dataSize() - { - int dataSize = 0; - for (QueueEntryList queueEntryList : _priorityLists) - { - dataSize += queueEntryList.dataSize(); - } - - return dataSize; - } - - @Override - public long memoryUsed() - { - int memoryUsed = 0; - for (QueueEntryList queueEntryList : _priorityLists) - { - memoryUsed += queueEntryList.memoryUsed(); - } - - return memoryUsed; - } - - @Override - public void setMemoryUsageMaximum(long maximumMemoryUsage) - { - _memoryUsageMaximum = maximumMemoryUsage; - - if (maximumMemoryUsage >= 0) - { - _disableFlowToDisk = false; - } - - long share = maximumMemoryUsage / _priorities; - - //Apply a share of the maximum To each prioirty quue - for (QueueEntryList queueEntryList : _priorityLists) - { - queueEntryList.setMemoryUsageMaximum(share); - } - - if (maximumMemoryUsage < 0) - { - if (_log.isInfoEnabled()) - { - _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); - } - _disableFlowToDisk = true; - return; - } - - //ensure we use the full allocation of memory - long remainder = maximumMemoryUsage - (share * _priorities); - if (remainder > 0) - { - _priorityLists[_priorities - 1].setMemoryUsageMaximum(share + remainder); - } - } - - @Override - public long getMemoryUsageMaximum() - { - return _memoryUsageMaximum; - } - - @Override - public void setMemoryUsageMinimum(long minimumMemoryUsage) - { - _memoryUsageMinimum = minimumMemoryUsage; - - //Apply a share of the minimum To each prioirty quue - for (QueueEntryList queueEntryList : _priorityLists) - { - queueEntryList.setMemoryUsageMaximum(minimumMemoryUsage / _priorities); - } - } - - @Override - public long getMemoryUsageMinimum() - { - return _memoryUsageMinimum; - } - + @Override public void stop() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index b6e6365189..e6223ef4ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -155,6 +155,13 @@ public class QueueEntryImpl implements QueueEntry return (_flags & DELIVERED_TO_CONSUMER) != 0; } + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + * + * This is now also used to unload the message if this entry is on a flowed queue. As a result this method should + * only be called after the message has been sent. + */ public void setDeliveredToSubscription() { _flags |= DELIVERED_TO_CONSUMER; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index a58c6eaf7d..2bbdf610de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -63,4 +63,14 @@ public interface QueueEntryList void entryLoadedUpdateMemory(QueueEntry queueEntry); void stop(); + + /** + * Mark this queue as part of another QueueEntryList for accounting purposes. + * + * All Calls from the QueueEntry to the QueueEntryList need to check if there is + * a parent QueueEntrylist upon which the action should take place. + * + * @param queueEntryList The parent queue that is performing accounting. + */ + void setParentQueueEntryList(FlowableBaseQueueEntryList queueEntryList); } -- cgit v1.2.1 From a0067baf167cf4f2eaf912a110dd8940577af657 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 27 Mar 2009 18:23:59 +0000 Subject: Reduce logging to ease CC builds git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@759297 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index ca7fc5abf6..a7c7d87a6e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -88,9 +88,9 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList protected void showUsage(String prefix) { - if (_log.isDebugEnabled()) + if (_log.isTraceEnabled()) { - _log.debug(prefix + " Queue(" + _queue.getName() + ") usage:" + memoryUsed() + _log.trace(prefix + " Queue(" + _queue.getName() + ") usage:" + memoryUsed() + "/" + getMemoryUsageMinimum() + "<>" + getMemoryUsageMaximum() + "/" + dataSize()); } @@ -527,7 +527,10 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList //If we are still flowed and are over the minimum value then schedule to run again. if (_flowed.get() && _atomicQueueInMemory.get() > _memoryUsageMinimum) { - _log.info("Rescheduling Purger:" + _queue.getName()); + if (_log.isInfoEnabled()) + { + _log.info("Rescheduling Purger:" + _queue.getName()); + } _purger.execute(messagePurger); } } -- cgit v1.2.1 From 6d97ee3f15c3da4d3f3eecbe83fa6c84be059e2c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 1 Apr 2009 16:25:58 +0000 Subject: QPID-1764 : Add a BaseTransactionLog that takes care of handling persistent message references so that the underlying TransactionLog need not worry about that. Updated MemoryMS to use this even to ensure that the code is exercised. To ensure that the new BaseTransactionLog was correctly used when used by a TransactionLog. The configure() method now returns an Object(TransactionLog) that is the newly configured TL. Existing tests and code where the original TL reference was used have been changed to use the output of the configure() call. NOTE: the return type should be changed to TransactionLog but until we have completely split the TransactionLog and RoutingTable implementations then this is not possible. The implementation also includes a number of items from the Flow To Disk review: - The old get* Methods have been removed from the TransactionLog interface. - Rollback should now rollback enqueues. (No test provided) - StoreContext now has enqueue/dequeue methods that track the messageId/Queue pairing - The linked list per message has been reduced to a link list per message that is enqueued on multiple queues. Messages that exist on only one queue have no additional overhead. - Optimisation also included to: Include message delete in 'dequeue transaction' where the message was only ever enqueued on a single queue. All other message deletes are peformed as part of an asynchrounous commit. The asynchrounous commit is setup via the StoreContext, which has had some work done to move it towards becomming a Qpid Transaction Object where all operations are performed against rather than going via the TransactionLog. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@760951 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/IncomingMessage.java | 6 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 13 +- .../apache/qpid/server/routing/RoutingTable.java | 2 +- .../qpid/server/store/DerbyMessageStore.java | 19 +- .../qpid/server/store/MemoryMessageStore.java | 57 ++--- .../org/apache/qpid/server/store/StoreContext.java | 121 ++++++++++- .../server/transactionlog/BaseTransactionLog.java | 234 +++++++++++++++++++++ .../qpid/server/transactionlog/TransactionLog.java | 81 +++---- .../qpid/server/virtualhost/VirtualHost.java | 15 +- 9 files changed, 456 insertions(+), 92 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 5eafd281c0..bab19fbc54 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -136,11 +136,7 @@ public class IncomingMessage implements Filterable if(_destinationQueues != null) { - for (int i = 0; i < _destinationQueues.size(); i++) - { - transactionLog.enqueueMessage(_txnContext.getStoreContext(), - _destinationQueues.get(i), getMessageId()); - } + transactionLog.enqueueMessage(_txnContext.getStoreContext(), _destinationQueues, getMessageId()); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index ed9b1eb8d7..e5898ceda9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -849,7 +849,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if (entry.isPersistent() && toQueue.isDurable()) { - transactionLog.enqueueMessage(storeContext, toQueue, entry.getMessageId()); + //FIXME + //fixme + ArrayList list = new ArrayList(); + list.add(toQueue); + transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); } // dequeue will remove the messages from the queue entry.dequeue(storeContext); @@ -941,10 +945,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if (!entry.isDeleted() && entry.isPersistent() && toQueue.isDurable()) { - transactionLog.enqueueMessage(storeContext, toQueue, entry.getMessageId()); + //fixme + //FIXME + ArrayList list = new ArrayList(); + list.add(toQueue); + transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); } } + // Commit and flush the move transcations. try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java index 0c62638710..883a41b55f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java @@ -42,7 +42,7 @@ public interface RoutingTable * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; + Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 33b3d8608e..157418d806 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -34,6 +34,7 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.transactionlog.BaseTransactionLog; import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -41,7 +42,6 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.mina.common.ByteBuffer; @@ -143,7 +143,7 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable private State _state = State.INITIAL; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { //Only initialise when loaded with the old 'store' confing ignore the new 'RoutingTable' config if (base.equals("store")) @@ -178,7 +178,9 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable recover(); stateTransition(State.RECOVERING, State.STARTED); + return new BaseTransactionLog(this); } + return null; } private static synchronized void initialiseDriver() throws ClassNotFoundException @@ -825,7 +827,18 @@ public class DerbyMessageStore implements TransactionLog, RoutingTable } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void enqueueMessage(StoreContext context, ArrayList queues, Long messageId) throws AMQException + { + for (AMQQueue q : queues) + { + if (q.isDurable()) + { + enqueueMessage(context,q,messageId); + } + } + } + + void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { AMQShortString name = queue.getName(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 3754b41a3e..d57b81c362 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.store; -import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; @@ -30,17 +29,14 @@ import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.routing.RoutingTable; import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.transactionlog.BaseTransactionLog; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -67,16 +63,16 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable private final AtomicLong _messageId = new AtomicLong(1); private AtomicBoolean _closed = new AtomicBoolean(false); - protected final Map> _messageEnqueueMap = new HashMap>(); - public void configure() + public TransactionLog configure() { _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); + return new BaseTransactionLog(this); } - public void configure(String base, VirtualHostConfiguration config) + public TransactionLog configure(String base, VirtualHostConfiguration config) { //Only initialise when called with current 'store' configs i.e. don't reinit when used as a 'RoutingTable' if (base.equals("store")) @@ -85,12 +81,14 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable _log.info("Using capacity " + hashtableCapacity + " for hash tables"); _metaDataMap = new ConcurrentHashMap(hashtableCapacity); _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); + return new BaseTransactionLog(this); } + return null; } - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { - configure(base, config); + return configure(base, config); } public void close() throws Exception @@ -108,7 +106,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } } - private void removeMessage(StoreContext context, Long messageId) throws AMQException + public void removeMessage(StoreContext context, Long messageId) throws AMQException { checkNotClosed(); if (_log.isDebugEnabled()) @@ -117,7 +115,6 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable } _metaDataMap.remove(messageId); _contentBodyMap.remove(messageId); - _messageEnqueueMap.remove(messageId); } public void createExchange(Exchange exchange) throws AMQException @@ -155,41 +152,25 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable // Not required to do anything } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void enqueueMessage(StoreContext context, final ArrayList queues, Long messageId) throws AMQException { - synchronized (_messageEnqueueMap) + for (AMQQueue q : queues) { - List queues = _messageEnqueueMap.get(messageId); - if (queues == null) + if (q.isDurable()) { - queues = new LinkedList(); - _messageEnqueueMap.put(messageId, queues); + enqueueMessage(context,q,messageId); } - - queues.add(queue); } } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException { - synchronized (_messageEnqueueMap) - { - List queues = _messageEnqueueMap.get(messageId); - if (queues == null || !queues.contains(queue)) - { - throw new RuntimeException("Attempt to dequeue messageID:" + messageId + " from queue:" + queue.getName() - + " but it is not enqueued on that queue."); - } - else - { - queues.remove(queue); - if (queues.isEmpty()) - { - removeMessage(context,messageId); - } - } - } + // Not required to do anything + } + public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + { + // Not required to do anything } public void beginTran(StoreContext context) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index fdb56a1a55..b5ae8ea284 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -21,6 +21,12 @@ package org.apache.qpid.server.store; import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQQueue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; /** * A context that the store can use to associate with a transactional context. For example, it could store @@ -32,17 +38,37 @@ public class StoreContext { private static final Logger _logger = Logger.getLogger(StoreContext.class); + private static final String DEFAULT_NAME = "StoreContext"; private String _name; private Object _payload; + private HashMap> _enqueueMap; + private HashMap> _dequeueMap; + private boolean _async; public StoreContext() { - _name = "StoreContext"; + this(DEFAULT_NAME); } public StoreContext(String name) + { + this(name,false); + } + + /** + * + * @param name The name of this Transaction + * @param asynchrouous Is this Transaction Asynchronous + */ + public StoreContext(String name, boolean asynchrouous) { _name = name; + _async = asynchrouous; + } + + public StoreContext(boolean asynchronous) + { + this(DEFAULT_NAME, asynchronous); } public Object getPayload() @@ -52,7 +78,7 @@ public class StoreContext public void setPayload(Object payload) { - if(_logger.isDebugEnabled()) + if (_logger.isDebugEnabled()) { _logger.debug("public void setPayload(Object payload = " + payload + "): called"); } @@ -68,4 +94,95 @@ public class StoreContext { return "<_name = " + _name + ", _payload = " + _payload + ">"; } + + public Map> getEnqueueMap() + { + return _enqueueMap; + } + + public Map> getDequeueMap() + { + return _dequeueMap; + } + + /** + * Record the enqueues for processing if we abort + * + * @param queues + * @param messageId + * + * @throws AMQException + */ + public void enqueueMessage(ArrayList queues, Long messageId) throws AMQException + { + if (inTransaction()) + { + ArrayList enqueues = _enqueueMap.get(messageId); + + if (enqueues == null) + { + enqueues = new ArrayList(); + _enqueueMap.put(messageId, enqueues); + } + + for (AMQQueue q : queues) + { + if (!enqueues.contains(q)) + { + enqueues.add(q); + } + } + + } + } + + /** + * Record the dequeue for processing on commit + * + * @param queue + * @param messageId + * + * @throws AMQException + */ + public void dequeueMessage(AMQQueue queue, Long messageId) throws AMQException + { + if (inTransaction()) + { + ArrayList dequeues = _dequeueMap.get(messageId); + + if (dequeues == null) + { + dequeues = new ArrayList(); + _dequeueMap.put(messageId, dequeues); + } + + dequeues.add(queue); + } + } + + public void beginTransaction() throws AMQException + { + _enqueueMap = new HashMap>(); + _dequeueMap = new HashMap>(); + } + + public void commitTransaction() throws AMQException + { + _dequeueMap.clear(); + } + + public void abortTransaction() throws AMQException + { + _enqueueMap.clear(); + } + + public boolean inTransaction() + { + return _payload != null; + } + + public boolean isAsync() + { + return _async; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java new file mode 100644 index 0000000000..4c3f1fcc49 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -0,0 +1,234 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transactionlog; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class BaseTransactionLog implements TransactionLog +{ + private static final Logger _logger = Logger.getLogger(BaseTransactionLog.class); + + TransactionLog _delegate; + private Map> _idToQueues = new HashMap>(); + + public BaseTransactionLog(TransactionLog delegate) + { + _delegate = delegate; + } + + public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + return _delegate.configure(virtualHost, base, config); + } + + public void close() throws Exception + { + _delegate.close(); + } + + public void enqueueMessage(StoreContext context, ArrayList queues, Long messageId) throws AMQException + { + context.enqueueMessage(queues, messageId); + + if (queues.size() > 0) + { + _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); + + //Clone the list incase someone else changes it. + _idToQueues.put(messageId, (ArrayList) queues.clone()); + } + + _delegate.enqueueMessage(context, queues, messageId); + } + + public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException + { + if (context.inTransaction()) + { + context.dequeueMessage(queue, messageId); + + Map> messageMap = context.getDequeueMap(); + + //For each Message ID that is in the map check + for (Long messageID : messageMap.keySet()) + { + //If we don't have a gloabl reference for this message then there is only a single enqueue + if (_idToQueues.get(messageID) == null) + { + // Add the removal of the message to this transaction + _delegate.removeMessage(context,messageID); + // Remove this message ID as we have processed it so we don't reprocess after the main commmit + messageMap.remove(messageID); + } + } + } + + _delegate.dequeueMessage(context, queue, messageId); + + if (!context.inTransaction()) + { + HashMap> dequeue = new HashMap>(); + ArrayList list = new ArrayList(); + list.add(queue); + dequeue.put(messageId, list); + processDequeues(dequeue); + } + } + + /** + * This should not be called from main broker code. + * // Perhaps we need a new interface: + * + * Broker <->TransactionLog + * Broker <->BaseTransactionLog<->(Log with removeMessage()) + */ + public void removeMessage(StoreContext context, Long messageId) throws AMQException + { + _delegate.removeMessage(context, messageId); + } + + public void beginTran(StoreContext context) throws AMQException + { + context.beginTransaction(); + _delegate.beginTran(context); + } + + public void commitTran(StoreContext context) throws AMQException + { + //Perform real commit of current data + _delegate.commitTran(context); + + // If we have dequeues to process then process them + if (context.getDequeueMap() != null) + { + processDequeues(context.getDequeueMap()); + } + + //Commit the recorded state for this transaction. + context.commitTransaction(); + } + + public void abortTran(StoreContext context) throws AMQException + { + // If we have enqueues to rollback + if (context.getEnqueueMap() != null) + { + processDequeues(context.getEnqueueMap()); + } + //Abort the recorded state for this transaction. + context.abortTransaction(); + + _delegate.abortTran(context); + } + + private void processDequeues(Map> messageMap) + throws AMQException + { + // Process any enqueues to bring our model up to date. + Set messageIDs = messageMap.keySet(); + + //Create a new Asynchronous Context. + StoreContext removeContext = new StoreContext(true); + + //Batch Process the Dequeues on the delegate + _delegate.beginTran(removeContext); + + try + { + //For each Message ID Decrement the reference for each of the queues it was on. + for (Long messageID : messageIDs) + { + ArrayList queueList = messageMap.get(messageID); + + // For each of the queues decrement the reference + for (AMQQueue queue : queueList) + { + ArrayList enqueuedList = _idToQueues.get(messageID); + + // If we have no mapping then this message was only enqueued on a single queue + // This will be the case when we are not in a larger transaction + if (enqueuedList == null) + { + _delegate.removeMessage(removeContext, messageID); + } + else + { + // Update the enqueued list + enqueuedList.remove(queue); + + // If the list is now empty then remove the message + if (enqueuedList.isEmpty()) + { + _delegate.removeMessage(removeContext, messageID); + } + } + } + } + + //Commit the removes on the delegate. + _delegate.commitTran(removeContext); + } + finally + { + if (removeContext.inTransaction()) + { + _delegate.abortTran(removeContext); + } + } + } + + public boolean inTran(StoreContext context) + { + return _delegate.inTran(context); + } + + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException + { + _delegate.storeContentBodyChunk(context, messageId, index, contentBody, lastContentBody); + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException + { + _delegate.storeMessageMetaData(context, messageId, messageMetaData); + } + + public boolean isPersistent() + { + return _delegate.isPersistent(); + } + + public TransactionLog getDelegate() + { + return _delegate; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java index 97a1ecb38c..73d57df6e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java @@ -20,19 +20,16 @@ */ package org.apache.qpid.server.transactionlog; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.store.StoreContext; +import java.util.ArrayList; + /** * TransactionLog defines the interface for performing transactions. * This is used to preserve the state of messages, queues @@ -68,7 +65,7 @@ public interface TransactionLog * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; + Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; /** * Called to close and cleanup any resources used by the message store. @@ -81,27 +78,33 @@ public interface TransactionLog * Places a message onto a specified queue, in a given transactional context. * * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to enqueue. - * @throws AMQException If the operation fails for any reason. + * @param queues + *@param messageId The message to enqueue. @throws AMQException If the operation fails for any reason. @throws org.apache.qpid.AMQException */ - void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + void enqueueMessage(StoreContext context, final ArrayList queues, Long messageId) throws AMQException; /** * Extracts a message from a specified queue, in a given transactional context. * * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to dequeue. - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + * @param queue + * @param messageId The message to dequeue. @throws AMQException If the operation fails for any reason, or if the specified message does not exist. */ void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + /** + * Remove the specified message from the log + * + * @param context The transactional context for the operation + * @param messageId The message to remove + * @throws AMQException + */ + void removeMessage(StoreContext context, Long messageId) throws AMQException; + /** * Begins a transactional context. * * @param context The transactional context to begin. - * * @throws AMQException If the operation fails for any reason. */ void beginTran(StoreContext context) throws AMQException; @@ -158,31 +161,31 @@ public interface TransactionLog * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. */ void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - - /** - * Retrieves message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the meta-data for. - * - * @return The message meta data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - - /** - * Retrieves a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the data chunk for. - * @param index The offset index of the data chunk within the message. - * - * @return A chunk of message data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; +// +// /** +// * Retrieves message meta-data. +// * +// * @param context The transactional context for the operation. +// * @param messageId The message to get the meta-data for. +// * +// * @return The message meta data. +// * +// * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. +// */ +// MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; +// +// /** +// * Retrieves a chunk of message data. +// * +// * @param context The transactional context for the operation. +// * @param messageId The message to get the data chunk for. +// * @param index The offset index of the data chunk within the message. +// * +// * @return A chunk of message data. +// * +// * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. +// */ +// ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; /** * Is this store capable of persisting the data diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 8a8cbd23cf..7bcfb9f59a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -51,6 +51,7 @@ import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.transactionlog.TransactionLog; +import org.apache.qpid.server.transactionlog.BaseTransactionLog; import javax.management.NotCompliantMBeanException; import java.util.Collections; @@ -206,6 +207,14 @@ public class VirtualHost implements Accessable { _routingTable = (RoutingTable) _transactionLog; } + else if (_transactionLog instanceof BaseTransactionLog) + { + TransactionLog delegate = ((BaseTransactionLog) _transactionLog).getDelegate(); + if (delegate instanceof RoutingTable) + { + _routingTable = (RoutingTable) delegate; + } + } } else { @@ -292,7 +301,8 @@ public class VirtualHost implements Accessable _routingTable = (RoutingTable) _transactionLog; } - _transactionLog.configure(this, "store", config); + // If a TransactionLog uses the BaseTransactionLog then it will return this object. + _transactionLog = (TransactionLog) _transactionLog.configure(this, "store", config); } //todo we need to move from store.class to transactionlog.class @@ -497,8 +507,9 @@ public class VirtualHost implements Accessable public List queue = new LinkedList(); public List bindings = new LinkedList(); - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { + return null; } public void close() throws Exception -- cgit v1.2.1 From 74981f1d496018b32ec07c751947e85b5e54c7c0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 1 Apr 2009 16:26:50 +0000 Subject: QPID-1783 : Relax MessageFactory to allow out of order recovery Relax MessageFactory to allow out of order. Updated test git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@760952 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/MessageFactory.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java index 9924733178..10e7dca18f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java @@ -85,17 +85,13 @@ public class MessageFactory throw new RuntimeException("Unable to create message by ID when not recovering"); } - long currentID = _messageId.get(); - if (messageId <= currentID) + if (messageId < 0L) { - throw new RuntimeException("Message IDs can only increase current id is:" - + currentID + ". Requested:" + messageId); - } - else - { - _messageId.set(messageId); + throw new RuntimeException("Message IDs can only be positive. Requested:" + messageId); } + _messageId.set((int)Math.max(messageId, _messageId.get())); + return createNextMessage(messageId, transactionLog, true); } -- cgit v1.2.1 From 829915afb74777469df68be7fb234ae7771c8053 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Apr 2009 13:26:55 +0000 Subject: QPID-1764 : Update to BaseTransactionLog to create a TestableTransactionLog, which will replace TestableMessageStore. Update to BaseTransactionLog/Test to work correctly with transactions and to fully test that functionality. Updated StoreContext to know when it is in a transaction as relying on a payload being set is not sufficient as that is not set when running with the MessageMemoryStore and so transactional testing in the BTLT was not correct. Update to Virtualhost to correctly set the RoutingTable when the specified TransactionLog is wrapped in a BaseTransactionLog. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761670 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/store/StoreContext.java | 32 ++++++++++---------- .../server/transactionlog/BaseTransactionLog.java | 34 ++++++++++------------ .../qpid/server/virtualhost/VirtualHost.java | 13 +++++++-- 3 files changed, 44 insertions(+), 35 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index b5ae8ea284..bb50df139f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -44,6 +44,7 @@ public class StoreContext private HashMap> _enqueueMap; private HashMap> _dequeueMap; private boolean _async; + private boolean _inTransaction; public StoreContext() { @@ -64,6 +65,9 @@ public class StoreContext { _name = name; _async = asynchrouous; + _inTransaction = false; + _enqueueMap = new HashMap>(); + _dequeueMap = new HashMap>(); } public StoreContext(boolean asynchronous) @@ -82,7 +86,7 @@ public class StoreContext { _logger.debug("public void setPayload(Object payload = " + payload + "): called"); } - _payload = payload; + _payload = payload; } /** @@ -137,7 +141,7 @@ public class StoreContext } /** - * Record the dequeue for processing on commit + * Record the dequeue for processing after the commit * * @param queue * @param messageId @@ -146,39 +150,37 @@ public class StoreContext */ public void dequeueMessage(AMQQueue queue, Long messageId) throws AMQException { - if (inTransaction()) - { - ArrayList dequeues = _dequeueMap.get(messageId); + ArrayList dequeues = _dequeueMap.get(messageId); - if (dequeues == null) - { - dequeues = new ArrayList(); - _dequeueMap.put(messageId, dequeues); - } - - dequeues.add(queue); + if (dequeues == null) + { + dequeues = new ArrayList(); + _dequeueMap.put(messageId, dequeues); } + + dequeues.add(queue); } public void beginTransaction() throws AMQException { - _enqueueMap = new HashMap>(); - _dequeueMap = new HashMap>(); + _inTransaction = true; } public void commitTransaction() throws AMQException { _dequeueMap.clear(); + _inTransaction = false; } public void abortTransaction() throws AMQException { _enqueueMap.clear(); + _inTransaction = false; } public boolean inTransaction() { - return _payload != null; + return _inTransaction; // _payload != null; } public boolean isAsync() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index 4c3f1fcc49..973ecd6c09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -39,7 +39,7 @@ public class BaseTransactionLog implements TransactionLog private static final Logger _logger = Logger.getLogger(BaseTransactionLog.class); TransactionLog _delegate; - private Map> _idToQueues = new HashMap>(); + protected Map> _idToQueues = new HashMap>(); public BaseTransactionLog(TransactionLog delegate) { @@ -60,7 +60,7 @@ public class BaseTransactionLog implements TransactionLog { context.enqueueMessage(queues, messageId); - if (queues.size() > 0) + if (queues.size() > 1) { _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); @@ -73,10 +73,10 @@ public class BaseTransactionLog implements TransactionLog public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException { + context.dequeueMessage(queue, messageId); + if (context.inTransaction()) { - context.dequeueMessage(queue, messageId); - Map> messageMap = context.getDequeueMap(); //For each Message ID that is in the map check @@ -97,11 +97,7 @@ public class BaseTransactionLog implements TransactionLog if (!context.inTransaction()) { - HashMap> dequeue = new HashMap>(); - ArrayList list = new ArrayList(); - list.add(queue); - dequeue.put(messageId, list); - processDequeues(dequeue); + processDequeues(context.getDequeueMap()); } } @@ -128,11 +124,7 @@ public class BaseTransactionLog implements TransactionLog //Perform real commit of current data _delegate.commitTran(context); - // If we have dequeues to process then process them - if (context.getDequeueMap() != null) - { - processDequeues(context.getDequeueMap()); - } + processDequeues(context.getDequeueMap()); //Commit the recorded state for this transaction. context.commitTransaction(); @@ -141,10 +133,8 @@ public class BaseTransactionLog implements TransactionLog public void abortTran(StoreContext context) throws AMQException { // If we have enqueues to rollback - if (context.getEnqueueMap() != null) - { - processDequeues(context.getEnqueueMap()); - } + processDequeues(context.getEnqueueMap()); + //Abort the recorded state for this transaction. context.abortTransaction(); @@ -154,6 +144,12 @@ public class BaseTransactionLog implements TransactionLog private void processDequeues(Map> messageMap) throws AMQException { + // Check we have dequeues to process then process them + if (messageMap == null || messageMap.isEmpty()) + { + return; + } + // Process any enqueues to bring our model up to date. Set messageIDs = messageMap.keySet(); @@ -190,6 +186,8 @@ public class BaseTransactionLog implements TransactionLog if (enqueuedList.isEmpty()) { _delegate.removeMessage(removeContext, messageID); + //Remove references list + _idToQueues.remove(messageID); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 7bcfb9f59a..dc12d97557 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -295,14 +295,23 @@ public class VirtualHost implements Accessable } _transactionLog = (TransactionLog) o; + // If a TransactionLog uses the BaseTransactionLog then it will return this object. + _transactionLog = (TransactionLog) _transactionLog.configure(this, "store", config); + //Assign RoutingTable as old MessageStores converted to TransactionLog will require the _routingTable. if (_transactionLog instanceof RoutingTable) { _routingTable = (RoutingTable) _transactionLog; } + else if (_transactionLog instanceof BaseTransactionLog) + { + TransactionLog delegate = ((BaseTransactionLog) _transactionLog).getDelegate(); + if (delegate instanceof RoutingTable) + { + _routingTable = (RoutingTable) delegate; + } + } - // If a TransactionLog uses the BaseTransactionLog then it will return this object. - _transactionLog = (TransactionLog) _transactionLog.configure(this, "store", config); } //todo we need to move from store.class to transactionlog.class -- cgit v1.2.1 From eef4cf28ebb5d45f0b44009b18be1cc36df39073 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Apr 2009 13:33:42 +0000 Subject: QPID-1784 Update to FlowableBaseQueueEntryList to ensure that the inhaler and purger threads will stop when the inMemory values are within the correct range. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761671 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/queue/FlowableBaseQueueEntryList.java | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index a7c7d87a6e..10d2f0ee2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -359,7 +359,12 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList _asynchronousInhaler.compareAndSet(messageInhaler, null); int inhaled = 1; + //Because we may not be able to totally fill up to _memoryUsageMaximum we need to be able to say we've done + // enough loading and this inhale process should stop + boolean finshedInhaling = false; + while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) // we havn't filled our max memory + && !finshedInhaling // Have we loaded all we can fit into memory && (_atomicQueueInMemory.get() < _atomicQueueSize.get()) // we haven't loaded all that is available && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do && (inhaled > 0) // ensure we could inhale something @@ -379,7 +384,9 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList // we won't have checked the last entry to see if we can load it. So create atEndofList and update it based // on the return from advance() which returns true if it can advance. boolean atEndofList = false; - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) // we havn't filled our max memory + + while ((_atomicQueueInMemory.get() <= _memoryUsageMaximum) // we haven't filled our max memory + && !finshedInhaling // Have we loaded all we can fit into memory && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do && !atEndofList) // We have reached end of list QueueEntries { @@ -394,7 +401,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList { _log.debug("Entry won't fit in memory stopping inhaler:" + entry.debugIdentity()); } - inhaled = BATCH_PROCESS_COUNT; + finshedInhaling = true; } else { @@ -421,7 +428,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. - if (_flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) + if (!finshedInhaling _flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) { if (_log.isInfoEnabled()) { @@ -471,7 +478,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList _asynchronousPurger.compareAndSet(messagePurger, null); int purged = 0; - while ((_atomicQueueInMemory.get() > _memoryUsageMinimum) + while ((_atomicQueueInMemory.get() > _memoryUsageMaximum) && purged < BATCH_PROCESS_COUNT && _asynchronousPurger.compareAndSet(null, messagePurger)) { @@ -496,6 +503,12 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList if (entry.isAvailable() && !entry.isFlowed()) { memoryUsage += entry.getSize(); + // If this message is what puts us over the limit then break + // out of this loop as we need to purge this item. + if (memoryUsage > _memoryUsageMaximum) + { + break; + } } atTail = !iterator.advance(); @@ -525,7 +538,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } //If we are still flowed and are over the minimum value then schedule to run again. - if (_flowed.get() && _atomicQueueInMemory.get() > _memoryUsageMinimum) + if (_flowed.get() && _atomicQueueInMemory.get() > _memoryUsageMaximum) { if (_log.isInfoEnabled()) { -- cgit v1.2.1 From 70bb32c02ee6102eec92648101819d2cbbd3c8c9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Apr 2009 13:46:43 +0000 Subject: QPID-1784 : Fixed compile error git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761674 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java index 10d2f0ee2b..b252c7304e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java @@ -428,7 +428,7 @@ public abstract class FlowableBaseQueueEntryList implements QueueEntryList } //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. - if (!finshedInhaling _flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) + if (!finshedInhaling && _flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) { if (_log.isInfoEnabled()) { -- cgit v1.2.1 From e03c0b0113aa67f1dd20e94cc8e49a6934cd77e6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Apr 2009 14:46:29 +0000 Subject: QPID-1764 : Resolved ConcurrentME. Perils of using the 'syntax sugar' for loop hides the message iterator that you need to call .remove(). Calling remove on the underlying Map will cause the resulting CME. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761700 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transactionlog/BaseTransactionLog.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index 973ecd6c09..dded7f7142 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.Iterator; public class BaseTransactionLog implements TransactionLog { @@ -80,15 +81,18 @@ public class BaseTransactionLog implements TransactionLog Map> messageMap = context.getDequeueMap(); //For each Message ID that is in the map check - for (Long messageID : messageMap.keySet()) + Iterator iterator = messageMap.keySet().iterator(); + + while (iterator.hasNext()) { + Long messageID = (Long) iterator.next(); //If we don't have a gloabl reference for this message then there is only a single enqueue if (_idToQueues.get(messageID) == null) { // Add the removal of the message to this transaction _delegate.removeMessage(context,messageID); // Remove this message ID as we have processed it so we don't reprocess after the main commmit - messageMap.remove(messageID); + iterator.remove(); } } } @@ -179,6 +183,15 @@ public class BaseTransactionLog implements TransactionLog } else { + //When a message is on more than one queue it is possible that this code section is exectuted + // by one thread per enqueue. + // It is however, thread safe because there is only removes being performed and so the + // last thread that does the remove will see the empty queue and remove the message + // At this stage there is nothing that is going to cause this operation to abort. So we don't + // need to worry about any potential adds. + // The message will no longer be enqueued as that operation has been committed before now so + // this is clean up of the data. + // Update the enqueued list enqueuedList.remove(queue); @@ -195,6 +208,8 @@ public class BaseTransactionLog implements TransactionLog //Commit the removes on the delegate. _delegate.commitTran(removeContext); + // Mark this context as committed. + removeContext.commitTransaction(); } finally { -- cgit v1.2.1 From b2e264634b9742c592af8cbaf40835e3a296f1b5 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 3 Apr 2009 16:36:14 +0000 Subject: QPID-1730: make it easy to configure queues, fix inheriting settings from the virtualhost. AMQQueue.configure: new method AMQQueueFactory: use AMQQueue.configure, don't set things directly SimpleAMQQueue.configure, MockAMQQueue.configure: implement new method from the interface QueueConfiguration: use VirtualHostConfiguration for default values if they're unset VirtualHostConfiguration: if a queue doesn't exist, give it a default configuration. Add methods to get default settings for configuration items QueueConfigurationTest: test case, checks that inheritance and defaults work along with explicitly set values. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761721 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/QueueConfiguration.java | 22 ++++++------- .../configuration/VirtualHostConfiguration.java | 36 +++++++++++++++++++++- .../org/apache/qpid/server/queue/AMQQueue.java | 2 ++ .../apache/qpid/server/queue/AMQQueueFactory.java | 8 +---- .../apache/qpid/server/queue/SimpleAMQQueue.java | 15 +++++++++ 5 files changed, 62 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index e6c5dee90d..256d15e7db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -21,30 +21,26 @@ package org.apache.qpid.server.configuration; import java.util.List; -import java.io.File; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.registry.ApplicationRegistry; public class QueueConfiguration { - - // FIXME AIDAN XXX -- deal with defaults private Configuration _config; private String _name; - private VirtualHostConfiguration _virtualHostConfiguration; + private VirtualHostConfiguration _vHostConfig; public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) { - _virtualHostConfiguration = virtualHostConfiguration; + _vHostConfig = virtualHostConfiguration; _config = config; _name = name; } public VirtualHostConfiguration getVirtualHostConfiguration() { - return _virtualHostConfiguration; + return _vHostConfig; } public boolean getDurable() @@ -87,29 +83,29 @@ public class QueueConfiguration return _name; } - public long getMaximumMessageAge() + public int getMaximumMessageAge() { - return _config.getLong("maximumMessageAge", 0); + return _config.getInt("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); } public long getMaximumQueueDepth() { - return _config.getLong("maximumQueueDepth", 0); + return _config.getLong("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth()); } public long getMaximumMessageSize() { - return _config.getLong("maximumMessageSize", 0); + return _config.getLong("maximumMessageSize", _vHostConfig.getMaximumMessageSize()); } public long getMaximumMessageCount() { - return _config.getLong("maximumMessageCount", 0); + return _config.getLong("maximumMessageCount", _vHostConfig.getMaximumMessageCount()); } public long getMinimumAlertRepeatGap() { - return _config.getLong("minimumAlertRepeatGap", 0); + return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); } public long getMemoryUsageMaximum() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 343abe4b5a..8d9f848b49 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -142,7 +142,16 @@ public class VirtualHostConfiguration public QueueConfiguration getQueueConfiguration(String queueName) { - return _queues.get(queueName); + // We might be asked for the config for a queue we don't know about, + // such as one that's been dynamically created. Those get the defaults by default. + if (_queues.containsKey(queueName)) + { + return _queues.get(queueName); + } + else + { + return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); + } } public long getMemoryUsageMaximum() @@ -166,4 +175,29 @@ public class VirtualHostConfiguration return _config.getString(FLOW_TO_DISK_PATH, getServerConfiguration().getQpidWork()); } + public int getMaximumMessageAge() + { + return _config.getInt("queues.maximumMessageAge", 0); + } + + public Long getMaximumQueueDepth() + { + return _config.getLong("queues.maximumQueueDepth", 0); + } + + public Long getMaximumMessageSize() + { + return _config.getLong("queues.maximumMessageSize", 0); + } + + public Long getMaximumMessageCount() + { + return _config.getLong("queues.maximumMessageCount", 0); + } + + public Long getMinimumAlertRepeatGap() + { + return _config.getLong("queues.minimumAlertRepeatGap", 0); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 43ec6c4d15..fae219e320 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -215,4 +215,6 @@ public interface AMQQueue extends Managable, Comparable { public void doTask(AMQQueue queue) throws AMQException; } + + void configure(QueueConfiguration config); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 6ba22321f1..b77a9d8f6a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -134,13 +134,7 @@ public class AMQQueueFactory } AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); - q.setMaximumMessageAge(config.getMaximumMessageAge()); - q.setMaximumQueueDepth(config.getMaximumQueueDepth()); - q.setMaximumMessageSize(config.getMaximumMessageSize()); - q.setMaximumMessageCount(config.getMaximumMessageCount()); - q.setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); - q.setMemoryUsageMaximum(config.getMemoryUsageMaximum()); - q.setMemoryUsageMinimum(config.getMemoryUsageMinimum()); + q.configure(config); return q; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index e5898ceda9..6805d8261e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -19,6 +19,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -1627,4 +1628,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { return getType() + "[Owner:" + _owner + "][Durable:" + _durable + "]"; } + + public void configure(QueueConfiguration config) + { + if (config != null) + { + setMaximumMessageAge(config.getMaximumMessageAge()); + setMaximumQueueDepth(config.getMaximumQueueDepth()); + setMaximumMessageSize(config.getMaximumMessageSize()); + setMaximumMessageCount(config.getMaximumMessageCount()); + setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); + setMemoryUsageMaximum(config.getMemoryUsageMaximum()); + setMemoryUsageMinimum(config.getMemoryUsageMinimum()); + } + } } -- cgit v1.2.1 From 2245b51ef87f73e38536c0a09309fcb6ae9ea6f2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 3 Apr 2009 17:54:44 +0000 Subject: QPID-1764 : Updated all tests to use the TestTransactionLog interface and split testing code into subclasses. TestableTransactionLog will now correctly wrap a TransactionLog for testing. To enable testing of the BaseTransactionLog a TestableBaseTransactionLog was needed to only return values that are actually stored in the BaseTL the TestableTransactionLog actually stores single enqueues so that they can be queried by the test. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@761741 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/MemoryMessageStore.java | 24 +++------------------- 1 file changed, 3 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index d57b81c362..f5819716cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -51,7 +51,7 @@ import java.util.concurrent.atomic.AtomicLong; */ public class MemoryMessageStore implements TransactionLog, RoutingTable { - private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); + protected static final Logger _log = Logger.getLogger(MemoryMessageStore.class); private static final int DEFAULT_HASHTABLE_CAPACITY = 50000; @@ -154,13 +154,7 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable public void enqueueMessage(StoreContext context, final ArrayList queues, Long messageId) throws AMQException { - for (AMQQueue q : queues) - { - if (q.isDurable()) - { - enqueueMessage(context,q,messageId); - } - } + // Not required to do anything } public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException @@ -232,25 +226,13 @@ public class MemoryMessageStore implements TransactionLog, RoutingTable _metaDataMap.put(messageId, messageMetaData); } - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - checkNotClosed(); - return _metaDataMap.get(messageId); - } - - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - checkNotClosed(); - List bodyList = _contentBodyMap.get(messageId); - return bodyList.get(index); - } public boolean isPersistent() { return false; } - private void checkNotClosed() throws MessageStoreClosedException + protected void checkNotClosed() throws MessageStoreClosedException { if (_closed.get()) { -- cgit v1.2.1 From a9380a46db39464134dd97fa4c2a890a221bbc71 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 6 Apr 2009 14:45:33 +0000 Subject: QPID-1790: add new attribute to logging management mbean to indicate available output levels. Update jmx management console to understand String[] attribute value and display contents properly git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@762365 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/management/LoggingManagement.java | 7 +++++++ .../server/logging/management/LoggingManagementMBean.java | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java index 79d60a6df0..f723ab206c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java @@ -47,6 +47,13 @@ public interface LoggingManagement description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") Integer getLog4jLogWatchInterval(); + /** + * Attribute to represent the available log4j logger output levels. + * @return The logging level names. + */ + @MBeanAttribute(name="AvailableLoggerLevels", description = "The values to which log output level can be set.") + String[] getAvailableLoggerLevels(); + //****** log4j runtime operations ****** // diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index f84cbbd786..cd3f85f8ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -69,7 +69,10 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); private String _log4jConfigFileName; private int _log4jLogWatchInterval; - + private static final String[] LEVELS = new String[]{Level.ALL.toString(), Level.TRACE.toString(), + Level.DEBUG.toString(), Level.INFO.toString(), + Level.WARN.toString(), Level.ERROR.toString(), + Level.FATAL.toString(),Level.OFF.toString()}; static TabularType _loggerLevelTabularType; static CompositeType _loggerLevelCompositeType; @@ -108,7 +111,11 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM { return _log4jLogWatchInterval; } - + + public String[] getAvailableLoggerLevels() + { + return LEVELS; + } @SuppressWarnings("unchecked") public synchronized boolean setRuntimeLoggerLevel(String logger, String level) { -- cgit v1.2.1 From e414722c8ea7a3f71f565130e86558a85233d79c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 7 Apr 2009 22:08:02 +0000 Subject: QPID-1792: make JMXManagedObjectRegistry.close() method attempt to de-register only qpid related MBeans, preventing the RuntimeException that is a result of attempting to de-register the platform MBeanServerDelegate MBean, which is not allowed. Also remove unused imports. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@762992 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 3fc460b325..5a113de5be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -25,21 +25,14 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; -import javax.management.InstanceNotFoundException; import javax.management.JMException; -import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; import javax.management.remote.rmi.RMIConnectorServer; @@ -342,7 +335,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry return false; } - // stops the RMIRegistry, if it was running and bound to a port + // stops the RMIRegistry and unregisters the MBeans from the MBeanServer public void close() throws RemoteException { if (_rmiRegistry != null) @@ -350,7 +343,19 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry // Stopping the RMI registry UnicastRemoteObject.unexportObject(_rmiRegistry, true); } - for (ObjectName name : _mbeanServer.queryNames(null, null)) + + //ObjectName query to gather all Qpid related MBeans + ObjectName mbeanNameQuery = null; + try + { + mbeanNameQuery = new ObjectName(ManagedObject.DOMAIN + ":*"); + } + catch (Exception e1) + { + _log.warn("Unable to generate MBean ObjectName query for close operation"); + } + + for (ObjectName name : _mbeanServer.queryNames(mbeanNameQuery, null)) { try { @@ -358,7 +363,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } catch (JMException e) { - // Really shouldn't happen, but we'll ignore that... + _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage()); } } } -- cgit v1.2.1 From 091364abd873861ea9591e99fc48816cca2544ed Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 8 Apr 2009 19:43:33 +0000 Subject: QPID-1793 : Increase logging on requeue to help diagnose what is being requeued. Not on critical path so logging should not impact performance. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@763360 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQChannel.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 72a2780c32..dcbd887896 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -467,7 +467,15 @@ public class AMQChannel { if (_log.isInfoEnabled()) { - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + // Requeue only occurs on connection close so this extra processing should not be a bottleneck + List ids=new LinkedList(); + for (QueueEntry entry: messagesToBeDelivered) + { + ids.add(entry.getMessageId()); + } + + _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages(" + ids + "). " + + "for " + toString()); } if (!(_txnContext instanceof NonTransactionalContext)) -- cgit v1.2.1 From 05fa2676fa1a25759b169dc1d43cec7111ccdbb7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 8 Apr 2009 19:44:34 +0000 Subject: QPID-1794 : Clear the StoreContext after non-transactional processing. Updated BaseTransactionLog to synchronize the on the enqueued messages from the _idToQueue Map as this will be being modified by many ack-ing threads and closing/requeue threads. Updated BaseTransactionLogTest so that it uses a single StoreContext per test rather than a fresh context for each operation. This was masking the problem. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@763361 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/store/StoreContext.java | 74 +++------- .../server/transactionlog/BaseTransactionLog.java | 153 ++++++++++++++------- .../qpid/server/transactionlog/TransactionLog.java | 6 + 3 files changed, 131 insertions(+), 102 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index bb50df139f..26892868f3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -27,6 +27,8 @@ import org.apache.qpid.server.queue.AMQQueue; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.List; +import java.util.Collections; /** * A context that the store can use to associate with a transactional context. For example, it could store @@ -41,8 +43,7 @@ public class StoreContext private static final String DEFAULT_NAME = "StoreContext"; private String _name; private Object _payload; - private HashMap> _enqueueMap; - private HashMap> _dequeueMap; + private Map> _dequeueMap; private boolean _async; private boolean _inTransaction; @@ -53,12 +54,11 @@ public class StoreContext public StoreContext(String name) { - this(name,false); + this(name, false); } /** - * - * @param name The name of this Transaction + * @param name The name of this Transaction * @param asynchrouous Is this Transaction Asynchronous */ public StoreContext(String name, boolean asynchrouous) @@ -66,8 +66,7 @@ public class StoreContext _name = name; _async = asynchrouous; _inTransaction = false; - _enqueueMap = new HashMap>(); - _dequeueMap = new HashMap>(); + _dequeueMap = Collections.synchronizedMap(new HashMap>()); } public StoreContext(boolean asynchronous) @@ -86,7 +85,7 @@ public class StoreContext { _logger.debug("public void setPayload(Object payload = " + payload + "): called"); } - _payload = payload; + _payload = payload; } /** @@ -99,49 +98,13 @@ public class StoreContext return "<_name = " + _name + ", _payload = " + _payload + ">"; } - public Map> getEnqueueMap() - { - return _enqueueMap; - } - - public Map> getDequeueMap() + public Map> getDequeueMap() { return _dequeueMap; } /** - * Record the enqueues for processing if we abort - * - * @param queues - * @param messageId - * - * @throws AMQException - */ - public void enqueueMessage(ArrayList queues, Long messageId) throws AMQException - { - if (inTransaction()) - { - ArrayList enqueues = _enqueueMap.get(messageId); - - if (enqueues == null) - { - enqueues = new ArrayList(); - _enqueueMap.put(messageId, enqueues); - } - - for (AMQQueue q : queues) - { - if (!enqueues.contains(q)) - { - enqueues.add(q); - } - } - - } - } - - /** - * Record the dequeue for processing after the commit + * Record the dequeue for processing after the commit * * @param queue * @param messageId @@ -150,15 +113,22 @@ public class StoreContext */ public void dequeueMessage(AMQQueue queue, Long messageId) throws AMQException { - ArrayList dequeues = _dequeueMap.get(messageId); + List dequeues = _dequeueMap.get(messageId); - if (dequeues == null) + synchronized (_dequeueMap) { - dequeues = new ArrayList(); - _dequeueMap.put(messageId, dequeues); + if (dequeues == null) + { + dequeues = Collections.synchronizedList(new ArrayList()); + _dequeueMap.put(messageId, dequeues); + } } dequeues.add(queue); + if (_logger.isInfoEnabled()) + { + _logger.info("Added (" + messageId + ") to dequeues:" + dequeues); + } } public void beginTransaction() throws AMQException @@ -174,13 +144,13 @@ public class StoreContext public void abortTransaction() throws AMQException { - _enqueueMap.clear(); + _dequeueMap.clear(); _inTransaction = false; } public boolean inTransaction() { - return _inTransaction; // _payload != null; + return _inTransaction; } public boolean isAsync() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index dded7f7142..ce2d67cf60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -31,16 +31,18 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; -import java.util.Iterator; +import java.util.Collections; +import java.util.List; public class BaseTransactionLog implements TransactionLog { private static final Logger _logger = Logger.getLogger(BaseTransactionLog.class); TransactionLog _delegate; - protected Map> _idToQueues = new HashMap>(); + protected Map> _idToQueues = Collections.synchronizedMap(new HashMap>()); public BaseTransactionLog(TransactionLog delegate) { @@ -59,14 +61,15 @@ public class BaseTransactionLog implements TransactionLog public void enqueueMessage(StoreContext context, ArrayList queues, Long messageId) throws AMQException { - context.enqueueMessage(queues, messageId); - if (queues.size() > 1) { - _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); + if (_logger.isInfoEnabled()) + { + _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); + } //Clone the list incase someone else changes it. - _idToQueues.put(messageId, (ArrayList) queues.clone()); + _idToQueues.put(messageId, (List)Collections.synchronizedList((ArrayList)queues.clone())); } _delegate.enqueueMessage(context, queues, messageId); @@ -78,21 +81,33 @@ public class BaseTransactionLog implements TransactionLog if (context.inTransaction()) { - Map> messageMap = context.getDequeueMap(); + + Map> messageMap = context.getDequeueMap(); //For each Message ID that is in the map check - Iterator iterator = messageMap.keySet().iterator(); + Set messageIDs = messageMap.keySet(); - while (iterator.hasNext()) + synchronized (messageMap) { - Long messageID = (Long) iterator.next(); - //If we don't have a gloabl reference for this message then there is only a single enqueue - if (_idToQueues.get(messageID) == null) + if (_logger.isInfoEnabled()) { - // Add the removal of the message to this transaction - _delegate.removeMessage(context,messageID); - // Remove this message ID as we have processed it so we don't reprocess after the main commmit - iterator.remove(); + _logger.info("Pre-Processing single dequeue of:" + messageIDs); + } + + Iterator iterator = messageIDs.iterator(); + + while (iterator.hasNext()) + { + Long messageID = (Long) iterator.next(); + //If we don't have a gloabl reference for this message then there is only a single enqueue + //can check here to see if this is the last reference? + if (_idToQueues.get(messageID) == null) + { + // Add the removal of the message to this transaction + _delegate.removeMessage(context, messageID); + // Remove this message ID as we have processed it so we don't reprocess after the main commmit + iterator.remove(); + } } } } @@ -136,22 +151,19 @@ public class BaseTransactionLog implements TransactionLog public void abortTran(StoreContext context) throws AMQException { - // If we have enqueues to rollback - processDequeues(context.getEnqueueMap()); - //Abort the recorded state for this transaction. context.abortTransaction(); _delegate.abortTran(context); } - private void processDequeues(Map> messageMap) + private void processDequeues(Map> messageMap) throws AMQException { // Check we have dequeues to process then process them if (messageMap == null || messageMap.isEmpty()) { - return; + return; } // Process any enqueues to bring our model up to date. @@ -162,50 +174,77 @@ public class BaseTransactionLog implements TransactionLog //Batch Process the Dequeues on the delegate _delegate.beginTran(removeContext); + removeContext.beginTransaction(); try { //For each Message ID Decrement the reference for each of the queues it was on. - for (Long messageID : messageIDs) + + synchronized (messageMap) { - ArrayList queueList = messageMap.get(messageID); + if (_logger.isInfoEnabled()) + { + _logger.info("Processing Dequeue for:" + messageIDs); + } - // For each of the queues decrement the reference - for (AMQQueue queue : queueList) + Iterator messageIDIterator = messageIDs.iterator(); + + while(messageIDIterator.hasNext()) { - ArrayList enqueuedList = _idToQueues.get(messageID); + Long messageID = messageIDIterator.next(); + List queueList = messageMap.get(messageID); - // If we have no mapping then this message was only enqueued on a single queue - // This will be the case when we are not in a larger transaction - if (enqueuedList == null) - { - _delegate.removeMessage(removeContext, messageID); - } - else + //Remove this message from our DequeueMap as we are processing it. + messageIDIterator.remove(); + + // For each of the queues decrement the reference + for (AMQQueue queue : queueList) { - //When a message is on more than one queue it is possible that this code section is exectuted - // by one thread per enqueue. - // It is however, thread safe because there is only removes being performed and so the - // last thread that does the remove will see the empty queue and remove the message - // At this stage there is nothing that is going to cause this operation to abort. So we don't - // need to worry about any potential adds. - // The message will no longer be enqueued as that operation has been committed before now so - // this is clean up of the data. - - // Update the enqueued list - enqueuedList.remove(queue); - - // If the list is now empty then remove the message - if (enqueuedList.isEmpty()) + List enqueuedList = _idToQueues.get(messageID); + + if (_logger.isInfoEnabled()) + { + _logger.info("Dequeue message:" + messageID + " from :" + queue); + } + + + // If we have no mapping then this message was only enqueued on a single queue + // This will be the case when we are not in a larger transaction + if (enqueuedList == null) { _delegate.removeMessage(removeContext, messageID); - //Remove references list - _idToQueues.remove(messageID); + } + else + { + //When a message is on more than one queue it is possible that this code section is exectuted + // by one thread per enqueue. + // It is however, thread safe because there is only removes being performed and so the + // last thread that does the remove will see the empty queue and remove the message + // At this stage there is nothing that is going to cause this operation to abort. So we don't + // need to worry about any potential adds. + // The message will no longer be enqueued as that operation has been committed before now so + // this is clean up of the data. + synchronized (enqueuedList) + { + // Update the enqueued list but if the queue is not in the list then we are trying + // to dequeue something that is not there anymore, or was never there. + if (!enqueuedList.remove(queue)) + { + throw new UnableToDequeueException(messageID, queue); + } + + // If the list is now empty then remove the message + if (enqueuedList.isEmpty()) + { + _delegate.removeMessage(removeContext, messageID); + //Remove references list + _idToQueues.remove(messageID); + } + } } } } } - //Commit the removes on the delegate. _delegate.commitTran(removeContext); // Mark this context as committed. @@ -244,4 +283,18 @@ public class BaseTransactionLog implements TransactionLog { return _delegate; } + + private class UnableToDequeueException extends RuntimeException + { + Long _messageID; + AMQQueue _queue; + + public UnableToDequeueException(Long messageID, AMQQueue queue) + { + super("Unable to dequeue message(" + messageID + ") from queue " + + "(" + queue + ") it is not/nolonger enqueued on it."); + _messageID = messageID; + _queue = queue; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java index 73d57df6e6..b2054c3436 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java @@ -77,6 +77,8 @@ public interface TransactionLog /** * Places a message onto a specified queue, in a given transactional context. * + * This method need not be thread safe as it is only called by the message delivery thread + * * @param context The transactional context for the operation. * @param queues *@param messageId The message to enqueue. @throws AMQException If the operation fails for any reason. @throws org.apache.qpid.AMQException @@ -86,6 +88,8 @@ public interface TransactionLog /** * Extracts a message from a specified queue, in a given transactional context. * + * This method MUST be thread safe as dequeue will be called by multiple threads, ack, requeue, delivery thread + * * @param context The transactional context for the operation. * @param queue * @param messageId The message to dequeue. @throws AMQException If the operation fails for any reason, or if the specified message does not exist. @@ -95,6 +99,8 @@ public interface TransactionLog /** * Remove the specified message from the log * + * This method MUST be thread safe as dequeue will be called by multiple threads, ack, requeue, delivery thread + * * @param context The transactional context for the operation * @param messageId The message to remove * @throws AMQException -- cgit v1.2.1 From 33472b64628102926497259f4ec94a94c48373de Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 8 Apr 2009 19:45:16 +0000 Subject: Wrapped log statement so it doesn't perform resolution when not logging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@763362 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/subscription/SubscriptionImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index bc1f56fee1..043caa53ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -596,7 +596,10 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage protected void sendToClient(final QueueEntry entry, final long deliveryTag) throws AMQException { - _logger.info("Sending Message(" + entry + ") DTag:" + deliveryTag + " to subscription:" + debugIdentity()); + if(_logger.isDebugEnabled()) + { + _logger.debug("Sending Message(" + entry + ") DTag:" + deliveryTag + " to subscription:" + debugIdentity()); + } _deliveryMethod.deliverToClient(this,entry,deliveryTag); } -- cgit v1.2.1 From 95ad30939516d2bf6bcd0b5a9c7a7d044be4ae14 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 8 Apr 2009 19:46:29 +0000 Subject: QPID-1794 : Removed unnecessary synchronisation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@763363 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/store/StoreContext.java | 11 +- .../server/transactionlog/BaseTransactionLog.java | 135 ++++++++++----------- 2 files changed, 70 insertions(+), 76 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index 26892868f3..eb28d83d92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -66,7 +66,7 @@ public class StoreContext _name = name; _async = asynchrouous; _inTransaction = false; - _dequeueMap = Collections.synchronizedMap(new HashMap>()); + _dequeueMap = new HashMap>(); } public StoreContext(boolean asynchronous) @@ -115,13 +115,10 @@ public class StoreContext { List dequeues = _dequeueMap.get(messageId); - synchronized (_dequeueMap) + if (dequeues == null) { - if (dequeues == null) - { - dequeues = Collections.synchronizedList(new ArrayList()); - _dequeueMap.put(messageId, dequeues); - } + dequeues = new ArrayList(); + _dequeueMap.put(messageId, dequeues); } dequeues.add(queue); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index ce2d67cf60..e200de7a6f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -69,7 +69,7 @@ public class BaseTransactionLog implements TransactionLog } //Clone the list incase someone else changes it. - _idToQueues.put(messageId, (List)Collections.synchronizedList((ArrayList)queues.clone())); + _idToQueues.put(messageId, Collections.synchronizedList((ArrayList)queues.clone())); } _delegate.enqueueMessage(context, queues, messageId); @@ -87,27 +87,24 @@ public class BaseTransactionLog implements TransactionLog //For each Message ID that is in the map check Set messageIDs = messageMap.keySet(); - synchronized (messageMap) + if (_logger.isInfoEnabled()) { - if (_logger.isInfoEnabled()) - { - _logger.info("Pre-Processing single dequeue of:" + messageIDs); - } + _logger.info("Pre-Processing single dequeue of:" + messageIDs); + } - Iterator iterator = messageIDs.iterator(); - - while (iterator.hasNext()) + Iterator iterator = messageIDs.iterator(); + + while (iterator.hasNext()) + { + Long messageID = (Long) iterator.next(); + //If we don't have a gloabl reference for this message then there is only a single enqueue + //can check here to see if this is the last reference? + if (_idToQueues.get(messageID) == null) { - Long messageID = (Long) iterator.next(); - //If we don't have a gloabl reference for this message then there is only a single enqueue - //can check here to see if this is the last reference? - if (_idToQueues.get(messageID) == null) - { - // Add the removal of the message to this transaction - _delegate.removeMessage(context, messageID); - // Remove this message ID as we have processed it so we don't reprocess after the main commmit - iterator.remove(); - } + // Add the removal of the message to this transaction + _delegate.removeMessage(context, messageID); + // Remove this message ID as we have processed it so we don't reprocess after the main commmit + iterator.remove(); } } } @@ -180,66 +177,66 @@ public class BaseTransactionLog implements TransactionLog { //For each Message ID Decrement the reference for each of the queues it was on. - synchronized (messageMap) + if (_logger.isInfoEnabled()) { - if (_logger.isInfoEnabled()) - { - _logger.info("Processing Dequeue for:" + messageIDs); - } + _logger.info("Processing Dequeue for:" + messageIDs); + } - Iterator messageIDIterator = messageIDs.iterator(); + Iterator messageIDIterator = messageIDs.iterator(); - while(messageIDIterator.hasNext()) - { - Long messageID = messageIDIterator.next(); - List queueList = messageMap.get(messageID); + while(messageIDIterator.hasNext()) + { + Long messageID = messageIDIterator.next(); + List queueList = messageMap.get(messageID); - //Remove this message from our DequeueMap as we are processing it. - messageIDIterator.remove(); + //Remove this message from our DequeueMap as we are processing it. + messageIDIterator.remove(); - // For each of the queues decrement the reference - for (AMQQueue queue : queueList) - { - List enqueuedList = _idToQueues.get(messageID); + // For each of the queues decrement the reference + for (AMQQueue queue : queueList) + { + List enqueuedList = _idToQueues.get(messageID); - if (_logger.isInfoEnabled()) - { - _logger.info("Dequeue message:" + messageID + " from :" + queue); - } + if (_logger.isInfoEnabled()) + { + _logger.info("Dequeue message:" + messageID + " from :" + queue); + } - // If we have no mapping then this message was only enqueued on a single queue - // This will be the case when we are not in a larger transaction - if (enqueuedList == null) - { - _delegate.removeMessage(removeContext, messageID); - } - else + // If we have no mapping then this message was only enqueued on a single queue + // This will be the case when we are not in a larger transaction + if (enqueuedList == null) + { + _delegate.removeMessage(removeContext, messageID); + } + else + { + //When a message is on more than one queue it is possible that this code section is exectuted + // by one thread per enqueue. + // It is however, thread safe because there is only removes being performed and so the + // last thread that does the remove will see the empty queue and remove the message + // At this stage there is nothing that is going to cause this operation to abort. So we don't + // need to worry about any potential adds. + // The message will no longer be enqueued as that operation has been committed before now so + // this is clean up of the data. + + //Must synchronize here as this list may have been extracted from _idToQueues in many threads + // and we must ensure only one of them update the list at a time. + synchronized (enqueuedList) { - //When a message is on more than one queue it is possible that this code section is exectuted - // by one thread per enqueue. - // It is however, thread safe because there is only removes being performed and so the - // last thread that does the remove will see the empty queue and remove the message - // At this stage there is nothing that is going to cause this operation to abort. So we don't - // need to worry about any potential adds. - // The message will no longer be enqueued as that operation has been committed before now so - // this is clean up of the data. - synchronized (enqueuedList) + // Update the enqueued list but if the queue is not in the list then we are trying + // to dequeue something that is not there anymore, or was never there. + if (!enqueuedList.remove(queue)) + { + throw new UnableToDequeueException(messageID, queue); + } + + // If the list is now empty then remove the message + if (enqueuedList.isEmpty()) { - // Update the enqueued list but if the queue is not in the list then we are trying - // to dequeue something that is not there anymore, or was never there. - if (!enqueuedList.remove(queue)) - { - throw new UnableToDequeueException(messageID, queue); - } - - // If the list is now empty then remove the message - if (enqueuedList.isEmpty()) - { - _delegate.removeMessage(removeContext, messageID); - //Remove references list - _idToQueues.remove(messageID); - } + _delegate.removeMessage(removeContext, messageID); + //Remove references list + _idToQueues.remove(messageID); } } } -- cgit v1.2.1 From c2f9da7dc06892f89b5b6fd7f1725c609a5e759a Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Fri, 10 Apr 2009 15:14:29 +0000 Subject: QPID-1801 Added method to show failure to PrincipalPermissionsTest.java and then adjusted the ternary operator in PrincipalPermissions.java to ensure we don't pass a null into the map (see JIRA descriptions). git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@763959 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/security/access/PrincipalPermissions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 35b76bcf32..f852514444 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -157,7 +157,7 @@ public class PrincipalPermissions AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName; + AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; // Get the queues map Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); -- cgit v1.2.1 From b50a93c2922b517cd7384b1054d863a588ef62e7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 10 Apr 2009 20:00:52 +0000 Subject: QPID-1798: Update AMQQueueMBean to use new constant value of DeliveryMode, replacing previously incorrect literal value used in conditional statement and thus preventing the reversal of delivery mode status. Also update other broker classes making similar comparisons using a literal value to use a constant git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764026 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 3 ++- .../main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java | 3 ++- .../src/main/java/org/apache/qpid/server/queue/IncomingMessage.java | 4 ++-- .../main/java/org/apache/qpid/server/queue/TransientMessageData.java | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 2ff54fb748..b46d6b6f12 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -443,7 +443,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); + list.add("JMSDeliveryMode = " + + ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); list.add("JMSPriority = " + headerProperties.getPriority()); list.add("JMSType = " + headerProperties.getType()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index a22eea2b5e..e98a40fc6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -116,7 +116,8 @@ public class FileQueueBackingStore implements QueueBackingStore mmd.setArrivalTime(arrivaltime); AMQMessage message; - if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2) + if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == + BasicContentHeaderProperties.PERSISTENT) { message = new PersistentAMQMessage(messageId, null); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index bab19fbc54..36ca197fa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -265,9 +265,9 @@ public class IncomingMessage implements Filterable public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == + BasicContentHeaderProperties.PERSISTENT; } public boolean isRedelivered() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 9b91c71a1d..b09283b11f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -120,8 +120,8 @@ public class TransientMessageData public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == + BasicContentHeaderProperties.PERSISTENT; } } -- cgit v1.2.1 From e9d3bc28203ac64a1b63e29c823731f0c598d764 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 10 Apr 2009 22:06:46 +0000 Subject: QPID-1800: modify SAMQQ to record transactionlog etry even when queue isnt durable(consistent with restof broker) and send both current and new queue to BTL for enqueue to ensure references are kept properly. Update BTL to check for prevous enqueues and record new enques in any existing list, despatching only new enqueues to the delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764075 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 31 +++++++++++++--- .../server/transactionlog/BaseTransactionLog.java | 43 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 6805d8261e..6a19acddd7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -823,6 +823,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); TransactionLog transactionLog = getVirtualHost().getTransactionLog(); + + if (toQueue.equals(this)) + { + //nothing to do here, message is already at the requested destination + return; + } List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -848,19 +854,24 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Move the messages in the transaction log. for (QueueEntry entry : entries) { - if (entry.isPersistent() && toQueue.isDurable()) + if (entry.isPersistent()) { //FIXME //fixme - ArrayList list = new ArrayList(); + + // Creating a list with the destination queue AND the current queue. + // This is a hack to ensure a reference is kept in the TLog to the new destination when dequeing + // the old destination below, thus preventing incorrect removal of the message from the store + ArrayList list = new ArrayList(); list.add(toQueue); + list.add(this); transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); } // dequeue will remove the messages from the queue entry.dequeue(storeContext); } - // Commit and flush the move transcations. + // Commit and flush the move transactions. try { transactionLog.commitTran(storeContext); @@ -891,7 +902,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener toQueue.enqueue(storeContext, entry.getMessage()); // As we only did a dequeue above now that we have moved the message we should perform a delete. // We cannot do this earlier as the message will be lost if flowed. - //entry.delete(); + entry.delete(); } } catch (MessageCleanupException e) @@ -913,6 +924,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); TransactionLog transactionLog = getVirtualHost().getTransactionLog(); + if (toQueue.equals(this)) + { + //nothing to do here, message is already at the requested destination + return; + } + List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -944,11 +961,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Move the messages in on the transaction log. for (QueueEntry entry : entries) { - if (!entry.isDeleted() && entry.isPersistent() && toQueue.isDurable()) + if (!entry.isDeleted() && entry.isPersistent()) { //fixme //FIXME + + // Creating a list with the destination queue AND the current queue. + // This is a hack to ensure a reference is kept in the TLog to the old destination when enqueing ArrayList list = new ArrayList(); + list.add(this); list.add(toQueue); transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index e200de7a6f..8d7b22d470 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -67,12 +67,47 @@ public class BaseTransactionLog implements TransactionLog { _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); } + + //list to hold which new queues to enqueue the message on + ArrayList toEnqueueList = new ArrayList(); + + List enqueuedList = _idToQueues.get(messageId); + if (enqueuedList != null) + { + //There are previous enqueues for this messageId + synchronized (enqueuedList) + { + for(AMQQueue queue : queues) + { + if(!enqueuedList.contains(queue)) + { + //update the old list. + enqueuedList.add(queue); + //keep track of new enqueues to be made + toEnqueueList.add(queue); + } + } + } + + if(toEnqueueList.isEmpty()) + { + //no new queues to enqueue message on + return; + } + } + else + { + //No existing list, add all provided queues (cloning toEnqueueList in case someone else changes original). + toEnqueueList.addAll(queues); + _idToQueues.put(messageId, Collections.synchronizedList((ArrayList)toEnqueueList.clone())); + } - //Clone the list incase someone else changes it. - _idToQueues.put(messageId, Collections.synchronizedList((ArrayList)queues.clone())); + _delegate.enqueueMessage(context, toEnqueueList, messageId); + } + else + { + _delegate.enqueueMessage(context, queues, messageId); } - - _delegate.enqueueMessage(context, queues, messageId); } public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException -- cgit v1.2.1 From 553e8cc73ff51c9850bdb3ddc8c8f4f356738a85 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 22:09:50 +0000 Subject: QPID-1794 : Moved processing of single message removals to just before the transaction commit rather than before the dequeue. As previously the list of dequeues was being traversed for every dequeue in that transaction batch with nothing to do. So removing this loop should increase performance in large batch cases. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764078 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transactionlog/BaseTransactionLog.java | 59 +++++++++++----------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index 8d7b22d470..7bf78ad977 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -114,36 +114,6 @@ public class BaseTransactionLog implements TransactionLog { context.dequeueMessage(queue, messageId); - if (context.inTransaction()) - { - - Map> messageMap = context.getDequeueMap(); - - //For each Message ID that is in the map check - Set messageIDs = messageMap.keySet(); - - if (_logger.isInfoEnabled()) - { - _logger.info("Pre-Processing single dequeue of:" + messageIDs); - } - - Iterator iterator = messageIDs.iterator(); - - while (iterator.hasNext()) - { - Long messageID = (Long) iterator.next(); - //If we don't have a gloabl reference for this message then there is only a single enqueue - //can check here to see if this is the last reference? - if (_idToQueues.get(messageID) == null) - { - // Add the removal of the message to this transaction - _delegate.removeMessage(context, messageID); - // Remove this message ID as we have processed it so we don't reprocess after the main commmit - iterator.remove(); - } - } - } - _delegate.dequeueMessage(context, queue, messageId); if (!context.inTransaction()) @@ -172,6 +142,35 @@ public class BaseTransactionLog implements TransactionLog public void commitTran(StoreContext context) throws AMQException { + + Map> messageMap = context.getDequeueMap(); + + //For each Message ID that is in the map check + Set messageIDs = messageMap.keySet(); + + if (_logger.isInfoEnabled()) + { + _logger.info("Pre-Processing single dequeue of:" + messageIDs); + } + + Iterator iterator = messageIDs.iterator(); + + while (iterator.hasNext()) + { + Long messageID = (Long) iterator.next(); + //If we don't have a gloabl reference for this message then there + // is only a single enqueue can check here to see if this is the + // last reference? + if (_idToQueues.get(messageID) == null) + { + // Add the removal of the message to this transaction + _delegate.removeMessage(context, messageID); + // Remove this message ID as we have processed it so we don't + // reprocess after the main commmit + iterator.remove(); + } + } + //Perform real commit of current data _delegate.commitTran(context); -- cgit v1.2.1 From 98548954e7ef986bfc0ad92da4610e807e719925 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 22:10:31 +0000 Subject: QPID-1791 : Replaced the get call before the dequeueAndDelete with a remove. So the remove call after the delete is now nolonger requried. Added manual test to assist identifing the problem git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764079 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/txn/NonTransactionalContext.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 2f27e1405a..9a90dd4bb2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -158,7 +158,7 @@ public class NonTransactionalContext implements TransactionalContext else { QueueEntry queueEntry; - queueEntry = unacknowledgedMessageMap.get(deliveryTag); + queueEntry = unacknowledgedMessageMap.remove(deliveryTag); if (debug) { @@ -187,9 +187,6 @@ public class NonTransactionalContext implements TransactionalContext // from the transaciton log queueEntry.dequeueAndDelete(_storeContext); - unacknowledgedMessageMap.remove(deliveryTag); - - } if(_inTran) { -- cgit v1.2.1 From b24e3ba7ce3b25775280e9066496ed3b7b830843 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 22:16:18 +0000 Subject: QPID-1633 : Ensured that FlowToDisk configuration defaults to 100Meg and is picked up from the configuration files. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764082 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/QueueConfiguration.java | 4 ++-- .../apache/qpid/server/configuration/VirtualHostConfiguration.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 256d15e7db..0b702b8505 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -110,11 +110,11 @@ public class QueueConfiguration public long getMemoryUsageMaximum() { - return _config.getLong("maximumMemoryUsage", 100 * 1024 * 1024); //100Meg + return _config.getLong("maximumMemoryUsage", _vHostConfig.getMemoryUsageMaximum()); } public long getMemoryUsageMinimum() { - return _config.getLong("minimumMemoryUsage", 0); + return _config.getLong("minimumMemoryUsage", _vHostConfig.getMemoryUsageMinimum()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 8d9f848b49..edcb32fc43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -156,7 +156,7 @@ public class VirtualHostConfiguration public long getMemoryUsageMaximum() { - return _config.getLong("queues.maximumMemoryUsage", 0); + return _config.getLong("queues.maximumMemoryUsage", 100 * 1024 * 1024); } public long getMemoryUsageMinimum() -- cgit v1.2.1 From 8d1c8e86ca56069aa7fe26ac08c3a5187e1f7929 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 22:18:02 +0000 Subject: QPID-1805 : Updated BackingStore to error if we cannot create the backing store. Also updated so that we store the queues evenly over 256 bins, thus giving us the ability to have around 8.1 million actives queues. The Hash function was borrowed from Apache Harmony. Added manual testing to ensure we are not limited by Linux's max file/dir per Inode of 31998. Made the test manual as creating 32000 queues does take a little while. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764083 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/queue/FileQueueBackingStoreFactory.java | 34 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java index 21073c22ae..b53d5a99ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java @@ -138,16 +138,39 @@ public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory return createStore(name, 0); } + /** + * Returns a hash code for non-null Object x. + * Uses the same hash code spreader as most other java.util hash tables. + * + * Borrowed from the Apache Harmony project + * @param x the object serving as a key + * @return the hash code + */ + public static int hash(Object x) { + int h = x.hashCode(); + h += ~(h << 9); + h ^= (h >>> 14); + h += (h << 4); + h ^= (h >>> 10); + return h; + } + private String createStore(String name, int index) { - String store = _flowToDiskLocation + File.separator + name; + int hash = hash(name); + + long bin = hash & 0xFFL; + + String store = _flowToDiskLocation + File.separator + bin + File.separator + name; + if (index > 0) { store += "-" + index; } - //TODO ensure store is safe for the OS + //TODO ensure name is safe for the OS i.e. on OSX you can't have any ':' + // Does java take care of this? File storeFile = new File(store); @@ -156,7 +179,12 @@ public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory return createStore(name, index + 1); } - storeFile.mkdirs(); + // Ensure we report an error if we cannot create the backing store. + if (!storeFile.mkdirs()) + { + _log.error("Unable to create queue backing directory for queue:" + name); + throw new RuntimeException("Unable to create queue backing directory for queue:" + name); + } storeFile.deleteOnExit(); -- cgit v1.2.1 From 67d42467daf75929c657f54b5b0a4c7421069b70 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 23:12:06 +0000 Subject: QPID-1806 : Ensure Flow to disk location is deleted when the queue is closed Note: As our queues do not stop processing on the close() call it is possible that the backing store may not beable to be deleted. In this case all that will occur is that it will log the failure to disk so an operations team can manually clean it up. When we improve the Queueing model for AMQP 1-0 we can address this behaviour. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764095 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/FileQueueBackingStore.java | 6 +++++- .../org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java index e98a40fc6c..b9d07d032b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java @@ -345,7 +345,11 @@ public class FileQueueBackingStore implements QueueBackingStore _log.info("Closing Backing store at:" + _flowToDiskLocation); if (!FileUtils.delete(new File(_flowToDiskLocation), true)) { - _log.error("Unable to fully delete backing store location"); + // Attempting a second time appears to ensure that it is deleted. + if (!FileUtils.delete(new File(_flowToDiskLocation), true)) + { + _log.error("Unable to fully delete backing store location"); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java index b53d5a99ee..8981db0071 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java @@ -33,7 +33,7 @@ public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory private static final Logger _log = Logger.getLogger(FileQueueBackingStoreFactory.class); private String _flowToDiskLocation; - private static final String QUEUE_BACKING_DIR = "queueBacking"; + public static final String QUEUE_BACKING_DIR = "queueBacking"; public void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException { -- cgit v1.2.1 From f0e81541320bc06abfd6c3a179f36054c4a1585c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 10 Apr 2009 23:37:27 +0000 Subject: QPID-1800: remove unecessary addAll() command, as the list is about to be cloned we can simply use the original list git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764105 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index 7bf78ad977..6af39e3d1b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -98,7 +98,7 @@ public class BaseTransactionLog implements TransactionLog else { //No existing list, add all provided queues (cloning toEnqueueList in case someone else changes original). - toEnqueueList.addAll(queues); + toEnqueueList = queues; _idToQueues.put(messageId, Collections.synchronizedList((ArrayList)toEnqueueList.clone())); } -- cgit v1.2.1 From 6ec7de67d683434d778cb55f5664891b35cc9071 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 10 Apr 2009 23:53:11 +0000 Subject: QPID-1793 : Update AMQChannel to remember any AMQException that occurs during requeue and then throws that after it has attempted to requeue all the messsagse from the unackedMap. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764111 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 37 ++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index dcbd887896..cb19532872 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -490,26 +490,45 @@ public class AMQChannel } } + // Place to hold any error that occured during the requeueing. + AMQException error = null; for (QueueEntry unacked : messagesToBeDelivered) { - if (!unacked.isQueueDeleted()) + try { - // Mark message redelivered - unacked.setRedelivered(true); + if (!unacked.isQueueDeleted()) + { + // Mark message redelivered + unacked.setRedelivered(true); - // Ensure message is released for redelivery - unacked.release(); + // Ensure message is released for redelivery + unacked.release(); - // Deliver Message - deliveryContext.requeue(unacked); + // Deliver Message + deliveryContext.requeue(unacked); + } + else + { + unacked.dequeueAndDelete(_storeContext); + } } - else + catch (AMQException e) { - unacked.dequeueAndDelete(_storeContext); + //Log the error and store it + _log.error(e.getMessage(),e); + // We store the last seen exception for rethrowing after + // attempting to process all the entries. + error = e; } } + // If we had an error during the requeue process throw it now. + if (error != null) + { + throw error; + } + } /** -- cgit v1.2.1 From dcb301530474a1b66f4f8939c58582c14868f586 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 10 Apr 2009 23:55:37 +0000 Subject: QPID-1800: only create the new empty arraylist after checking for a previous enqueue list, as it often wont be required git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764113 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transactionlog/BaseTransactionLog.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java index 6af39e3d1b..9c8cad4240 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java @@ -68,13 +68,16 @@ public class BaseTransactionLog implements TransactionLog _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); } - //list to hold which new queues to enqueue the message on - ArrayList toEnqueueList = new ArrayList(); + //variable to hold which new queues to enqueue the message on + ArrayList toEnqueueList = null; List enqueuedList = _idToQueues.get(messageId); if (enqueuedList != null) { //There are previous enqueues for this messageId + //create new empty list to hold additions + toEnqueueList = new ArrayList(); + synchronized (enqueuedList) { for(AMQQueue queue : queues) -- cgit v1.2.1 From 3e7f6b624a7131c352e2240495da116f060fafc9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 14 Apr 2009 15:46:39 +0000 Subject: QPID-1807 : Remove old broker and FlowToDisk related tests git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764838 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 1007 ------------ .../apache/qpid/configuration/Configuration.java | 188 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 237 --- .../java/org/apache/qpid/server/AMQChannel.java | 931 ----------- .../qpid/server/ConsumerTagNotUniqueException.java | 25 - .../qpid/server/ExtractResendAndRequeue.java | 105 -- .../src/main/java/org/apache/qpid/server/Main.java | 509 ------ .../org/apache/qpid/server/ManagedChannel.java | 68 - .../qpid/server/RequiredDeliveryException.java | 76 - .../java/org/apache/qpid/server/ack/TxAck.java | 145 -- .../qpid/server/ack/UnacknowledgedMessageMap.java | 81 - .../server/ack/UnacknowledgedMessageMapImpl.java | 230 --- .../configuration/ExchangeConfiguration.java | 58 - .../server/configuration/QueueConfiguration.java | 120 -- .../configuration/SecurityConfiguration.java | 41 - .../server/configuration/ServerConfiguration.java | 520 ------ .../configuration/VirtualHostConfiguration.java | 203 --- .../management/ConfigurationManagement.java | 43 - .../management/ConfigurationManagementMBean.java | 49 - .../qpid/server/connection/ConnectionRegistry.java | 73 - .../server/connection/IConnectionRegistry.java | 38 - .../qpid/server/exchange/AbstractExchange.java | 211 --- .../server/exchange/DefaultExchangeFactory.java | 114 -- .../server/exchange/DefaultExchangeRegistry.java | 138 -- .../qpid/server/exchange/DirectExchange.java | 251 --- .../org/apache/qpid/server/exchange/Exchange.java | 98 -- .../qpid/server/exchange/ExchangeFactory.java | 41 - .../server/exchange/ExchangeInUseException.java | 45 - .../qpid/server/exchange/ExchangeRegistry.java | 51 - .../apache/qpid/server/exchange/ExchangeType.java | 35 - .../qpid/server/exchange/FanoutExchange.java | 224 --- .../qpid/server/exchange/HeadersBinding.java | 219 --- .../qpid/server/exchange/HeadersExchange.java | 350 ---- .../org/apache/qpid/server/exchange/Index.java | 99 -- .../qpid/server/exchange/ManagedExchange.java | 99 -- .../apache/qpid/server/exchange/MessageRouter.java | 40 - .../qpid/server/exchange/NoRouteException.java | 48 - .../apache/qpid/server/exchange/TopicExchange.java | 670 -------- .../qpid/server/exchange/headers/HeaderKey.java | 40 - .../exchange/headers/HeaderKeyDictionary.java | 50 - .../exchange/headers/HeaderMatcherResult.java | 25 - .../exchange/headers/HeadersMatcherDFAState.java | 339 ---- .../server/exchange/headers/HeadersParser.java | 439 ------ .../exchange/topic/TopicMatcherDFAState.java | 295 ---- .../server/exchange/topic/TopicMatcherResult.java | 25 - .../qpid/server/exchange/topic/TopicParser.java | 613 ------- .../qpid/server/exchange/topic/TopicWord.java | 54 - .../server/exchange/topic/TopicWordDictionary.java | 63 - .../qpid/server/filter/ArithmeticExpression.java | 275 ---- .../qpid/server/filter/BinaryExpression.java | 106 -- .../qpid/server/filter/BooleanExpression.java | 39 - .../qpid/server/filter/ComparisonExpression.java | 599 ------- .../qpid/server/filter/ConstantExpression.java | 209 --- .../org/apache/qpid/server/filter/Expression.java | 36 - .../apache/qpid/server/filter/FilterManager.java | 37 - .../qpid/server/filter/FilterManagerFactory.java | 67 - .../qpid/server/filter/JMSSelectorFilter.java | 56 - .../apache/qpid/server/filter/LogicExpression.java | 120 -- .../apache/qpid/server/filter/MessageFilter.java | 28 - .../qpid/server/filter/NoConsumerFilter.java | 42 - .../qpid/server/filter/PropertyExpression.java | 271 ---- .../qpid/server/filter/SimpleFilterManager.java | 76 - .../apache/qpid/server/filter/UnaryExpression.java | 369 ----- .../apache/qpid/server/filter/XPathExpression.java | 126 -- .../qpid/server/filter/XQueryExpression.java | 57 - .../qpid/server/filter/XalanXPathEvaluator.java | 102 -- .../server/flow/AbstractFlowCreditManager.java | 62 - .../qpid/server/flow/BytesOnlyCreditManager.java | 74 - .../apache/qpid/server/flow/FlowCreditManager.java | 45 - .../qpid/server/flow/LimitlessCreditManager.java | 44 - .../server/flow/MessageAndBytesCreditManager.java | 77 - .../qpid/server/flow/MessageOnlyCreditManager.java | 76 - .../qpid/server/flow/Pre0_10CreditManager.java | 185 --- .../qpid/server/handler/AccessRequestHandler.java | 61 - .../qpid/server/handler/BasicAckMethodHandler.java | 67 - .../server/handler/BasicCancelMethodHandler.java | 74 - .../server/handler/BasicConsumeMethodHandler.java | 173 -- .../qpid/server/handler/BasicGetMethodHandler.java | 190 --- .../server/handler/BasicPublishMethodHandler.java | 106 -- .../qpid/server/handler/BasicQosHandler.java | 58 - .../server/handler/BasicRecoverMethodHandler.java | 73 - .../handler/BasicRecoverSyncMethodHandler.java | 75 - .../server/handler/BasicRejectMethodHandler.java | 125 -- .../qpid/server/handler/ChannelCloseHandler.java | 77 - .../qpid/server/handler/ChannelCloseOkHandler.java | 53 - .../qpid/server/handler/ChannelFlowHandler.java | 66 - .../qpid/server/handler/ChannelOpenHandler.java | 103 -- .../handler/ConnectionCloseMethodHandler.java | 72 - .../handler/ConnectionCloseOkMethodHandler.java | 63 - .../handler/ConnectionOpenMethodHandler.java | 102 -- .../handler/ConnectionSecureOkMethodHandler.java | 126 -- .../handler/ConnectionStartOkMethodHandler.java | 163 -- .../handler/ConnectionTuneOkMethodHandler.java | 54 - .../qpid/server/handler/ExchangeBoundHandler.java | 178 --- .../server/handler/ExchangeDeclareHandler.java | 122 -- .../qpid/server/handler/ExchangeDeleteHandler.java | 75 - .../server/handler/OnCurrentThreadExecutor.java | 34 - .../qpid/server/handler/QueueBindHandler.java | 143 -- .../qpid/server/handler/QueueDeclareHandler.java | 203 --- .../qpid/server/handler/QueueDeleteHandler.java | 126 -- .../qpid/server/handler/QueuePurgeHandler.java | 122 -- .../qpid/server/handler/QueueUnbindHandler.java | 137 -- .../server/handler/ServerMethodDispatcherImpl.java | 566 ------- .../handler/ServerMethodDispatcherImpl_0_9.java | 164 -- .../handler/ServerMethodDispatcherImpl_8_0.java | 86 - .../qpid/server/handler/TxCommitHandler.java | 78 - .../qpid/server/handler/TxRollbackHandler.java | 77 - .../qpid/server/handler/TxSelectHandler.java | 63 - .../server/handler/UnexpectedMethodException.java | 33 - .../logging/management/LoggingManagement.java | 136 -- .../logging/management/LoggingManagementMBean.java | 674 -------- .../qpid/server/management/AMQManagedObject.java | 97 -- .../server/management/DefaultManagedObject.java | 200 --- .../management/JMXManagedObjectRegistry.java | 371 ----- .../qpid/server/management/MBeanAttribute.java | 41 - .../qpid/server/management/MBeanConstructor.java | 39 - .../qpid/server/management/MBeanDescription.java | 38 - .../qpid/server/management/MBeanIntrospector.java | 388 ----- .../management/MBeanInvocationHandlerImpl.java | 257 --- .../qpid/server/management/MBeanOperation.java | 43 - .../server/management/MBeanOperationParameter.java | 37 - .../apache/qpid/server/management/Managable.java | 34 - .../qpid/server/management/ManagedBroker.java | 98 -- .../qpid/server/management/ManagedObject.java | 58 - .../server/management/ManagedObjectRegistry.java | 51 - .../management/NoopManagedObjectRegistry.java | 60 - .../server/output/ProtocolOutputConverter.java | 58 - .../output/ProtocolOutputConverterRegistry.java | 61 - .../amqp0_8/ProtocolOutputConverterImpl.java | 273 ---- .../amqp0_9/ProtocolOutputConverterImpl.java | 378 ----- .../org/apache/qpid/server/plugins/Activator.java | 44 - .../apache/qpid/server/plugins/PluginManager.java | 176 --- .../server/protocol/AMQMinaProtocolSession.java | 859 ---------- .../protocol/AMQNoMethodHandlerException.java | 46 - .../server/protocol/AMQPFastProtocolHandler.java | 284 ---- .../qpid/server/protocol/AMQPProtocolProvider.java | 52 - .../qpid/server/protocol/AMQProtocolSession.java | 207 --- .../server/protocol/AMQProtocolSessionMBean.java | 304 ---- .../qpid/server/protocol/ExchangeInitialiser.java | 51 - .../qpid/server/protocol/ManagedConnection.java | 136 -- .../protocol/UnknnownMessageTypeException.java | 46 - .../org/apache/qpid/server/queue/AMQMessage.java | 99 -- .../apache/qpid/server/queue/AMQPriorityQueue.java | 77 - .../org/apache/qpid/server/queue/AMQQueue.java | 220 --- .../apache/qpid/server/queue/AMQQueueFactory.java | 140 -- .../apache/qpid/server/queue/AMQQueueMBean.java | 494 ------ .../qpid/server/queue/DefaultQueueRegistry.java | 71 - .../apache/qpid/server/queue/ExchangeBinding.java | 84 - .../apache/qpid/server/queue/ExchangeBindings.java | 82 - .../qpid/server/queue/FailedDequeueException.java | 50 - .../qpid/server/queue/FileQueueBackingStore.java | 385 ----- .../server/queue/FileQueueBackingStoreFactory.java | 194 --- .../org/apache/qpid/server/queue/Filterable.java | 33 - .../server/queue/FlowableBaseQueueEntryList.java | 550 ------- .../apache/qpid/server/queue/IncomingMessage.java | 301 ---- .../org/apache/qpid/server/queue/ManagedQueue.java | 302 ---- .../qpid/server/queue/MessageCleanupException.java | 52 - .../apache/qpid/server/queue/MessageFactory.java | 119 -- .../apache/qpid/server/queue/MessageMetaData.java | 92 -- .../qpid/server/queue/NoConsumersException.java | 47 - .../qpid/server/queue/NotificationCheck.java | 129 -- .../qpid/server/queue/PersistentAMQMessage.java | 73 - .../qpid/server/queue/PriorityQueueEntryList.java | 178 --- .../qpid/server/queue/QueueBackingStore.java | 64 - .../server/queue/QueueBackingStoreFactory.java | 32 - .../org/apache/qpid/server/queue/QueueEntry.java | 233 --- .../apache/qpid/server/queue/QueueEntryImpl.java | 568 ------- .../qpid/server/queue/QueueEntryIterator.java | 30 - .../apache/qpid/server/queue/QueueEntryList.java | 76 - .../qpid/server/queue/QueueEntryListFactory.java | 26 - .../server/queue/QueueNotificationListener.java | 27 - .../apache/qpid/server/queue/QueueRegistry.java | 43 - .../apache/qpid/server/queue/SimpleAMQQueue.java | 1666 -------------------- .../qpid/server/queue/SimpleQueueEntryList.java | 181 --- .../qpid/server/queue/TransientAMQMessage.java | 332 ---- .../qpid/server/queue/TransientMessageData.java | 127 -- .../server/queue/UnableToFlowMessageException.java | 29 - .../queue/UnableToRecoverMessageException.java | 29 - .../server/queue/UnauthorizedAccessException.java | 45 - .../qpid/server/registry/ApplicationRegistry.java | 290 ---- .../ConfigurationFileApplicationRegistry.java | 87 - .../qpid/server/registry/IApplicationRegistry.java | 79 - .../apache/qpid/server/routing/RoutingTable.java | 124 -- .../qpid/server/security/access/ACLManager.java | 322 ---- .../qpid/server/security/access/ACLPlugin.java | 70 - .../server/security/access/ACLPluginFactory.java | 33 - .../qpid/server/security/access/AccessResult.java | 65 - .../qpid/server/security/access/AccessRights.java | 63 - .../qpid/server/security/access/Accessable.java | 27 - .../security/access/AuthorizationManager.java | 6 - .../qpid/server/security/access/Permission.java | 38 - .../security/access/PrincipalPermissions.java | 612 ------- .../server/security/access/VirtualHostAccess.java | 68 - .../access/management/AMQUserManagementMBean.java | 501 ------ .../security/access/management/UserManagement.java | 121 -- .../security/access/plugins/AbstractACLPlugin.java | 99 -- .../server/security/access/plugins/AllowAll.java | 54 - .../security/access/plugins/BasicACLPlugin.java | 129 -- .../server/security/access/plugins/DenyAll.java | 75 - .../access/plugins/LegacyAccessPlugin.java | 71 - .../server/security/access/plugins/SimpleXML.java | 432 ----- .../access/plugins/network/FirewallFactory.java | 45 - .../access/plugins/network/FirewallPlugin.java | 264 ---- .../server/security/auth/AuthenticationResult.java | 63 - .../Base64MD5PasswordFilePrincipalDatabase.java | 541 ------- .../ConfigurationFilePrincipalDatabaseManager.java | 232 --- .../server/security/auth/database/HashedUser.java | 169 -- .../PlainPasswordFilePrincipalDatabase.java | 491 ------ .../server/security/auth/database/PlainUser.java | 106 -- .../security/auth/database/PrincipalDatabase.java | 105 -- .../auth/database/PrincipalDatabaseManager.java | 35 - .../auth/database/PropertiesPrincipalDatabase.java | 169 -- .../PropertiesPrincipalDatabaseManager.java | 50 - .../auth/manager/AuthenticationManager.java | 38 - .../PrincipalDatabaseAuthenticationManager.java | 237 --- .../auth/rmi/RMIPasswordAuthenticator.java | 119 -- .../sasl/AuthenticationProviderInitialiser.java | 76 - .../server/security/auth/sasl/JCAProvider.java | 46 - .../auth/sasl/UsernamePasswordInitialiser.java | 123 -- .../security/auth/sasl/UsernamePrincipal.java | 44 - .../auth/sasl/amqplain/AmqPlainInitialiser.java | 38 - .../auth/sasl/amqplain/AmqPlainSaslServer.java | 132 -- .../sasl/amqplain/AmqPlainSaslServerFactory.java | 60 - .../sasl/crammd5/CRAMMD5HashedInitialiser.java | 50 - .../auth/sasl/crammd5/CRAMMD5HashedSaslServer.java | 105 -- .../sasl/crammd5/CRAMMD5HashedServerFactory.java | 61 - .../auth/sasl/crammd5/CRAMMD5Initialiser.java | 71 - .../security/auth/sasl/plain/PlainInitialiser.java | 38 - .../security/auth/sasl/plain/PlainSaslServer.java | 151 -- .../auth/sasl/plain/PlainSaslServerFactory.java | 60 - .../org/apache/qpid/server/state/AMQState.java | 36 - .../apache/qpid/server/state/AMQStateManager.java | 263 --- .../state/IllegalStateTransitionException.java | 52 - .../server/state/StateAwareMethodListener.java | 35 - .../apache/qpid/server/state/StateListener.java | 30 - .../qpid/server/store/DerbyMessageStore.java | 1461 ----------------- .../qpid/server/store/MemoryMessageStore.java | 242 --- .../server/store/MessageStoreClosedException.java | 36 - .../org/apache/qpid/server/store/StoreContext.java | 157 -- .../server/subscription/ClientDeliveryMethod.java | 29 - .../server/subscription/RecordDeliveryMethod.java | 28 - .../qpid/server/subscription/Subscription.java | 96 -- .../server/subscription/SubscriptionFactory.java | 59 - .../subscription/SubscriptionFactoryImpl.java | 103 -- .../qpid/server/subscription/SubscriptionImpl.java | 623 -------- .../qpid/server/subscription/SubscriptionList.java | 247 --- .../server/transactionlog/BaseTransactionLog.java | 334 ---- .../qpid/server/transactionlog/TransactionLog.java | 203 --- .../qpid/server/transport/ThreadPoolFilter.java | 705 --------- .../qpid/server/txn/LocalTransactionalContext.java | 284 ---- .../qpid/server/txn/NonTransactionalContext.java | 211 --- .../qpid/server/txn/StoreMessageOperation.java | 58 - .../qpid/server/txn/TransactionalContext.java | 179 --- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 109 -- .../java/org/apache/qpid/server/txn/TxnOp.java | 55 - .../apache/qpid/server/util/CircularBuffer.java | 131 -- .../server/util/ConcurrentLinkedQueueNoSize.java | 38 - .../org/apache/qpid/server/util/LoggingProxy.java | 105 -- .../qpid/server/util/NullApplicationRegistry.java | 86 - .../server/virtualhost/ManagedVirtualHost.java | 45 - .../qpid/server/virtualhost/VirtualHost.java | 597 ------- .../server/virtualhost/VirtualHostRegistry.java | 70 - .../qpid/tools/messagestore/MessageStoreTool.java | 652 -------- .../messagestore/commands/AbstractCommand.java | 66 - .../qpid/tools/messagestore/commands/Clear.java | 85 - .../qpid/tools/messagestore/commands/Command.java | 36 - .../qpid/tools/messagestore/commands/Copy.java | 55 - .../qpid/tools/messagestore/commands/Dump.java | 302 ---- .../qpid/tools/messagestore/commands/Help.java | 98 -- .../qpid/tools/messagestore/commands/List.java | 314 ---- .../qpid/tools/messagestore/commands/Load.java | 94 -- .../qpid/tools/messagestore/commands/Move.java | 206 --- .../qpid/tools/messagestore/commands/Purge.java | 67 - .../qpid/tools/messagestore/commands/Quit.java | 54 - .../qpid/tools/messagestore/commands/Select.java | 233 --- .../qpid/tools/messagestore/commands/Show.java | 489 ------ .../org/apache/qpid/tools/security/Passwd.java | 81 - .../org/apache/qpid/tools/utils/CommandParser.java | 51 - .../java/org/apache/qpid/tools/utils/Console.java | 90 -- .../qpid/tools/utils/SimpleCommandParser.java | 121 -- .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 ----- 281 files changed, 46815 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java delete mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java deleted file mode 100644 index 7e0c4defe1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.log4j; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.Writer; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.zip.GZIPOutputStream; - -import org.apache.log4j.helpers.CountingQuietWriter; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.helpers.OptionConverter; -import org.apache.log4j.spi.LoggingEvent; - -/** - *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either - * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is - * crossed at which time it rolls all of those files as per the DailyRollingFileAppender) based on the setting for - * rollingStyle.

      To use CompositeRollingAppender to roll log files as they reach a certain size - * (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      To use CompositeRollingAppender to roll log - * files at certain time intervals (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      To - * have CompositeRollingAppender roll log files at a certain size AND rename those according to time intervals, set - * rollingStyle=3 (@see config.composite)
      - * - *

      A of few additional optional features have been added:
      -- Attach date pattern for current log file (@see - * staticLogFileName)
      -- Backup number increments for newer files (@see countDirection)
      -- Infinite number of - * backups by file size (@see maxSizeRollBackups)

      A few notes and warnings: For large or infinite number of - * backups countDirection > 0 is highly recommended, with staticLogFileName = false if time based rolling is also used - * -- this will reduce the number of file renamings to few or none. Changing staticLogFileName or countDirection - * without clearing the directory could have nasty side effects. If Date/Time based rolling is enabled, - * CompositeRollingAppender will attempt to roll existing files in the directory without a date/time tag based on the - * last modified date of the base log files last modification.

      A maximum number of backups based on - * date/time boundries would be nice but is not yet implemented.
      - * - * @author Kevin Steppe - * @author Heinz Richter - * @author Eirik Lygre - * @author Ceki Gülcü - * @author Martin Ritchie - */ -public class QpidCompositeRollingAppender extends FileAppender -{ - // The code assumes that the following 'time' constants are in a increasing - // sequence. - static final int TOP_OF_TROUBLE = -1; - static final int TOP_OF_MINUTE = 0; - static final int TOP_OF_HOUR = 1; - static final int HALF_DAY = 2; - static final int TOP_OF_DAY = 3; - static final int TOP_OF_WEEK = 4; - static final int TOP_OF_MONTH = 5; - - /** Style of rolling to use */ - static final int BY_SIZE = 1; - static final int BY_DATE = 2; - static final int BY_COMPOSITE = 3; - - // Not currently used - static final String S_BY_SIZE = "Size"; - static final String S_BY_DATE = "Date"; - static final String S_BY_COMPOSITE = "Composite"; - - /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ - private String datePattern = "'.'yyyy-MM-dd"; - - /** - * The actual formatted filename that is currently being written to or will be the file transferred to on roll over - * (based on staticLogFileName). - */ - private String scheduledFilename = null; - - /** The timestamp when we shall next recompute the filename. */ - private long nextCheck = System.currentTimeMillis() - 1; - - /** Holds date of last roll over */ - Date now = new Date(); - - SimpleDateFormat sdf; - - /** Helper class to determine next rollover time */ - RollingCalendar rc = new RollingCalendar(); - - /** Current period for roll overs */ - int checkPeriod = TOP_OF_TROUBLE; - - /** The default maximum file size is 10MB. */ - protected long maxFileSize = 10 * 1024 * 1024; - - /** There is zero backup files by default. */ - protected int maxSizeRollBackups = 0; - /** How many sized based backups have been made so far */ - protected int curSizeRollBackups = 0; - - /** not yet implemented */ - protected int maxTimeRollBackups = -1; - protected int curTimeRollBackups = 0; - - /** - * By default newer files have lower numbers. (countDirection < 0) ie. log.1 is most recent, log.5 is the 5th - * backup, etc... countDirection > 0 does the opposite ie. log.1 is the first backup made, log.5 is the 5th backup - * made, etc. For infinite backups use countDirection > 0 to reduce rollOver costs. - */ - protected int countDirection = -1; - - /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ - protected int rollingStyle = BY_COMPOSITE; - protected boolean rollDate = true; - protected boolean rollSize = true; - - /** - * By default file.log is always the current file. Optionally file.log.yyyy-mm-dd for current formated datePattern - * can by the currently logging file (or file.log.curSizeRollBackup or even file.log.yyyy-mm-dd.curSizeRollBackup) - * This will make time based roll overs with a large number of backups much faster -- it won't have to rename all - * the backups! - */ - protected boolean staticLogFileName = true; - - /** FileName provided in configuration. Used for rolling properly */ - protected String baseFileName; - - /** Do we want to .gz our backup files. */ - protected boolean compress = false; - - /** Do we want to use a second thread when compressing our backup files. */ - protected boolean compressAsync = false; - - /** Do we want to start numbering files at zero. */ - protected boolean zeroBased = false; - - /** Path provided in configuration. Used for moving backup files to */ - protected String backupFilesToPath = null; - private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); - private AtomicBoolean _compressing = new AtomicBoolean(false); - - /** The default constructor does nothing. */ - public QpidCompositeRollingAppender() - { } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The - * opened filename will become the ouput destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern) throws IOException - { - this(layout, filename, datePattern, true); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the ouput destination for this appender. - * - *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by - * filename will be truncated before being opened. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) throws IOException - { - super(layout, filename, append); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the ouput destination for this appender. - */ - public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern, boolean append) - throws IOException - { - super(layout, filename, append); - this.datePattern = datePattern; - activateOptions(); - } - - /** - * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename - * will become the output destination for this appender. - * - *

      The file will be appended to. DatePattern is default. - */ - public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException - { - super(layout, filename); - } - - /** - * The DatePattern takes a string in the same format as expected by {@link java.text.SimpleDateFormat}. This - * options determines the rollover schedule. - */ - public void setDatePattern(String pattern) - { - datePattern = pattern; - } - - /** Returns the value of the DatePattern option. */ - public String getDatePattern() - { - return datePattern; - } - - /** Returns the value of the maxSizeRollBackups option. */ - public int getMaxSizeRollBackups() - { - return maxSizeRollBackups; - } - - /** - * Get the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - * @since 1.1 - */ - public long getMaximumFileSize() - { - return maxFileSize; - } - - /** - *

      Set the maximum number of backup files to keep around based on file size. - * - *

      The MaxSizeRollBackups option determines how many backup files are kept before the oldest is erased. - * This option takes an integer value. If set to zero, then there will be no backup files and the log file will be - * truncated when it reaches MaxFileSize. If a negative number is supplied then no deletions will be - * made. Note that this could result in very slow performance as a large number of files are rolled over unless - * {@link #setCountDirection} up is used. - * - *

      The maximum applys to -each- time based group of files and -not- the total. Using a daily roll the maximum - * total files would be (#days run) * (maxSizeRollBackups) - */ - public void setMaxSizeRollBackups(int maxBackups) - { - maxSizeRollBackups = maxBackups; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter - * taking a long argument from the setter taking a String argument by the JavaBeans {@link - * java.beans.Introspector Introspector}. - * - * @see #setMaxFileSize(String) - */ - public void setMaxFileSize(long maxFileSize) - { - this.maxFileSize = maxFileSize; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter - * taking a long argument from the setter taking a String argument by the JavaBeans {@link - * java.beans.Introspector Introspector}. - * - * @see #setMaxFileSize(String) - */ - public void setMaximumFileSize(long maxFileSize) - { - this.maxFileSize = maxFileSize; - } - - /** - * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. - * - *

      In configuration files, the MaxFileSize option takes an long integer in the range 0 - 2^63. You can - * specify the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed - * respectively in kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240. - */ - public void setMaxFileSize(String value) - { - maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); - } - - protected void setQWForFiles(Writer writer) - { - qw = new CountingQuietWriter(writer, errorHandler); - } - - // Taken verbatum from DailyRollingFileAppender - int computeCheckPeriod() - { - RollingCalendar c = new RollingCalendar(); - // set sate to 1970-01-01 00:00:00 GMT - Date epoch = new Date(0); - if (datePattern != null) - { - for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) - { - String r0 = sdf.format(epoch); - c.setType(i); - Date next = new Date(c.getNextCheckMillis(epoch)); - String r1 = sdf.format(next); - // LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); - if ((r0 != null) && (r1 != null) && !r0.equals(r1)) - { - return i; - } - } - } - - return TOP_OF_TROUBLE; // Deliberately head for trouble... - } - - // Now for the new stuff - /** - * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked - * first) or time (checked second) is need and then appends to the file last. - */ - protected void subAppend(LoggingEvent event) - { - - if (rollDate) - { - long n = System.currentTimeMillis(); - if (n >= nextCheck) - { - now.setTime(n); - nextCheck = rc.getNextCheckMillis(now); - - rollOverTime(); - } - } - - if (rollSize) - { - if ((fileName != null) && (((CountingQuietWriter) qw).getCount() >= maxFileSize)) - { - rollOverSize(); - } - } - - super.subAppend(event); - } - - public void setFile(String file) - { - baseFileName = file.trim(); - fileName = file.trim(); - } - - /** - * Creates and opens the file for logging. If staticLogFileName is false then the fully qualified name - * is determined and used. - */ - public synchronized void setFile(String fileName, boolean append) throws IOException - { - if (!staticLogFileName) - { - scheduledFilename = fileName = fileName.trim() + sdf.format(now); - if (countDirection > 0) - { - scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); - } - } - - super.setFile(fileName, append, bufferedIO, bufferSize); - - if (append) - { - File f = new File(fileName); - ((CountingQuietWriter) qw).setCount(f.length()); - } - } - - public int getCountDirection() - { - return countDirection; - } - - public void setCountDirection(int direction) - { - countDirection = direction; - } - - public int getRollingStyle() - { - return rollingStyle; - } - - public void setRollingStyle(int style) - { - rollingStyle = style; - switch (rollingStyle) - { - - case BY_SIZE: - rollDate = false; - rollSize = true; - break; - - case BY_DATE: - rollDate = true; - rollSize = false; - break; - - case BY_COMPOSITE: - rollDate = true; - rollSize = true; - break; - - default: - errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); - } - } - - /* - public void setRollingStyle(String style) { - if (style == S_BY_SIZE) { - rollingStyle = BY_SIZE; - } - else if (style == S_BY_DATE) { - rollingStyle = BY_DATE; - } - else if (style == S_BY_COMPOSITE) { - rollingStyle = BY_COMPOSITE; - } - } - */ - public boolean getStaticLogFileName() - { - return staticLogFileName; - } - - public void setStaticLogFileName(boolean s) - { - staticLogFileName = s; - } - - public void setStaticLogFileName(String value) - { - setStaticLogFileName(OptionConverter.toBoolean(value, true)); - } - - public boolean getCompressBackupFiles() - { - return compress; - } - - public void setCompressBackupFiles(boolean c) - { - compress = c; - } - - public boolean getCompressAsync() - { - return compressAsync; - } - - public void setCompressAsync(boolean c) - { - compressAsync = c; - if (compressAsync) - { - executor = Executors.newFixedThreadPool(1); - - compressor = new Compressor(); - } - } - - public boolean getZeroBased() - { - return zeroBased; - } - - public void setZeroBased(boolean z) - { - zeroBased = z; - } - - public String getBackupFilesToPath() - { - return backupFilesToPath; - } - - public void setbackupFilesToPath(String path) - { - File td = new File(path); - if (!td.exists()) - { - td.mkdirs(); - } - - backupFilesToPath = path; - } - - /** - * Initializes based on exisiting conditions at time of activateOptions. The following is done:
      - *
      A) determine curSizeRollBackups
      B) determine curTimeRollBackups (not implemented)
      C) initiates a - * roll over if needed for crossing a date boundary since the last run. - */ - protected void existingInit() - { - - if (zeroBased) - { - curSizeRollBackups = -1; - } - - curTimeRollBackups = 0; - - // part A starts here - String filter; - if (staticLogFileName || !rollDate) - { - filter = baseFileName + ".*"; - } - else - { - filter = scheduledFilename + ".*"; - } - - File f = new File(baseFileName); - f = f.getParentFile(); - if (f == null) - { - f = new File("."); - } - - LogLog.debug("Searching for existing files in: " + f); - String[] files = f.list(); - - if (files != null) - { - for (int i = 0; i < files.length; i++) - { - if (!files[i].startsWith(baseFileName)) - { - continue; - } - - int index = files[i].lastIndexOf("."); - - if (staticLogFileName) - { - int endLength = files[i].length() - index; - if ((baseFileName.length() + endLength) != files[i].length()) - { - // file is probably scheduledFilename + .x so I don't care - continue; - } - } - - try - { - int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); - LogLog.debug("From file: " + files[i] + " -> " + backup); - if (backup > curSizeRollBackups) - { - curSizeRollBackups = backup; - } - } - catch (Exception e) - { - // this happens when file.log -> file.log.yyyy-mm-dd which is normal - // when staticLogFileName == false - LogLog.debug("Encountered a backup file not ending in .x " + files[i]); - } - } - } - - LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); - // part A ends here - - // part B not yet implemented - - // part C - if (staticLogFileName && rollDate) - { - File old = new File(baseFileName); - if (old.exists()) - { - Date last = new Date(old.lastModified()); - if (!(sdf.format(last).equals(sdf.format(now)))) - { - scheduledFilename = baseFileName + sdf.format(last); - LogLog.debug("Initial roll over to: " + scheduledFilename); - rollOverTime(); - } - } - } - - LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); - // part C ends here - - } - - /** - * Sets initial conditions including date/time roll over information, first check, scheduledFilename, and calls - * existingInit to initialize the current # of backups. - */ - public void activateOptions() - { - - // REMOVE removed rollDate from boolean to enable Alex's change - if (datePattern != null) - { - now.setTime(System.currentTimeMillis()); - sdf = new SimpleDateFormat(datePattern); - int type = computeCheckPeriod(); - // printPeriodicity(type); - rc.setType(type); - // next line added as this removes the name check in rollOver - nextCheck = rc.getNextCheckMillis(now); - } - else - { - if (rollDate) - { - LogLog.error("Either DatePattern or rollingStyle options are not set for [" + name + "]."); - } - } - - existingInit(); - - if (rollDate && (fileName != null) && (scheduledFilename == null)) - { - scheduledFilename = fileName + sdf.format(now); - } - - try - { - this.setFile(fileName, true); - } - catch (IOException e) - { - errorHandler.error("Cannot set file name:" + fileName); - } - - super.activateOptions(); - } - - /** - * Rollover the file(s) to date/time tagged file(s). Opens the new file (through setFile) and resets - * curSizeRollBackups. - */ - protected void rollOverTime() - { - - curTimeRollBackups++; - - this.closeFile(); // keep windows happy. - - // delete the old stuff here - - if (staticLogFileName) - { - /* Compute filename, but only if datePattern is specified */ - if (datePattern == null) - { - errorHandler.error("Missing DatePattern option in rollOver()."); - - return; - } - - // is the new file name equivalent to the 'current' one - // something has gone wrong if we hit this -- we should only - // roll over if the new file will be different from the old - String dateFormat = sdf.format(now); - if (scheduledFilename.equals(fileName + dateFormat)) - { - errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); - - return; - } - - // close current file, and rename it to datedFilename - this.closeFile(); - - // we may have to roll over a large number of backups here - String from, to; - for (int i = 1; i <= curSizeRollBackups; i++) - { - from = fileName + '.' + i; - to = scheduledFilename + '.' + i; - rollFile(from, to, false); - } - - rollFile(fileName, scheduledFilename, compress); - } - else - { - if (compress) - { - compress(fileName); - } - } - - try - { - // This will also close the file. This is OK since multiple - // close operations are safe. - curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new - - // new scheduled name - scheduledFilename = fileName + sdf.format(now); - this.setFile(baseFileName, false); - } - catch (IOException e) - { - errorHandler.error("setFile(" + fileName + ", false) call failed."); - } - - } - - /** - * Renames file from to file to. It also checks for existence of target file and deletes - * if it does. - */ - protected void rollFile(String from, String to, boolean compress) - { - if (from.equals(to)) - { - if (compress) - { - LogLog.debug("Attempting to compress file with same output name."); - } - - return; - } - - File target = new File(to); - if (target.exists()) - { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } - - File file = new File(from); - if (compress) - { - compress(file, target); - } - else - { - if (!file.getPath().equals(target.getPath())) - { - file.renameTo(target); - } - } - - LogLog.debug(from + " -> " + to); - } - - protected void compress(String file) - { - File f = new File(file); - compress(f, f); - } - - private void compress(File from, File target) - { - if (compressAsync) - { - synchronized (_compress) - { - _compress.offer(new CompressJob(from, target)); - } - - startCompression(); - } - else - { - doCompress(from, target); - } - } - - private void startCompression() - { - if (_compressing.compareAndSet(false, true)) - { - executor.execute(compressor); - } - } - - /** Delete's the specified file if it exists */ - protected static void deleteFile(String fileName) - { - File file = new File(fileName); - if (file.exists()) - { - file.delete(); - } - } - - /** - * Implements roll overs base on file size. - * - *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If - * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} - * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is - * renamed File.1 and closed.
      - * - * A new file is created to receive further log output. - * - *

      If maxSizeRollBackups is equal to zero, then the File is truncated with no backup - * files created. - * - *

      If maxSizeRollBackups < 0, then File is renamed if needed and no files are deleted. - */ - - // synchronization not necessary since doAppend is alreasy synched - protected void rollOverSize() - { - File file; - - this.closeFile(); // keep windows happy. - - LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); - LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); - LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); - LogLog.debug("countDirection = " + countDirection); - - // If maxBackups <= 0, then there is no file renaming to be done. - if (maxSizeRollBackups != 0) - { - - if (countDirection < 0) - { - // Delete the oldest file, to keep Windows happy. - if (curSizeRollBackups == maxSizeRollBackups) - { - deleteFile(fileName + '.' + maxSizeRollBackups); - curSizeRollBackups--; - } - - // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} - for (int i = curSizeRollBackups; i >= 1; i--) - { - rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); - } - - curSizeRollBackups++; - // Rename fileName to fileName.1 - rollFile(fileName, fileName + ".1", compress); - - } // REMOVE This code branching for Alexander Cerna's request - else if (countDirection == 0) - { - // rollFile based on date pattern - curSizeRollBackups++; - now.setTime(System.currentTimeMillis()); - scheduledFilename = fileName + sdf.format(now); - rollFile(fileName, scheduledFilename, compress); - } - else - { // countDirection > 0 - if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) - { - // delete the first and keep counting up. - int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; - deleteFile(fileName + '.' + oldestFileIndex); - } - - if (staticLogFileName) - { - curSizeRollBackups++; - rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); - } - else - { - if (compress) - { - compress(fileName); - } - } - } - } - - try - { - // This will also close the file. This is OK since multiple - // close operations are safe. - this.setFile(baseFileName, false); - } - catch (IOException e) - { - LogLog.error("setFile(" + fileName + ", false) call failed.", e); - } - } - - protected synchronized void doCompress(File from, File to) - { - String toFile; - if (backupFilesToPath == null) - { - toFile = to.getPath() + ".gz"; - } - else - { - toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; - } - - File target = new File(toFile); - if (target.exists()) - { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } - - try - { - // Create the GZIP output stream - GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); - - // Open the input file - FileInputStream in = new FileInputStream(from); - - // Transfer bytes from the input file to the GZIP output stream - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) - { - out.write(buf, 0, len); - } - - in.close(); - - // Complete the GZIP file - out.finish(); - out.close(); - // Remove old file. - from.delete(); - } - catch (IOException e) - { - if (target.exists()) - { - target.delete(); - } - - rollFile(from.getPath(), to.getPath(), false); - } - } - - private class CompressJob - { - File _from, _to; - - CompressJob(File from, File to) - { - _from = from; - _to = to; - } - - File getFrom() - { - return _from; - } - - File getTo() - { - return _to; - } - } - - Compressor compressor = null; - - Executor executor; - - private class Compressor implements Runnable - { - public void run() - { - boolean running = true; - while (running) - { - CompressJob job = _compress.poll(); - - doCompress(job.getFrom(), job.getTo()); - - synchronized (_compress) - { - if (_compress.isEmpty()) - { - running = false; - _compressing.set(false); - } - } - } - - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java deleted file mode 100644 index 40ff590a0a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.configuration; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -public class Configuration -{ - public static final String QPID_HOME = "QPID_HOME"; - - final String QPIDHOME = System.getProperty(QPID_HOME); - - private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); - - public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - protected final Options _options = new Options(); - protected CommandLine _commandLine; - protected File _configFile; - - - public Configuration() - { - - } - - public void processCommandline(String[] args) throws InitException - { - try - { - _commandLine = new PosixParser().parse(_options, args); - } - catch (ParseException e) - { - throw new InitException("Unable to parse commmandline", e); - } - - final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); - setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); - } - - public void setConfig(File file) - { - _configFile = file; - } - - /** - * @param option The option to set. - */ - public void setOption(Option option) - { - _options.addOption(option); - } - - /** - * getOptionValue from the configuration - * @param option variable argument, first string is option to get, second if present is the default value. - * @return the String for the given option or null if not present (if default value not specified) - */ - public String getOptionValue(String... option) - { - if (option.length == 1) - { - return _commandLine.getOptionValue(option[0]); - } - else if (option.length == 2) - { - return _commandLine.getOptionValue(option[0], option[1]); - } - return null; - } - - public void loadConfig(File file) throws InitException - { - setConfig(file); - loadConfig(); - } - - private void loadConfig() throws InitException - { - 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, null); - } - else - { - _devlog.debug("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); -// } - } - - -// private void configureLogging(File logConfigFile, String logWatchConfig) -// { -// int logWatchTime = 0; -// try -// { -// logWatchTime = Integer.parseInt(logWatchConfig); -// } -// catch (NumberFormatException e) -// { -// _devlog.error("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()) -// { -// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); -// if (logWatchTime > 0) -// { -// _devlog.info("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(); -// } -// } - - public File getConfigFile() - { - return _configFile; - } - - - public class InitException extends Exception - { - InitException(String msg, Throwable cause) - { - super(msg, cause); - } - } -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java deleted file mode 100644 index 22bdae8267..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedBroker; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.routing.RoutingTable; - -/** - * This MBean 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") -public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBroker -{ - private final QueueRegistry _queueRegistry; - private final ExchangeRegistry _exchangeRegistry; - private final ExchangeFactory _exchangeFactory; - private final TransactionLog _tranasctionLog; - private final RoutingTable _routingTable; - - private final VirtualHost.VirtualHostMBean _virtualHostMBean; - - @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException - { - super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); - - _virtualHostMBean = virtualHostMBean; - VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); - - _queueRegistry = virtualHost.getQueueRegistry(); - _exchangeRegistry = virtualHost.getExchangeRegistry(); - _tranasctionLog = virtualHost.getTransactionLog(); - _exchangeFactory = virtualHost.getExchangeFactory(); - _routingTable = virtualHost.getRoutingTable(); - } - - public String getObjectInstanceName() - { - return _virtualHostMBean.getVirtualHost().getName(); - } - - /** - * Creates new exchange and registers it with the registry. - * - * @param exchangeName - * @param type - * @param durable - * @throws JMException - */ - public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException - { - try - { - synchronized (_exchangeRegistry) - { - Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); - if (exchange == null) - { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), - durable, false, 0); - _exchangeRegistry.registerExchange(exchange); - } - else - { - throw new JMException("The exchange \"" + exchangeName + "\" already exists."); - } - } - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error in creating exchange " + exchangeName); - } - } - - /** - * Unregisters the exchange from registry. - * - * @param exchangeName - * @throws JMException - */ - public void unregisterExchange(String exchangeName) throws JMException - { - // TODO - // Check if the exchange is in use. - // boolean inUse = false; - // Check if there are queue-bindings with the exchange and unregister - // when there are no bindings. - try - { - _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); - } - } - - /** - * 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 - * @throws JMException - */ - public void createNewQueue(String queueName, String owner, boolean durable) throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue != null) - { - throw new JMException("The queue \"" + queueName + "\" already exists."); - } - - try - { - AMQShortString ownerShortString = null; - if (owner != null) - { - ownerShortString = new AMQShortString(owner); - } - - queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost(), - null); - if (queue.isDurable() && !queue.isAutoDelete()) - { - _routingTable.createQueue(queue); - } - - _queueRegistry.registerQueue(queue); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); - throw new MBeanException(jme, "Error in creating queue " + queueName); - } - } - - private VirtualHost getVirtualHost() - { - return _virtualHostMBean.getVirtualHost(); - } - - /** - * Deletes the queue from queue registry and persistant storage. - * - * @param queueName - * @throws JMException - */ - public void deleteQueue(String queueName) throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("The Queue " + queueName + " is not a registerd queue."); - } - - try - { - queue.delete(); - _routingTable.removeQueue(queue); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); - throw new MBeanException(jme, "Error in deleting queue " + queueName); - } - } - - public ManagedObject getParentObject() - { - return _virtualHostMBean; - } - - // This will have a single instance for a virtual host, so not having the name property in the ObjectName - public ObjectName getObjectName() throws MalformedObjectNameException - { - return getObjectNameForSingleInstanceMBean(); - } -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java deleted file mode 100644 index cb19532872..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.NoRouteException; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.flow.Pre0_10CreditManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.UnauthorizedAccessException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.transactionlog.TransactionLog; - -public class AMQChannel -{ - public static final int DEFAULT_PREFETCH = 5000; - - private static final Logger _log = Logger.getLogger(AMQChannel.class); - - private final int _channelId; - - - private final Pre0_10CreditManager _creditManager = new Pre0_10CreditManager(0l,0l); - - /** - * 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 long _deliveryTag = 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 IncomingMessage _currentMessage; - - /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */ - protected final Map _tag2SubscriptionMap = new HashMap(); - - private final TransactionLog _transactionLog; - - private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - - private final AtomicBoolean _suspended = new AtomicBoolean(false); - - private TransactionalContext _txnContext; - - /** - * A context used by the message store enabling it to track context for a given channel even across thread - * boundaries - */ - private final StoreContext _storeContext; - - private final List _returnMessages = new LinkedList(); - - // Why do we need this reference ? - ritchiem - private final AMQProtocolSession _session; - private boolean _closing; - - public AMQChannel(AMQProtocolSession session, int channelId, TransactionLog transactionLog) - throws AMQException - { - _session = session; - _channelId = channelId; - _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); - - - _transactionLog = transactionLog; - - // by default the session is non-transactional - _txnContext = new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); - } - - /** Sets this channel to be part of a local transaction */ - public void setLocalTransactional() - { - _txnContext = new LocalTransactionalContext(this); - } - - public boolean isTransactional() - { - // this does not look great but there should only be one "non-transactional" - // transactional context, while there could be several transactional ones in - // theory - return !(_txnContext instanceof NonTransactionalContext); - } - - public int getChannelId() - { - return _channelId; - } - - public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException - { - - _currentMessage = new IncomingMessage(info, _txnContext, _session, _transactionLog); - _currentMessage.setExchange(e); - } - - public void publishContentHeader(ContentHeaderBody contentHeaderBody) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content header without previously receiving a BasicPublish frame"); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug("Content header received on channel " + _channelId); - } - - _currentMessage.setContentHeaderBody(contentHeaderBody); - - _currentMessage.setExpiration(); - - routeCurrentMessage(); - - _currentMessage.routingComplete(_transactionLog); - - deliverCurrentMessageIfComplete(); - - } - } - - private void deliverCurrentMessageIfComplete() - throws AMQException - { - // check and deliver if header says body length is zero - if (_currentMessage.allContentReceived()) - { - try - { - _currentMessage.deliverToQueues(); - } - catch (NoRouteException e) - { - _returnMessages.add(e); - } - catch(UnauthorizedAccessException ex) - { - _returnMessages.add(ex); - } - finally - { - // callback to allow the context to do any post message processing - // primary use is to allow message return processing in the non-tx case - _txnContext.messageProcessed(_session); - _currentMessage = null; - } - } - - } - - public void publishContentBody(ContentBody contentBody) throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content body without previously receiving a JmsPublishBody"); - } - - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + "Content body received on channel " + _channelId); - } - - try - { - - // returns true iff the message was delivered (i.e. if all data was - // received - _currentMessage.addContentBodyFrame( - _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody)); - - deliverCurrentMessageIfComplete(); - } - 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 - { - try - { - _currentMessage.route(); - } - catch (NoRouteException e) - { - _returnMessages.add(e); - } - } - - public long getNextDeliveryTag() - { - return ++_deliveryTag; - } - - 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 acks Are acks enabled for this subscriber - * @param filters Filters to apply to this subscriber - * - * @param noLocal Flag stopping own messages being receivied. - * @param exclusive Flag requesting exclusive access to the queue - * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests - * - * @throws ConsumerTagNotUniqueException if the tag is not unique - * @throws AMQException if something goes wrong - */ - public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException - { - if (tag == null) - { - tag = new AMQShortString("sgen_" + getNextConsumerTag()); - } - - if (_tag2SubscriptionMap.containsKey(tag)) - { - throw new ConsumerTagNotUniqueException(); - } - - Subscription subscription = - SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager); - - - // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. - // We add before we register as the Async Delivery process may AutoClose the subscriber - // so calling _cT2QM.remove before we have done put which was after the register succeeded. - // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. - - _tag2SubscriptionMap.put(tag, subscription); - - try - { - queue.registerSubscription(subscription, exclusive); - } - catch (AMQException e) - { - _tag2SubscriptionMap.remove(tag); - throw e; - } - return tag; - } - - /** - * Unsubscribe a consumer from a queue. - * @param consumerTag - * @return true if the consumerTag had a mapped queue that could be unregistered. - * @throws AMQException - */ - public boolean unsubscribeConsumer(AMQShortString consumerTag) throws AMQException - { - - Subscription sub = _tag2SubscriptionMap.remove(consumerTag); - if (sub != null) - { - try - { - sub.getSendLock(); - sub.getQueue().unregisterSubscription(sub); - } - finally - { - sub.releaseSendLock(); - } - return true; - } - else - { - _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); - } - return false; - } - - /** - * Called from the protocol session to close this channel and clean up. T - * - * @throws AMQException if there is an error during closure - */ - public void close() throws AMQException - { - _txnContext.rollback(); - unsubscribeAllConsumers(); - try - { - requeue(); - } - catch (AMQException e) - { - _log.error("Caught AMQException whilst attempting to reque:" + e); - } - - setClosing(true); - } - - private void setClosing(boolean closing) - { - _closing = closing; - } - - private void unsubscribeAllConsumers() throws AMQException - { - if (_log.isInfoEnabled()) - { - if (!_tag2SubscriptionMap.isEmpty()) - { - _log.info("Unsubscribing all consumers on channel " + toString()); - } - else - { - _log.info("No consumers to unsubscribe on channel " + toString()); - } - } - - for (Map.Entry me : _tag2SubscriptionMap.entrySet()) - { - if (_log.isInfoEnabled()) - { - _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); - } - - Subscription sub = me.getValue(); - - try - { - sub.getSendLock(); - sub.getQueue().unregisterSubscription(sub); - } - finally - { - sub.releaseSendLock(); - } - - } - - _tag2SubscriptionMap.clear(); - } - - /** - * Add a message to the channel-based list of unacknowledged messages - * - * @param entry the record of the message on the queue that was delivered - * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the - * delivery tag) - * @param subscription The consumer that is to acknowledge this message. - */ - public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription) - { - if (_log.isDebugEnabled()) - { - if (entry.getQueue() == null) - { - _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity()); - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug(debugIdentity() + " Adding unacked message(" + entry.toString() + " DT:" + deliveryTag - + ") with a queue(" + entry.getQueue() + ") for " + subscription); - } - } - } - - _unacknowledgedMessageMap.add(deliveryTag, entry); - - } - - private final String id = "(" + System.identityHashCode(this) + ")"; - - public String debugIdentity() - { - return _channelId + id; - } - - /** - * Called to attempt re-delivery 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(); - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext = null; - - if (!messagesToBeDelivered.isEmpty()) - { - if (_log.isInfoEnabled()) - { - // Requeue only occurs on connection close so this extra processing should not be a bottleneck - List ids=new LinkedList(); - for (QueueEntry entry: messagesToBeDelivered) - { - ids.add(entry.getMessageId()); - } - - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages(" + ids + "). " + - "for " + toString()); - } - - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } - } - - // Place to hold any error that occured during the requeueing. - AMQException error = null; - for (QueueEntry unacked : messagesToBeDelivered) - { - try - { - if (!unacked.isQueueDeleted()) - { - // Mark message redelivered - unacked.setRedelivered(true); - - // Ensure message is released for redelivery - unacked.release(); - - // Deliver Message - deliveryContext.requeue(unacked); - - } - else - { - unacked.dequeueAndDelete(_storeContext); - } - } - catch (AMQException e) - { - //Log the error and store it - _log.error(e.getMessage(),e); - // We store the last seen exception for rethrowing after - // attempting to process all the entries. - error = e; - } - } - - // If we had an error during the requeue process throw it now. - if (error != null) - { - throw error; - } - - } - - /** - * Requeue a single message - * - * @param deliveryTag The message to requeue - * - * @throws AMQException If something goes wrong. - */ - public void requeue(long deliveryTag) throws AMQException - { - QueueEntry unacked = _unacknowledgedMessageMap.remove(deliveryTag); - - if (unacked != null) - { - // Mark message redelivered - unacked.setRedelivered(true); - - // Ensure message is released for redelivery - if (!unacked.isQueueDeleted()) - { - unacked.release(); - } - - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); - - } - else - { - deliveryContext = _txnContext; - } - - if (!unacked.isQueueDeleted()) - { - // Redeliver the messages to the front of the queue - deliveryContext.requeue(unacked); - // Deliver increments the message count but we have already deliverted this once so don't increment it again - // this was because deliver did an increment changed this. - } - else - { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.debugIdentity() - + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - - unacked.dequeueAndDelete(_storeContext); - } - } - else - { - _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." - + _unacknowledgedMessageMap.size()); - - } - - } - - /** - * Called to resend all outstanding unacknowledged messages to this same channel. - * - * @param requeue Are the messages to be requeued or dropped. - * - * @throws AMQException When something goes wrong. - */ - public void resend(final boolean requeue) throws AMQException - { - - - final Map msgToRequeue = new LinkedHashMap(); - final Map msgToResend = new LinkedHashMap(); - - if (_log.isDebugEnabled()) - { - _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); - } - - // Process the Unacked-Map. - // Marking messages who still have a consumer for to be resent - // and those that don't to be requeued. - _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, requeue, _storeContext)); - - - // Process Messages to Resend - if (_log.isDebugEnabled()) - { - if (!msgToResend.isEmpty()) - { - _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); - } - else - { - _log.debug("No message to resend."); - } - } - - for (Map.Entry entry : msgToResend.entrySet()) - { - QueueEntry queueEntry = entry.getValue(); - long deliveryTag = entry.getKey(); - - AMQQueue queue = queueEntry.getQueue(); - - // Our Java Client will always suspend the channel when resending! - // If the client has requested the messages be resent then it is - // their responsibility to ensure that thay are capable of receiving them - // i.e. The channel hasn't been server side suspended. - // if (isSuspended()) - // { - // _log.info("Channel is suspended so requeuing"); - // //move this message to requeue - // msgToRequeue.add(message); - // } - // else - // { - // release to allow it to be delivered - - // Without any details from the client about what has been processed we have to mark - // all messages in the unacked map as redelivered. - queueEntry.setRedelivered(true); - - Subscription sub = queueEntry.getDeliveredSubscription(); - - if (sub != null) - { - - if(!queue.resend(queueEntry, sub)) - { - msgToRequeue.put(deliveryTag, queueEntry); - } - } - else - { - - if (_log.isInfoEnabled()) - { - _log.info("DeliveredSubscription not recorded so just requeueing(" + queueEntry.toString() - + ")to prevent loss"); - } - // move this message to requeue - msgToRequeue.put(deliveryTag, queueEntry); - } - } // for all messages - // } else !isSuspend - - if (_log.isInfoEnabled()) - { - if (!msgToRequeue.isEmpty()) - { - _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); - } - } - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_transactionLog, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } - - // Process Messages to Requeue at the front of the queue - for (Map.Entry entry : msgToRequeue.entrySet()) - { - QueueEntry message = entry.getValue(); - long deliveryTag = entry.getKey(); - - message.release(); - message.setRedelivered(true); - - deliveryContext.requeue(message); - - _unacknowledgedMessageMap.remove(deliveryTag); - } - } - - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to - * remove the queue reference and also decrement any message reference counts, without actually removing the item - * since we may get an ack for a delivery tag that was generated from the deleted queue. - * - * @param queue the queue that has been deleted - * - */ - /* public void queueDeleted(final AMQQueue queue) - { - try - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) - { - if (message.getQueue() == queue) - { - try - { - message.dequeueAndDelete(_storeContext); - message.setQueueDeleted(true); - - } - catch (AMQException e) - { - _log.error( - "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); - throw new RuntimeException(e); - } - } - - return false; - } - - public void visitComplete() - { - } - }); - } - catch (AMQException e) - { - _log.error("Unexpected Error while handling deletion of queue", e); - throw new RuntimeException(e); - } - - } -*/ - /** - * Acknowledge one or more messages. - * - * @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); - } - - /** - * Used only for testing purposes. - * - * @return the map of unacknowledged messages - */ - public UnacknowledgedMessageMap getUnacknowledgedMessageMap() - { - return _unacknowledgedMessageMap; - } - - - public void setSuspended(boolean suspended) - { - - - boolean wasSuspended = _suspended.getAndSet(suspended); - if (wasSuspended != suspended) - { - if (wasSuspended) - { - // may need to deliver queued messages - for (Subscription s : _tag2SubscriptionMap.values()) - { - s.getQueue().deliverAsync(s); - } - } - } - } - - public boolean isSuspended() - { - return _suspended.get(); - } - - public void commit() throws AMQException - { - if (!isTransactional()) - { - throw new AMQException("Fatal error: commit called on non-transactional channel"); - } - - _txnContext.commit(); - } - - public void rollback() throws AMQException - { - _txnContext.rollback(); - } - - public String toString() - { - return "["+_session.toString()+":"+_channelId+"]"; - } - - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } - - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void processReturns() throws AMQException - { - if (!_returnMessages.isEmpty()) - { - for (RequiredDeliveryException bouncedMessage : _returnMessages) - { - AMQMessage message = bouncedMessage.getAMQMessage(); - _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); - } - - _returnMessages.clear(); - } - } - - - public TransactionalContext getTransactionalContext() - { - return _txnContext; - } - - public boolean isClosing() - { - return _closing; - } - - public AMQProtocolSession getProtocolSession() - { - return _session; - } - - public FlowCreditManager getCreditManager() - { - return _creditManager; - } - - public void setCredit(final long prefetchSize, final int prefetchCount) - { - _creditManager.setCreditLimits(prefetchSize, prefetchCount); - } - - public List getReturnMessages() - { - return _returnMessages; - } - - public TransactionLog getTransactionLog() - { - return _transactionLog; - } - - private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod() - { - - public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) - throws AMQException - { - getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), deliveryTag, sub.getConsumerTag()); - } - }; - - public ClientDeliveryMethod getClientDeliveryMethod() - { - return _clientDeliveryMethod; - } - - private final RecordDeliveryMethod _recordDeliveryMethod = new RecordDeliveryMethod() - { - - public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) - { - addUnacknowledgedMessage(entry, deliveryTag, sub); - } - }; - - public RecordDeliveryMethod getRecordDeliveryMethod() - { - return _recordDeliveryMethod; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java deleted file mode 100644 index 9a98af5689..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -public class ConsumerTagNotUniqueException extends Exception -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java deleted file mode 100644 index 8d41cc58d2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; - -import java.util.Map; - -public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor -{ - private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class); - - private Map _msgToRequeue; - private Map _msgToResend; - private boolean _requeueIfUnabletoResend; - private StoreContext _storeContext; - private UnacknowledgedMessageMap _unacknowledgedMessageMap; - - public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, - Map msgToRequeue, - Map msgToResend, - boolean requeueIfUnabletoResend, - StoreContext storeContext) - { - _unacknowledgedMessageMap = unacknowledgedMessageMap; - _msgToRequeue = msgToRequeue; - _msgToResend = msgToResend; - _requeueIfUnabletoResend = requeueIfUnabletoResend; - _storeContext = storeContext; - } - - public boolean callback(final long deliveryTag, QueueEntry queueEntry) throws AMQException - { - - queueEntry.setRedelivered(true); - final Subscription subscription = queueEntry.getDeliveredSubscription(); - if (subscription != null) - { - // Consumer exists - if (!subscription.isClosed()) - { - _msgToResend.put(deliveryTag, queueEntry); - } - else // consumer has gone - { - _msgToRequeue.put(deliveryTag, queueEntry); - } - } - else - { - // Message has no consumer tag, so was "delivered" to a GET - // or consumer no longer registered - // cannot resend, so re-queue. - if (!queueEntry.isQueueDeleted()) - { - if (_requeueIfUnabletoResend) - { - _msgToRequeue.put(deliveryTag, queueEntry); - } - else - { - queueEntry.dequeueAndDelete(_storeContext); - _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + queueEntry); - } - } - else - { - queueEntry.dequeueAndDelete(_storeContext); - _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + queueEntry); - } - } - - // false means continue processing - return false; - } - - public void visitComplete() - { - _unacknowledgedMessageMap.clear(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java deleted file mode 100644 index 49619ac5b0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.FixedSizeByteBufferAllocator; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; -import org.apache.mina.transport.socket.nio.SocketSessionConfig; -import org.apache.mina.util.NewThreadExecutor; -import org.apache.qpid.AMQException; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; -import org.apache.qpid.server.logging.management.LoggingManagementMBean; -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; - -/** - * Main entry point for AMQPD. - * - */ -@SuppressWarnings({"AccessStaticViaInstance"}) -public class Main -{ - private static final Logger _logger = Logger.getLogger(Main.class); - public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); - - private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - public static final String QPID_HOME = "QPID_HOME"; - private static final int IPV4_ADDRESS_LENGTH = 4; - - private static final char IPV4_LITERAL_SEPARATOR = '.'; - - protected static class InitException extends Exception - { - InitException(String msg, Throwable cause) - { - super(msg, cause); - } - } - - 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 mport = - OptionBuilder.withArgName("mport").hasArg() - .withDescription("listen on the specified management port. Overrides any value in the config file") - .withLongOpt("mport").create("m"); - - - 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(mport); - 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 = QpidProperties.getVersionString(); - - StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: "); - - boolean first = true; - for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) - { - if (first) - { - first = false; - } - else - { - protocol.append(", "); - } - - protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); - - } - - System.out.println(ver + " (" + protocol + ")"); - } - else - { - try - { - startup(); - } - catch (InitException e) - { - System.out.println(e.getMessage()); - _brokerLogger.error("Initialisation Error : " + e.getMessage()); - shutdown(1); - } - catch (Throwable e) - { - System.out.println("Error initialising message broker: " + e); - _brokerLogger.error("Error initialising message broker: " + e); - e.printStackTrace(); - shutdown(1); - } - } - } - - protected void shutdown(int status) - { - ApplicationRegistry.removeAll(); - System.exit(status); - } - - protected void startup() throws Exception - { - final String QpidHome = System.getProperty(QPID_HOME); - final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE); - 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, null); - } - else - { - System.out.println("Using configuration file " + configFile.getAbsolutePath()); - } - - String logConfig = commandLine.getOptionValue("l"); - String logWatchConfig = commandLine.getOptionValue("w", "0"); - - int logWatchTime = 0; - try - { - logWatchTime = Integer.parseInt(logWatchConfig); - } - catch (NumberFormatException e) - { - System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " - + "a non-negative integer. Using default of zero (no watching configured"); - } - - File logConfigFile; - if (logConfig != null) - { - logConfigFile = new File(logConfig); - configureLogging(logConfigFile, logWatchTime); - } - else - { - File configFileDirectory = configFile.getParentFile(); - logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); - configureLogging(logConfigFile, logWatchTime); - } - - ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); - ServerConfiguration serverConfig = config.getConfiguration(); - updateManagementPort(serverConfig, commandLine.getOptionValue("m")); - - ApplicationRegistry.initialise(config); - - configureLoggingManagementMBean(logConfigFile, logWatchTime); - - ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); - configMBean.register(); - - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues - // that are causing the broker build to pick up the wrong properties file and hence say - // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - - ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); - - // 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 (!serverConfig.getEnablePooledAllocator()) - { - ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); - } - - if(serverConfig.getUseBiasedWrites()) - { - System.setProperty("org.apache.qpid.use_write_biased_pool","true"); - } - - int port = serverConfig.getPort(); - - String portStr = commandLine.getOptionValue("p"); - if (portStr != null) - { - try - { - port = Integer.parseInt(portStr); - } - catch (NumberFormatException e) - { - throw new InitException("Invalid port: " + portStr, e); - } - } - - bind(port, serverConfig); - } - - /** - * Update the configuration data with the management port. - * @param configuration - * @param managementPort The string from the command line - */ - private void updateManagementPort(ServerConfiguration configuration, String managementPort) - { - if (managementPort != null) - { - try - { - configuration.setJMXManagementPort(Integer.parseInt(managementPort)); - } - catch (NumberFormatException e) - { - _logger.warn("Invalid management port: " + managementPort + " will use:" + configuration.getJMXManagementPort(), e); - } - } - } - - protected void bind(int port, ServerConfiguration config) throws BindException - { - String bindAddr = commandLine.getOptionValue("b"); - if (bindAddr == null) - { - bindAddr = config.getBind(); - } - - try - { - IoAcceptor acceptor; - - if (ApplicationRegistry.getInstance().getConfiguration().getQpidNIO()) - { - _logger.warn("Using Qpid Multithreaded IO Processing"); - acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(config.getProcessors(), new NewThreadExecutor()); - } - else - { - _logger.warn("Using Mina IO Processing"); - acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(config.getProcessors(), new NewThreadExecutor()); - } - - SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); - SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); - - sc.setReceiveBufferSize(config.getReceiveBufferSize()); - sc.setSendBufferSize(config.getWriteBufferSize()); - sc.setTcpNoDelay(config.getTcpNoDelay()); - - // if we do not use the executor pool threading model we get the default leader follower - // implementation provided by MINA - if (config.getEnableExecutorPool()) - { - sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); - } - - if (!config.getEnableSSL() || !config.getSSLOnly()) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - InetSocketAddress bindAddress; - if (bindAddr.equals("wildcard")) - { - bindAddress = new InetSocketAddress(port); - } - else - { - bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); - } - - bind(acceptor, bindAddress, handler, sconfig); - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); - } - - if (config.getEnableSSL()) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - try - { - - bind(acceptor, new InetSocketAddress(config.getSSLPort()), handler, sconfig); - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on SSL port " + config.getSSLPort()); - - } - catch (IOException e) - { - _brokerLogger.error("Unable to listen on SSL port: " + e, e); - } - } - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - } - catch (Exception e) - { - _logger.error("Unable to bind service to registry: " + e, e); - //fixme this need tidying up - throw new BindException(e.getMessage()); - } - } - - /** - * Ensure that any bound Acceptors are recorded in the registry so they can be closed later. - * - * @param acceptor - * @param bindAddress - * @param handler - * @param sconfig - * - * @throws IOException from the acceptor.bind command - */ - private void bind(IoAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException - { - acceptor.bind(bindAddress, handler, sconfig); - - ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor); - } - - public static void main(String[] args) - { - - new Main(args); - } - - private byte[] parseIP(String address) throws Exception - { - char[] literalBuffer = address.toCharArray(); - int byteCount = 0; - int currByte = 0; - byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; - for (int i = 0; i < literalBuffer.length; i++) - { - char currChar = literalBuffer[i]; - if ((currChar >= '0') && (currChar <= '9')) - { - currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); - } - - if (currChar == IPV4_LITERAL_SEPARATOR || (i + 1 == literalBuffer.length)) - { - ip[byteCount++] = (byte) currByte; - currByte = 0; - } - } - - if (byteCount != 4) - { - throw new Exception("Invalid IP address: " + address); - } - return ip; - } - - private void configureLogging(File logConfigFile, int logWatchTime) - { - 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 configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception - { - LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); - - try - { - blm.register(); - } - catch (AMQException e) - { - throw new InitException("Unable to initialise the Logging Management MBean: ", e); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java deleted file mode 100644 index e76f9c3f6c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server; - -import java.io.IOException; - -import javax.management.JMException; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java deleted file mode 100644 index a81b2cc2db..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the - * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. - * - *

      The failed message is associated with this error condition, by taking a reference to it. This enables the - * correct compensating action to be taken against the message, for example, bouncing it back to the sender. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      Associate the failed message with the error condition. {@link AMQMessage} - *
      - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private AMQMessage _amqMessage; - - public RequiredDeliveryException(String message, AMQMessage payload) - { - super(message); - - setMessage(payload); - } - - - public RequiredDeliveryException(String message) - { - super(message); - } - - public void setMessage(final AMQMessage payload) - { - // we need to keep this message around so we can return it in the - // handler. - // Messages are all kept in memory now. Only queues can push messages out of memory. - _amqMessage = payload; - } - - public AMQMessage getAMQMessage() - { - return _amqMessage; - } - - public AMQConstant getErrorCode() - { - return getReplyCode(); - } - - public abstract AMQConstant getReplyCode(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java deleted file mode 100644 index 95de0dc8c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TxnOp; -import org.apache.qpid.server.queue.QueueEntry; - -/** - * A TxnOp implementation for handling accumulated acks - */ -public class TxAck implements TxnOp -{ - private final UnacknowledgedMessageMap _map; - private final Map _unacked = new HashMap(); - private List _individual; - private long _deliveryTag; - private boolean _multiple; - - public TxAck(UnacknowledgedMessageMap map) - { - _map = map; - } - - public void update(long deliveryTag, boolean multiple) - { - _unacked.clear(); - if (!multiple) - { - if(_individual == null) - { - _individual = new ArrayList(); - } - //have acked a single message that is not part of - //the previously acked region so record - //individually - _individual.add(deliveryTag);//_multiple && !multiple - } - else if (deliveryTag > _deliveryTag) - { - //have simply moved the last acked message on a - //bit - _deliveryTag = deliveryTag; - _multiple = true; - } - } - - public void consolidate() - { - if(_unacked.isEmpty()) - { - //lookup all the unacked messages that have been acked in this transaction - if (_multiple) - { - //get all the unacked messages for the accumulated - //multiple acks - _map.collect(_deliveryTag, true, _unacked); - } - if(_individual != null) - { - //get any unacked messages for individual acks outside the - //range covered by multiple acks - for (long tag : _individual) - { - if(_deliveryTag < tag) - { - _map.collect(tag, false, _unacked); - } - } - } - } - } - - public boolean checkPersistent() throws AMQException - { - consolidate(); - //if any of the messages in unacked are persistent the txn - //buffer must be marked as persistent: - for (QueueEntry msg : _unacked.values()) - { - if (msg.isPersistent()) - { - return true; - } - } - return false; - } - - public void prepare(StoreContext storeContext) throws AMQException - { - //make persistent changes, i.e. dequeue and decrementReference - for (QueueEntry msg : _unacked.values()) - { - //Message has been ack so dequeueAndDelete it. - // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed - // from the transaciton log - msg.dequeueAndDelete(storeContext); - } - } - - public void undoPrepare() - { - //As this is transaction the above dequeueAndDelete will only request the message be dequeue from the - // transactionLog. Only when the transaction succesfully completes will it perform any - // update of the internal transactionLog reference counting and any resulting message data deletion. - // The success or failure of the data deletion is not important to this transaction only that the ack has been - // successfully recorded. - } - - public void commit(StoreContext storeContext) - { - //remove the unacked messages from the channels map - _map.remove(_unacked); - } - - public void rollback(StoreContext storeContext) - { - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java deleted file mode 100644 index c80a96f967..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.Map; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; - -public interface UnacknowledgedMessageMap -{ - public interface Visitor - { - /** - * @param deliveryTag - *@param message the message being iterated over @return true to stop iteration, false to continue - * @throws AMQException - */ - boolean callback(final long deliveryTag, QueueEntry message) throws AMQException; - - void visitComplete(); - } - - void visit(Visitor visitor) throws AMQException; - - void add(long deliveryTag, QueueEntry message); - - void collect(long deliveryTag, boolean multiple, Map msgs); - - boolean contains(long deliveryTag) throws AMQException; - - void remove(Map msgs); - - QueueEntry remove(long deliveryTag); - - public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException; - - Collection cancelAllMessages(); - - void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; - - int size(); - - void clear(); - - QueueEntry get(long deliveryTag); - - /** - * Get the set of delivery tags that are outstanding. - * - * @return a set of delivery tags - */ - Set getDeliveryTags(); - - public long getUnacknowledgeBytes(); -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java deleted file mode 100644 index 5c38185696..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.server.store.StoreContext; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.txn.TransactionalContext; - -public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap -{ - private final Object _lock = new Object(); - - private long _unackedSize; - - private Map _map; - - private long _lastDeliveryTag; - - private final int _prefetchLimit; - - public UnacknowledgedMessageMapImpl(int prefetchLimit) - { - _prefetchLimit = prefetchLimit; - _map = new LinkedHashMap(prefetchLimit); - } - - public void collect(long deliveryTag, boolean multiple, Map msgs) - { - if (multiple) - { - collect(deliveryTag, msgs); - } - else - { - msgs.put(deliveryTag, get(deliveryTag)); - } - - } - - public boolean contains(long deliveryTag) throws AMQException - { - synchronized (_lock) - { - return _map.containsKey(deliveryTag); - } - } - - public void remove(Map msgs) - { - synchronized (_lock) - { - for (Long deliveryTag : msgs.keySet()) - { - remove(deliveryTag); - } - } - } - - public QueueEntry remove(long deliveryTag) - { - synchronized (_lock) - { - - QueueEntry message = _map.remove(deliveryTag); - if(message != null) - { - _unackedSize -= message.getSize(); - - } - - return message; - } - } - - public void visit(Visitor visitor) throws AMQException - { - synchronized (_lock) - { - Set> currentEntries = _map.entrySet(); - for (Map.Entry entry : currentEntries) - { - visitor.callback(entry.getKey().longValue(), entry.getValue()); - } - visitor.visitComplete(); - } - } - - public void add(long deliveryTag, QueueEntry message) - { - synchronized (_lock) - { - _map.put(deliveryTag, message); - _unackedSize += message.getSize(); - _lastDeliveryTag = deliveryTag; - } - } - - public Collection cancelAllMessages() - { - synchronized (_lock) - { - Collection currentEntries = _map.values(); - _map = new LinkedHashMap(_prefetchLimit); - _unackedSize = 0l; - 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(); - _unackedSize = 0l; - } - } - - public void drainTo(long deliveryTag, StoreContext storeContext) 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()); - } - - //Message has been ack so dequeueAndDelete it. - // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed - // from the transaciton log - unacked.getValue().dequeueAndDelete(storeContext); - - it.remove(); - - _unackedSize -= unacked.getValue().getSize(); - - - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - } - - public QueueEntry get(long key) - { - synchronized (_lock) - { - return _map.get(key); - } - } - - public Set getDeliveryTags() - { - synchronized (_lock) - { - return _map.keySet(); - } - } - - private void collect(long key, Map msgs) - { - synchronized (_lock) - { - for (Map.Entry entry : _map.entrySet()) - { - msgs.put(entry.getKey(),entry.getValue()); - if (entry.getKey() == key) - { - break; - } - } - } - } - - public long getUnacknowledgeBytes() - { - return _unackedSize; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java deleted file mode 100644 index c7cf0c0892..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import org.apache.commons.configuration.Configuration; - - -public class ExchangeConfiguration -{ - - private Configuration _config; - private String _name; - - public ExchangeConfiguration(String exchName, Configuration subset) - { - _name = exchName; - _config = subset; - } - - public String getName() - { - return _name; - } - - public String getType() - { - return _config.getString("type","direct"); - } - - public boolean getDurable() - { - return _config.getBoolean("durable", false); - } - - public boolean getAutoDelete() - { - return _config.getBoolean("autodelete",false); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java deleted file mode 100644 index 0b702b8505..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import java.util.List; - -import org.apache.commons.configuration.Configuration; - -public class QueueConfiguration -{ - - private Configuration _config; - private String _name; - private VirtualHostConfiguration _vHostConfig; - - public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) - { - _vHostConfig = virtualHostConfiguration; - _config = config; - _name = name; - } - - public VirtualHostConfiguration getVirtualHostConfiguration() - { - return _vHostConfig; - } - - public boolean getDurable() - { - return _config.getBoolean("durable" ,false); - } - - public boolean getAutoDelete() - { - return _config.getBoolean("autodelete", false); - } - - public String getOwner() - { - return _config.getString("owner", null); - } - - public boolean getPriority() - { - return _config.getBoolean("priority", false); - } - - public int getPriorities() - { - return _config.getInt("priorities", -1); - } - - public String getExchange() - { - return _config.getString("exchange", null); - } - - public List getRoutingKeys() - { - return _config.getList("routingKey"); - } - - public String getName() - { - return _name; - } - - public int getMaximumMessageAge() - { - return _config.getInt("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); - } - - public long getMaximumQueueDepth() - { - return _config.getLong("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth()); - } - - public long getMaximumMessageSize() - { - return _config.getLong("maximumMessageSize", _vHostConfig.getMaximumMessageSize()); - } - - public long getMaximumMessageCount() - { - return _config.getLong("maximumMessageCount", _vHostConfig.getMaximumMessageCount()); - } - - public long getMinimumAlertRepeatGap() - { - return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); - } - - public long getMemoryUsageMaximum() - { - return _config.getLong("maximumMemoryUsage", _vHostConfig.getMemoryUsageMaximum()); - } - - public long getMemoryUsageMinimum() - { - return _config.getLong("minimumMemoryUsage", _vHostConfig.getMemoryUsageMinimum()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java deleted file mode 100644 index 5d080f8df1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.configuration; - -import org.apache.commons.configuration.Configuration; - -public class SecurityConfiguration -{ - - private Configuration _conf; - - public SecurityConfiguration(Configuration configuration) - { - _conf = configuration; - } - - public Configuration getConfiguration() - { - return _conf; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java deleted file mode 100644 index ea8b29c76b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.configuration; - -import java.io.File; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.ConfigurationFactory; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sun.misc.Signal; -import sun.misc.SignalHandler; - -public class ServerConfiguration implements SignalHandler -{ - - private static Configuration _config; - - private static final int DEFAULT_FRAME_SIZE = 65536; - private static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; - private static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; - private static final int DEFAULT_PORT = 5672; - private static final int DEFAUL_SSL_PORT = 8672; - private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; - private static final int DEFAULT_JMXPORT = 8999; - - private static int _jmxPort = DEFAULT_JMXPORT; - - private Map _virtualHosts = new HashMap(); - private SecurityConfiguration _securityConfiguration = null; - - private File _configFile; - - private Logger _log = LoggerFactory.getLogger(this.getClass()); - - private ConfigurationManagementMBean _mbean; - - - // Map of environment variables to config items - private static final Map envVarMap = new HashMap(); - - { - envVarMap.put("QPID_PORT", "connector.port"); - envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers"); - envVarMap.put("QPID_SSLPORT", "connector.ssl.port"); - envVarMap.put("QPID_NIO", "connector.qpidnio"); - envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool"); - envVarMap.put("QPID_JMXPORT", "management.jmxport"); - envVarMap.put("QPID_FRAMESIZE", "advanced.framesize"); - envVarMap.put("QPID_MSGAUTH", "security.msg-auth"); - envVarMap.put("QPID_AUTOREGISTER", "auto_register"); - envVarMap.put("QPID_MANAGEMENTENABLED", "management.enabled"); - envVarMap.put("QPID_HEARTBEATDELAY", "heartbeat.delay"); - envVarMap.put("QPID_HEARTBEATTIMEOUTFACTOR", "heartbeat.timeoutFactor"); - envVarMap.put("QPID_MAXIMUMMESSAGEAGE", "maximumMessageAge"); - envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount"); - envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth"); - envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize"); - envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap"); - envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer"); - envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer"); - envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay"); - envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator"); - } - - public ServerConfiguration(File configurationURL) throws ConfigurationException - { - this(parseConfig(configurationURL)); - _configFile = configurationURL; - sun.misc.Signal.handle(new sun.misc.Signal("HUP"), this); - } - - public ServerConfiguration(Configuration conf) throws ConfigurationException - { - _config = conf; - - substituteEnvironmentVariables(); - - _jmxPort = _config.getInt("management.jmxport", 8999); - _securityConfiguration = new SecurityConfiguration(conf.subset("security")); - - setupVirtualHosts(conf); - - } - - private void setupVirtualHosts(Configuration conf) throws ConfigurationException - { - List vhosts = conf.getList("virtualhosts"); - Iterator i = vhosts.iterator(); - while (i.hasNext()) - { - Object thing = i.next(); - if (thing instanceof String) - { - XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); - List hosts = vhostConfiguration.getList("virtualhost.name"); - for (int j = 0; j < hosts.size(); j++) - { - String name = (String) hosts.get(j); - // Add the keys of the virtual host to the main config then bail out - - Configuration myConf = vhostConfiguration.subset("virtualhost." + name); - Iterator k = myConf.getKeys(); - while (k.hasNext()) - { - String key = (String) k.next(); - conf.setProperty("virtualhosts.virtualhost."+name+"."+key, myConf.getProperty(key)); - } - VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name), this); - _virtualHosts.put(vhostConfig.getName(), vhostConfig); - } - } - } - } - - private void substituteEnvironmentVariables() - { - for (Entry var : envVarMap.entrySet()) - { - String val = System.getenv(var.getKey()); - if (val != null) - { - _config.setProperty(var.getValue(), val); - } - } - } - - private final static Configuration parseConfig(File file) throws ConfigurationException - { - ConfigurationFactory factory = new ConfigurationFactory(); - factory.setConfigurationFileName(file.getAbsolutePath()); - Configuration conf = factory.getConfiguration(); - Iterator keys = conf.getKeys(); - if (!keys.hasNext()) - { - keys = null; - conf = flatConfig(file); - } - return conf; - } - - // 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 final static Configuration flatConfig(File file) throws ConfigurationException - { - // We have to override the interpolate methods so that - // interpolation takes place accross the entirety of the - // composite configuration. Without doing this each - // configuration object only interpolates variables defined - // inside itself. - final MyConfiguration conf = new MyConfiguration(); - conf.addConfiguration(new SystemConfiguration() - { - protected String interpolate(String o) - { - return conf.interpolate(o); - } - }); - conf.addConfiguration(new XMLConfiguration(file) - { - protected String interpolate(String o) - { - return conf.interpolate(o); - } - }); - return conf; - } - - @Override - public void handle(Signal arg0) - { - try - { - reparseConfigFile(); - } - catch (ConfigurationException e) - { - _log.error("Could not reload configuration file", e); - } - } - - public void reparseConfigFile() throws ConfigurationException - { - if (_configFile != null) - { - Configuration newConfig = parseConfig(_configFile); - _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); - ApplicationRegistry.getInstance().getAccessManager().configurePlugins(_securityConfiguration); - - VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); - for (String hostname : _virtualHosts.keySet()) - { - VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); - SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security")); - vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); - } - } - } - - public String getQpidWork() - { - return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); - } - - public void setJMXManagementPort(int mport) - { - _jmxPort = mport; - } - - public int getJMXManagementPort() - { - return _jmxPort; - } - - public boolean getPlatformMbeanserver() - { - return _config.getBoolean("management.platform-mbeanserver", true); - } - - public String[] getVirtualHosts() - { - return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); - } - - public String getPluginDirectory() - { - return _config.getString("plugin-directory"); - } - - public VirtualHostConfiguration getVirtualHostConfig(String name) - { - return _virtualHosts.get(name); - } - - public List getPrincipalDatabaseNames() - { - return _config.getList("security.principal-databases.principal-database.name"); - } - - public List getPrincipalDatabaseClass() - { - return _config.getList("security.principal-databases.principal-database.class"); - } - - public List getPrincipalDatabaseAttributeNames(int index) - { - String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name"; - return _config.getList(name); - } - - public List getPrincipalDatabaseAttributeValues(int index) - { - String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value"; - return _config.getList(name); - } - - public List getManagementPrincipalDBs() - { - return _config.getList("security.jmx.principal-database"); - } - - public List getManagementAccessList() - { - return _config.getList("security.jmx.access"); - } - - public int getFrameSize() - { - return _config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); - } - - public boolean getProtectIOEnabled() - { - return _config.getBoolean("broker.connector.protectio.enabled", false); - } - - public int getBufferReadLimit() - { - return _config.getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); - } - - public int getBufferWriteLimit() - { - return _config.getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); - } - - public boolean getSynchedClocks() - { - return _config.getBoolean("advanced.synced-clocks", false); - } - - public boolean getMsgAuth() - { - return _config.getBoolean("security.msg-auth", false); - } - - public String getJMXPrincipalDatabase() - { - return _config.getString("security.jmx.principal-database"); - } - - public String getManagementKeyStorePath() - { - return _config.getString("management.ssl.keyStorePath", null); - } - - public boolean getManagementSSLEnabled() - { - return _config.getBoolean("management.ssl.enabled", true); - } - - public String getManagementKeyStorePassword() - { - return _config.getString("management.ssl.keyStorePassword"); - } - - public SecurityConfiguration getSecurityConfiguration() - { - return _securityConfiguration; - } - - public boolean getQueueAutoRegister() - { - return _config.getBoolean("queue.auto_register", true); - } - - public boolean getManagementEnabled() - { - return _config.getBoolean("management.enabled", true); - } - - public void setManagementEnabled(boolean enabled) - { - _config.setProperty("management.enabled", enabled); - } - - - public int getHeartBeatDelay() - { - return _config.getInt("heartbeat.delay", 5); - } - - public double getHeartBeatTimeout() - { - return _config.getDouble("heartbeat.timeoutFactor", 2.0); - } - - public int getDeliveryPoolSize() - { - return _config.getInt("delivery.poolsize", 0); - } - - public long getMaximumMessageAge() - { - return _config.getLong("maximumMessageAge", 0); - } - - public long getMaximumMessageCount() - { - return _config.getLong("maximumMessageCount", 0); - } - - public long getMaximumQueueDepth() - { - return _config.getLong("maximumQueueDepth", 0); - } - - public long getMaximumMessageSize() - { - return _config.getLong("maximumMessageSize", 0); - } - - public long getMinimumAlertRepeatGap() - { - return _config.getLong("minimumAlertRepeatGap", 0); - } - - public int getProcessors() - { - return _config.getInt("connector.processors", 4); - } - - public int getPort() - { - return _config.getInt("connector.port", DEFAULT_PORT); - } - - public String getBind() - { - return _config.getString("connector.bind", "wildcard"); - } - - public int getReceiveBufferSize() - { - return _config.getInt("connector.socketReceiveBuffer", 32767); - } - - public int getWriteBufferSize() - { - return _config.getInt("connector.socketWriteBuffer", 32767); - } - - public boolean getTcpNoDelay() - { - return _config.getBoolean("connector.tcpNoDelay", true); - } - - public boolean getEnableExecutorPool() - { - return _config.getBoolean("advanced.filterchain[@enableExecutorPool]", false); - } - - public boolean getEnablePooledAllocator() - { - return _config.getBoolean("advanced.enablePooledAllocator", false); - } - - public boolean getEnableDirectBuffers() - { - return _config.getBoolean("advanced.enableDirectBuffers", false); - } - - public boolean getEnableSSL() - { - return _config.getBoolean("connector.ssl.enabled", false); - } - - public boolean getSSLOnly() - { - return _config.getBoolean("connector.ssl.sslOnly", true); - } - - public int getSSLPort() - { - return _config.getInt("connector.ssl.port", DEFAUL_SSL_PORT); - } - - public String getKeystorePath() - { - return _config.getString("connector.ssl.keystorePath", "none"); - } - - public String getKeystorePassword() - { - return _config.getString("connector.ssl.keystorePassword", "none"); - } - - public String getCertType() - { - return _config.getString("connector.ssl.certType", "SunX509"); - } - - public boolean getQpidNIO() - { - return _config.getBoolean("connector.qpidnio", false); - } - - public boolean getUseBiasedWrites() - { - return _config.getBoolean("advanced.useWriteBiasedPool", false); - } - - public String getDefaultVirtualHost() - { - return _config.getString("virtualhosts.default"); - } - - public void setHousekeepingExpiredMessageCheckPeriod(long value) - { - _config.setProperty("housekeeping.expiredMessageCheckPeriod", value); - } - - public long getHousekeepingCheckPeriod() - { - return _config.getLong("housekeeping.checkPeriod", - _config.getLong("housekeeping.expiredMessageCheckPeriod", - DEFAULT_HOUSEKEEPING_PERIOD)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java deleted file mode 100644 index edcb32fc43..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MemoryMessageStore; - -public class VirtualHostConfiguration -{ - private Configuration _config; - private String _name; - private Map _queues = new HashMap(); - private Map _exchanges = new HashMap(); - private ServerConfiguration _serverConfiguration; - - public VirtualHostConfiguration(String name, Configuration config, - ServerConfiguration serverConfiguration) throws ConfigurationException - { - _serverConfiguration = serverConfiguration; - _config = config; - _name = name; - - Iterator i = _config.getList("queues.queue.name").iterator(); - - while (i.hasNext()) - { - String queueName = (String) i.next(); - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); - mungedConf.addConfiguration(_config.subset("queues")); - _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); - } - - i = _config.getList("exchanges.exchange.name").iterator(); - int count = 0; - while (i.hasNext()) - { - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); - mungedConf.addConfiguration(_config.subset("exchanges")); - String exchName = (String) i.next(); - _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); - } - } - - /** - * All future usages should use the constructor that takes the ServerConfiguration. - * - * This can be removed after QPID-1696 has been resolved. - * - * @param name - * @param mungedConf - * @throws ConfigurationException - */ - @Deprecated - public VirtualHostConfiguration(String name, Configuration mungedConf) throws ConfigurationException - { - this(name,mungedConf, ApplicationRegistry.getInstance().getConfiguration()); - } - - public String getName() - { - return _name; - } - - public long getHousekeepingExpiredMessageCheckPeriod() - { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", _serverConfiguration.getHousekeepingCheckPeriod()); - } - - public String getAuthenticationDatabase() - { - return _config.getString("security.authentication.name"); - } - - public List getCustomExchanges() - { - return _config.getList("custom-exchanges.class-name"); - } - - public SecurityConfiguration getSecurityConfiguration() - { - return new SecurityConfiguration(_config.subset("security")); - } - - public Configuration getStoreConfiguration() - { - return _config.subset("store"); - } - - public String getRoutingTableClass() - { - return _config.getString("routingtable.class"); - } - - public String getTransactionLogClass() - { - return _config.getString("store.class", MemoryMessageStore.class.getName()); - } - - public List getExchanges() - { - return _config.getList("exchanges.exchange.name"); - } - - public ExchangeConfiguration getExchangeConfiguration(String exchangeName) - { - return _exchanges.get(exchangeName); - } - - public String[] getQueueNames() - { - return _queues.keySet().toArray(new String[_queues.size()]); - } - - public QueueConfiguration getQueueConfiguration(String queueName) - { - // We might be asked for the config for a queue we don't know about, - // such as one that's been dynamically created. Those get the defaults by default. - if (_queues.containsKey(queueName)) - { - return _queues.get(queueName); - } - else - { - return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); - } - } - - public long getMemoryUsageMaximum() - { - return _config.getLong("queues.maximumMemoryUsage", 100 * 1024 * 1024); - } - - public long getMemoryUsageMinimum() - { - return _config.getLong("queues.minimumMemoryUsage", 0); - } - - public ServerConfiguration getServerConfiguration() - { - return _serverConfiguration; - } - - public static final String FLOW_TO_DISK_PATH = "flowToDiskPath"; - public String getFlowToDiskLocation() - { - return _config.getString(FLOW_TO_DISK_PATH, getServerConfiguration().getQpidWork()); - } - - public int getMaximumMessageAge() - { - return _config.getInt("queues.maximumMessageAge", 0); - } - - public Long getMaximumQueueDepth() - { - return _config.getLong("queues.maximumQueueDepth", 0); - } - - public Long getMaximumMessageSize() - { - return _config.getLong("queues.maximumMessageSize", 0); - } - - public Long getMaximumMessageCount() - { - return _config.getLong("queues.maximumMessageCount", 0); - } - - public Long getMinimumAlertRepeatGap() - { - return _config.getLong("queues.minimumAlertRepeatGap", 0); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java deleted file mode 100644 index 8e4bf01c6a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.management; - -import javax.management.MBeanOperationInfo; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.management.MBeanOperation; - -public interface ConfigurationManagement -{ - - String TYPE = "ConfigurationManagement"; - int VERSION = 1; - - /** - * Reload the - * @throws ConfigurationException - */ - @MBeanOperation(name="reloadSecurityConfiguration", - description = "Force a reload of the security configuration sections", - impact = MBeanOperationInfo.ACTION) - void reloadSecurityConfiguration() throws ConfigurationException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java deleted file mode 100644 index ead6053d70..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.management; - -import javax.management.NotCompliantMBeanException; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement -{ - - public ConfigurationManagementMBean() throws NotCompliantMBeanException - { - super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION); - } - - @Override - public String getObjectInstanceName() - { - return ConfigurationManagement.TYPE; - } - - @Override - public void reloadSecurityConfiguration() throws ConfigurationException - { - ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java deleted file mode 100644 index d287595e2d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.connection; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.protocol.AMQConstant; - -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.List; - -public class ConnectionRegistry implements IConnectionRegistry -{ - private List _registry = new CopyOnWriteArrayList(); - - private VirtualHost _virtualHost; - - public ConnectionRegistry(VirtualHost virtualHost) - { - _virtualHost = virtualHost; - } - - public void initialise() - { - - } - - /** Close all of the currently open connections. */ - public void close() throws AMQException - { - while (!_registry.isEmpty()) - { - AMQProtocolSession connection = _registry.get(0); - - connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", - 0, 0, - connection.getProtocolOutputConverter().getProtocolMajorVersion(), - connection.getProtocolOutputConverter().getProtocolMinorVersion(), - (Throwable) null), true); - } - } - - public void registerConnection(AMQProtocolSession connnection) - { - _registry.add(connnection); - } - - public void deregisterConnection(AMQProtocolSession connnection) - { - _registry.remove(connnection); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java deleted file mode 100644 index d64fde1c20..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.connection; - -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; - -public interface IConnectionRegistry -{ - - public void initialise(); - - public void close() throws AMQException; - - public void registerConnection(AMQProtocolSession connnection); - - public void deregisterConnection(AMQProtocolSession connnection); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java deleted file mode 100644 index 30af09ce4b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.ArrayType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public abstract class AbstractExchange implements Exchange, Managable -{ - private AMQShortString _name; - - - - protected boolean _durable; - protected String _exchangeType; - protected int _ticket; - - private VirtualHost _virtualHost; - - 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 - { - // open mbean data types for representing exchange bindings - protected String[] _bindingItemNames; - protected String[] _bindingItemIndexNames; - protected OpenType[] _bindingItemTypes; - protected CompositeType _bindingDataType; - protected TabularType _bindinglistDataType; - protected TabularDataSupport _bindingList; - - public ExchangeMBean() throws NotCompliantMBeanException - { - super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); - } - - protected void init() throws OpenDataException - { - _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; - - _bindingItemTypes = new OpenType[2]; - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - - public ManagedObject getParentObject() - { - return _virtualHost.getManagedObject(); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public String getExchangeType() - { - return _exchangeType; - } - - public Integer getTicketNo() - { - return _ticket; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - // Added exchangetype in the object name lets maangement apps to do any customization required - public ObjectName getObjectName() throws MalformedObjectNameException - { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + _exchangeType; - return new ObjectName(objNameString); - } - - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - } // End of MBean class - - public AMQShortString 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(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException - { - _virtualHost = host; - _name = name; - _durable = durable; - _autoDelete = autoDelete; - _ticket = ticket; - _exchangeMbean = createMBean(); - _exchangeMbean.register(); - } - - 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().getSimpleName() + "[" + getName() +"]"; - } - - public ManagedObject getManagedObject() - { - return _exchangeMbean; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public QueueRegistry getQueueRegistry() - { - return getVirtualHost().getQueueRegistry(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java deleted file mode 100644 index c04b6c559c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class DefaultExchangeFactory implements ExchangeFactory -{ - private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); - - private Map> _exchangeClassMap = new HashMap>(); - private final VirtualHost _host; - - public DefaultExchangeFactory(VirtualHost host) - { - _host = host; - registerExchangeType(DirectExchange.TYPE); - registerExchangeType(TopicExchange.TYPE); - registerExchangeType(HeadersExchange.TYPE); - registerExchangeType(FanoutExchange.TYPE); - } - - public void registerExchangeType(ExchangeType type) - { - _exchangeClassMap.put(type.getName(), type); - } - - public Collection> getRegisteredTypes() - { - return _exchangeClassMap.values(); - } - - public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException - { - ExchangeType exchType = _exchangeClassMap.get(type); - if (exchType == null) - { - - throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); - } - Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); - return e; - } - - @Override - public void initialise(VirtualHostConfiguration hostConfig) - { - - if (hostConfig == null) - { - return; - } - - for(Object className : hostConfig.getCustomExchanges()) - { - try - { - ExchangeType exchangeType = ApplicationRegistry.getInstance().getPluginManager().getExchanges().get(String.valueOf(className)); - if (exchangeType == null) - { - _logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\""); - return; - } - Class exchangeTypeClass = exchangeType.getClass(); - ExchangeType type = exchangeTypeClass.newInstance(); - registerExchangeType(type); - } - catch (ClassCastException classCastEx) - { - _logger.error("No custom exchange class: \""+String.valueOf(className)+"\" cannot be registered as it does not extend class \""+ExchangeType.class+"\""); - } - catch (IllegalAccessException e) - { - _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); - } - catch (InstantiationException e) - { - _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); - } - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java deleted file mode 100644 index 3e930364df..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.routing.RoutingTable; - -import java.util.Collection; -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(); - - private Exchange _defaultExchange; - private VirtualHost _host; - - public DefaultExchangeRegistry(VirtualHost host) - { - //create 'standard' exchanges: - _host = host; - - } - - public void initialise() throws AMQException - { - new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); - } - - public RoutingTable getRoutingTable() - { - return _host.getRoutingTable(); - } - - public void registerExchange(Exchange exchange) throws AMQException - { - _exchangeMap.put(exchange.getName(), exchange); - if (exchange.isDurable()) - { - getRoutingTable().createExchange(exchange); - } - } - - public void setDefaultExchange(Exchange exchange) - { - _defaultExchange = exchange; - } - - public Exchange getDefaultExchange() - { - return _defaultExchange; - } - - public Collection getExchangeNames() - { - return _exchangeMap.keySet(); - } - - public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException - { - // TODO: check inUse argument - Exchange e = _exchangeMap.remove(name); - if (e != null) - { - if (e.isDurable()) - { - getRoutingTable().removeExchange(e); - } - e.close(); - } - else - { - throw new AMQException("Unknown exchange " + name); - } - } - - public Exchange getExchange(AMQShortString name) - { - if ((name == null) || name.length() == 0) - { - return getDefaultExchange(); - } - else - { - 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(IncomingMessage payload) throws AMQException - { - final AMQShortString exchange = payload.getExchange(); - final Exchange exch = getExchange(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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java deleted file mode 100644 index e9af92bad8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class DirectExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(DirectExchange.class); - - /** - * Maps from queue name to queue instances - */ - private final Index _index = new Index(); - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return DirectExchange.class; - } - - public DirectExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - DirectExchange exch = new DirectExchange(); - exch.initialise(host,name,durable,ticket,autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.DIRECT_EXCHANGE_NAME; - } - }; - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DirectExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DirectExchangeMBean() throws JMException - { - super(); - _exchangeType = "direct"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - Map> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : bindings.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(DirectExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - }// End of MBean class - - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DirectExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } - } - - public AMQShortString getType() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - if (!_index.add(routingKey, queue)) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this); - } - } - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that _routing key"); - } - } - - public void route(IncomingMessage payload) throws AMQException - { - - final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); - - final ArrayList queues = (routingKey == null) ? null : _index.get(routingKey); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + queues); - } - - payload.enqueue(queues); - - - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey,queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - final List queues = _index.get(routingKey); - return queues != null && queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - final List queues = _index.get(routingKey); - return queues != null && !queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - Map> bindings = _index.getBindingsMap(); - for (List queues : bindings.values()) - { - if (queues.contains(queue)) - { - return true; - } - } - return false; - } - - public boolean hasBindings() - { - return !_index.getBindingsMap().isEmpty(); - } - - public Map> getBindings() - { - return _index.getBindingsMap(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java deleted file mode 100644 index 06209c5458..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; - -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.List; -import java.util.Map; - -public interface Exchange -{ - AMQShortString getName(); - - AMQShortString getType(); - - void initialise(VirtualHost host, AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - void route(IncomingMessage message) throws AMQException; - - - /** - * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments - * @param routingKey - * @param arguments - * @param queue - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); - - /** - * Determines whether a message would be isBound to a particular queue using a specific routing key - * @param routingKey - * @param queue - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey, AMQQueue queue); - - /** - * Determines whether a message is routing to any queue using a specific _routing key - * @param routingKey - * @return - * @throws AMQException - */ - boolean isBound(AMQShortString routingKey); - - boolean isBound(AMQQueue queue); - - /** - * Returns true if this exchange has at least one binding associated with it. - * @return - * @throws AMQException - */ - boolean hasBindings(); - - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java deleted file mode 100644 index 2f76d41228..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.Collection; - -import org.apache.commons.configuration.Configuration; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; - - -public interface ExchangeFactory -{ - Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException; - - void initialise(VirtualHostConfiguration hostConfig); - - Collection> getRegisteredTypes(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java deleted file mode 100644 index c77f114428..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; - -/** - * ExchangeInUseRegistry indicates that an exchange cannot be unregistered because it is currently being used. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to unregister exchange that is in use. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo This exception is not used. However, it is part of the ExchangeRegistry interface, and looks like code is - * going to need to be added to throw/deal with this. Alternatively ExchangeResitries may be able to handle the - * issue internally. - */ -public class ExchangeInUseException extends AMQException -{ - public ExchangeInUseException(String exchangeName) - { - super("Exchange " + exchangeName + " is currently in use"); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java deleted file mode 100644 index fe3b19e74e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; - -import java.util.Collection; - - -public interface ExchangeRegistry extends MessageRouter -{ - void registerExchange(Exchange exchange) throws AMQException; - - /** - * 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(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; - - Exchange getExchange(AMQShortString name); - - void setDefaultExchange(Exchange exchange); - - Exchange getDefaultExchange(); - - Collection getExchangeNames(); - - void initialise() throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java deleted file mode 100644 index 0b55caa2f1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.virtualhost.VirtualHost; - - -public interface ExchangeType -{ - public AMQShortString getName(); - public Class getExchangeClass(); - public T newInstance(VirtualHost host, AMQShortString name, - boolean durable, int ticket, boolean autoDelete) throws AMQException; - public AMQShortString getDefaultExchangeName(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java deleted file mode 100644 index e9fd4d548b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArraySet; - -public class FanoutExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(FanoutExchange.class); - - /** - * Maps from queue name to queue instances - */ - private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Fanout Exchange") - private final class FanoutExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException - { - super(); - _exchangeType = "fanout"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (AMQQueue queue : _queues) - { - String queueName = queue.getName().toString(); - - Object[] bindingItemValues = {queueName, new String[]{queueName}}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(FanoutExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new FanoutExchange.FanoutExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } - } - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return FanoutExchange.class; - } - - public FanoutExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - FanoutExchange exch = new FanoutExchange(); - exch.initialise(host, name, durable, ticket, autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.FANOUT_EXCHANGE_NAME; - } - }; - - public Map> getBindings() - { - return null; - } - - public AMQShortString getType() - { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (_queues.contains(queue)) - { - _logger.debug("Queue " + queue + " is already registered"); - } - else - { - _queues.add(queue); - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); - } - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (!_queues.remove(queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); - } - } - - public void route(IncomingMessage payload) throws AMQException - { - - - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + _queues); - } - - payload.enqueue(new ArrayList(_queues)); - - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return _queues.contains(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - - return (_queues != null) && !_queues.isEmpty(); - } - - public boolean isBound(AMQQueue queue) - { - - return _queues.contains(queue); - } - - public boolean hasBindings() - { - return !_queues.isEmpty(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java deleted file mode 100644 index 2b7df4361a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.log4j.Logger; -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.FieldTable; - -/** - * Defines binding and matching based on a set of headers. - */ -class HeadersBinding -{ - private static final Logger _logger = Logger.getLogger(HeadersBinding.class); - - private final FieldTable _mappings; - private final Set required = new HashSet(); - private final Map matches = new HashMap(); - private boolean matchAny; - - private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor - { - private Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor - { - Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if(required.contains(propertyName)) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - - - /** - * 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(FieldTable mappings) - { - _mappings = mappings; - initMappings(); - } - - private void initMappings() - { - - _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if (isSpecial(propertyName)) - { - processSpecial(propertyName, value.getValue()); - } - else if (value.getValue() == null || value.getValue().equals("")) - { - required.add(propertyName); - } - else - { - matches.put(propertyName,value.getValue()); - } - - return true; - } - - public Object getResult() - { - return null; - } - }); - } - - protected FieldTable 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(FieldTable headers) - { - if(headers == null) - { - return required.isEmpty() && matches.isEmpty(); - } - else - { - return matchAny ? or(headers) : and(headers); - } - } - - private boolean and(FieldTable headers) - { - if(headers.keys().containsAll(required)) - { - for(Map.Entry e : matches.entrySet()) - { - if(!e.getValue().equals(headers.getObject(e.getKey()))) - { - return false; - } - } - return true; - } - else - { - return false; - } - } - - - private boolean or(final FieldTable headers) - { - if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) - { - return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) - || (required.isEmpty() && matches.isEmpty()); - } - else - { - return true; - } - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java deleted file mode 100644 index 1ee1f35de6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Collection; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * An exchange that binds queues based on a set of required headers and header values - * and routes messages to these queues by matching the headers of the message against - * those with which the queues were bound. - *

      - *

      - * The Headers Exchange
      - *
      - *  Routes messages according to the value/presence of fields in the message header table.
      - *  (Basic and JMS content has a content header field called "headers" that is a table of
      - *   message header fields).
      - *
      - *  class = "headers"
      - *  routing key is not used
      - *
      - *  Has the following binding arguments:
      - *
      - *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
      - *  other fields prefixed with "X-" are ignored (and generate a console warning message).
      - *  a field with no value or empty value indicates a match on presence only.
      - *  a field with a value indicates match on field presence and specific value.
      - *
      - *  Standard instances:
      - *
      - *  amq.match - pub/sub on field content/value
      - *  
      - */ -public class HeadersExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - - - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return HeadersExchange.class; - } - - public HeadersExchange newInstance(VirtualHost host, AMQShortString name, boolean durable, int ticket, - boolean autoDelete) throws AMQException - { - HeadersExchange exch = new HeadersExchange(); - exch.initialise(host, name, durable, ticket, autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - - return ExchangeDefaults.HEADERS_EXCHANGE_NAME; - } - }; - - - 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 - { - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException - { - super(); - _exchangeType = "headers"; - init(); - } - - /** - * initialises the OpenType objects. - */ - protected void init() throws OpenDataException - { - _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; - - _bindingItemTypes = new OpenType[3]; - _bindingItemTypes[0] = SimpleType.INTEGER; - _bindingItemTypes[1] = SimpleType.STRING; - _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); - } - - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - int count = 1; - for (Iterator itr = _bindings.iterator(); itr.hasNext();) - { - Registration registration = itr.next(); - String queueName = registration.queue.getName().toString(); - - HeadersBinding headers = registration.binding; - FieldTable headerMappings = headers.getMappings(); - final List mappingList = new ArrayList(); - - headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - mappingList.add(propertyName + "=" + value.getValue()); - return true; - } - - public Object getResult() - { - return mappingList; - } - }); - - - Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - /** - * Creates bindings. Binding pattern is as follows- - * =,=,... - * @param queueName - * @param binding - * @throws javax.management.JMException - */ - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - String[] bindings = binding.split(","); - FieldTable bindingMap = new FieldTable(); - for (int i = 0; i < bindings.length; i++) - { - String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length < 2) - { - throw new JMException("Format for headers binding should be \"=,=\" "); - } - bindingMap.setString(keyAndValue[0], keyAndValue[1]); - } - - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); - _bindings.add(new Registration(new HeadersBinding(args), queue)); - } - - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - if(!_bindings.remove(new Registration(new HeadersBinding(args), queue))) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with headers args " + args); - } - } - - public void route(IncomingMessage payload) throws AMQException - { - FieldTable headers = getHeaders(payload.getContentHeaderBody()); - if (_logger.isDebugEnabled()) - { - _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); - } - boolean routed = false; - ArrayList queues = new ArrayList(); - 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()); - } - queues.add(e.queue); - - routed = true; - } - } - payload.enqueue(queues); - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - //fixme isBound here should take the arguements in to consideration. - return isBound(routingKey, queue); - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return isBound(queue); - } - - public boolean isBound(AMQShortString routingKey) - { - return hasBindings(); - } - - public boolean isBound(AMQQueue queue) - { - for (Registration r : _bindings) - { - if (r.queue.equals(queue)) - { - return true; - } - } - return false; - } - - public boolean hasBindings() - { - return !_bindings.isEmpty(); - } - - protected FieldTable 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 (JMException ex) - { - _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); - } - } - - public Map> getBindings() - { - return null; - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java deleted file mode 100644 index ec83161029..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * An index of queues against routing key. Allows multiple queues to be stored - * against the same key. Used in the DirectExchange. - */ -class Index -{ - private ConcurrentMap> _index - = new ConcurrentHashMap>(); - - synchronized boolean add(AMQShortString key, AMQQueue queue) - { - ArrayList queues = _index.get(key); - if(queues == null) - { - queues = new ArrayList(); - } - else - { - queues = new ArrayList(queues); - } - //next call is atomic, so there is no race to create the list - _index.put(key, queues); - - if(queues.contains(queue)) - { - return false; - } - else - { - return queues.add(queue); - } - } - - synchronized boolean remove(AMQShortString key, AMQQueue queue) - { - ArrayList queues = _index.get(key); - if (queues != null) - { - queues = new ArrayList(queues); - boolean removed = queues.remove(queue); - if(removed) - { - if (queues.size() == 0) - { - _index.remove(key); - } - else - { - _index.put(key, queues); - } - } - return removed; - } - return false; - } - - ArrayList get(AMQShortString key) - { - return _index.get(key); - } - - Map> getBindingsMap() - { - return new HashMap>(_index); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java deleted file mode 100644 index 317ff385ab..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The management interface exposed to allow management of an Exchange. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedExchange -{ - static final String TYPE = "Exchange"; - static final int VERSION = 1; - - /** - * Returns the name of the managed exchange. - * @return the name of the exchange. - * @throws IOException - */ - @MBeanAttribute(name="Name", description=TYPE + " Name") - String getName() throws IOException; - - @MBeanAttribute(name="ExchangeType", description="Exchange Type") - String getExchangeType() throws IOException; - - @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") - Integer getTicketNo() throws IOException; - - /** - * Tells if the exchange is durable or not. - * @return true if the exchange is durable. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description="true if Exchange is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the exchange is set for autodelete or not. - * @return true if the exchange is set as autodelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") - boolean isAutoDelete() throws IOException; - - // Operations - - /** - * Returns all the bindings this exchange has with the queues. - * @return the bindings with the exchange. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") - TabularData bindings() throws IOException, JMException; - - /** - * Creates new binding with the given queue and binding. - * @param queueName - * @param binding - * @throws JMException - */ - @MBeanOperation(name="createNewBinding", - description="create a new binding with this exchange", - impact= MBeanOperationInfo.ACTION) - void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, - @MBeanOperationParameter(name="Binding", description="New binding")String binding) - throws JMException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java deleted file mode 100644 index f0c2d3903e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.IncomingMessage; - -/** - * 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(IncomingMessage message) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java deleted file mode 100644 index d44afa8494..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message - * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report - * this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoRouteException extends RequiredDeliveryException -{ - public NoRouteException(String msg, AMQMessage amqMessage) - { - super(msg, amqMessage); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_ROUTE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java deleted file mode 100644 index bc303a219d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ /dev/null @@ -1,670 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.common.AMQPFilterTypes; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortStringTokenizer; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.topic.TopicParser; -import org.apache.qpid.server.exchange.topic.TopicMatcherResult; -import org.apache.qpid.server.filter.MessageFilter; -import org.apache.qpid.server.filter.JMSSelectorFilter; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.lang.ref.WeakReference; - -public class TopicExchange extends AbstractExchange -{ - - public static final ExchangeType TYPE = new ExchangeType() - { - - public AMQShortString getName() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public Class getExchangeClass() - { - return TopicExchange.class; - } - - public TopicExchange newInstance(VirtualHost host, - AMQShortString name, - boolean durable, - int ticket, - boolean autoDelete) throws AMQException - { - TopicExchange exch = new TopicExchange(); - exch.initialise(host, name, durable, ticket, autoDelete); - return exch; - } - - public AMQShortString getDefaultExchangeName() - { - return ExchangeDefaults.TOPIC_EXCHANGE_NAME; - } - }; - - - private static final Logger _logger = Logger.getLogger(TopicExchange.class); - -/* - private final ConcurrentHashMap> _bindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _simpleBindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _wildCardBindingKey2queues = - new ConcurrentHashMap>(); -*/ - // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); - private static final byte TOPIC_SEPARATOR = (byte)'.'; - private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); - private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); - private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); - - private static final byte HASH_BYTE = (byte)'#'; - private static final byte STAR_BYTE = (byte)'*'; - - private final TopicParser _parser = new TopicParser(); - - private final Map _topicExchangeResults = - new ConcurrentHashMap(); - - private final Map _bindings = new HashMap(); - - private final Map>> _selectorCache = new WeakHashMap>>(); - - public static class Binding - { - private final AMQShortString _bindingKey; - private final AMQQueue _queue; - private final FieldTable _args; - - public Binding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) - { - _bindingKey = bindingKey; - _queue = queue; - _args = args; - } - - public AMQShortString getBindingKey() - { - return _bindingKey; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public int hashCode() - { - return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); - } - - public boolean equals(Object o) - { - if(this == o) - { - return true; - } - if(o instanceof Binding) - { - Binding other = (Binding) o; - return (_queue == other._queue) - && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); - } - return false; - } - } - - - - private final class TopicExchangeResult implements TopicMatcherResult - { - private final Map _unfilteredQueues = new ConcurrentHashMap(); - private final ConcurrentHashMap,Integer>> _filteredQueues = new ConcurrentHashMap, Integer>>(); - - public void addUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == null) - { - _unfilteredQueues.put(queue, 1); - } - else - { - _unfilteredQueues.put(queue, instances + 1); - } - } - - public void removeUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == 1) - { - _unfilteredQueues.remove(queue); - } - else - { - _unfilteredQueues.put(queue,instances - 1); - } - - } - - - public void addFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map,Integer> filters = _filteredQueues.get(queue); - if(filters == null) - { - filters = new ConcurrentHashMap,Integer>(); - _filteredQueues.put(queue, filters); - } - Integer instances = filters.get(filter); - if(instances == null) - { - filters.put(filter,1); - } - else - { - filters.put(filter, instances + 1); - } - - } - - public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map,Integer> filters = _filteredQueues.get(queue); - if(filters != null) - { - Integer instances = filters.get(filter); - if(instances != null) - { - if(instances == 1) - { - filters.remove(filter); - if(filters.isEmpty()) - { - _filteredQueues.remove(queue); - } - } - else - { - filters.put(filter, instances - 1); - } - } - - } - - } - - public void replaceQueueFilter(AMQQueue queue, - MessageFilter oldFilter, - MessageFilter newFilter) - { - Map,Integer> filters = _filteredQueues.get(queue); - Map,Integer> newFilters = new ConcurrentHashMap,Integer>(filters); - Integer oldFilterInstances = filters.get(oldFilter); - if(oldFilterInstances == 1) - { - newFilters.remove(oldFilter); - } - else - { - newFilters.put(oldFilter, oldFilterInstances-1); - } - Integer newFilterInstances = filters.get(newFilter); - if(newFilterInstances == null) - { - newFilters.put(newFilter, 1); - } - else - { - newFilters.put(newFilter, newFilterInstances+1); - } - _filteredQueues.put(queue,newFilters); - } - - public Collection processMessage(IncomingMessage msg, Collection queues) - { - if(queues == null) - { - if(_filteredQueues.isEmpty()) - { - return new ArrayList(_unfilteredQueues.keySet()); - } - else - { - queues = new HashSet(); - } - } - else if(!(queues instanceof Set)) - { - queues = new HashSet(queues); - } - - queues.addAll(_unfilteredQueues.keySet()); - if(!_filteredQueues.isEmpty()) - { - for(Map.Entry, Integer>> entry : _filteredQueues.entrySet()) - { - if(!queues.contains(entry.getKey())) - { - for(MessageFilter filter : entry.getValue().keySet()) - { - if(filter.matches(msg)) - { - queues.add(entry.getKey()); - } - } - } - } - } - return queues; - } - - } - - - /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class TopicExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public TopicExchangeMBean() throws JMException - { - super(); - _exchangeType = "topic"; - init(); - } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - Map> bindingData = new HashMap>(); - for (Binding binding : _bindings.keySet()) - { - String key = binding.getBindingKey().toString(); - List queueNames = bindingData.get(key); - if(queueNames == null) - { - queueNames = new ArrayList(); - bindingData.put(key, queueNames); - } - queueNames.add(binding.getQueue().getName().toString()); - - } - for(Map.Entry> entry : bindingData.entrySet()) - { - Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); - _bindingList.put(bindingCompositeData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - queue.bind(TopicExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; - } - - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); - - - AMQShortString routingKey; - - if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) - { - routingKey = normalize(rKey); - } - else - { - routingKey = rKey; - } - - Binding binding = new Binding(rKey, queue, args); - - if(_bindings.containsKey(binding)) - { - FieldTable oldArgs = _bindings.get(binding); - TopicExchangeResult result = _topicExchangeResults.get(routingKey); - - if(argumentsContainSelector(args)) - { - if(argumentsContainSelector(oldArgs)) - { - result.replaceQueueFilter(queue,createSelectorFilter(oldArgs), createSelectorFilter(args)); - } - else - { - result.addFilteredQueue(queue,createSelectorFilter(args)); - result.removeUnfilteredQueue(queue); - } - } - else - { - if(argumentsContainSelector(oldArgs)) - { - result.addUnfilteredQueue(queue); - result.removeFilteredQueue(queue, createSelectorFilter(oldArgs)); - } - else - { - // TODO - fix control flow - return; - } - } - - } - else - { - - TopicExchangeResult result = _topicExchangeResults.get(routingKey); - if(result == null) - { - result = new TopicExchangeResult(); - if(argumentsContainSelector(args)) - { - result.addFilteredQueue(queue, createSelectorFilter(args)); - } - else - { - result.addUnfilteredQueue(queue); - } - _parser.addBinding(routingKey, result); - _topicExchangeResults.put(routingKey,result); - } - else - { - if(argumentsContainSelector(args)) - { - result.addFilteredQueue(queue, createSelectorFilter(args)); - } - else - { - result.addUnfilteredQueue(queue); - } - } - _bindings.put(binding, args); - } - - - } - - private JMSSelectorFilter createSelectorFilter(final FieldTable args) - throws AMQException - { - - final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - WeakReference> selectorRef = _selectorCache.get(selectorString); - JMSSelectorFilter selector = null; - - if(selectorRef == null || (selector = selectorRef.get())==null) - { - selector = new JMSSelectorFilter(selectorString); - _selectorCache.put(selectorString, new WeakReference>(selector)); - } - return selector; - } - - private static boolean argumentsContainSelector(final FieldTable args) - { - return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0; - } - - private AMQShortString normalize(AMQShortString routingKey) - { - if(routingKey == null) - { - routingKey = AMQShortString.EMPTY_STRING; - } - - AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); - - List subscriptionList = new ArrayList(); - - while (routingTokens.hasMoreTokens()) - { - subscriptionList.add(routingTokens.nextToken()); - } - - int size = subscriptionList.size(); - - for (int index = 0; index < size; index++) - { - // if there are more levels - if ((index + 1) < size) - { - if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) - { - if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) - { - // we don't need #.# delete this one - subscriptionList.remove(index); - size--; - // redo this normalisation - index--; - } - - if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) - { - // we don't want #.* swap to *.# - // remove it and put it in at index + 1 - subscriptionList.add(index + 1, subscriptionList.remove(index)); - } - } - } // if we have more levels - } - - - - AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); - - return normalizedString; - } - - public void route(IncomingMessage payload) throws AMQException - { - - final AMQShortString routingKey = payload.getRoutingKey(); - - // The copy here is unfortunate, but not too bad relevant to the amount of - // things created and copied in getMatchedQueues - ArrayList queues = new ArrayList(); - queues.addAll(getMatchedQueues(payload, routingKey)); - - if(queues == null || queues.isEmpty()) - { - _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); - } - - payload.enqueue(queues); - - } - - public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) - { - Binding binding = new Binding(routingKey, queue, arguments); - if (arguments == null) - { - return _bindings.containsKey(binding); - } - else - { - FieldTable o = _bindings.get(binding); - if (o != null) - { - return o.equals(arguments); - } - else - { - return false; - } - - } - } - - public boolean isBound(AMQShortString routingKey, AMQQueue queue) - { - return isBound(routingKey, null, queue); - } - - public boolean isBound(AMQShortString routingKey) - { - for(Binding b : _bindings.keySet()) - { - if(b.getBindingKey().equals(routingKey)) - { - return true; - } - } - - return false; - } - - public boolean isBound(AMQQueue queue) - { - for(Binding b : _bindings.keySet()) - { - if(b.getQueue().equals(queue)) - { - return true; - } - } - - return false; - } - - public boolean hasBindings() - { - return !_bindings.isEmpty(); - } - - public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - Binding binding = new Binding(rKey, queue, args); - - - if (!_bindings.containsKey(binding)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName() - + " with routing key " + rKey + "."); - } - - FieldTable bindingArgs = _bindings.remove(binding); - AMQShortString bindingKey = normalize(rKey); - TopicExchangeResult result = _topicExchangeResults.get(bindingKey); - if(argumentsContainSelector(bindingArgs)) - { - result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs)); - } - else - { - result.removeUnfilteredQueue(queue); - } - - } - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new TopicExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); - } - } - - private Collection getMatchedQueues(IncomingMessage message, AMQShortString routingKey) - { - - Collection results = _parser.parse(routingKey); - if(results.isEmpty()) - { - return Collections.EMPTY_SET; - } - else - { - Collection queues = results.size() == 1 ? null : new HashSet(); - for(TopicMatcherResult result : results) - { - - queues = ((TopicExchangeResult)result).processMessage(message, queues); - } - return queues; - } - - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java deleted file mode 100644 index 8fdb91cbef..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apache.qpid.server.exchange.headers; - -import org.apache.qpid.framing.AMQShortString; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class HeaderKey -{ - public static final HeaderKey UNKNOWN = new HeaderKey(new AMQShortString("<< UNKNOWN >>")); - private AMQShortString _key; - - public HeaderKey(final AMQShortString key) - { - _key = key; - } - - public String toString() - { - return _key.toString(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java deleted file mode 100644 index 7be99a88c9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.apache.qpid.server.exchange.headers; - -import org.apache.qpid.framing.AMQShortString; - -import java.util.Map; -import java.util.HashMap; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class HeaderKeyDictionary -{ - - private final Map _dictionary = new HashMap(); - - - public HeaderKey get(final AMQShortString key) - { - HeaderKey headerKey = _dictionary.get(key); - return headerKey == null ? HeaderKey.UNKNOWN : headerKey; - } - - public HeaderKey getOrCreate(final AMQShortString key) - { - HeaderKey headerKey = _dictionary.get(key); - if(headerKey == null) - { - headerKey = new HeaderKey(key); - _dictionary.put(key, headerKey); - } - return headerKey; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java deleted file mode 100644 index 518064bb29..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.apache.qpid.server.exchange.headers; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class HeaderMatcherResult -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java deleted file mode 100644 index 9da93d483a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java +++ /dev/null @@ -1,339 +0,0 @@ -package org.apache.qpid.server.exchange.headers; - -import org.apache.qpid.framing.AMQTypedValue; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.topic.TopicMatcherDFAState; -import org.apache.qpid.server.exchange.topic.TopicWord; -import org.apache.qpid.server.exchange.topic.TopicMatcherResult; - -import java.util.*; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class HeadersMatcherDFAState -{ - - - private final Collection _results; - private final Map> _nextStateMap; - private final HeaderKeyDictionary _dictionary; - - public HeadersMatcherDFAState(Map> nextStateMap, - Collection results, - HeaderKeyDictionary dictionary) - { - _nextStateMap = nextStateMap; - _results = results; - _dictionary = dictionary; - } - - - public Collection match(final FieldTable table) - { - return match(table.iterator()); - } - - - - public Collection match(Iterator> fieldTableIterator) - { - - if(_nextStateMap.isEmpty()) - { - return _results; - } - - while(fieldTableIterator.hasNext()) - { - - Map.Entry fieldTableEntry = fieldTableIterator.next(); - HeaderKey key = _dictionary.get(fieldTableEntry.getKey()); - if(key != HeaderKey.UNKNOWN) - { - Map valueToStateMap = _nextStateMap.get(key); - - if(valueToStateMap != null) - { - HeadersMatcherDFAState nextState = valueToStateMap.get(fieldTableEntry.getValue()); - - if(nextState == null) - { - nextState = valueToStateMap.get(null); - } - if(nextState != null && nextState != this) - { - return nextState.match(fieldTableIterator); - } - } - - } - } - - return _results; - - } - - - HeadersMatcherDFAState mergeStateMachines(HeadersMatcherDFAState otherStateMachine) - { - - assert(otherStateMachine._dictionary == _dictionary); - - Map, HeadersMatcherDFAState> newStateMap= new HashMap, HeadersMatcherDFAState>(); - - Collection results; - - if(_results.isEmpty()) - { - results = otherStateMachine._results; - } - else if(otherStateMachine._results.isEmpty()) - { - results = _results; - } - else - { - results = new HashSet(_results); - results.addAll(otherStateMachine._results); - } - - - final Map> newNextStateMap = new HashMap>(); - - HeadersMatcherDFAState newState = new HeadersMatcherDFAState(newNextStateMap, results, _dictionary); - - - Set oldStates = new HashSet(); - oldStates.add(this); - oldStates.add(otherStateMachine); - - newStateMap.put(oldStates, newState); - - mergeStateMachines(oldStates, newNextStateMap, newStateMap); - - return newState; - - - } - - private void mergeStateMachines(final Set oldStates, - final Map> newNextStateMap, - final Map, HeadersMatcherDFAState> newStateMap) - { - Map>> nfaMap = new HashMap>>(); - - Set distinctKeys = new HashSet(); - - for(HeadersMatcherDFAState state : oldStates) - { - Map> map = state._nextStateMap; - - for(Map.Entry> entry : map.entrySet()) - { - Map> valueToStatesMap = nfaMap.get(entry.getKey()); - - if(valueToStatesMap == null) - { - valueToStatesMap = new HashMap>(); - nfaMap.put(entry.getKey(), valueToStatesMap); - } - - for(Map.Entry valueToStateEntry : entry.getValue().entrySet()) - { - Set states = valueToStatesMap.get(valueToStateEntry.getKey()); - if(states == null) - { - states = new HashSet(); - valueToStatesMap.put(valueToStateEntry.getKey(),states); - } - states.add(valueToStateEntry.getValue()); - } - - distinctKeys.add(entry.getKey()); - } - } - - Map> anyValueStates = new HashMap>(); - - for(HeaderKey distinctKey : distinctKeys) - { - Map> valueToStateMap = nfaMap.get(distinctKey); - if(valueToStateMap != null) - { - Set statesForKeyDefault = valueToStateMap.get(null); - if(statesForKeyDefault != null) - { - anyValueStates.put(distinctKey, statesForKeyDefault); - } - } - } - - // add the defaults for "null" to all other specified values of a given header key - - for( Map.Entry>> entry : nfaMap.entrySet()) - { - Map> valueToStatesMap = entry.getValue(); - for(Map.Entry> valueToStates : valueToStatesMap.entrySet()) - { - if(valueToStates.getKey() != null) - { - - - Set defaults = anyValueStates.get(entry.getKey()); - if(defaults != null) - { - valueToStates.getValue().addAll(defaults); - } - } - } - } - - // if a given header key is not mentioned in the map of a machine; then that machine would stay at the same state - // for that key. - for(HeaderKey distinctKey : distinctKeys) - { - Map> valueToStatesMap = nfaMap.get(distinctKey); - for(HeadersMatcherDFAState oldState : oldStates) - { - if(!oldState._nextStateMap.containsKey(distinctKey)) - { - for(Set endStates : valueToStatesMap.values()) - { - endStates.add(oldState); - } - } - } - } - - - - - for(Map.Entry>> transitionClass : nfaMap.entrySet()) - { - Map valueToDFAState = newNextStateMap.get(transitionClass.getKey()); - if(valueToDFAState == null) - { - valueToDFAState = new HashMap(); - newNextStateMap.put(transitionClass.getKey(), valueToDFAState); - } - - for(Map.Entry> transition : transitionClass.getValue().entrySet()) - { - Set destinations = transition.getValue(); - - - HeadersMatcherDFAState nextState = newStateMap.get(destinations); - - if(nextState == null) - { - - if(destinations.size() == 1) - { - nextState = destinations.iterator().next(); - newStateMap.put(destinations, nextState); - } - else - { - Collection results; - - Set> resultSets = new HashSet>(); - for(HeadersMatcherDFAState destination : destinations) - { - resultSets.add(destination._results); - } - resultSets.remove(Collections.EMPTY_SET); - if(resultSets.size() == 0) - { - results = Collections.EMPTY_SET; - } - else if(resultSets.size() == 1) - { - results = resultSets.iterator().next(); - } - else - { - results = new HashSet(); - for(Collection oldResult : resultSets) - { - results.addAll(oldResult); - } - } - - final Map> nextStateMap = new HashMap>(); - - nextState = new HeadersMatcherDFAState(nextStateMap, results, _dictionary); - newStateMap.put(destinations, nextState); - - mergeStateMachines( - destinations, - nextStateMap, - newStateMap); - - - } - - - } - valueToDFAState.put(transition.getKey(),nextState); - } - } - - - - final ArrayList removeKeyList = new ArrayList(); - - for(Map.Entry> entry : _nextStateMap.entrySet()) - { - final ArrayList removeValueList = new ArrayList(); - - for(Map.Entry valueToDFAState : entry.getValue().entrySet()) - { - if(valueToDFAState.getValue() == this) - { - HeadersMatcherDFAState defaultState = entry.getValue().get(null); - if(defaultState == null || defaultState == this) - { - removeValueList.add(valueToDFAState.getKey()); - } - } - } - - for(AMQTypedValue removeValue : removeValueList) - { - entry.getValue().remove(removeValue); - } - - if(entry.getValue().isEmpty()) - { - removeKeyList.add(entry.getKey()); - } - - } - - for(HeaderKey removeKey : removeKeyList) - { - _nextStateMap.remove(removeKey); - } - - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java deleted file mode 100644 index 85e74122c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.apache.qpid.server.exchange.headers; - -import org.apache.qpid.framing.*; - -import java.util.*; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class HeadersParser -{ - - private final HeaderKeyDictionary _dictionary = new HeaderKeyDictionary(); - private static final AMQShortString MATCHING_TYPE_KEY = new AMQShortString("x-match"); - private static final String ANY_MATCHING = "any"; - private static final AMQShortString RESERVED_KEY_PREFIX = new AMQShortString("x-"); - - - HeadersMatcherDFAState createStateMachine(FieldTable bindingArguments, HeaderMatcherResult result) - { - String matchingType = bindingArguments.getString(MATCHING_TYPE_KEY); - boolean matchAny = matchingType.equalsIgnoreCase(ANY_MATCHING); - if(matchAny) - { - return createStateMachineForAnyMatch(bindingArguments, result); - } - else - { - return createStateMachineForAllMatch(bindingArguments, result); - } - - - } - - - private HeadersMatcherDFAState createStateMachineForAnyMatch(final FieldTable bindingArguments, - final HeaderMatcherResult result) - { - - // DFAs for "any" matches have only two states, "not-matched" and "matched"... they start in the former - // and upon meeting any of the criteria they move to the latter - - //noinspection unchecked - final HeadersMatcherDFAState successState = - new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); - - Map> nextStateMap = - new HashMap>(); - - Set seenKeys = new HashSet(); - - Iterator> tableIterator = bindingArguments.iterator(); - - while(tableIterator.hasNext()) - { - final Map.Entry entry = tableIterator.next(); - final AMQShortString key = entry.getKey(); - final AMQTypedValue value = entry.getValue(); - - - if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) - { - final AMQType type = value.getType(); - - final HeaderKey headerKey = _dictionary.getOrCreate(key); - final Map valueMap; - - if(type == AMQType.VOID || - ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) - { - valueMap = Collections.singletonMap(null,successState); - - } - else - { - valueMap = Collections.singletonMap(value,successState); - } - nextStateMap.put(headerKey,valueMap); - - } - - } - - if(seenKeys.size() == 0) - { - return successState; - } - else - { - return new HeadersMatcherDFAState(nextStateMap,Collections.EMPTY_SET,_dictionary); - } - - - } - - - private HeadersMatcherDFAState createStateMachineForAllMatch(final FieldTable bindingArguments, - final HeaderMatcherResult result) - { - // DFAs for "all" matches have a "success" state, a "fail" state, and states for every subset of - // matches which are possible, starting with the empty subset. For example if we have a binding - // { x-match="all" - // a=1 - // b=1 - // c=1 - // d=1 } - // Then we would have the following states - // (1) Seen none of a, b, c, or d - // (2) Seen a=1 ; none of b,c, or d - // (3) Seen b=1 ; none of a,c, or d - // (4) Seen c=1 ; none of a,b, or d - // (5) Seen d=1 ; none of a,b, or c - // (6) Seen a=1,b=1 ; none of c,d - // (7) Seen a=1,c=1 ; none of b,d - // (8) Seen a=1,d=1 ; none of b,c - // (9) Seen b=1,c=1 ; none of a,d - //(10) Seen b=1,d=1 ; none of c,d - //(11) Seen c=1,d=1 ; none of a,b - //(12) Seen a=1,b=1,c=1 ; not d - //(13) Seen a=1,b=1,d=1 ; not c - //(14) Seen a=1,c=1,d=1 ; not b - //(15) Seen b=1,c=1,d=1 ; not a - //(16) success - //(17) fail - // - // All states but (16) can transition to (17); additionally: - // (1) can transition to (2),(3),(4),(5) - // (2) can transition to (6),(7),(8) - // (3) can transition to (6),(9),(10) - // (4) can transition to (7),(9),(11) - // (5) can transition to (8),(10),(11) - // (6) can transition to (12),(13) - // (7) can transition to (12),(14) - // (8) can transition to (13),(14) - // (9) can transition to (12),(15) - //(10) can transition to (13),(15) - //(11) can transition to (14),(15) - //(12)-(15) can transition to (16) - - Set seenKeys = new HashSet(); - List requiredTerms = new ArrayList(bindingArguments.size()); - - Iterator> tableIterator = bindingArguments.iterator(); - - - - while(tableIterator.hasNext()) - { - final Map.Entry entry = tableIterator.next(); - final AMQShortString key = entry.getKey(); - final AMQTypedValue value = entry.getValue(); - - - if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) - { - final AMQType type = value.getType(); - - if(type == AMQType.VOID || - ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) - { - requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),null)); - } - else - { - requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),value)); - } - } - - } - - final HeadersMatcherDFAState successState = - new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); - - final HeadersMatcherDFAState failState = - new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.EMPTY_SET,_dictionary); - - Map, HeadersMatcherDFAState> notSeenTermsToStateMap = - new HashMap, HeadersMatcherDFAState>(); - - notSeenTermsToStateMap.put(Collections.EMPTY_SET, successState); - - - final int numberOfTerms = requiredTerms.size(); - - for(int numMissingTerms = 1; numMissingTerms <= numberOfTerms; numMissingTerms++) - { - int[] pos = new int[numMissingTerms]; - for(int i = 0; i < numMissingTerms; i++) - { - pos[i] = i; - } - - final int maxTermValue = (numberOfTerms - (numMissingTerms - 1)); - - while(pos[0] < maxTermValue) - { - - Set stateSet = new HashSet(); - for(int posIndex = 0; posIndex < pos.length; posIndex++) - { - stateSet.add(requiredTerms.get(pos[posIndex])); - } - - final Map> nextStateMap = - new HashMap>(); - - - for(int posIndex = 0; posIndex < pos.length; posIndex++) - { - KeyValuePair nextTerm = requiredTerms.get(pos[posIndex]); - HashSet nextStateSet = - new HashSet(stateSet); - nextStateSet.remove(nextTerm); - - Map valueToStateMap = - new HashMap(); - nextStateMap.put(nextTerm._key, valueToStateMap); - - valueToStateMap.put( nextTerm._value,notSeenTermsToStateMap.get(nextStateSet)); - if(nextTerm._value != null) - { - valueToStateMap.put(null, failState); - } - - - } - - - HeadersMatcherDFAState newState = new HeadersMatcherDFAState(nextStateMap, Collections.EMPTY_SET, _dictionary); - - notSeenTermsToStateMap.put(stateSet, newState); - - int i = numMissingTerms; - while(i-- != 0) - { - if(++pos[i] <= numberOfTerms -(numMissingTerms-i)) - { - int k = pos[i]; - for(int j = i+1; j < numMissingTerms; j++) - { - pos[j] = ++k; - } - break; - } - } - } - - - - - } - - - return notSeenTermsToStateMap.get(new HashSet(requiredTerms)); - - - - } - - public static void main(String[] args) throws AMQFrameDecodingException - { - - FieldTable bindingTable = new FieldTable(); - - bindingTable.setString(new AMQShortString("x-match"),"all"); - bindingTable.setInteger("a",1); - bindingTable.setVoid(new AMQShortString("b")); - bindingTable.setString("c",""); - bindingTable.setInteger("d",4); - bindingTable.setInteger("e",1); - - - - FieldTable bindingTable2 = new FieldTable(); - bindingTable2.setString(new AMQShortString("x-match"),"all"); - bindingTable2.setInteger("a",1); - bindingTable2.setVoid(new AMQShortString("b")); - bindingTable2.setString("c",""); - bindingTable2.setInteger("d",4); - bindingTable2.setInteger("e",1); - bindingTable2.setInteger("f",1); - - - FieldTable table = new FieldTable(); - table.setInteger("a",1); - table.setInteger("b",2); - table.setString("c",""); - table.setInteger("d",4); - table.setInteger("e",1); - table.setInteger("f",1); - table.setInteger("h",1); - table.setInteger("i",1); - table.setInteger("j",1); - table.setInteger("k",1); - table.setInteger("l",1); - - org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.allocate( (int) table.getEncodedSize()); - EncodingUtils.writeFieldTableBytes(buffer, table); - buffer.flip(); - - FieldTable table2 = EncodingUtils.readFieldTable(buffer); - - - - FieldTable bindingTable3 = new FieldTable(); - bindingTable3.setString(new AMQShortString("x-match"),"any"); - bindingTable3.setInteger("a",1); - bindingTable3.setInteger("b",3); - - - FieldTable bindingTable4 = new FieldTable(); - bindingTable4.setString(new AMQShortString("x-match"),"any"); - bindingTable4.setVoid(new AMQShortString("a")); - - - FieldTable bindingTable5 = new FieldTable(); - bindingTable5.setString(new AMQShortString("x-match"),"all"); - bindingTable5.setString(new AMQShortString("h"),"hello"); - - for(int i = 0; i < 100; i++) - { - printMatches(new FieldTable[] {bindingTable5} , table2); - } - - - - } - - - - private static void printMatches(final FieldTable[] bindingKeys, final FieldTable routingKey) - { - HeadersMatcherDFAState sm = null; - Map resultMap = new HashMap(); - - HeadersParser parser = new HeadersParser(); - - for(int i = 0; i < bindingKeys.length; i++) - { - HeaderMatcherResult r = new HeaderMatcherResult(); - resultMap.put(r, bindingKeys[i].toString()); - - - if(i==0) - { - sm = parser.createStateMachine(bindingKeys[i], r); - } - else - { - sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeys[i], r)); - } - } - - Collection results = null; - long beforeTime = System.currentTimeMillis(); - for(int i = 0; i < 1000000; i++) - { - routingKey.size(); - - assert sm != null; - results = sm.match(routingKey); - - } - long elapsed = System.currentTimeMillis() - beforeTime; - System.out.println("1000000 Iterations took: " + elapsed); - Collection resultStrings = new ArrayList(); - - assert results != null; - for(HeaderMatcherResult result : results) - { - resultStrings.add(resultMap.get(result)); - } - - final ArrayList nonMatches = new ArrayList(); - for(FieldTable key : bindingKeys) - { - nonMatches.add(key.toString()); - } - nonMatches.removeAll(resultStrings); - System.out.println("\""+routingKey+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); - - - } - - - public final static class KeyValuePair - { - public final HeaderKey _key; - public final AMQTypedValue _value; - private final int _hashCode; - - public KeyValuePair(final HeaderKey key, final AMQTypedValue value) - { - _key = key; - _value = value; - int hash = (1 + 31 * _key.hashCode()); - if(_value != null) - { - hash+=_value.hashCode(); - } - _hashCode = hash; - } - - public int hashCode() - { - return _hashCode; - } - - public boolean equals(Object o) - { - KeyValuePair other = (KeyValuePair)o; - return (_key == other._key) && (_value == null ? other._value == null : _value.equals(other._value)); - } - - - public String toString() - { - return "{" + _key + " -> " + _value + "}"; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java deleted file mode 100644 index 36076cf75b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.apache.qpid.server.exchange.topic; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQShortStringTokenizer; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class TopicMatcherDFAState -{ - private static final AtomicInteger stateId = new AtomicInteger(); - - private final int _id = stateId.incrementAndGet(); - - private final Collection _results; - private final Map _nextStateMap; - private static final byte TOPIC_DELIMITTER = (byte)'.'; - - - public TopicMatcherDFAState(Map nextStateMap, - Collection results ) - { - _nextStateMap = nextStateMap; - _results = results; - } - - - public TopicMatcherDFAState nextState(TopicWord word) - { - final TopicMatcherDFAState nextState = _nextStateMap.get(word); - return nextState == null ? _nextStateMap.get(TopicWord.ANY_WORD) : nextState; - } - - public Collection terminate() - { - return _results; - } - - - public Collection parse(TopicWordDictionary dictionary, AMQShortString routingKey) - { - return parse(dictionary, routingKey.tokenize(TOPIC_DELIMITTER)); - } - - private Collection parse(final TopicWordDictionary dictionary, - final AMQShortStringTokenizer tokens) - { - if(!tokens.hasMoreTokens()) - { - return _results; - } - TopicWord word = dictionary.getWord(tokens.nextToken()); - TopicMatcherDFAState nextState = _nextStateMap.get(word); - if(nextState == null && word != TopicWord.ANY_WORD) - { - nextState = _nextStateMap.get(TopicWord.ANY_WORD); - } - if(nextState == null) - { - return Collections.EMPTY_SET; - } - // Shortcut if we are at a looping terminal state - if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD)) - { - return _results; - } - - return nextState.parse(dictionary, tokens); - - } - - - public TopicMatcherDFAState mergeStateMachines(TopicMatcherDFAState otherStateMachine) - { - Map, TopicMatcherDFAState> newStateMap= new HashMap, TopicMatcherDFAState>(); - - Collection results; - - if(_results.isEmpty()) - { - results = otherStateMachine._results; - } - else if(otherStateMachine._results.isEmpty()) - { - results = _results; - } - else - { - results = new HashSet(_results); - results.addAll(otherStateMachine._results); - } - - - final Map newNextStateMap = new HashMap(); - - TopicMatcherDFAState newState = new TopicMatcherDFAState(newNextStateMap, results); - - - Set oldStates = new HashSet(); - oldStates.add(this); - oldStates.add(otherStateMachine); - - newStateMap.put(oldStates, newState); - - mergeStateMachines(oldStates, newNextStateMap, newStateMap); - - return newState; - - } - - private static void mergeStateMachines( - final Set oldStates, - final Map newNextStateMap, - final Map, TopicMatcherDFAState> newStateMap) - { - Map> nfaMap = new HashMap>(); - - for(TopicMatcherDFAState state : oldStates) - { - Map map = state._nextStateMap; - for(Map.Entry entry : map.entrySet()) - { - Set states = nfaMap.get(entry.getKey()); - if(states == null) - { - states = new HashSet(); - nfaMap.put(entry.getKey(), states); - } - states.add(entry.getValue()); - } - } - - Set anyWordStates = nfaMap.get(TopicWord.ANY_WORD); - - for(Map.Entry> transition : nfaMap.entrySet()) - { - Set destinations = transition.getValue(); - - if(anyWordStates != null) - { - destinations.addAll(anyWordStates); - } - - TopicMatcherDFAState nextState = newStateMap.get(destinations); - if(nextState == null) - { - - if(destinations.size() == 1) - { - nextState = destinations.iterator().next(); - newStateMap.put(destinations, nextState); - } - else - { - Collection results; - - Set> resultSets = new HashSet>(); - for(TopicMatcherDFAState destination : destinations) - { - resultSets.add(destination._results); - } - resultSets.remove(Collections.EMPTY_SET); - if(resultSets.size() == 0) - { - results = Collections.EMPTY_SET; - } - else if(resultSets.size() == 1) - { - results = resultSets.iterator().next(); - } - else - { - results = new HashSet(); - for(Collection oldResult : resultSets) - { - results.addAll(oldResult); - } - } - - final Map nextStateMap = new HashMap(); - - nextState = new TopicMatcherDFAState(nextStateMap, results); - newStateMap.put(destinations, nextState); - - mergeStateMachines( - destinations, - nextStateMap, - newStateMap); - - - } - - - } - newNextStateMap.put(transition.getKey(),nextState); - } - - // Remove redundant transitions where defined tokenWord has same action as ANY_WORD - TopicMatcherDFAState anyWordState = newNextStateMap.get(TopicWord.ANY_WORD); - if(anyWordState != null) - { - List removeList = new ArrayList(); - for(Map.Entry entry : newNextStateMap.entrySet()) - { - if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) - { - removeList.add(entry.getKey()); - } - } - for(TopicWord removeKey : removeList) - { - newNextStateMap.remove(removeKey); - } - } - - - - } - - - public String toString() - { - StringBuilder transitions = new StringBuilder(); - for(Map.Entry entry : _nextStateMap.entrySet()) - { - transitions.append("[ "); - transitions.append(entry.getKey()); - transitions.append("\t ->\t "); - transitions.append(entry.getValue()._id); - transitions.append(" ]\n"); - } - - - return "[ State " + _id + " ]\n" + transitions + "\n"; - - } - - public String reachableStates() - { - StringBuilder result = new StringBuilder("Start state: " + _id + "\n"); - - SortedSet reachableStates = - new TreeSet(new Comparator() - { - public int compare(final TopicMatcherDFAState o1, final TopicMatcherDFAState o2) - { - return o1._id - o2._id; - } - }); - reachableStates.add(this); - - int count; - - do - { - count = reachableStates.size(); - Collection originalStates = new ArrayList(reachableStates); - for(TopicMatcherDFAState state : originalStates) - { - reachableStates.addAll(state._nextStateMap.values()); - } - } - while(reachableStates.size() != count); - - - - for(TopicMatcherDFAState state : reachableStates) - { - result.append(state.toString()); - } - - return result.toString(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java deleted file mode 100644 index 71d30adfac..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.apache.qpid.server.exchange.topic; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public interface TopicMatcherResult -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java deleted file mode 100644 index 3e9facf412..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java +++ /dev/null @@ -1,613 +0,0 @@ -package org.apache.qpid.server.exchange.topic; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQShortStringTokenizer; - -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; -import java.io.IOException; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class TopicParser -{ - private static final byte TOPIC_DELIMITER = (byte)'.'; - - private final TopicWordDictionary _dictionary = new TopicWordDictionary(); - private final AtomicReference _stateMachine = new AtomicReference(); - - private static class Position - { - private final TopicWord _word; - private final boolean _selfTransition; - private final int _position; - private final boolean _endState; - private boolean _followedByAnyLoop; - - - public Position(final int position, final TopicWord word, final boolean selfTransition, final boolean endState) - { - _position = position; - _word = word; - _selfTransition = selfTransition; - _endState = endState; - } - - - } - - private static final Position ERROR_POSITION = new Position(Integer.MAX_VALUE,null, true, false); - - private static class SimpleState - { - Set _positions; - Map _nextState; - } - - - public void addBinding(AMQShortString bindingKey, TopicMatcherResult result) - { - - TopicMatcherDFAState startingStateMachine; - TopicMatcherDFAState newStateMachine; - - do - { - startingStateMachine = _stateMachine.get(); - if(startingStateMachine == null) - { - newStateMachine = createStateMachine(bindingKey, result); - } - else - { - newStateMachine = startingStateMachine.mergeStateMachines(createStateMachine(bindingKey, result)); - } - - } - while(!_stateMachine.compareAndSet(startingStateMachine,newStateMachine)); - - } - - public Collection parse(AMQShortString routingKey) - { - TopicMatcherDFAState stateMachine = _stateMachine.get(); - if(stateMachine == null) - { - return Collections.EMPTY_SET; - } - else - { - return stateMachine.parse(_dictionary,routingKey); - } - } - - - TopicMatcherDFAState createStateMachine(AMQShortString bindingKey, TopicMatcherResult result) - { - List wordList = createTopicWordList(bindingKey); - int wildCards = 0; - for(TopicWord word : wordList) - { - if(word == TopicWord.WILDCARD_WORD) - { - wildCards++; - } - } - if(wildCards == 0) - { - TopicMatcherDFAState[] states = new TopicMatcherDFAState[wordList.size()+1]; - states[states.length-1] = new TopicMatcherDFAState(Collections.EMPTY_MAP, Collections.singleton(result)); - for(int i = states.length-2; i >= 0; i--) - { - states[i] = new TopicMatcherDFAState(Collections.singletonMap(wordList.get(i),states[i+1]),Collections.EMPTY_SET); - - } - return states[0]; - } - else if(wildCards == wordList.size()) - { - Map stateMap = new HashMap(); - TopicMatcherDFAState state = new TopicMatcherDFAState(stateMap, Collections.singleton(result)); - stateMap.put(TopicWord.ANY_WORD, state); - return state; - } - - - int positionCount = wordList.size() - wildCards; - - Position[] positions = new Position[positionCount+1]; - - int lastWord; - - if(wordList.get(wordList.size()-1)== TopicWord.WILDCARD_WORD) - { - lastWord = wordList.size()-1; - positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, true, true); - } - else - { - lastWord = wordList.size(); - positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, false, true); - } - - - int pos = 0; - int wordPos = 0; - - - while(wordPos < lastWord) - { - TopicWord word = wordList.get(wordPos++); - - if(word == TopicWord.WILDCARD_WORD) - { - int nextWordPos = wordPos++; - word = wordList.get(nextWordPos); - - positions[pos] = new Position(pos++,word,true,false); - } - else - { - positions[pos] = new Position(pos++,word,false,false); - } - - } - - - for(int p = 0; p,SimpleState> stateMap = new HashMap,SimpleState>(); - - - SimpleState state = new SimpleState(); - state._positions = Collections.singleton( positions[0] ); - stateMap.put(state._positions, state); - - calculateNextStates(state, stateMap, positions); - - SimpleState[] simpleStates = stateMap.values().toArray(new SimpleState[stateMap.size()]); - HashMap[] dfaStateMaps = new HashMap[simpleStates.length]; - Map simple2DFAMap = new HashMap(); - - for(int i = 0; i < simpleStates.length; i++) - { - - Collection results; - boolean endState = false; - - for(Position p : simpleStates[i]._positions) - { - if(p._endState) - { - endState = true; - break; - } - } - - if(endState) - { - results = Collections.singleton(result); - } - else - { - results = Collections.EMPTY_SET; - } - - dfaStateMaps[i] = new HashMap(); - simple2DFAMap.put(simpleStates[i], new TopicMatcherDFAState(dfaStateMaps[i],results)); - - } - for(int i = 0; i < simpleStates.length; i++) - { - SimpleState simpleState = simpleStates[i]; - - Map nextSimpleStateMap = simpleState._nextState; - for(Map.Entry stateMapEntry : nextSimpleStateMap.entrySet()) - { - dfaStateMaps[i].put(stateMapEntry.getKey(), simple2DFAMap.get(stateMapEntry.getValue())); - } - - } - - return simple2DFAMap.get(state); - - } - - - - private void calculateNextStates(final SimpleState state, - final Map, SimpleState> stateMap, - final Position[] positions) - { - Map> transitions = new HashMap>(); - - for(Position pos : state._positions) - { - if(pos._selfTransition) - { - Set dest = transitions.get(TopicWord.ANY_WORD); - if(dest == null) - { - dest = new HashSet(); - transitions.put(TopicWord.ANY_WORD,dest); - } - dest.add(pos); - } - - final int nextPos = pos._position + 1; - Position nextPosition = nextPos == positions.length ? ERROR_POSITION : positions[nextPos]; - - Set dest = transitions.get(pos._word); - if(dest == null) - { - dest = new HashSet(); - transitions.put(pos._word,dest); - } - dest.add(nextPosition); - - } - - Set anyWordTransitions = transitions.get(TopicWord.ANY_WORD); - if(anyWordTransitions != null) - { - for(Set dest : transitions.values()) - { - dest.addAll(anyWordTransitions); - } - } - - state._nextState = new HashMap(); - - for(Map.Entry> dest : transitions.entrySet()) - { - - if(dest.getValue().size()>1) - { - dest.getValue().remove(ERROR_POSITION); - } - Position loopingTerminal = null; - for(Position destPos : dest.getValue()) - { - if(destPos._selfTransition && destPos._endState) - { - loopingTerminal = destPos; - break; - } - } - - if(loopingTerminal!=null) - { - dest.setValue(Collections.singleton(loopingTerminal)); - } - else - { - Position anyLoop = null; - for(Position destPos : dest.getValue()) - { - if(destPos._followedByAnyLoop) - { - if(anyLoop == null || anyLoop._position removals = new ArrayList(); - for(Position destPos : dest.getValue()) - { - if(destPos._position < anyLoop._position) - { - removals.add(destPos); - } - } - dest.getValue().removeAll(removals); - } - } - - SimpleState stateForEntry = stateMap.get(dest.getValue()); - if(stateForEntry == null) - { - stateForEntry = new SimpleState(); - stateForEntry._positions = dest.getValue(); - stateMap.put(dest.getValue(),stateForEntry); - calculateNextStates(stateForEntry, - stateMap, - positions); - } - state._nextState.put(dest.getKey(),stateForEntry); - - - - } - - // remove redundant transitions - SimpleState anyWordState = state._nextState.get(TopicWord.ANY_WORD); - if(anyWordState != null) - { - List removeList = new ArrayList(); - for(Map.Entry entry : state._nextState.entrySet()) - { - if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) - { - removeList.add(entry.getKey()); - } - } - for(TopicWord removeKey : removeList) - { - state._nextState.remove(removeKey); - } - } - - - } - - private List createTopicWordList(final AMQShortString bindingKey) - { - AMQShortStringTokenizer tokens = bindingKey.tokenize(TOPIC_DELIMITER); - TopicWord previousWord = null; - - List wordList = new ArrayList(); - - while(tokens.hasMoreTokens()) - { - TopicWord nextWord = _dictionary.getOrCreateWord(tokens.nextToken()); - if(previousWord == TopicWord.WILDCARD_WORD) - { - - if(nextWord == TopicWord.WILDCARD_WORD) - { - // consecutive wildcards can be merged - // i.e. subsequent wildcards can be discarded - continue; - } - else if(nextWord == TopicWord.ANY_WORD) - { - // wildcard and anyword can be reordered to always put anyword first - wordList.set(wordList.size()-1,TopicWord.ANY_WORD); - nextWord = TopicWord.WILDCARD_WORD; - } - } - wordList.add(nextWord); - previousWord = nextWord; - - } - return wordList; - } - - - public static void main(String[] args) - { - - printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.*.q.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); - printMatches(new String[]{ - "#.a.#", - "#.b.#", - "#.c.#", - "#.d.#", - "#.e.#", - "#.f.#", - "#.g.#", - "#.h.#", - "#.i.#", - "#.j.#", - "#.k.#", - "#.l.#", - "#.m.#", - "#.n.#", - "#.o.#", - "#.p.#", - "#.q.#" - - }, "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); -/* - printMatches(new String[]{ - "#.a.#", - "#.b.#", - "#.c.#", - "#.d.#", - "#.e.#", - "#.f.#", - "#.g.#", - "#.h.#", - "#.i.#", - "#.j.#", - "#.k.#", - "#.l.#", - "#.m.#", - "#.n.#", - "#.o.#", - "#.p.#", - "#.q.#", - "#.r.#", - "#.s.#", - "#.t.#", - "#.u.#", - "#.v.#", - "#.w.#", - "#.x.#", - "#.y.#", - "#.z.#" - - - },"a.b"); - - printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); - printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); - printMatches("a.#.b.#","a.b.b.b.b.b.b.b.c"); - -*/ - - printMatches("",""); - printMatches("a","a"); - printMatches("a",""); - printMatches("","a"); - printMatches("a.b","a.b"); - printMatches("a","a.b"); - printMatches("a.b","a"); - printMatches("*","a"); - printMatches("*.b","a.b"); - printMatches("*.*","a.b"); - printMatches("a.*","a.b"); - printMatches("a.*.#","a.b"); - printMatches("a.#.b","a.b"); - - printMatches("#.b","a"); - printMatches("#.b","a.b"); - printMatches("#.a.b","a.b"); - - - printMatches("#",""); - printMatches("#","a"); - printMatches("#","a.b"); - printMatches("#.#","a.b"); - printMatches("#.*","a.b"); - - printMatches("#.a.b","a.b"); - printMatches("a.b.#","a.b"); - printMatches("a.#","a.b"); - printMatches("#.*.#","a.b"); - printMatches("#.*.b.#","a.b"); - printMatches("#.a.*.#","a.b"); - printMatches("#.a.#.b.#","a.b"); - printMatches("#.*.#.*.#","a.b"); - printMatches("*.#.*.#","a.b"); - printMatches("#.*.#.*","a.b"); - - - printMatches(new String[]{"a.#.b.#","a.*.#.b.#"},"a.b.b.b.b.b.b.b.c"); - - - printMatches(new String[]{"a.b", "a.c"},"a.b"); - printMatches(new String[]{"a.#", "a.c", "#.b"},"a.b"); - printMatches(new String[]{"a.#", "a.c", "#.b", "#", "*.*"},"a.b"); - - printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.e"); - printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.f.g"); - - - - - } - - private static void printMatches(final String[] bindingKeys, final String routingKey) - { - TopicMatcherDFAState sm = null; - Map resultMap = new HashMap(); - - TopicParser parser = new TopicParser(); - - long start = System.currentTimeMillis(); - for(int i = 0; i < bindingKeys.length; i++) - { - System.out.println((System.currentTimeMillis() - start) + ":\t" + bindingKeys[i]); - TopicMatcherResult r = new TopicMatcherResult(){}; - resultMap.put(r, bindingKeys[i]); - AMQShortString bindingKeyShortString = new AMQShortString(bindingKeys[i]); - - System.err.println("====================================================="); - System.err.println("Adding binding key: " + bindingKeyShortString); - System.err.println("-----------------------------------------------------"); - - - if(i==0) - { - sm = parser.createStateMachine(bindingKeyShortString, r); - } - else - { - sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeyShortString, r)); - } - System.err.println(sm.reachableStates()); - System.err.println("====================================================="); - try - { - System.in.read(); - } - catch (IOException e) - { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - } - AMQShortString routingKeyShortString = new AMQShortString(routingKey); - - Collection results = sm.parse(parser._dictionary, routingKeyShortString); - Collection resultStrings = new ArrayList(); - - for(TopicMatcherResult result : results) - { - resultStrings.add(resultMap.get(result)); - } - - final ArrayList nonMatches = new ArrayList(Arrays.asList(bindingKeys)); - nonMatches.removeAll(resultStrings); - System.out.println("\""+routingKeyShortString+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); - - - } - - private static void printMatches(String bindingKey, String routingKey) - { - printMatches(new String[] { bindingKey }, routingKey); - } - - - private static boolean matches(String bindingKey, String routingKey) - { - AMQShortString bindingKeyShortString = new AMQShortString(bindingKey); - AMQShortString routingKeyShortString = new AMQShortString(routingKey); - TopicParser parser = new TopicParser(); - - final TopicMatcherResult result = new TopicMatcherResult(){}; - - TopicMatcherDFAState sm = parser.createStateMachine(bindingKeyShortString, result); - return !sm.parse(parser._dictionary,routingKeyShortString).isEmpty(); - - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java deleted file mode 100644 index f14d70f8a1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.apache.qpid.server.exchange.topic; - -import org.apache.qpid.framing.AMQShortString; - -import java.util.Map; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public final class TopicWord -{ - public static final TopicWord ANY_WORD = new TopicWord("*"); - public static final TopicWord WILDCARD_WORD = new TopicWord("#"); - private String _word; - - public TopicWord() - { - - } - - public TopicWord(String s) - { - _word = s; - } - - public TopicWord(final AMQShortString name) - { - _word = name.toString(); - } - - public String toString() - { - return _word; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java deleted file mode 100644 index 65a0cd3107..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.apache.qpid.server.exchange.topic; - -import org.apache.qpid.framing.AMQShortString; - -import java.util.concurrent.ConcurrentHashMap; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class TopicWordDictionary -{ - private final ConcurrentHashMap _dictionary = - new ConcurrentHashMap(); - - - - public TopicWordDictionary() - { - _dictionary.put(new AMQShortString("*"), TopicWord.ANY_WORD); - _dictionary.put(new AMQShortString("#"), TopicWord.WILDCARD_WORD); - } - - - - - public TopicWord getOrCreateWord(AMQShortString name) - { - TopicWord word = _dictionary.putIfAbsent(name, new TopicWord(name)); - if(word == null) - { - word = _dictionary.get(name); - } - return word; - } - - - public TopicWord getWord(AMQShortString name) - { - TopicWord word = _dictionary.get(name); - if(word == null) - { - word = TopicWord.ANY_WORD; - } - return word; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java deleted file mode 100644 index a964bce306..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ /dev/null @@ -1,275 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -/** - * An expression which performs an operation on two expression values - */ -public abstract class ArithmeticExpression extends BinaryExpression -{ - - protected static final int INTEGER = 1; - protected static final int LONG = 2; - protected static final int DOUBLE = 3; - - /** - * @param left - * @param right - */ - public ArithmeticExpression(Expression left, Expression right) - { - super(left, right); - } - - public static Expression createPlus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof String) - { - String text = (String) lvalue; - String answer = text + rvalue; - - return answer; - } - else if (lvalue instanceof Number) - { - return plus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "+"; - } - }; - } - - public static Expression createMinus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return minus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "-"; - } - }; - } - - public static Expression createMultiply(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return multiply((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "*"; - } - }; - } - - public static Expression createDivide(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return divide((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "/"; - } - }; - } - - public static Expression createMod(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return mod((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "%"; - } - }; - } - - protected Number plus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() + right.intValue()); - - case LONG: - return new Long(left.longValue() + right.longValue()); - - default: - return new Double(left.doubleValue() + right.doubleValue()); - } - } - - protected Number minus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() - right.intValue()); - - case LONG: - return new Long(left.longValue() - right.longValue()); - - default: - return new Double(left.doubleValue() - right.doubleValue()); - } - } - - protected Number multiply(Number left, Number right) - { - switch (numberType(left, right)) - { - - case INTEGER: - return new Integer(left.intValue() * right.intValue()); - - case LONG: - return new Long(left.longValue() * right.longValue()); - - default: - return new Double(left.doubleValue() * right.doubleValue()); - } - } - - protected Number divide(Number left, Number right) - { - return new Double(left.doubleValue() / right.doubleValue()); - } - - protected Number mod(Number left, Number right) - { - return new Double(left.doubleValue() % right.doubleValue()); - } - - private int numberType(Number left, Number right) - { - if (isDouble(left) || isDouble(right)) - { - return DOUBLE; - } - else if ((left instanceof Long) || (right instanceof Long)) - { - return LONG; - } - else - { - return INTEGER; - } - } - - private boolean isDouble(Number n) - { - return (n instanceof Float) || (n instanceof Double); - } - - protected Number asNumber(Object value) - { - if (value instanceof Number) - { - return (Number) value; - } - else - { - throw new RuntimeException("Cannot convert value: " + value + " into a number"); - } - } - - public Object evaluate(Filterable message) throws E - { - Object lvalue = left.evaluate(message); - if (lvalue == null) - { - return null; - } - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - return evaluate(lvalue, rvalue); - } - - /** - * @param lvalue - * @param rvalue - * @return - */ - protected abstract Object evaluate(Object lvalue, Object rvalue); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java deleted file mode 100644 index 7308de80d6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -/** - * An expression which performs an operation on two expression values. - */ -public abstract class BinaryExpression implements Expression -{ - protected Expression left; - protected Expression right; - - public BinaryExpression(Expression left, Expression right) - { - this.left = left; - this.right = right; - } - - public Expression getLeft() - { - return left; - } - - public Expression getRight() - { - return right; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - - /** - * @param expression - */ - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @param expression - */ - public void setLeft(Expression expression) - { - left = expression; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java deleted file mode 100644 index dd3e17a870..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.server.queue.Filterable; - -/** - * A BooleanExpression is an expression that always - * produces a Boolean result. - */ -public interface BooleanExpression extends Expression -{ - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws E - */ - public boolean matches(Filterable message) throws E; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java deleted file mode 100644 index 65d9a8c221..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ /dev/null @@ -1,599 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.util.HashSet; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.qpid.server.queue.Filterable; - -/** - * A filter performing a comparison of two objects - */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); - } - - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); - } - - private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); - - static - { - REGEXP_CONTROL_CHARS.add(new Character('.')); - REGEXP_CONTROL_CHARS.add(new Character('\\')); - REGEXP_CONTROL_CHARS.add(new Character('[')); - REGEXP_CONTROL_CHARS.add(new Character(']')); - REGEXP_CONTROL_CHARS.add(new Character('^')); - REGEXP_CONTROL_CHARS.add(new Character('$')); - REGEXP_CONTROL_CHARS.add(new Character('?')); - REGEXP_CONTROL_CHARS.add(new Character('*')); - REGEXP_CONTROL_CHARS.add(new Character('+')); - REGEXP_CONTROL_CHARS.add(new Character('{')); - REGEXP_CONTROL_CHARS.add(new Character('}')); - REGEXP_CONTROL_CHARS.add(new Character('|')); - REGEXP_CONTROL_CHARS.add(new Character('(')); - REGEXP_CONTROL_CHARS.add(new Character(')')); - REGEXP_CONTROL_CHARS.add(new Character(':')); - REGEXP_CONTROL_CHARS.add(new Character('&')); - REGEXP_CONTROL_CHARS.add(new Character('<')); - REGEXP_CONTROL_CHARS.add(new Character('>')); - REGEXP_CONTROL_CHARS.add(new Character('=')); - REGEXP_CONTROL_CHARS.add(new Character('!')); - } - - static class LikeExpression extends UnaryExpression implements BooleanExpression - { - - Pattern likePattern; - - /** - * @param right - */ - public LikeExpression(Expression right, String like, int escape) - { - super(right); - - StringBuffer regexp = new StringBuffer(like.length() * 2); - regexp.append("\\A"); // The beginning of the input - for (int i = 0; i < like.length(); i++) - { - char c = like.charAt(i); - if (escape == (0xFFFF & c)) - { - i++; - if (i >= like.length()) - { - // nothing left to escape... - break; - } - - char t = like.charAt(i); - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & t)); - } - else if (c == '%') - { - regexp.append(".*?"); // Do a non-greedy match - } - else if (c == '_') - { - regexp.append("."); // match one - } - else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) - { - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & c)); - } - else - { - regexp.append(c); - } - } - - regexp.append("\\z"); // The end of the input - - likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); - } - - /** - * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() - */ - public String getExpressionSymbol() - { - return "LIKE"; - } - - /** - * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) - */ - public Object evaluate(Filterable message) throws E - { - - Object rv = this.getRight().evaluate(message); - - if (rv == null) - { - return null; - } - - if (!(rv instanceof String)) - { - return - Boolean.FALSE; - // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); - } - - return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; - } - - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static BooleanExpression createLike(Expression left, String right, String escape) - { - if ((escape != null) && (escape.length() != 1)) - { - throw new RuntimeException( - "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); - } - - int c = -1; - if (escape != null) - { - c = 0xFFFF & escape.charAt(0); - } - - return new LikeExpression(left, right, c); - } - - public static BooleanExpression createNotLike(Expression left, String right, String escape) - { - return UnaryExpression.createNOT(createLike(left, right, escape)); - } - - public static BooleanExpression createInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); - - } - - public static BooleanExpression createNotInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); - - } - - public static BooleanExpression createIsNull(Expression left) - { - return doCreateEqual(left, ConstantExpression.NULL); - } - - public static BooleanExpression createIsNotNull(Expression left) - { - return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); - } - - public static BooleanExpression createNotEqual(Expression left, Expression right) - { - return UnaryExpression.createNOT(createEqual(left, right)); - } - - public static BooleanExpression createEqual(Expression left, Expression right) - { - checkEqualOperand(left); - checkEqualOperand(right); - checkEqualOperandCompatability(left, right); - - return doCreateEqual(left, right); - } - - private static BooleanExpression doCreateEqual(Expression left, Expression right) - { - return new EqualExpression(left, right); - } - - public static BooleanExpression createGreaterThan(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer > 0; - } - - public String getExpressionSymbol() - { - return ">"; - } - }; - } - - public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer >= 0; - } - - public String getExpressionSymbol() - { - return ">="; - } - }; - } - - public static BooleanExpression createLessThan(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer < 0; - } - - public String getExpressionSymbol() - { - return "<"; - } - - }; - } - - public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) - { - checkLessThanOperand(left); - checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer <= 0; - } - - public String getExpressionSymbol() - { - return "<="; - } - }; - } - - /** - * Only Numeric expressions can be used in >, >=, < or <= expressions.s - * - * @param expr - */ - public static void checkLessThanOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value instanceof Number) - { - return; - } - - // Else it's boolean or a String.. - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - - if (expr instanceof BooleanExpression) - { - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - } - - /** - * Validates that the expression can be used in == or <> expression. - * Cannot not be NULL TRUE or FALSE litterals. - * - * @param expr - */ - public static void checkEqualOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value == null) - { - throw new RuntimeException("'" + expr + "' cannot be compared."); - } - } - } - - /** - * - * @param left - * @param right - */ - private static void checkEqualOperandCompatability(Expression left, Expression right) - { - if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) - { - if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) - { - throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); - } - } - } - - /** - * @param left - * @param right - */ - public ComparisonExpression(Expression left, Expression right) - { - super(left, right); - } - - public Object evaluate(Filterable message) throws E - { - Comparable lv = (Comparable) left.evaluate(message); - if (lv == null) - { - return null; - } - - Comparable rv = (Comparable) right.evaluate(message); - if (rv == null) - { - return null; - } - - return compare(lv, rv); - } - - protected Boolean compare(Comparable lv, Comparable rv) - { - Class lc = lv.getClass(); - Class rc = rv.getClass(); - // If the the objects are not of the same type, - // try to convert up to allow the comparison. - if (lc != rc) - { - if (lc == Byte.class) - { - if (rc == Short.class) - { - lv = new Short(((Number) lv).shortValue()); - } - else if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Short.class) - { - if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Integer.class) - { - if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Long.class) - { - if (rc == Integer.class) - { - rv = new Long(((Number) rv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Float.class) - { - if (rc == Integer.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Long.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Double.class) - { - if (rc == Integer.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Long.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Float.class) - { - rv = new Float(((Number) rv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else - { - return Boolean.FALSE; - } - } - - return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; - } - - protected abstract boolean asBoolean(int answer); - - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - - private static class EqualExpression extends ComparisonExpression - { - public EqualExpression(final Expression left, final Expression right) - { - super(left, right); - } - - public Object evaluate(Filterable message) throws E - { - Object lv = left.evaluate(message); - Object rv = right.evaluate(message); - - // Iff one of the values is null - if ((lv == null) ^ (rv == null)) - { - return Boolean.FALSE; - } - - if ((lv == rv) || lv.equals(rv)) - { - return Boolean.TRUE; - } - - if ((lv instanceof Comparable) && (rv instanceof Comparable)) - { - return compare((Comparable) lv, (Comparable) rv); - } - - return Boolean.FALSE; - } - - protected boolean asBoolean(int answer) - { - return answer == 0; - } - - public String getExpressionSymbol() - { - return "="; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java deleted file mode 100644 index c58adaf35f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.math.BigDecimal; - -import org.apache.qpid.server.queue.Filterable; - -/** - * Represents a constant expression - */ -public class ConstantExpression implements Expression -{ - - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression - { - public BooleanConstantExpression(Object value) - { - super(value); - } - - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); - public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); - public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); - - private Object value; - - public static ConstantExpression createFromDecimal(String text) - { - - // Strip off the 'l' or 'L' if needed. - if (text.endsWith("l") || text.endsWith("L")) - { - text = text.substring(0, text.length() - 1); - } - - Number value; - try - { - value = new Long(text); - } - catch (NumberFormatException e) - { - // The number may be too big to fit in a long. - value = new BigDecimal(text); - } - - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromHex(String text) - { - Number value = new Long(Long.parseLong(text.substring(2), 16)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromOctal(String text) - { - Number value = new Long(Long.parseLong(text, 8)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFloat(String text) - { - Number value = new Double(text); - - return new ConstantExpression(value); - } - - public ConstantExpression(Object value) - { - this.value = value; - } - - public Object evaluate(Filterable message) throws E - { - return value; - } - - public Object getValue() - { - return value; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - if (value == null) - { - return "NULL"; - } - - if (value instanceof Boolean) - { - return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; - } - - if (value instanceof String) - { - return encodeString((String) value); - } - - return value.toString(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Encodes the value of string so that it looks like it would look like - * when it was provided in a selector. - * - * @param s - * @return - */ - public static String encodeString(String s) - { - StringBuffer b = new StringBuffer(); - b.append('\''); - for (int i = 0; i < s.length(); i++) - { - char c = s.charAt(i); - if (c == '\'') - { - b.append(c); - } - - b.append(c); - } - - b.append('\''); - - return b.toString(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java deleted file mode 100644 index fd41f5bacc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.server.queue.Filterable; - -/** - * Represents an expression - */ -public interface Expression -{ - - /** - * @return the value of this expression - */ - public Object evaluate(Filterable message) throws E; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java deleted file mode 100644 index c37578f8e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.server.queue.Filterable; - -public interface FilterManager -{ - void add(MessageFilter filter); - - void remove(MessageFilter filter); - - boolean allAllow(Filterable msg); - - boolean hasFilters(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java deleted file mode 100644 index a7f49d0566..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.AMQException; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.framing.FieldTable; - - -public class FilterManagerFactory -{ - //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); - private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); - - //fixme move to a common class so it can be refered to from client code. - - public static FilterManager createManager(FieldTable filters) throws AMQException - { - FilterManager manager = null; - - if (filters != null) - { - - - - if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) - { - String selector = filters.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - - if (selector != null && !selector.equals("")) - { - manager = new SimpleFilterManager(); - manager.add(new JMSSelectorFilter(selector)); - } - - } - - - } - else - { - _logger.debug("No Filters found."); - } - - - return manager; - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java deleted file mode 100644 index 96c9353872..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.filter.jms.selector.SelectorParser; -import org.apache.qpid.server.queue.Filterable; - - -public class JMSSelectorFilter implements MessageFilter -{ - private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); - - private String _selector; - private BooleanExpression _matcher; - - public JMSSelectorFilter(String selector) throws AMQException - { - _selector = selector; - _matcher = new SelectorParser().parse(selector); - } - - public boolean matches(Filterable message) throws E - { - boolean match = _matcher.matches(message); - if(_logger.isDebugEnabled()) - { - _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); - } - return match; - } - - public String getSelector() - { - return _selector; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java deleted file mode 100644 index e376dcd409..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.qpid.server.queue.Filterable; - -/** - * A filter performing a comparison of two objects - */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new OrExpression(lvalue, rvalue); - } - - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new AndExpression(lvalue, rvalue); - } - - /** - * @param left - * @param right - */ - public LogicExpression(BooleanExpression left, BooleanExpression right) - { - super(left, right); - } - - public abstract Object evaluate(Filterable message) throws E; - - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - - private static class OrExpression extends LogicExpression - { - public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) - { - super(lvalue, rvalue); - } - - public Object evaluate(Filterable message) throws E - { - - Boolean lv = (Boolean) left.evaluate(message); - // Can we do an OR shortcut?? - if ((lv != null) && lv.booleanValue()) - { - return Boolean.TRUE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "OR"; - } - } - - private static class AndExpression extends LogicExpression - { - public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) - { - super(lvalue, rvalue); - } - - public Object evaluate(Filterable message) throws E - { - - Boolean lv = (Boolean) left.evaluate(message); - - // Can we do an AND shortcut?? - if (lv == null) - { - return null; - } - - if (!lv.booleanValue()) - { - return Boolean.FALSE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "AND"; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java deleted file mode 100644 index 38e3424be5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.server.queue.Filterable; - -public interface MessageFilter -{ - boolean matches(Filterable message) throws E; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java deleted file mode 100644 index f1b3b2511d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -public class NoConsumerFilter implements MessageFilter -{ - private final static Logger _logger = org.apache.log4j.Logger.getLogger(NoConsumerFilter.class); - - - public NoConsumerFilter() throws AMQException - { - _logger.info("Created NoConsumerFilter"); - } - - public boolean matches(Filterable message) - { - return true; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java deleted file mode 100644 index fa276169bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.util.HashMap; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.server.queue.Filterable; - -/** - * Represents a property expression - */ -public class PropertyExpression implements Expression -{ - // Constants - defined the same as JMS - private static final int NON_PERSISTENT = 1; - private static final int PERSISTENT = 2; - private static final int DEFAULT_PRIORITY = 4; - - private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - - private static final HashMap> JMS_PROPERTY_EXPRESSIONS = new HashMap>(); - - { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() - { - public Object evaluate(Filterable message) - { - //TODO - return null; - } - }); - JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new ReplyToExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSType", new TypeExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new DeliveryModeExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new CorrelationIdExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); - - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new RedeliveredExpression()); - } - - private final String name; - private final Expression jmsPropertyExpression; - - public boolean outerTest() - { - return false; - } - - public PropertyExpression(String name) - { - this.name = name; - - - - jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); - } - - public Object evaluate(Filterable message) throws E - { - - if (jmsPropertyExpression != null) - { - return jmsPropertyExpression.evaluate(message); - } - else - { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking up property:" + name); - _logger.debug("Properties are:" + _properties.getHeaders().keySet()); - } - - return _properties.getHeaders().getObject(name); - } - } - - public String getName() - { - return name; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return name; - } - - /** - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return name.hashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return name.equals(((PropertyExpression) o).name); - - } - - private static class ReplyToExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - - return (replyTo == null) ? null : replyTo.toString(); - - } - - } - - private static class TypeExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - - return (type == null) ? null : type.toString(); - - } - } - - private static class DeliveryModeExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; - if (_logger.isDebugEnabled()) - { - _logger.debug("JMSDeliveryMode is :" + mode); - } - - return mode; - } - } - - private static class PriorityExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return (int) _properties.getPriority(); - } - } - - private static class MessageIDExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); - - return (messageId == null) ? null : messageId; - - } - } - - private static class TimestampExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getTimestamp(); - } - } - - private static class CorrelationIdExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - - return (correlationId == null) ? null : correlationId.toString(); - } - } - - private static class ExpirationExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getExpiration(); - - } - } - - private static class RedeliveredExpression implements Expression - { - public Object evaluate(Filterable message) throws E - { - return message.isRedelivered(); - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java deleted file mode 100644 index 864a87a14f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.filter; - -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -public class SimpleFilterManager implements FilterManager -{ - private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - - private final ConcurrentLinkedQueue> _filters; - - public SimpleFilterManager() - { - _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue>(); - } - - public void add(MessageFilter filter) - { - _filters.add(filter); - } - - public void remove(MessageFilter filter) - { - _filters.remove(filter); - } - - public boolean allAllow(Filterable msg) - { - for (MessageFilter filter : _filters) - { - try - { - if (!filter.matches(msg)) - { - return false; - } - } - catch (AMQException e) - { - //fixme - e.printStackTrace(); - return false; - } - } - return true; - } - - public boolean hasFilters() - { - return !_filters.isEmpty(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java deleted file mode 100644 index 799a38af5a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -/** - * An expression which performs an operation on two expression values - */ -public abstract class UnaryExpression implements Expression -{ - - private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression right; - - public static Expression createNegate(Expression left) - { - return new NegativeExpression(left); - } - - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) - { - - // Use a HashSet if there are many elements. - Collection t; - if (elements.size() == 0) - { - t = null; - } - else if (elements.size() < 5) - { - t = elements; - } - else - { - t = new HashSet(elements); - } - - final Collection inList = t; - - return new InExpression(right, inList, not); - } - - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression - { - public BooleanUnaryExpression(Expression left) - { - super(left); - } - - public boolean matches(Filterable message) throws E - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - ; - - public static BooleanExpression createNOT(BooleanExpression left) - { - return new NotExpression(left); - } - - public static BooleanExpression createXPath(final String xpath) - { - return new XPathExpression(xpath); - } - - public static BooleanExpression createXQuery(final String xpath) - { - return new XQueryExpression(xpath); - } - - public static BooleanExpression createBooleanCast(Expression left) - { - return new BooleanCastExpression(left); - } - - private static Number negate(Number left) - { - Class clazz = left.getClass(); - if (clazz == Integer.class) - { - return new Integer(-left.intValue()); - } - else if (clazz == Long.class) - { - return new Long(-left.longValue()); - } - else if (clazz == Float.class) - { - return new Float(-left.floatValue()); - } - else if (clazz == Double.class) - { - return new Double(-left.doubleValue()); - } - else if (clazz == BigDecimal.class) - { - // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the - // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it - // as a Big decimal. But it gets Negated right away.. to here we try to covert it back - // to a Long. - BigDecimal bd = (BigDecimal) left; - bd = bd.negate(); - - if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) - { - return new Long(Long.MIN_VALUE); - } - - return bd; - } - else - { - throw new RuntimeException("Don't know how to negate: " + left); - } - } - - public UnaryExpression(Expression left) - { - this.right = left; - } - - public Expression getRight() - { - return right; - } - - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return "(" + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - - private static class NegativeExpression extends UnaryExpression - { - public NegativeExpression(final Expression left) - { - super(left); - } - - public Object evaluate(Filterable message) throws E - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue instanceof Number) - { - return negate((Number) rvalue); - } - - return null; - } - - public String getExpressionSymbol() - { - return "-"; - } - } - - private static class InExpression extends BooleanUnaryExpression - { - private final Collection _inList; - private final boolean _not; - - public InExpression(final PropertyExpression right, final Collection inList, final boolean not) - { - super(right); - _inList = inList; - _not = not; - } - - public Object evaluate(Filterable message) throws E - { - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue.getClass() != String.class) - { - return null; - } - - if (((_inList != null) && _inList.contains(rvalue)) ^ _not) - { - return Boolean.TRUE; - } - else - { - return Boolean.FALSE; - } - - } - - public String toString() - { - StringBuffer answer = new StringBuffer(); - answer.append(right); - answer.append(" "); - answer.append(getExpressionSymbol()); - answer.append(" ( "); - - int count = 0; - for (Iterator i = _inList.iterator(); i.hasNext();) - { - Object o = (Object) i.next(); - if (count != 0) - { - answer.append(", "); - } - - answer.append(o); - count++; - } - - answer.append(" )"); - - return answer.toString(); - } - - public String getExpressionSymbol() - { - if (_not) - { - return "NOT IN"; - } - else - { - return "IN"; - } - } - } - - private static class NotExpression extends BooleanUnaryExpression - { - public NotExpression(final BooleanExpression left) - { - super(left); - } - - public Object evaluate(Filterable message) throws E - { - Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) - { - return null; - } - - return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - - public String getExpressionSymbol() - { - return "NOT"; - } - } - - private static class BooleanCastExpression extends BooleanUnaryExpression - { - public BooleanCastExpression(final Expression left) - { - super(left); - } - - public Object evaluate(Filterable message) throws E - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (!rvalue.getClass().equals(Boolean.class)) - { - return Boolean.FALSE; - } - - return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; - } - - public String toString() - { - return right.toString(); - } - - public String getExpressionSymbol() - { - return ""; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java deleted file mode 100644 index 24ddd1c678..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Used to evaluate an XPath Expression in a JMS selector. - */ -public final class XPathExpression implements BooleanExpression { - - private static final Logger log = Logger.getLogger(XPathExpression.class); - private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.qpid.server.filter.XPathEvaluatorClassName"; - private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName(); - - private static final Constructor EVALUATOR_CONSTRUCTOR; - - static { - String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); - Constructor m = null; - try { - try { - m = getXPathEvaluatorConstructor(cn); - } catch (Throwable e) { - log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e); - cn = DEFAULT_EVALUATOR_CLASS_NAME; - try { - m = getXPathEvaluatorConstructor(cn); - } catch (Throwable e2) { - log.error("Default XPath evaluator could not be loaded",e); - } - } - } finally { - EVALUATOR_CONSTRUCTOR = m; - } - } - - private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { - Class c = XPathExpression.class.getClassLoader().loadClass(cn); - if( !XPathEvaluator.class.isAssignableFrom(c) ) { - throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class); - } - return c.getConstructor(new Class[]{String.class}); - } - - private final String xpath; - private final XPathEvaluator evaluator; - - static public interface XPathEvaluator { - public boolean evaluate(Filterable message) throws AMQException; - } - - XPathExpression(String xpath) { - this.xpath = xpath; - this.evaluator = createEvaluator(xpath); - } - - private XPathEvaluator createEvaluator(String xpath2) { - try { - return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath}); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if( cause instanceof RuntimeException ) { - throw (RuntimeException)cause; - } - throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); - } catch (Throwable e) { - throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); - } - } - - public Object evaluate(Filterable message) throws AMQException { -// try { -//FIXME this is flow to disk work -// if( message.isDropped() ) -// return null; - return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE; -// } catch (IOException e) { -// -// JMSException exception = new JMSException(e.getMessage()); -// exception.initCause(e); -// throw exception; -// -// } - - } - - public String toString() { - return "XPATH "+ConstantExpression.encodeString(xpath); - } - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException - */ - public boolean matches(Filterable message) throws AMQException - { - Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java deleted file mode 100644 index ff6360e752..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.filter; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; - -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -/** - * Used to evaluate an XQuery Expression in a JMS selector. - */ -public final class XQueryExpression implements BooleanExpression { - private final String xpath; - - XQueryExpression(String xpath) { - super(); - this.xpath = xpath; - } - - public Object evaluate(Filterable message) throws AMQException { - return Boolean.FALSE; - } - - public String toString() { - return "XQUERY "+ConstantExpression.encodeString(xpath); - } - - /** - * @param message - * @return true if the expression evaluates to Boolean.TRUE. - * @throws AMQException - */ - public boolean matches(Filterable message) throws AMQException - { - Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java deleted file mode 100644 index 9db3f17fdb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project -// - -import java.io.ByteArrayInputStream; -import java.io.StringReader; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.Filterable; -import org.apache.xpath.CachedXPathAPI; -import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; -import org.xml.sax.InputSource; - -public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { - - private final String xpath; - - public XalanXPathEvaluator(String xpath) { - this.xpath = xpath; - } - - public boolean evaluate(Filterable m) throws AMQException - { - // TODO - we would have to check the content type and then evaluate the content - // here... is this really a feature we wish to implement? - RobG - /* - - if( m instanceof TextMessage ) { - String text = ((TextMessage)m).getText(); - return evaluate(text); - } else if ( m instanceof BytesMessage ) { - BytesMessage bm = (BytesMessage) m; - byte data[] = new byte[(int) bm.getBodyLength()]; - bm.readBytes(data); - return evaluate(data); - } - */ - return false; - - } - - private boolean evaluate(byte[] data) { - try { - - InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder dbuilder = factory.newDocumentBuilder(); - Document doc = dbuilder.parse(inputSource); - - CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); - NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); - return iterator.nextNode()!=null; - - } catch (Throwable e) { - return false; - } - } - - private boolean evaluate(String text) { - try { - InputSource inputSource = new InputSource(new StringReader(text)); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder dbuilder = factory.newDocumentBuilder(); - Document doc = dbuilder.parse(inputSource); - - // We should associated the cachedXPathAPI object with the message being evaluated - // since that should speedup subsequent xpath expressions. - CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); - NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); - return iterator.nextNode()!=null; - } catch (Throwable e) { - return false; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java deleted file mode 100644 index 895db7b15b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java +++ /dev/null @@ -1,62 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.flow; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Set; -import java.util.HashSet; - -public abstract class AbstractFlowCreditManager implements FlowCreditManager -{ - protected final AtomicBoolean _suspended = new AtomicBoolean(false); - private final Set _listeners = new HashSet(); - - public final void addStateListener(FlowCreditManagerListener listener) - { - _listeners.add(listener); - } - - public final boolean removeListener(FlowCreditManagerListener listener) - { - return _listeners.remove(listener); - } - - private void notifyListeners(final boolean suspended) - { - for(FlowCreditManagerListener listener : _listeners) - { - listener.creditStateChanged(!suspended); - } - } - - protected final void setSuspended(final boolean suspended) - { - if(_suspended.compareAndSet(!suspended, suspended)) - { - notifyListeners(suspended); - } - } - - protected final void notifyIncreaseBytesCredit() - { - notifyListeners(false); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java deleted file mode 100644 index 0bb428cd8f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.QueueEntry; - -import java.util.concurrent.atomic.AtomicLong; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class BytesOnlyCreditManager extends AbstractFlowCreditManager -{ - private final AtomicLong _bytesCredit; - - public BytesOnlyCreditManager(long initialCredit) - { - _bytesCredit = new AtomicLong(initialCredit); - } - - public void addCredit(long messageCredit, long bytesCredit) - { - _bytesCredit.addAndGet(bytesCredit); - setSuspended(false); - } - - public void removeAllCredit() - { - _bytesCredit.set(0L); - } - - public boolean hasCredit() - { - return _bytesCredit.get() > 0L; - } - - public boolean useCreditForMessage(QueueEntry queueEntry) - { - final long msgSize = queueEntry.getSize(); - if(hasCredit()) - { - if(_bytesCredit.addAndGet(-msgSize) >= 0) - { - return true; - } - else - { - _bytesCredit.addAndGet(msgSize); - setSuspended(true); - return false; - } - } - else - { - return false; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java deleted file mode 100644 index 297e5a4826..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public interface FlowCreditManager -{ - - public static interface FlowCreditManagerListener - { - void creditStateChanged(boolean hasCredit); - } - - void addStateListener(FlowCreditManagerListener listener); - - boolean removeListener(FlowCreditManagerListener listener); - - public void addCredit(long messageCredit, long bytesCredit); - - public void removeAllCredit(); - - public boolean hasCredit(); - - public boolean useCreditForMessage(QueueEntry queueEntry); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java deleted file mode 100644 index 437b7b0469..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.QueueEntry; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager -{ - public void addCredit(long messageCredit, long bytesCredit) - { - } - - public void removeAllCredit() - { - } - - public boolean hasCredit() - { - return true; - } - - public boolean useCreditForMessage(QueueEntry queueEntry) - { - return true; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java deleted file mode 100644 index 15ecb5f292..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.QueueEntry; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class MessageAndBytesCreditManager extends AbstractFlowCreditManager implements FlowCreditManager -{ - private long _messageCredit; - private long _bytesCredit; - - MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) - { - _messageCredit = messageCredit; - _bytesCredit = bytesCredit; - } - - public synchronized void addCredit(long messageCredit, long bytesCredit) - { - _messageCredit += messageCredit; - _bytesCredit += bytesCredit; - setSuspended(hasCredit()); - } - - public synchronized void removeAllCredit() - { - _messageCredit = 0L; - _bytesCredit = 0L; - setSuspended(true); - } - - public synchronized boolean hasCredit() - { - return (_messageCredit > 0L) && ( _bytesCredit > 0L ); - } - - public synchronized boolean useCreditForMessage(QueueEntry queueEntry) - { - if(_messageCredit == 0L) - { - setSuspended(true); - return false; - } - else - { - final long msgSize = queueEntry.getSize(); - if(msgSize > _bytesCredit) - { - setSuspended(true); - return false; - } - _messageCredit--; - _bytesCredit -= msgSize; - setSuspended(false); - return true; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java deleted file mode 100644 index 3e28d779b1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.QueueEntry; - -import java.util.concurrent.atomic.AtomicLong; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class MessageOnlyCreditManager extends AbstractFlowCreditManager implements FlowCreditManager -{ - private final AtomicLong _messageCredit; - - public MessageOnlyCreditManager(final long initialCredit) - { - _messageCredit = new AtomicLong(initialCredit); - } - - public void addCredit(long messageCredit, long bytesCredit) - { - setSuspended(false); - _messageCredit.addAndGet(messageCredit); - } - - public void removeAllCredit() - { - setSuspended(true); - _messageCredit.set(0L); - } - - public boolean hasCredit() - { - return _messageCredit.get() > 0L; - } - - public boolean useCreditForMessage(QueueEntry queueEntry) - { - if(hasCredit()) - { - if(_messageCredit.addAndGet(-1L) >= 0) - { - setSuspended(false); - return true; - } - else - { - _messageCredit.addAndGet(1L); - setSuspended(true); - return false; - } - } - else - { - setSuspended(true); - return false; - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java deleted file mode 100644 index 5cdd3a0328..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java +++ /dev/null @@ -1,185 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.flow; - -import org.apache.qpid.server.queue.QueueEntry; - -public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager -{ - - private volatile long _bytesCreditLimit; - private volatile long _messageCreditLimit; - - private volatile long _bytesCredit; - private volatile long _messageCredit; - - public Pre0_10CreditManager(long bytesCreditLimit, long messageCreditLimit) - { - _bytesCreditLimit = bytesCreditLimit; - _messageCreditLimit = messageCreditLimit; - _bytesCredit = bytesCreditLimit; - _messageCredit = messageCreditLimit; - } - - - public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit) - { - long bytesCreditChange = bytesCreditLimit - _bytesCreditLimit; - long messageCreditChange = messageCreditLimit - _messageCreditLimit; - - - - if(bytesCreditChange != 0L) - { - if(bytesCreditLimit == 0L) - { - _bytesCredit = 0; - } - else - { - _bytesCredit += bytesCreditChange; - } - } - - - if(messageCreditChange != 0L) - { - if(messageCreditLimit == 0L) - { - _messageCredit = 0; - } - else - { - _messageCredit += messageCreditChange; - } - } - - - _bytesCreditLimit = bytesCreditLimit; - _messageCreditLimit = messageCreditLimit; - - setSuspended(!hasCredit()); - - } - - - public synchronized void addCredit(final long messageCredit, final long bytesCredit) - { - final long messageCreditLimit = _messageCreditLimit; - boolean notifyIncrease = true; - if(messageCreditLimit != 0L) - { - notifyIncrease = (_messageCredit != 0); - long newCredit = _messageCredit + messageCredit; - _messageCredit = newCredit > messageCreditLimit ? messageCreditLimit : newCredit; - } - - - final long bytesCreditLimit = _bytesCreditLimit; - if(bytesCreditLimit != 0L) - { - long newCredit = _bytesCredit + bytesCredit; - _bytesCredit = newCredit > bytesCreditLimit ? bytesCreditLimit : newCredit; - if(notifyIncrease && bytesCredit>0) - { - notifyIncreaseBytesCredit(); - } - } - - - - setSuspended(!hasCredit()); - - } - - public synchronized void removeAllCredit() - { - _bytesCredit = 0L; - _messageCredit = 0L; - setSuspended(!hasCredit()); - } - - public synchronized boolean hasCredit() - { - return (_bytesCreditLimit == 0L || _bytesCredit > 0) - && (_messageCreditLimit == 0L || _messageCredit > 0); - } - - public synchronized boolean useCreditForMessage(final QueueEntry queueEntry) - { - if(_messageCreditLimit != 0L) - { - if(_messageCredit != 0L) - { - if(_bytesCreditLimit == 0L) - { - _messageCredit--; - - return true; - } - else - { - if((_bytesCredit >= queueEntry.getSize()) || (_bytesCredit == _bytesCreditLimit)) - { - _messageCredit--; - _bytesCredit -= queueEntry.getSize(); - - return true; - } - else - { - //setSuspended(true); - return false; - } - } - } - else - { - setSuspended(true); - return false; - } - } - else - { - if(_bytesCreditLimit == 0L) - { - - return true; - } - else - { - if((_bytesCredit >= queueEntry.getSize()) || (_bytesCredit == _bytesCreditLimit)) - { - _bytesCredit -= queueEntry.getSize(); - - return true; - } - else - { - //setSuspended(true); - return false; - } - } - - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java deleted file mode 100644 index e64eaeae76..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.apache.qpid.server.handler; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; - -/** - * @author Apache Software Foundation - * - * - */ -public class AccessRequestHandler implements StateAwareMethodListener -{ - private static final AccessRequestHandler _instance = new AccessRequestHandler(); - - - public static AccessRequestHandler getInstance() - { - return _instance; - } - - private AccessRequestHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - - // We don't implement access control class, but to keep clients happy that expect it - // always use the "0" ticket. - AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); - - session.writeFrame(response.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java deleted file mode 100644 index f90e7c3dff..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicAckBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class BasicAckMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicAckMethodHandler.class); - - private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); - - public static BasicAckMethodHandler getInstance() - { - return _instance; - } - - private BasicAckMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicAckBody body, int channelId) throws AMQException - { - AMQProtocolSession protocolSession = stateManager.getProtocolSession(); - - - if (_log.isDebugEnabled()) - { - _log.debug("Ack(Tag:" + body.getDeliveryTag() + ":Mult:" + body.getMultiple() + ") received on channel " + channelId); - } - - final AMQChannel channel = protocolSession.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - // this method throws an AMQException if the delivery tag is not known - channel.acknowledgeMessage(body.getDeliveryTag(), body.getMultiple()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java deleted file mode 100644 index 29054f55c1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicCancelBody; -import org.apache.qpid.framing.BasicCancelOkBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; - -public class BasicCancelMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicCancelMethodHandler.class); - - private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); - - public static BasicCancelMethodHandler getInstance() - { - return _instance; - } - - private BasicCancelMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicCancelBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - final AMQChannel channel = session.getChannel(channelId); - - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - if (_log.isDebugEnabled()) - { - _log.debug("BasicCancel: for:" + body.getConsumerTag() + - " nowait:" + body.getNowait()); - } - - channel.unsubscribeConsumer(body.getConsumerTag()); - if (!body.getNowait()) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - BasicCancelOkBody cancelOkBody = methodRegistry.createBasicCancelOkBody(body.getConsumerTag()); - session.writeFrame(cancelOkBody.generateFrame(channelId)); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java deleted file mode 100644 index 08610f24cd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.*; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicConsumeMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicConsumeMethodHandler.class); - - private static final BasicConsumeMethodHandler _instance = new BasicConsumeMethodHandler(); - - public static BasicConsumeMethodHandler getInstance() - { - return _instance; - } - - private BasicConsumeMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicConsumeBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - - - AMQChannel channel = session.getChannel(channelId); - - VirtualHost vHost = session.getVirtualHost(); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("BasicConsume: from '" + body.getQueue() + - "' for:" + body.getConsumerTag() + - " nowait:" + body.getNowait() + - " args:" + body.getArguments()); - } - - AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue().intern()); - - if (queue == null) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("No queue for '" + body.getQueue() + "'"); - } - if (body.getQueue() != null) - { - String msg = "No such queue, '" + body.getQueue() + "'"; - throw body.getChannelException(AMQConstant.NOT_FOUND, msg); - } - else - { - String msg = "No queue name provided, no default queue defined."; - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg); - } - } - else - { - - final AMQShortString consumerTagName; - - // Check authz - if (!vHost.getAccessManager().authoriseConsume(session, - body.getExclusive(), body.getNoAck(), - body.getNoLocal(), body.getNowait(), queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - if (body.getConsumerTag() != null) - { - consumerTagName = body.getConsumerTag().intern(); - } - else - { - consumerTagName = null; - } - - try - { - AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(), - body.getArguments(), body.getNoLocal(), body.getExclusive()); - if (!body.getNowait()) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - - - } - catch (org.apache.qpid.AMQInvalidArgumentException ise) - { - _logger.debug("Closing connection due to invalid selector"); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createChannelCloseBody(AMQConstant.INVALID_ARGUMENT.getCode(), - new AMQShortString(ise.getMessage()), - body.getClazz(), - body.getMethod()); - session.writeFrame(responseBody.generateFrame(channelId)); - - - } - catch (ConsumerTagNotUniqueException e) - { - AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode - msg, // replytext - body.getClazz(), - body.getMethod()); - session.writeFrame(responseBody.generateFrame(0)); - } - catch (AMQQueue.ExistingExclusiveSubscription e) - { - throw body.getChannelException(AMQConstant.ACCESS_REFUSED, - "Cannot subscribe to queue " - + queue.getName() - + " as it already has an existing exclusive consumer"); - } - catch (AMQQueue.ExistingSubscriptionPreventsExclusive e) - { - throw body.getChannelException(AMQConstant.ACCESS_REFUSED, - "Cannot subscribe to queue " - + queue.getName() - + " exclusively as it already has a consumer"); - } - - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java deleted file mode 100644 index a626114792..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.BasicGetBody; -import org.apache.qpid.framing.BasicGetEmptyBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.flow.MessageOnlyCreditManager; -import org.apache.qpid.server.subscription.SubscriptionImpl; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.SimpleAMQQueue; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicGetMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); - - private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); - - public static BasicGetMethodHandler getInstance() - { - return _instance; - } - - private BasicGetMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - VirtualHost vHost = session.getVirtualHost(); - - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - else - { - AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); - if (queue == null) - { - _log.info("No queue for '" + body.getQueue() + "'"); - if(body.getQueue()!=null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, - "No such queue, '" + body.getQueue()+ "'"); - } - else - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "No queue name provided, no default queue defined."); - } - } - else - { - - //Perform ACLs - if (!vHost.getAccessManager().authoriseConsume(session, body.getNoAck(), queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - if (!performGet(queue,session, channel, !body.getNoAck())) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - // TODO - set clusterId - BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); - - - session.writeFrame(responseBody.generateFrame(channelId)); - } - } - } - } - - public static boolean performGet(final AMQQueue queue, - final AMQProtocolSession session, - final AMQChannel channel, - final boolean acks) - throws AMQException - { - - final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); - - final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod() - { - - int _msg; - - public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) - throws AMQException - { - singleMessageCredit.useCreditForMessage(entry); - session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(), - deliveryTag, queue.getMessageCount()); - - } - }; - final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() - { - - public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) - { - channel.addUnacknowledgedMessage(entry, deliveryTag, null); - } - }; - - Subscription sub; - if(acks) - { - sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod); - } - else - { - sub = new GetNoAckSubscription(channel, - session, - null, - null, - false, - singleMessageCredit, - getDeliveryMethod, - getRecordMethod); - } - - queue.registerSubscription(sub,false); - queue.flushSubscription(sub); - queue.unregisterSubscription(sub); - return(!singleMessageCredit.hasCredit()); - - - } - - public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription - { - public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); - } - - public boolean wouldSuspend(QueueEntry queueEntry) - { - return !getCreditManager().useCreditForMessage(queueEntry); - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java deleted file mode 100644 index a7d3ad6217..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicPublishMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicPublishMethodHandler.class); - - private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); - - - public static BasicPublishMethodHandler getInstance() - { - return _instance; - } - - private BasicPublishMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicPublishBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - if (_logger.isDebugEnabled()) - { - _logger.debug("Publish received on channel " + channelId); - } - - AMQShortString exchange = body.getExchange(); - // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? - if (exchange == null) - { - exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; - - } - - VirtualHost vHost = session.getVirtualHost(); - Exchange e = vHost.getExchangeRegistry().getExchange(exchange); - // if the exchange does not exist we raise a channel exception - if (e == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name"); - } - 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 = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //Access Control - if (!vHost.getAccessManager().authorisePublish(session, - body.getImmediate(), body.getMandatory(), - body.getRoutingKey(), e)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body); - info.setExchange(exchange); - channel.setPublishFrame(info, e); - } - } - -} - - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java deleted file mode 100644 index dd3281c65f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicQosBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class BasicQosHandler implements StateAwareMethodListener -{ - private static final BasicQosHandler _instance = new BasicQosHandler(); - - public static BasicQosHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, BasicQosBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount()); - - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java deleted file mode 100644 index c7842cd643..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.BasicRecoverOkBody; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, BasicRecoverBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); - AMQChannel channel = session.getChannel(channelId); - - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.resend(body.getRequeue()); - - // Qpid 0-8 hacks a synchronous -ok onto recover. - // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant - if(session.getProtocolVersion().equals(ProtocolVersion.v8_0)) - { - MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) session.getMethodRegistry(); - AMQMethodBody recoverOk = methodRegistry.createBasicRecoverOkBody(); - session.writeFrame(recoverOk.generateFrame(channelId)); - - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java deleted file mode 100644 index 2c264c3d45..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.apache.qpid.server.handler; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import org.apache.log4j.Logger; - -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.BasicRecoverSyncBody; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.AMQException; - -public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); - - private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); - - public static BasicRecoverSyncMethodHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); - AMQChannel channel = session.getChannel(channelId); - - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.resend(body.getRequeue()); - - // Qpid 0-8 hacks a synchronous -ok onto recover. - // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant - if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) - { - MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); - AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); - session.writeFrame(recoverOk.generateFrame(channelId)); - - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java deleted file mode 100644 index 8b04315d33..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicRejectBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; - -public class BasicRejectMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRejectMethodHandler.class); - - private static BasicRejectMethodHandler _instance = new BasicRejectMethodHandler(); - - public static BasicRejectMethodHandler getInstance() - { - return _instance; - } - - private BasicRejectMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicRejectBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Rejecting:" + body.getDeliveryTag() + - ": Requeue:" + body.getRequeue() + - //": Resend:" + evt.getMethod().resend + - " on channel:" + channel.debugIdentity()); - } - - long deliveryTag = body.getDeliveryTag(); - - QueueEntry queueEntry = channel.getUnacknowledgedMessageMap().get(deliveryTag); - - if (queueEntry == null) - { - _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag); -// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known"); - } - else - { - if (queueEntry.isQueueDeleted()) - { - _logger.warn("Message's Queue as already been purged, unable to Reject. " + - "Dropping message should use Dead Letter Queue"); - queueEntry = channel.getUnacknowledgedMessageMap().remove(deliveryTag); - if(queueEntry != null) - { - queueEntry.dequeueAndDelete(channel.getStoreContext()); - } - //sendtoDeadLetterQueue(msg) - return; - } - - if (queueEntry.isDeleted()) - { - _logger.warn("QueueEntry as already been deleted, unable to Reject."); - return; - } - - - if (_logger.isDebugEnabled()) - { - _logger.debug("Rejecting: DT:" + deliveryTag + "-" + queueEntry.debugIdentity() + - ": Requeue:" + body.getRequeue() + - //": Resend:" + evt.getMethod().resend + - " on channel:" + channel.debugIdentity()); - } - - // If we haven't requested message to be resent to this consumer then reject it from ever getting it. - //if (!evt.getMethod().resend) - { - queueEntry.reject(); - } - - if (body.getRequeue()) - { - channel.requeue(deliveryTag); - } - else - { - _logger.warn("Dropping message as requeue not required and there is no dead letter queue"); - queueEntry = channel.getUnacknowledgedMessageMap().remove(deliveryTag); - //sendtoDeadLetterQueue(AMQMessage message) -// message.queue = channel.getDefaultDeadLetterQueue(); -// channel.requeue(deliveryTag); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java deleted file mode 100644 index 9133cce6b7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -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.ChannelCloseBody; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -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, ChannelCloseBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - if (_logger.isInfoEnabled()) - { - _logger.info("Received channel close for id " + channelId + " citing class " + body.getClassId() + - " and method " + body.getMethodId()); - } - - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel"); - } - - session.closeChannel(channelId); - // Client requested closure so we don't wait for ok we send it - stateManager.getProtocolSession().closeChannelOk(channelId); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - ChannelCloseOkBody responseBody = methodRegistry.createChannelCloseOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java deleted file mode 100644 index a857490e7e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, ChannelCloseOkBody body, int channelId) throws AMQException - { - - _logger.info("Received channel-close-ok for channel-id " + channelId); - - // Let the Protocol Session know the channel is now closed. - stateManager.getProtocolSession().closeChannelOk(channelId); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java deleted file mode 100644 index 696ca8a63b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, ChannelFlowBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.setSuspended(!body.getActive()); - _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive()); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createChannelFlowOkBody(body.getActive()); - session.writeFrame(responseBody.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java deleted file mode 100644 index 0a7d5cfe6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.UUID; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class ChannelOpenHandler implements StateAwareMethodListener -{ - private static ChannelOpenHandler _instance = new ChannelOpenHandler(); - - public static ChannelOpenHandler getInstance() - { - return _instance; - } - - private ChannelOpenHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, ChannelOpenBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - - final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getTransactionLog() - ); - session.addChannel(channel); - - ChannelOpenOkBody response; - - ProtocolVersion pv = session.getProtocolVersion(); - - if(pv.equals(ProtocolVersion.v8_0)) - { - MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - response = methodRegistry.createChannelOpenOkBody(); - - } - else if(pv.equals(ProtocolVersion.v0_9)) - { - MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); - UUID uuid = UUID.randomUUID(); - ByteArrayOutputStream output = new ByteArrayOutputStream(); - DataOutputStream dataOut = new DataOutputStream(output); - try - { - dataOut.writeLong(uuid.getMostSignificantBits()); - dataOut.writeLong(uuid.getLeastSignificantBits()); - dataOut.flush(); - dataOut.close(); - } - catch (IOException e) - { - // This *really* shouldn't happen as we're not doing any I/O - throw new RuntimeException("I/O exception when writing to byte array", e); - } - - // should really associate this channelId to the session - byte[] channelName = output.toByteArray(); - - response = methodRegistry.createChannelOpenOkBody(channelName); - } - else - { - throw new AMQException(AMQConstant.INTERNAL_ERROR, "Got channel open for protocol version not catered for: " + pv, null); - } - - - session.writeFrame(response.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java deleted file mode 100644 index dade5d5f54..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, ConnectionCloseBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - if (_logger.isInfoEnabled()) - { - _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" + - body.getReplyText() + " for " + session); - } - try - { - session.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - - MethodRegistry methodRegistry = session.getMethodRegistry(); - ConnectionCloseOkBody responseBody = methodRegistry.createConnectionCloseOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java deleted file mode 100644 index bc6e5ab403..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.ConnectionCloseOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, ConnectionCloseOkBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - //todo should this not do more than just log the method? - _logger.info("Received Connection-close-ok"); - - try - { - stateManager.changeState(AMQState.CONNECTION_CLOSED); - session.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java deleted file mode 100644 index 824f084f57..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.log4j.Logger; - -public class ConnectionOpenMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); - - private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); - - public static ConnectionOpenMethodHandler getInstance() - { - return _instance; - } - - private ConnectionOpenMethodHandler() - { - } - - private static AMQShortString generateClientID() - { - return new AMQShortString(Long.toString(System.currentTimeMillis())); - } - - public void methodReceived(AMQStateManager stateManager, ConnectionOpenBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - - //ignore leading '/' - String virtualHostName; - if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/') - { - virtualHostName = new StringBuilder(body.getVirtualHost().subSequence(1, body.getVirtualHost().length())).toString(); - } - else - { - virtualHostName = body.getVirtualHost() == null ? null : String.valueOf(body.getVirtualHost()); - } - - VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); - - if (virtualHost == null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'"); - } - else - { - session.setVirtualHost(virtualHost); - - //Perform ACL - if (!virtualHost.getAccessManager().authoriseConnect(session, virtualHost)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - // See Spec (0.8.2). Section 3.1.2 Virtual Hosts - if (session.getContextKey() == null) - { - session.setContextKey(generateClientID()); - } - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost()); - - stateManager.changeState(AMQState.CONNECTION_OPEN); - - session.writeFrame(responseBody.generateFrame(channelId)); - - - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java deleted file mode 100644 index a2a6faf21b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionSecureBody; -import org.apache.qpid.framing.ConnectionSecureOkBody; -import org.apache.qpid.framing.ConnectionTuneBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -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, ConnectionSecureOkBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); - - SaslServer ss = session.getSaslServer(); - if (ss == null) - { - throw new AMQException("No SASL context set up in session"); - } - MethodRegistry methodRegistry = session.getMethodRegistry(); - AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); - switch (authResult.status) - { - case ERROR: - Exception cause = authResult.getCause(); - - _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); - - // This should be abstracted - stateManager.changeState(AMQState.CONNECTION_CLOSING); - - ConnectionCloseBody connectionCloseBody = - methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), - AMQConstant.NOT_ALLOWED.getName(), - body.getClazz(), - body.getMethod()); - - session.writeFrame(connectionCloseBody.generateFrame(0)); - disposeSaslServer(session); - break; - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - - ConnectionTuneBody tuneBody = - methodRegistry.createConnectionTuneBody(0xFFFF, - ConnectionStartOkMethodHandler.getConfiguredFrameSize(), - ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); - session.writeFrame(tuneBody.generateFrame(0)); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); - disposeSaslServer(session); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - - ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); - session.writeFrame(secureBody.generateFrame(0)); - } - } - - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java deleted file mode 100644 index 6698ae888a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionSecureBody; -import org.apache.qpid.framing.ConnectionStartOkBody; -import org.apache.qpid.framing.ConnectionTuneBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - - -public class ConnectionStartOkMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionStartOkMethodHandler.class); - - private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler(); - - public static ConnectionStartOkMethodHandler getInstance() - { - return _instance; - } - - private ConnectionStartOkMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, ConnectionStartOkBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - _logger.info("SASL Mechanism selected: " + body.getMechanism()); - _logger.info("Locale selected: " + body.getLocale()); - - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); - - SaslServer ss = null; - try - { - ss = authMgr.createSaslServer(String.valueOf(body.getMechanism()), session.getLocalFQDN()); - - if (ss == null) - { - throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism() - ); - } - - session.setSaslServer(ss); - - AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); - - //save clientProperties - if (session.getClientProperties() == null) - { - session.setClientProperties(body.getClientProperties()); - } - - MethodRegistry methodRegistry = session.getMethodRegistry(); - - switch (authResult.status) - { - case ERROR: - Exception cause = authResult.getCause(); - - _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); - - stateManager.changeState(AMQState.CONNECTION_CLOSING); - - ConnectionCloseBody closeBody = - methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode - AMQConstant.NOT_ALLOWED.getName(), - body.getClazz(), - body.getMethod()); - - session.writeFrame(closeBody.generateFrame(0)); - disposeSaslServer(session); - break; - - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); - - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - - ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, - getConfiguredFrameSize(), - ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); - session.writeFrame(tuneBody.generateFrame(0)); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - - ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); - session.writeFrame(secureBody.generateFrame(0)); - } - } - catch (SaslException e) - { - disposeSaslServer(session); - 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 ServerConfiguration config = ApplicationRegistry.getInstance().getConfiguration(); - final int framesize = config.getFrameSize(); - _logger.info("Framesize set to " + framesize); - return framesize; - } -} - - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java deleted file mode 100644 index 0fe8c5dc92..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionTuneOkBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -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, ConnectionTuneOkBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - if (_logger.isDebugEnabled()) - { - _logger.debug(body); - } - stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); - session.initHeartbeats(body.getHeartbeat()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java deleted file mode 100644 index ccd42204d9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.*; -import org.apache.qpid.server.exchange.Exchange; -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.qpid.server.virtualhost.VirtualHost; - -/** - * @author Apache Software Foundation - * - * - */ -public class ExchangeBoundHandler implements StateAwareMethodListener -{ - private static final ExchangeBoundHandler _instance = new ExchangeBoundHandler(); - - public static final int OK = 0; - - public static final int EXCHANGE_NOT_FOUND = 1; - - public static final int QUEUE_NOT_FOUND = 2; - - public static final int NO_BINDINGS = 3; - - public static final int QUEUE_NOT_BOUND = 4; - - public static final int NO_QUEUE_BOUND_WITH_RK = 5; - - public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; - - public static ExchangeBoundHandler getInstance() - { - return _instance; - } - - private ExchangeBoundHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, ExchangeBoundBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MethodRegistry methodRegistry = session.getMethodRegistry(); - - - - - AMQShortString exchangeName = body.getExchange(); - AMQShortString queueName = body.getQueue(); - AMQShortString routingKey = body.getRoutingKey(); - if (exchangeName == null) - { - throw new AMQException("Exchange exchange must not be null"); - } - Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); - ExchangeBoundOkBody response; - if (exchange == null) - { - - - response = methodRegistry.createExchangeBoundOkBody(EXCHANGE_NOT_FOUND, - new AMQShortString("Exchange " + exchangeName + " not found")); - } - else if (routingKey == null) - { - if (queueName == null) - { - if (exchange.hasBindings()) - { - response = methodRegistry.createExchangeBoundOkBody(OK, null); - } - else - { - - response = methodRegistry.createExchangeBoundOkBody(NO_BINDINGS, // replyCode - null); // replyText - } - } - else - { - - AMQQueue queue = queueRegistry.getQueue(queueName); - if (queue == null) - { - - response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode - new AMQShortString("Queue " + queueName + " not found")); // replyText - } - else - { - if (exchange.isBound(queue)) - { - - response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode - null); // replyText - } - else - { - - response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_BOUND, // replyCode - new AMQShortString("Queue " + queueName + " not bound to exchange " + exchangeName)); // replyText - } - } - } - } - else if (queueName != null) - { - AMQQueue queue = queueRegistry.getQueue(queueName); - if (queue == null) - { - - response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode - new AMQShortString("Queue " + queueName + " not found")); // replyText - } - else - { - if (exchange.isBound(body.getRoutingKey(), queue)) - { - - response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode - null); // replyText - } - else - { - - response = methodRegistry.createExchangeBoundOkBody(SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode - new AMQShortString("Queue " + queueName + " not bound with routing key " + - body.getRoutingKey() + " to exchange " + exchangeName)); // replyText - } - } - } - else - { - if (exchange.isBound(body.getRoutingKey())) - { - - response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode - null); // replyText - } - else - { - - response = methodRegistry.createExchangeBoundOkBody(NO_QUEUE_BOUND_WITH_RK, // replyCode - new AMQShortString("No queue bound with routing key " + body.getRoutingKey() + - " to exchange " + exchangeName)); // replyText - } - } - session.writeFrame(response.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java deleted file mode 100644 index ba60808492..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQConnectionException; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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 ExchangeDeclareHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, ExchangeDeclareBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); - - if (!body.getPassive()) - { - // Perform ACL if request is not passive - if (!virtualHost.getAccessManager().authoriseCreateExchange(session, body.getAutoDelete(), - body.getDurable(), body.getExchange(), body.getInternal(), body.getNowait(), body.getPassive(), - body.getType())) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + body.getExchange()); - } - synchronized(exchangeRegistry) - { - Exchange exchange = exchangeRegistry.getExchange(body.getExchange()); - - - - if (exchange == null) - { - if(body.getPassive() && ((body.getType() == null) || body.getType().length() ==0)) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + body.getExchange()); - } - else - { - try - { - - exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), - body.getType() == null ? null : body.getType().intern(), - body.getDurable(), - body.getPassive(), body.getTicket()); - exchangeRegistry.registerExchange(exchange); - } - catch(AMQUnknownExchangeType e) - { - throw body.getConnectionException(AMQConstant.COMMAND_INVALID, "Unknown exchange: " + body.getExchange(),e); - } - } - } - else if (!exchange.getType().equals(body.getType())) - { - - throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null); - } - - } - if(!body.getNowait()) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java deleted file mode 100644 index bd4b610933..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ExchangeDeleteBody; -import org.apache.qpid.framing.ExchangeDeleteOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.exchange.ExchangeInUseException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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, ExchangeDeleteBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(session, - exchangeRegistry.getExchange(body.getExchange()))) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - try - { - exchangeRegistry.unregisterExchange(body.getExchange(), body.getIfUnused()); - - ExchangeDeleteOkBody responseBody = session.getMethodRegistry().createExchangeDeleteOkBody(); - - session.writeFrame(responseBody.generateFrame(channelId)); - } - catch (ExchangeInUseException e) - { - // TODO: sort out consistent channel close mechanism that does all clean up etc. - } - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java deleted file mode 100644 index ac516b6133..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import java.util.concurrent.Executor; - -/** - * An executor that executes the task on the current thread. - */ -public class OnCurrentThreadExecutor implements Executor -{ - public void execute(Runnable command) - { - command.run(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java deleted file mode 100644 index 84491c1d2e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -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, QueueBindBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - - final AMQQueue queue; - final AMQShortString routingKey; - - if (body.getQueue() == null) - { - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - queue = channel.getDefaultQueue(); - - if (queue == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); - } - - if (body.getRoutingKey() == null) - { - routingKey = queue.getName(); - } - else - { - routingKey = body.getRoutingKey().intern(); - } - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - routingKey = body.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : body.getRoutingKey().intern(); - } - - if (queue == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); - if (exch == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); - } - - - try - { - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseBind(session, exch, - queue, routingKey)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - if (!exch.isBound(routingKey, body.getArguments(), queue)) - { - queue.bind(exch, routingKey, body.getArguments()); - } - } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); - } - catch (AMQException e) - { - throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); - } - - if (_log.isInfoEnabled()) - { - _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); - } - if (!body.getNowait()) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java deleted file mode 100644 index 7f500cfb8a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.QueueDeclareOkBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.routing.RoutingTable; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class QueueDeclareHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(QueueDeclareHandler.class); - - private static final QueueDeclareHandler _instance = new QueueDeclareHandler(); - - public static QueueDeclareHandler getInstance() - { - return _instance; - } - - public boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister(); - - private final AtomicInteger _counter = new AtomicInteger(); - - public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - RoutingTable routingTable = virtualHost.getRoutingTable(); - - - if (!body.getPassive()) - { - // Perform ACL if request is not passive - if (!virtualHost.getAccessManager().authoriseCreateQueue(session, body.getAutoDelete(), body.getDurable(), - body.getExclusive(), body.getNowait(), body.getPassive(), body.getQueue())) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - } - - final AMQShortString queueName; - - // if we aren't given a queue name, we create one which we return to the client - - if ((body.getQueue() == null) || (body.getQueue().length() == 0)) - { - queueName = createName(); - } - else - { - queueName = body.getQueue().intern(); - } - - AMQQueue queue; - //TODO: do we need to check that the queue already exists with exactly the same "configuration"? - - synchronized (queueRegistry) - { - - - - if (((queue = queueRegistry.getQueue(queueName)) == null)) - { - - if (body.getPassive()) - { - String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; - throw body.getChannelException(AMQConstant.NOT_FOUND, msg); - } - else - { - queue = createQueue(queueName, body, virtualHost, session); - if (queue.isDurable() && !queue.isAutoDelete()) - { - routingTable.createQueue(queue, body.getArguments()); - } - queueRegistry.registerQueue(queue); - if (autoRegister) - { - Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); - - queue.bind(defaultExchange, queueName, null); - _logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getName() + ")"); - } - } - } - else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) - { - throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + queueName + "')," - + " as exclusive queue with same name " - + "declared on another client ID('" - + queue.getOwner() + "')"); - } - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //set this as the default queue on the channel: - channel.setDefaultQueue(queue); - } - - if (!body.getNowait()) - { - MethodRegistry methodRegistry = session.getMethodRegistry(); - QueueDeclareOkBody responseBody = - methodRegistry.createQueueDeclareOkBody(queueName, - queue.getMessageCount(), - queue.getConsumerCount()); - session.writeFrame(responseBody.generateFrame(channelId)); - - _logger.info("Queue " + queueName + " declared successfully"); - } - } - - protected AMQShortString createName() - { - return new AMQShortString("tmp_" + UUID.randomUUID()); - } - - protected AMQQueue createQueue(final AMQShortString queueName, - QueueDeclareBody body, - VirtualHost virtualHost, - final AMQProtocolSession session) - throws AMQException - { - final QueueRegistry registry = virtualHost.getQueueRegistry(); - AMQShortString owner = body.getExclusive() ? session.getContextKey() : null; - - final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost, - body.getArguments()); - - - if (body.getExclusive() && !body.getDurable()) - { - final AMQProtocolSession.Task deleteQueueTask = - new AMQProtocolSession.Task() - { - public void doTask(AMQProtocolSession session) throws AMQException - { - if (registry.getQueue(queueName) == queue) - { - queue.delete(); - } - } - }; - - session.addSessionCloseTask(deleteQueueTask); - - queue.addQueueDeleteTask(new AMQQueue.Task() - { - public void doTask(AMQQueue queue) - { - session.removeSessionCloseTask(deleteQueueTask); - } - }); - }// if exclusive and not durable - - return queue; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java deleted file mode 100644 index 85a697f3b7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.QueueDeleteBody; -import org.apache.qpid.framing.QueueDeleteOkBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQConstant; -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.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.routing.RoutingTable; - -public class QueueDeleteHandler implements StateAwareMethodListener -{ - private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); - - public static QueueDeleteHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueueDeleteHandler() - { - this(true); - } - - public QueueDeleteHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - - } - - public void methodReceived(AMQStateManager stateManager, QueueDeleteBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - RoutingTable routingTable = virtualHost.getRoutingTable(); - - AMQQueue queue; - if (body.getQueue() == null) - { - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - } - - if (queue == null) - { - if (_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - } - else - { - if (body.getIfEmpty() && !queue.isEmpty()) - { - throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is not empty."); - } - else if (body.getIfUnused() && !queue.isUnused()) - { - // TODO - Error code - throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used."); - - } - else - { - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(session, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - int purged = queue.delete(); - - - if (queue.isDurable()) - { - routingTable.removeQueue(queue); - } - - MethodRegistry methodRegistry = session.getMethodRegistry(); - QueueDeleteOkBody responseBody = methodRegistry.createQueueDeleteOkBody(purged); - session.writeFrame(responseBody.generateFrame(channelId)); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java deleted file mode 100644 index 2768518f53..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.QueuePurgeBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -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.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.security.access.Permission; - -public class QueuePurgeHandler implements StateAwareMethodListener -{ - private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); - - public static QueuePurgeHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueuePurgeHandler() - { - this(true); - } - - public QueuePurgeHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - } - - public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - AMQChannel channel = session.getChannel(channelId); - - - AMQQueue queue; - if(body.getQueue() == null) - { - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); - } - } - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - } - else - { - - //Perform ACLs - if (!virtualHost.getAccessManager().authorisePurge(session, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - long purged = queue.clearQueue(channel.getStoreContext()); - - - if(!body.getNowait()) - { - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); - session.writeFrame(responseBody.generateFrame(channelId)); - - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java deleted file mode 100644 index d4272239d1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.apache.qpid.server.handler; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import org.apache.log4j.Logger; - -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.protocol.AMQConstant; - -public class QueueUnbindHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(QueueUnbindHandler.class); - - private static final QueueUnbindHandler _instance = new QueueUnbindHandler(); - - public static QueueUnbindHandler getInstance() - { - return _instance; - } - - private QueueUnbindHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueUnbindBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); - ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - - final AMQQueue queue; - final AMQShortString routingKey; - - if (body.getQueue() == null) - { - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - queue = channel.getDefaultQueue(); - - if (queue == null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); - } - - routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); - - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); - } - - if (queue == null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); - if (exch == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); - } - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseUnbind(session, exch, routingKey, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - try - { - queue.unBind(exch, routingKey, body.getArguments()); - } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); - } - catch (AMQException e) - { - if(e.getErrorCode() == AMQConstant.NOT_FOUND) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND,e.getMessage(),e); - } - throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); - } - - if (_log.isInfoEnabled()) - { - _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); - } - - MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueueUnbindOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java deleted file mode 100644 index 9475b83c8f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.Map; -import java.util.HashMap; - -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.framing.*; -import org.apache.qpid.AMQException; - -public class ServerMethodDispatcherImpl implements MethodDispatcher -{ - private final AMQStateManager _stateManager; - - private static interface DispatcherFactory - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); - } - - private static final Map _dispatcherFactories = - new HashMap(); - - - static - { - _dispatcherFactories.put(ProtocolVersion.v8_0, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_8_0(stateManager); - } - }); - - _dispatcherFactories.put(ProtocolVersion.v0_9, - new DispatcherFactory() - { - public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) - { - return new ServerMethodDispatcherImpl_0_9(stateManager); - } - }); - - } - - - private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); - private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); - private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); - private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); - private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); - private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); - private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); - private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); - private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); - private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); - private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); - private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); - private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); - private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); - private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); - private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); - private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); - private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); - private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); - private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); - private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); - private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); - private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); - private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); - private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); - private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); - private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); - private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); - private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); - - - - public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) - { - return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); - } - - - public ServerMethodDispatcherImpl(AMQStateManager stateManager) - { - _stateManager = stateManager; - } - - - protected AMQStateManager getStateManager() - { - return _stateManager; - } - - - - public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException - { - _accessRequestHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException - { - _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException - { - _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException - { - _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException - { - _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException - { - _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException - { - _basicQosHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException - { - _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException - { - _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException - { - _channelOpenHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException - { - _channelCloseHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException - { - _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException - { - _channelFlowHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException - { - _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException - { - _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException - { - _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - - public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException - { - _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException - { - _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException - { - _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException - { - _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException - { - _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException - { - _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException - { - _queueBindHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException - { - _queueDeclareHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException - { - _queueDeleteHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException - { - _queuePurgeHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException - { - _txCommitHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException - { - _txRollbackHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException - { - _txSelectHandler.methodReceived(_stateManager, body, channelId); - return true; - } - - - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java deleted file mode 100644 index 8b1dca77ba..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.amqp_0_9.MethodDispatcher_0_9; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - - - -public class ServerMethodDispatcherImpl_0_9 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_0_9 - -{ - - private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = - BasicRecoverSyncMethodHandler.getInstance(); - private static final QueueUnbindHandler _queueUnbindHandler = - QueueUnbindHandler.getInstance(); - - - public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException - { - _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); - return true; - } - - public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException - { - _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); - return true; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java deleted file mode 100644 index d599ca3d4e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.AMQException; - -public class ServerMethodDispatcherImpl_8_0 - extends ServerMethodDispatcherImpl - implements MethodDispatcher_8_0 -{ - public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) - { - super(stateManager); - } - - public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException - { - throw new UnexpectedMethodException(body); - } - - public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException - { - return false; - } - - public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException - { - return false; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java deleted file mode 100644 index 9b23d88838..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxCommitBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxCommitHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(TxCommitHandler.class); - - private static TxCommitHandler _instance = new TxCommitHandler(); - - public static TxCommitHandler getInstance() - { - return _instance; - } - - private TxCommitHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, TxCommitBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - try - { - if (_log.isDebugEnabled()) - { - _log.debug("Commit received on channel " + channelId); - } - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.commit(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - channel.processReturns(); - } - catch (AMQException e) - { - throw body.getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java deleted file mode 100644 index 5f402f3fda..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -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.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxRollbackHandler implements StateAwareMethodListener -{ - private static TxRollbackHandler _instance = new TxRollbackHandler(); - - public static TxRollbackHandler getInstance() - { - return _instance; - } - - private TxRollbackHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - try - { - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.rollback(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - - - //Now resend all the unacknowledged messages back to the original subscribers. - //(Must be done after the TxnRollback-ok response). - // Why, are we not allowed to send messages back to client before the ok method? - channel.resend(false); - } - catch (AMQException e) - { - throw body.getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java deleted file mode 100644 index 308f5b73cf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class TxSelectHandler implements StateAwareMethodListener -{ - private static TxSelectHandler _instance = new TxSelectHandler(); - - public static TxSelectHandler getInstance() - { - return _instance; - } - - private TxSelectHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, TxSelectBody body, int channelId) throws AMQException - { - AMQProtocolSession session = stateManager.getProtocolSession(); - - AMQChannel channel = session.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - channel.setLocalTransactional(); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - TxSelectOkBody responseBody = methodRegistry.createTxSelectOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java deleted file mode 100644 index fb18519fe1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - - -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.AMQException; - -public class UnexpectedMethodException extends AMQException -{ - public UnexpectedMethodException(AMQMethodBody body) - { - super("Unexpected method recevied: " + body.getClass().getName()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java deleted file mode 100644 index f723ab206c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.management; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -public interface LoggingManagement -{ - String TYPE = "LoggingManagement"; - int VERSION = 1; - - //TabularType and contained CompositeType key/description information - String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; - String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; - String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; - - /** - * Attribute to represent the log4j xml configuration file's LogWatch interval. - * @return The logwatch interval in seconds. - */ - @MBeanAttribute(name="Log4jLogWatchInterval", - description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") - Integer getLog4jLogWatchInterval(); - - /** - * Attribute to represent the available log4j logger output levels. - * @return The logging level names. - */ - @MBeanAttribute(name="AvailableLoggerLevels", description = "The values to which log output level can be set.") - String[] getAvailableLoggerLevels(); - - - //****** log4j runtime operations ****** // - - /** - * Sets the level of an active Log4J logger - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Retrieves a TabularData set of the active log4j loggers and their levels - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - */ - @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + - "for active log4j logger's.", impact = MBeanOperationInfo.INFO) - TabularData viewEffectiveRuntimeLoggerLevels(); - - /** - * Sets the level of the active Log4J RootLogger - * @param level The level to set the RootLogger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Attribute to represent the level of the active Log4J RootLogger - * @return The level of the RootLogger. - */ - @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") - String getRuntimeRootLoggerLevel(); - - - //****** log4j XML configuration file operations ****** // - - /** - * Updates the level of an existing Log4J logger within the xml configuration file - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + - "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) - TabularData viewConfigFileLoggerLevels() throws IOException; - - /** - * Updates the level of the Log4J RootLogger within the xml configuration file if it is present - * @param level The level to set the logger to - * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Attribute to represent the level of the Log4J RootLogger within the xml configuration file - * @return The level of the RootLogger, or null if it is not present - */ - @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + - "in the log4j xml configuration file.") - String getConfigFileRootLoggerLevel() throws IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java deleted file mode 100644 index cd3f85f8ca..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.management; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.Log4jEntityResolver; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - - -/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ -@MBeanDescription("Logging Management Interface") -public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement -{ - - private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); - private String _log4jConfigFileName; - private int _log4jLogWatchInterval; - private static final String[] LEVELS = new String[]{Level.ALL.toString(), Level.TRACE.toString(), - Level.DEBUG.toString(), Level.INFO.toString(), - Level.WARN.toString(), Level.ERROR.toString(), - Level.FATAL.toString(),Level.OFF.toString()}; - static TabularType _loggerLevelTabularType; - static CompositeType _loggerLevelCompositeType; - - static - { - try - { - OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; - - _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); - - _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", - _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); - } - catch (OpenDataException e) - { - _logger.error("Tabular data setup for viewing logger levels was incorrect."); - _loggerLevelTabularType = null; - } - } - - public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException - { - super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); - _log4jConfigFileName = log4jConfigFileName; - _log4jLogWatchInterval = log4jLogWatchInterval; - } - - public String getObjectInstanceName() - { - return LoggingManagement.TYPE; - } - - public Integer getLog4jLogWatchInterval() - { - return _log4jLogWatchInterval; - } - - public String[] getAvailableLoggerLevels() - { - return LEVELS; - } - @SuppressWarnings("unchecked") - public synchronized boolean setRuntimeLoggerLevel(String logger, String level) - { - //check specified level is valid - Level newLevel; - try - { - newLevel = getLevel(level); - } - catch (Exception e) - { - return false; - } - - //check specified logger exists - Enumeration loggers = LogManager.getCurrentLoggers(); - Boolean loggerExists = false; - - while(loggers.hasMoreElements()) - { - Logger log = (Logger) loggers.nextElement(); - if (log.getName().equals(logger)) - { - loggerExists = true; - break; - } - } - - if(!loggerExists) - { - return false; - } - - //set the logger to the new level - _logger.info("Setting level to " + level + " for logger: " + logger); - - Logger log = Logger.getLogger(logger); - log.setLevel(newLevel); - - return true; - } - - @SuppressWarnings("unchecked") - public synchronized TabularData viewEffectiveRuntimeLoggerLevels() - { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting levels for currently active log4j loggers"); - - Enumeration loggers = LogManager.getCurrentLoggers(); - - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); - - Logger logger; - String loggerName; - String level; - - try - { - while(loggers.hasMoreElements()){ - logger = (Logger) loggers.nextElement(); - - loggerName = logger.getName(); - level = logger.getEffectiveLevel().toString(); - - Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - - return loggerLevelList; - - } - - public synchronized String getRuntimeRootLoggerLevel() - { - Logger rootLogger = Logger.getRootLogger(); - - return rootLogger.getLevel().toString(); - } - - public synchronized boolean setRuntimeRootLoggerLevel(String level) - { - Level newLevel; - try - { - newLevel = getLevel(level); - } - catch (Exception e) - { - return false; - } - - _logger.info("Setting RootLogger level to " + level); - - Logger log = Logger.getRootLogger(); - log.setLevel(newLevel); - - return true; - } - - //method to convert from a string to a log4j Level, throws exception if the given value is invalid - private Level getLevel(String level) throws Exception - { - Level newLevel = Level.toLevel(level); - - //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. - if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug"))) - { - //received DEBUG but we did not ask for it, the Level request failed. - throw new Exception("Invalid level name"); - } - - return newLevel; - } - - //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - private class SaxErrorHandler implements ErrorHandler - { - - public void error(SAXParseException e) throws SAXException - { - throw new SAXException("Error parsing XML file: " + e.getMessage()); - } - - public void fatalError(SAXParseException e) throws SAXException - { - throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); - } - - public void warning(SAXParseException e) throws SAXException - { - throw new SAXException("Warning parsing XML file: " + e.getMessage()); - } - } - - //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private synchronized Document parseConfigFile(String fileName) throws IOException - { - //check file was specified, exists, and is readable - if(fileName == null) - { - _logger.warn("No log4j XML configuration file has been set"); - throw new IOException("No log4j XML configuration file has been set"); - } - - File configFile = new File(fileName); - - if (!configFile.exists()) - { - _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); - throw new IOException("Specified log4j XML configuration file does not exist"); - } - else if (!configFile.canRead()) - { - _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); - throw new IOException("Specified log4j XML configuration file is not readable"); - } - - //parse it - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder; - Document doc; - - ErrorHandler errHandler = new SaxErrorHandler(); - try - { - docFactory.setValidating(true); - docBuilder = docFactory.newDocumentBuilder(); - docBuilder.setErrorHandler(errHandler); - docBuilder.setEntityResolver(new Log4jEntityResolver()); - doc = docBuilder.parse(fileName); - } - catch (ParserConfigurationException e) - { - _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); - //recommended that MBeans should use java.* and javax.* exceptions only - throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); - } - catch (SAXException e) - { - _logger.warn("The specified log4j XML file is invalid: " + e); - //recommended that MBeans should use standard java.* and javax.* exceptions only - throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); - } - catch (IOException e) - { - _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file", e); - } - - return doc; - } - - - private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException - { - File log4jConfigFile = new File(log4jConfigFileName); - - if (!log4jConfigFile.canWrite()) - { - _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); - throw new IOException("Specified log4j XML configuration file is not writable"); - } - - Transformer transformer = null; - try - { - transformer = TransformerFactory.newInstance().newTransformer(); - } - catch (Exception e) - { - _logger.warn("Could not create an XML transformer: " +e); - return false; - } - - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); - DOMSource source = new DOMSource(doc); - - File tmp; - try - { - tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); - tmp.deleteOnExit(); - StreamResult result = new StreamResult(tmp); - transformer.transform(source, result); - } - catch (TransformerException e) - { - _logger.warn("Could not transform the XML into new file: " +e); - return false; - } - catch (IOException e) - { - _logger.warn("Could not create the new file: " +e); - return false; - } - - // Swap temp file in to replace existing configuration file. - File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - log4jConfigFile.renameTo(old); - return tmp.renameTo(log4jConfigFile); - } - - - /* The log4j XML configuration file DTD defines three possible element - * combinations for specifying optional logger+level settings. - * Must account for the following: - * - * OR - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - - - public synchronized TabularData viewConfigFileLoggerLevels() throws IOException - { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); - - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); - - //retrieve the 'category' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - - String categoryName; - String priority = null; - - for (int i = 0; i < categoryElements.getLength(); i++) - { - Element categoryElement = (Element) categoryElements.item(i); - categoryName = categoryElement.getAttribute("name"); - - //retrieve the category's mandatory 'priority' or 'level' element's value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = categoryElement.getElementsByTagName("priority"); - NodeList levelElements = categoryElement.getElementsByTagName("level"); - - if (priorityElements.getLength() != 0) - { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value").toUpperCase(); - } - else if (levelElements.getLength() != 0) - { - Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value").toUpperCase(); - } - else - { - //there is no exiting priority or level to view, move onto next category/logger - continue; - } - - try - { - Object[] itemData = {categoryName, priority}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - } - - //retrieve the 'logger' element nodes - NodeList loggerElements = doc.getElementsByTagName("logger"); - - String loggerName; - String level; - - for (int i = 0; i < loggerElements.getLength(); i++) - { - Element loggerElement = (Element) loggerElements.item(i); - loggerName = loggerElement.getAttribute("name"); - - //retrieve the logger's mandatory 'level' element's value - //It may not be the only child node, so request by tag name. - NodeList levelElements = loggerElement.getElementsByTagName("level"); - - Element levelElement = (Element) levelElements.item(0); - level = levelElement.getAttribute("value").toUpperCase(); - - try - { - Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } - } - - return loggerLevelList; - } - - public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException - { - //check that the specified level is a valid log4j Level - try - { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for logger '" + logger - + "' in log4j xml configuration file: " + _log4jConfigFileName); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the 'category' and 'logger' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - NodeList loggerElements = doc.getElementsByTagName("logger"); - - //collect them into a single elements list - List logElements = new ArrayList(); - - for (int i = 0; i < categoryElements.getLength(); i++) - { - logElements.add((Element) categoryElements.item(i)); - } - for (int i = 0; i < loggerElements.getLength(); i++) - { - logElements.add((Element) loggerElements.item(i)); - } - - //try to locate the specified logger/category in the elements retrieved - Element logElement = null; - for (Element e : logElements) - { - if (e.getAttribute("name").equals(logger)) - { - logElement = e; - break; - } - } - - if (logElement == null) - { - //no loggers/categories with given name found, does not exist to update - _logger.warn("Specified logger does not exist in the configuration file: " +logger); - return false; - } - - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = logElement.getElementsByTagName("priority"); - NodeList levelElements = logElement.getElementsByTagName("level"); - - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); - } - else - { - //there is no exiting priority or level element to update - return false; - } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); - } - - - /* The log4j XML configuration file DTD defines 2 possible element - * combinations for specifying the optional root logger level settings - * Must account for the following: - * - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - - public synchronized String getConfigFileRootLoggerLevel() throws IOException - { - _logger.info("Getting root logger level from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - //there is not root logger definition - return null; - } - - Element rootElement = (Element) rootElements.item(0); - - //retrieve the optional 'priority' or 'level' element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); - String priority = null; - - if (priorityElements.getLength() != 0) - { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value"); - } - else if(levelElements.getLength() != 0) - { - Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value"); - } - - if(priority != null) - { - return priority.toUpperCase(); - } - else - { - return null; - } - } - - public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException - { - //check that the specified level is a valid log4j Level - try - { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for the Root logger in " + - "log4j xml configuration file: " + _log4jConfigFileName); - - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - return false; - } - - Element rootElement = (Element) rootElements.item(0); - - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); - - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); - } - else - { - //there is no exiting priority/level to update - return false; - } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java deleted file mode 100644 index c6e07f6f48..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.ListenerNotFoundException; -import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; - -/** - * This class provides additinal feature of Notification Broadcaster to the - * DefaultManagedObject. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public abstract class AMQManagedObject extends DefaultManagedObject - implements NotificationBroadcaster -{ - /** - * broadcaster support class - */ - protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); - - /** - * sequence number for notifications - */ - protected long _notificationSequenceNumber = 0; - - protected MBeanInfo _mbeanInfo; - - protected AMQManagedObject(Class managementInterface, String typeName, int version) - throws NotCompliantMBeanException - { - super(managementInterface, typeName, version); - 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java deleted file mode 100644 index 67aee90ba4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.StandardMBean; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; - -/** - * 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; - private int _version; - - protected DefaultManagedObject(Class managementInterface, String typeName, int version) - throws NotCompliantMBeanException - { - super(managementInterface); - _managementInterface = managementInterface; - _typeName = typeName; - _version = version; - } - - public String getType() - { - return _typeName; - } - - public Class getManagementInterface() - { - return _managementInterface; - } - - public ManagedObject getParentObject() - { - return null; - } - - public void register() throws AMQException - { - try - { - getManagedObjectRegistry().registerObject(this); - } - catch (JMException e) - { - throw new AMQException("Error registering managed object " + this + ": " + e, e); - } - } - - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - - public void unregister() throws AMQException - { - try - { - 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); - - objectName.append(","); - objectName.append("version=").append(_version); - - - return new ObjectName(objectName.toString()); - } - - protected ObjectName getObjectNameForSingleInstanceMBean() throws MalformedObjectNameException - { - StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); - - objectName.append(":type="); - objectName.append(getHierarchicalType(this)); - - String hierarchyName = getHierarchicalName(this); - if (hierarchyName != null) - { - objectName.append(","); - objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); - } - - objectName.append(","); - objectName.append("version=").append(_version); - - return new ObjectName(objectName.toString()); - } - - protected String getHierarchicalType(ManagedObject obj) - { - if (obj.getParentObject() != null) - { - String parentType = getHierarchicalType(obj.getParentObject()).toString(); - return parentType + "." + obj.getType(); - } - else - return obj.getType(); - } - - protected String getHierarchicalName(ManagedObject obj) - { - if (obj.getParentObject() != null) - { - String 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; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java deleted file mode 100644 index 5a113de5be..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; - -import javax.management.JMException; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.rmi.RMIConnectorServer; -import javax.management.remote.rmi.RMIJRMPServerImpl; -import javax.management.remote.rmi.RMIServerImpl; -import javax.rmi.ssl.SslRMIClientSocketFactory; -import javax.rmi.ssl.SslRMIServerSocketFactory; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.rmi.AlreadyBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; -import java.rmi.server.RMIServerSocketFactory; -import java.rmi.server.UnicastRemoteObject; -import java.util.HashMap; -import java.util.Map; - -/** - * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no - * security features implemented like user authentication and authorisation. - */ -public class JMXManagedObjectRegistry implements ManagedObjectRegistry -{ - private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); - private static final Logger _startupLog = Logger.getLogger("Qpid.Broker"); - - public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; - public static final int MANAGEMENT_PORT_DEFAULT = 8999; - public static final int PORT_EXPORT_OFFSET = 100; - - private final MBeanServer _mbeanServer; - private Registry _rmiRegistry; - - - public JMXManagedObjectRegistry() throws AMQException - { - _log.info("Initialising managed object registry using platform MBean server"); - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - - // Retrieve the config parameters - boolean platformServer = appRegistry.getConfiguration().getPlatformMbeanserver(); - - _mbeanServer = - platformServer ? ManagementFactory.getPlatformMBeanServer() - : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); - } - - - public void start() throws IOException, ConfigurationException - { - //check if system properties are set to use the JVM's out-of-the-box JMXAgent - if (areOutOfTheBoxJMXOptionsSet()) - { - _log.warn("JMX: Using the out of the box JMX Agent"); - _startupLog.warn("JMX: Using the out of the box JMX Agent"); - return; - } - - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - int port = appRegistry.getConfiguration().getJMXManagementPort(); - - //retrieve the Principal Database assigned to JMX authentication duties - String jmxDatabaseName = appRegistry.getConfiguration().getJMXPrincipalDatabase(); - Map map = appRegistry.getDatabaseManager().getDatabases(); - PrincipalDatabase db = map.get(jmxDatabaseName); - - final JMXConnectorServer cs; - HashMap env = new HashMap(); - - //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration - RMIClientSocketFactory csf; - RMIServerSocketFactory ssf; - - //check ssl enabled option in config, default to true if option is not set - boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); - - if (sslEnabled) - { - //set the SSL related system properties used by the SSL RMI socket factories to the values - //given in the configuration file, unless command line settings have already been specified - String keyStorePath; - - if(System.getProperty("javax.net.ssl.keyStore") != null) - { - keyStorePath = System.getProperty("javax.net.ssl.keyStore"); - } - else - { - keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); - } - - //check the keystore path value is valid - if (keyStorePath == null) - { - throw new ConfigurationException("JMX management SSL keystore path not defined, " + - "unable to start SSL protected JMX ConnectorServer"); - } - else - { - //ensure the system property is set - System.setProperty("javax.net.ssl.keyStore", keyStorePath); - - //check the file is usable - File ksf = new File(keyStorePath); - - if (!ksf.exists()) - { - throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf + "\n" - + "Check broker configuration, or see create-example-ssl-stores script" - + "in the bin/ directory if you need to generate an example store."); - } - if (!ksf.canRead()) - { - throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " - + ksf + ". Check permissions."); - } - - _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - } - - //check the key store password is set - if (System.getProperty("javax.net.ssl.keyStorePassword") == null) - { - - if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) - { - throw new ConfigurationException("JMX management SSL keystore password not defined, " + - "unable to start requested SSL protected JMX server"); - } - else - { - System.setProperty("javax.net.ssl.keyStorePassword", - appRegistry.getConfiguration().getManagementKeyStorePassword()); - } - } - - //create the SSL RMI socket factories - csf = new SslRMIClientSocketFactory(); - ssf = new SslRMIServerSocketFactory(); - - _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - } - else - { - //Do not specify any specific RMI socket factories, resulting in use of the defaults. - csf = null; - ssf = null; - - _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - } - - //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server - RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); - rmipa.setPrincipalDatabase(db); - env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); - - /* - * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. - * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. - * As a result, only binds made using the object reference will succeed, thus securing it from external change. - */ - System.setProperty("java.rmi.server.randomIDs", "true"); - _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); - - /* - * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls - * to bind the ConnectorServer to the registry, which will now fail as for security we have - * locked it from any RMI based modifications, including our own. Instead, we will manually bind - * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. - * - * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer - * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. - */ - final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); - final String hostname = InetAddress.getLocalHost().getHostName(); - final JMXServiceURL externalUrl = new JMXServiceURL( - "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); - - final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); - cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) - { - @Override - public synchronized void start() throws IOException - { - try - { - //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent - _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); - } - catch (AlreadyBoundException abe) - { - //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means. - - //IOExceptions are the only checked type throwable by the method, wrap and rethrow - IOException ioe = new IOException(abe.getMessage()); - ioe.initCause(abe); - throw ioe; - } - - //now do the normal tasks - super.start(); - } - - @Override - public JMXServiceURL getAddress() - { - //must return our pre-crafted url that includes the full details, inc JNDI details - return externalUrl; - } - - }; - - - //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); - cs.start(); - } - - /* - * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry. - * Supplied to the registry at creation, this will prevent RMI-based operations on the - * registry such as attempting to bind a new object, thereby securing it from tampering. - * This is accomplished by always returning null when attempting to determine the address - * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc - * made using the object reference will not be affected and continue to operate normally. - */ - - private class CustomRMIServerSocketFactory implements RMIServerSocketFactory - { - - public ServerSocket createServerSocket(int port) throws IOException - { - return new NoLocalAddressServerSocket(port); - } - - private class NoLocalAddressServerSocket extends ServerSocket - { - NoLocalAddressServerSocket(int port) throws IOException - { - super(port); - } - - @Override - public Socket accept() throws IOException - { - Socket s = new NoLocalAddressSocket(); - super.implAccept(s); - return s; - } - } - - private class NoLocalAddressSocket extends Socket - { - @Override - public InetAddress getInetAddress() - { - return null; - } - } - } - - - public void registerObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.unregisterMBean(managedObject.getObjectName()); - } - - // checks if the system properties are set which enable the JVM's out-of-the-box JMXAgent. - private boolean areOutOfTheBoxJMXOptionsSet() - { - if (System.getProperty("com.sun.management.jmxremote") != null) - { - return true; - } - - if (System.getProperty("com.sun.management.jmxremote.port") != null) - { - return true; - } - - return false; - } - - // stops the RMIRegistry and unregisters the MBeans from the MBeanServer - public void close() throws RemoteException - { - if (_rmiRegistry != null) - { - // Stopping the RMI registry - UnicastRemoteObject.unexportObject(_rmiRegistry, true); - } - - //ObjectName query to gather all Qpid related MBeans - ObjectName mbeanNameQuery = null; - try - { - mbeanNameQuery = new ObjectName(ManagedObject.DOMAIN + ":*"); - } - catch (Exception e1) - { - _log.warn("Unable to generate MBean ObjectName query for close operation"); - } - - for (ObjectName name : _mbeanServer.queryNames(mbeanNameQuery, null)) - { - try - { - _mbeanServer.unregisterMBean(name); - } - catch (JMException e) - { - _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage()); - } - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java deleted file mode 100644 index 7d42297699..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean attributes. This should be used with getter or setter - * methods of attributes. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanAttribute -{ - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java deleted file mode 100644 index 9138e03085..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean constructors. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.CONSTRUCTOR) -@Inherited -public @interface MBeanConstructor -{ - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java deleted file mode 100644 index 448fed3280..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean class. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -public @interface MBeanDescription { - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java deleted file mode 100644 index 0c2ec2aebd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanConstructorInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.NotCompliantMBeanException; - -/** - * 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()) - { - 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; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java deleted file mode 100644 index e9b4d85e66..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.server.configuration.management.ConfigurationManagement; -import org.apache.qpid.server.logging.management.LoggingManagement; -import org.apache.qpid.server.security.access.management.UserManagement; -import org.apache.log4j.Logger; - -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.JMXPrincipal; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.JMException; -import javax.security.auth.Subject; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.Principal; -import java.security.AccessControlContext; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; -import java.util.Properties; - -/** - * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements - * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite - * and admin users. - */ -public class MBeanInvocationHandlerImpl implements InvocationHandler -{ - private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); - - public final static String ADMIN = "admin"; - public final static String READWRITE = "readwrite"; - public final static String READONLY = "readonly"; - private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; - private MBeanServer _mbs; - private static Properties _userRoles = new Properties(); - - private static HashSet _adminOnlyMethods = new HashSet(); - { - _adminOnlyMethods.add(UserManagement.TYPE); - _adminOnlyMethods.add(LoggingManagement.TYPE); - _adminOnlyMethods.add(ConfigurationManagement.TYPE); - } - - public static MBeanServerForwarder newProxyInstance() - { - final InvocationHandler handler = new MBeanInvocationHandlerImpl(); - final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; - - Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); - return MBeanServerForwarder.class.cast(proxy); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - final String methodName = method.getName(); - - if (methodName.equals("getMBeanServer")) - { - return _mbs; - } - - if (methodName.equals("setMBeanServer")) - { - if (args[0] == null) - { - throw new IllegalArgumentException("Null MBeanServer"); - } - if (_mbs != null) - { - throw new IllegalArgumentException("MBeanServer object already initialized"); - } - _mbs = (MBeanServer) args[0]; - return null; - } - - // Retrieve Subject from current AccessControlContext - AccessControlContext acc = AccessController.getContext(); - Subject subject = Subject.getSubject(acc); - - // Allow operations performed locally on behalf of the connector server itself - if (subject == null) - { - return method.invoke(_mbs, args); - } - - if (args == null || DELEGATE.equals(args[0])) - { - return method.invoke(_mbs, args); - } - - // Restrict access to "createMBean" and "unregisterMBean" to any user - if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) - { - _logger.debug("User trying to create or unregister an MBean"); - throw new SecurityException("Access denied"); - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - throw new SecurityException("Access denied"); - } - - Principal principal = principals.iterator().next(); - String identity = principal.getName(); - - if (isAdminMethod(args)) - { - if (isAdmin(identity)) - { - return method.invoke(_mbs, args); - } - else - { - throw new SecurityException("Access denied"); - } - } - - // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAllowedToModify(identity)) - { - return method.invoke(_mbs, args); - } - - // These users can only call "getAttribute" on the MBeanServerDelegate MBean - // Here we can add other fine grained permissions like specific method for a particular mbean - if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) - { - return method.invoke(_mbs, args); - } - - throw new SecurityException("Access denied"); - } - - private boolean isAdminMethod(Object[] args) - { - if (args[0] instanceof ObjectName) - { - ObjectName object = (ObjectName) args[0]; - - return _adminOnlyMethods.contains(object.getKeyProperty("type")); - } - return false; - } - - // Initialises the user roles - public static void setAccessRights(Properties accessRights) - { - _userRoles = accessRights; - } - - private boolean isAdmin(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isAllowedToModify(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName)) - || READWRITE.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isReadOnlyUser(String userName) - { - if (READONLY.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } - - private boolean isReadOnlyMethod(Method method, Object[] args) - { - String methodName = method.getName(); - - //handle standard get/set/query and select 'is' methods from MBeanServer - if (methodName.startsWith("query") || methodName.startsWith("get") - ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) - { - return true; - } - else if (methodName.startsWith("set")) - { - return false; - } - - //handle invocation of other methods on mbeans - if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) - { - - //get invoked method name - String mbeanMethod = (args.length > 1) ? (String) args[1] : null; - if (mbeanMethod == null) - { - return false; - } - - try - { - //check if the given method is tagged with an INFO impact attribute - MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); - if (mbeanInfo != null) - { - MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); - for (MBeanOperationInfo opInfo : opInfos) - { - if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) - { - return true; - } - } - } - } - catch (JMException ex) - { - ex.printStackTrace(); - } - } - - return false; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java deleted file mode 100644 index a2dca3e51d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.management.MBeanOperationInfo; - -/** - * Annotation for MBean operations. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanOperation -{ - String name(); - String description(); - int impact() default MBeanOperationInfo.INFO; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java deleted file mode 100644 index aba5ec70d8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean operation parameters. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface MBeanOperationParameter { - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java deleted file mode 100644 index 166a2a376d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -/** - * Any object that can return a related MBean should implement this interface. - * - * This enables other classes to get the managed object, which in turn is useful when - * constructing relationships between managed objects without having to maintain - * separate data structures containing MBeans. - * - */ -public interface Managable -{ - ManagedObject getManagedObject(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java deleted file mode 100644 index c18417fc43..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.management; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; - -import org.apache.qpid.server.exchange.ManagedExchange; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The ManagedBroker is the management interface to expose management - * features of the Broker. - * - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedBroker -{ - static final String TYPE = "VirtualHostManager"; - - static final int VERSION = 1 ; - - /** - * Creates a new Exchange. - * @param name - * @param type - * @param durable - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) - void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, - @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) - throws IOException, JMException; - - /** - * unregisters all the channels, queuebindings etc and unregisters - * this exchange from managed objects. - * @param exchange - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="unregisterExchange", - description="Unregisters all the related channels and queuebindings of this exchange", - impact= MBeanOperationInfo.ACTION) - void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) - throws IOException, JMException; - - /** - * Create a new Queue on the Broker server - * @param queueName - * @param durable - * @param owner - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) - void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, - @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) - throws IOException, JMException; - - /** - * Unregisters the Queue bindings, removes the subscriptions and unregisters - * from the managed objects. - * @param queueName - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteQueue", - description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", - impact= MBeanOperationInfo.ACTION) - void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) - throws IOException, JMException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java deleted file mode 100644 index 42ea8921a4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.apache.qpid.AMQException; - -/** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java deleted file mode 100644 index b58b17ba86..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; - -import org.apache.commons.configuration.ConfigurationException; - -import java.rmi.RemoteException; -import java.io.IOException; - -/** - * 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 start() throws IOException, ConfigurationException; - - void registerObject(ManagedObject managedObject) throws JMException; - - void unregisterObject(ManagedObject managedObject) throws JMException; - - void close() throws RemoteException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java deleted file mode 100644 index b4fbed6948..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; - -import org.apache.log4j.Logger; - -import java.rmi.RemoteException; - -/** - * 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 start() - { - //no-op - } - - public void registerObject(ManagedObject managedObject) throws JMException - { - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - } - - public void close() throws RemoteException - { - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java deleted file mode 100644 index 5438e0a7da..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.AMQException; - -public interface ProtocolOutputConverter -{ - void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); - - interface Factory - { - ProtocolOutputConverter newInstance(AMQProtocolSession session); - } - - void writeDeliver(QueueEntry queueEntry, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException; - - void writeGetOk(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) throws AMQException; - - byte getProtocolMinorVersion(); - - byte getProtocolMajorVersion(); - - void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException; - - void writeFrame(AMQDataBlock block); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java deleted file mode 100644 index 36e7e88fd6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output; - -import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.framing.ProtocolVersion; - -import java.util.Map; -import java.util.HashMap; - -public class ProtocolOutputConverterRegistry -{ - - private static final Map _registry = - new HashMap(); - - - static - { - register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); - register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); - - } - - private static void register(ProtocolVersion version, Factory converter) - { - - _registry.put(version,converter); - } - - - public static ProtocolOutputConverter getConverter(AMQProtocolSession session) - { - return _registry.get(session.getProtocolVersion()).newInstance(session); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java deleted file mode 100644 index ea94f23ff9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/* - * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. - * Supported AMQP versions: - * 8-0 - */ -package org.apache.qpid.server.output.amqp0_8; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.AMQException; - -import java.util.Iterator; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(QueueEntry queueEntry, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - final AMQMessage message = queueEntry.getMessage(); - - AMQDataBlock deliver = createEncodedDeliverFrame(queueEntry, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final int bodyCount = message.getBodyCount(); - - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = message.getContentChunk(0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = message.getContentChunk(i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - public void writeGetOk(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) throws AMQException - { - final AMQMessage message = queueEntry.getMessage(); - - AMQDataBlock deliver = createEncodedGetOkFrame(queueEntry, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final int bodyCount = message.getBodyCount(); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = message.getContentChunk(0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = message.getContentChunk(i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - - } - - - } - - - private AMQDataBlock createEncodedDeliverFrame(QueueEntry queueEntry, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - final AMQMessage message = queueEntry.getMessage(); - - final MessagePublishInfo pb = message.getMessagePublishInfo(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicDeliverBody deliverBody = - methodRegistry.createBasicDeliverBody(consumerTag, - deliveryTag, - queueEntry.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey()); - return deliverBody.generateFrame(channelId); - } - - private AMQDataBlock createEncodedGetOkFrame(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final AMQMessage message = queueEntry.getMessage(); - final MessagePublishInfo pb = message.getMessagePublishInfo(); - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicGetOkBody getOkBody = - methodRegistry.createBasicGetOkBody(deliveryTag, - queueEntry.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - return getOkBody.generateFrame(channelId); - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicReturnBody basicReturnBody = - methodRegistry.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - return basicReturnBody.generateFrame(channelId); - - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java deleted file mode 100644 index b71b118275..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ /dev/null @@ -1,378 +0,0 @@ -package org.apache.qpid.server.output.amqp0_9; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; - -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; - -public class ProtocolOutputConverterImpl implements ProtocolOutputConverter -{ - private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); - private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); - - - public static Factory getInstanceFactory() - { - return new Factory() - { - - public ProtocolOutputConverter newInstance(AMQProtocolSession session) - { - return new ProtocolOutputConverterImpl(session); - } - }; - } - - private final AMQProtocolSession _protocolSession; - - private ProtocolOutputConverterImpl(AMQProtocolSession session) - { - _protocolSession = session; - } - - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void writeDeliver(QueueEntry queueEntry, int channelId, long deliveryTag, AMQShortString consumerTag) - throws AMQException - { - AMQMessage message = queueEntry.getMessage(); - - AMQBody deliverBody = createEncodedDeliverFrame(queueEntry, channelId, deliveryTag, consumerTag); - final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); - - final int bodyCount = message.getBodyCount(); - - if(bodyCount == 0) - { - SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, - contentHeaderBody); - - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = message.getContentChunk(0); - - AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); - - CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = message.getContentChunk(i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - } - - private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) - { - - return ContentHeaderBody.createAMQFrame(channelId, contentHeaderBody); - } - - - public void writeGetOk(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) throws AMQException - { - - final AMQMessage message = queueEntry.getMessage(); - - AMQFrame deliver = createEncodedGetOkFrame(queueEntry, channelId, deliveryTag, queueSize); - - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - final int bodyCount = message.getBodyCount(); - if(bodyCount == 0) - { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); - } - else - { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = message.getContentChunk(0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = message.getContentChunk(i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - - } - - - } - - - private AMQBody createEncodedDeliverFrame(QueueEntry queueEntry, final int channelId, final long deliveryTag, final AMQShortString consumerTag) - throws AMQException - { - AMQMessage message= queueEntry.getMessage(); - - final MessagePublishInfo pb = message.getMessagePublishInfo(); - - final boolean isRedelivered = queueEntry.isRedelivered(); - final AMQShortString exchangeName = pb.getExchange(); - final AMQShortString routingKey = pb.getRoutingKey(); - - return new AMQBody() - { - - public AMQBody _underlyingBody; - - public AMQBody createAMQBody() - { - return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, - deliveryTag, - isRedelivered, - exchangeName, - routingKey); - - - - - - } - - public byte getFrameType() - { - return AMQMethodBody.TYPE; - } - - public int getSize() - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - return _underlyingBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - if(_underlyingBody == null) - { - _underlyingBody = createAMQBody(); - } - _underlyingBody.writePayload(buffer); - } - - public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) - throws AMQException - { - throw new AMQException("This block should never be dispatched!"); - } - }; - } - - private AMQFrame createEncodedGetOkFrame(QueueEntry queueEntry, int channelId, long deliveryTag, int queueSize) - throws AMQException - { - final AMQMessage message = queueEntry.getMessage(); - final MessagePublishInfo pb = message.getMessagePublishInfo(); - - BasicGetOkBody getOkBody = - METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, - queueEntry.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), - queueSize); - return getOkBody.generateFrame(channelId); - } - - public byte getProtocolMinorVersion() - { - return getProtocolSession().getProtocolMinorVersion(); - } - - public byte getProtocolMajorVersion() - { - return getProtocolSession().getProtocolMajorVersion(); - } - - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException - { - - BasicReturnBody basicReturnBody = - METHOD_REGISTRY.createBasicReturnBody(replyCode, - replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - return basicReturnBody.generateFrame(channelId); - } - - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) - throws AMQException - { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - - writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } - } - - - public void writeFrame(AMQDataBlock block) - { - getProtocolSession().writeFrame(block); - } - - - public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) - { - - BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); - writeFrame(basicCancelOkBody.generateFrame(channelId)); - - } - - - public static final class CompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final AMQBody _contentBody; - private final int _channel; - - - public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - _contentBody = contentBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); - } - } - - public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock - { - public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); - - private final AMQBody _methodBody; - private final AMQBody _headerBody; - private final int _channel; - - - public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) - { - _channel = channel; - _methodBody = methodBody; - _headerBody = headerBody; - - } - - public long getSize() - { - return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; - } - - public void writePayload(ByteBuffer buffer) - { - AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java deleted file mode 100644 index b0ebf197f9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.qpid.server.plugins; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class Activator implements BundleActivator -{ - - BundleContext _context = null; - - public void start(BundleContext ctx) throws Exception - { - _context = ctx; - } - - public void stop(BundleContext ctx) throws Exception - { - start(null); - } - - public BundleContext getContext() - { - return _context; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java deleted file mode 100644 index dbfcefb6ab..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.qpid.server.plugins; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.felix.framework.Felix; -import org.apache.felix.framework.cache.BundleCache; -import org.apache.felix.framework.util.FelixConstants; -import org.apache.felix.framework.util.StringMap; -import org.apache.qpid.server.exchange.ExchangeType; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.plugins.AllowAll; -import org.apache.qpid.server.security.access.plugins.DenyAll; -import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; -import org.apache.qpid.server.security.access.plugins.SimpleXML; -import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleException; -import org.osgi.util.tracker.ServiceTracker; - -/** - * - * @author aidan - * - * Provides access to pluggable elements, such as exchanges - */ - -public class PluginManager -{ - - private Felix _felix = null; - private ServiceTracker _exchangeTracker = null; - private ServiceTracker _securityTracker = null; - private Activator _activator = null; - private boolean _empty; - private Map _securityPlugins; - - public PluginManager(String plugindir) throws Exception - { - StringMap configMap = new StringMap(false); - - // Tell felix it's being embedded - configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); - // Add the bundle provided service interface package and the core OSGi - // packages to be exported from the class path via the system bundle. - configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, "org.osgi.framework; version=1.3.0," - + "org.osgi.service.packageadmin; version=1.2.0," + - "org.osgi.service.startlevel; version=1.0.0," + - "org.osgi.service.url; version=1.0.0," + - "org.apache.qpid.framing; version=0.2.1," + - "org.apache.qpid.server.exchange; version=0.2.1," + - "org.apache.qpid.server.management; version=0.2.1,"+ - "org.apache.qpid.protocol; version=0.2.1,"+ - "org.apache.qpid.server.virtualhost; version=0.2.1," + - "org.apache.qpid; version=0.2.1," + - "org.apache.qpid.server.queue; version=0.2.1," + - "javax.management.openmbean; version=1.0.0,"+ - "javax.management; version=1.0.0,"+ - "org.apache.qpid.junit.extensions.util; version=0.6.1," - ); - - if (plugindir == null) - { - _empty = true; - return; - } - - // Set the list of bundles to load - File dir = new File(plugindir); - if (!dir.exists()) - { - _empty = true; - return; - } - StringBuffer pluginJars = new StringBuffer(); - - if (dir.isDirectory()) - { - for (String child : dir.list()) - { - if (child.endsWith("jar")) - { - pluginJars.append(String.format(" file:%s%s%s", plugindir,File.separator,child)); - } - } - } - if (pluginJars.length() == 0) - { - _empty = true; - return; - } - - configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); - configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); - - List activators = new ArrayList(); - _activator = new Activator(); - activators.add(_activator); - - _felix = new Felix(configMap, activators); - try - { - _felix.start(); - - _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); - _exchangeTracker.open(); - - _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); - _exchangeTracker.open(); - - } - catch (BundleException e) - { - throw new Exception("Could not create bundle"); - } - } - - private Map getServices(ServiceTracker tracker) - { - Mapexchanges = new HashMap(); - - if (tracker != null) - { - for (Object service : tracker.getServices()) - { - exchanges.put(service.getClass().getName(), (type) service); - } - } - - return exchanges; - } - - public Map> getExchanges() - { - return getServices(_exchangeTracker); - } - - public Map getSecurityPlugins() - { - if (_securityPlugins == null) - { - _securityPlugins = getServices(_securityTracker); - // A little gross that we have to add them here, but not all the plugins are OSGIfied - _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); - _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); - _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); - _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); - _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); - } - return _securityPlugins; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java deleted file mode 100644 index 205ca73f13..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ /dev/null @@ -1,859 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.log4j.Logger; - -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoServiceConfig; -import org.apache.mina.common.IoSession; -import org.apache.mina.common.CloseFuture; -import org.apache.mina.transport.vmpipe.VmPipeAddress; - -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.codec.AMQDecoder; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.transport.Sender; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; - -public class AMQMinaProtocolSession implements AMQProtocolSession, Managable -{ - private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - // to save boxing the channelId and looking up in a map... cache in an array the low numbered - // channels. This value must be of the form 2^x - 1. - private static final int CHANNEL_CACHE_SIZE = 0xff; - - private final IoSession _minaProtocolSession; - - private AMQShortString _contextKey; - - private AMQShortString _clientVersion = null; - - private VirtualHost _virtualHost; - - private final Map _channelMap = new HashMap(); - - private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; - - private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); - - private final AMQStateManager _stateManager; - - private AMQCodecFactory _codecFactory; - - private AMQProtocolSessionMBean _managedObject; - - private SaslServer _saslServer; - - private Object _lastReceived; - - private Object _lastSent; - - protected boolean _closed; - // maximum number of channels this session should have - private long _maxNoOfChannels = 1000; - - /* AMQP Version for this session */ - private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); - - private FieldTable _clientProperties; - private final List _taskList = new CopyOnWriteArrayList(); - - private List _closingChannelsList = new CopyOnWriteArrayList(); - private ProtocolOutputConverter _protocolOutputConverter; - private Principal _authorizedID; - private MethodDispatcher _dispatcher; - private ProtocolSessionIdentifier _sessionIdentifier; - - private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L; - private org.apache.mina.common.WriteFuture _lastWriteFuture; - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) - throws AMQException - { - _stateManager = new AMQStateManager(virtualHostRegistry, this); - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - try - { - IoServiceConfig config = session.getServiceConfig(); - ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); - threadModel.getAsynchronousReadFilter().createNewJobForSession(session); - threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); - } - catch (RuntimeException e) - { - e.printStackTrace(); - throw e; - - } - } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, - AMQStateManager stateManager) throws AMQException - { - _stateManager = stateManager; - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - } - - private AMQProtocolSessionMBean createMBean() throws AMQException - { - try - { - return new AMQProtocolSessionMBean(this); - } - catch (JMException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed ", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); - } - } - - public IoSession getIOSession() - { - return _minaProtocolSession; - } - - public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) - { - return (AMQProtocolSession) minaProtocolSession.getAttachment(); - } - - public void dataBlockReceived(AMQDataBlock message) throws Exception - { - _lastReceived = message; - if (message instanceof ProtocolInitiation) - { - protocolInitiationReceived((ProtocolInitiation) message); - - } - else if (message instanceof AMQFrame) - { - AMQFrame frame = (AMQFrame) message; - frameReceived(frame); - - } - else - { - throw new UnknnownMessageTypeException(message); - } - } - - private void frameReceived(AMQFrame frame) throws AMQException - { - int channelId = frame.getChannel(); - AMQBody body = frame.getBodyFrame(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Frame Received: " + frame); - } - - // Check that this channel is not closing - if (channelAwaitingClosure(channelId)) - { - if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); - } - } - else - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); - } - - closeProtocolSession(); - return; - } - } - - try - { - body.handle(channelId, this); - } - catch (AMQException e) - { - closeChannel(channelId); - throw e; - } - - } - - private void protocolInitiationReceived(ProtocolInitiation pi) - { - // this ensures the codec never checks for a PI message again - ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); - try - { - ProtocolVersion pv = pi.checkVersion(); // Fails if not correct - - // This sets the protocol version (and hence framing classes) for this session. - setProtocolVersion(pv); - - String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); - - String locales = "en_US"; - - AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), - (short) getProtocolMinorVersion(), - null, - mechanisms.getBytes(), - locales.getBytes()); - _minaProtocolSession.write(responseBody.generateFrame(0)); - - } - catch (AMQException e) - { - _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion()); - - _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - // TODO: Close connection (but how to wait until message is sent?) - // ritchiem 2006-12-04 will this not do? - // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); - // future.join(); - // close connection - - } - } - - public void methodFrameReceived(int channelId, AMQMethodBody methodBody) - { - - final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); - - try - { - try - { - - boolean wasAnyoneInterested = _stateManager.methodReceived(evt); - - if (!_frameListeners.isEmpty()) - { - for (AMQMethodListener listener : _frameListeners) - { - wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; - } - } - - if (!wasAnyoneInterested) - { - throw new AMQNoMethodHandlerException(evt); - } - } - catch (AMQChannelException e) - { - if (getChannel(channelId) != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing channel due to: " + e.getMessage()); - } - - writeFrame(e.getCloseFrame(channelId)); - closeChannel(channelId); - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - AMQConnectionException ce = - evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, - AMQConstant.CHANNEL_ERROR.getName().toString()); - - closeConnection(channelId, ce, false); - } - } - catch (AMQConnectionException e) - { - closeConnection(channelId, e, false); - } - } - catch (Exception e) - { - - for (AMQMethodListener listener : _frameListeners) - { - listener.error(e); - } - - _logger.error("Unexpected exception while processing frame. Closing connection.", e); - - closeProtocolSession(); - } - } - - public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException - { - - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentHeader(body); - - } - - public void contentBodyReceived(int channelId, ContentBody body) throws AMQException - { - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentBody(body); - } - - public void heartbeatBodyReceived(int channelId, HeartbeatBody body) - { - // NO - OP - } - - /** - * Convenience method that writes a frame to the protocol session. Equivalent to calling - * getProtocolSession().write(). - * - * @param frame the frame to write - */ - public void writeFrame(AMQDataBlock frame) - { - _lastSent = frame; - - _lastWriteFuture = _minaProtocolSession.write(frame); - } - - public AMQShortString getContextKey() - { - return _contextKey; - } - - public void setContextKey(AMQShortString contextKey) - { - _contextKey = contextKey; - } - - public List getChannels() - { - return new ArrayList(_channelMap.values()); - } - - public AMQChannel getAndAssertChannel(int channelId) throws AMQException - { - AMQChannel channel = getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); - } - - return channel; - } - - public AMQChannel getChannel(int channelId) throws AMQException - { - final AMQChannel channel = - ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); - if ((channel == null) || channel.isClosing()) - { - return null; - } - else - { - return channel; - } - } - - public boolean channelAwaitingClosure(int channelId) - { - return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId); - } - - public void addChannel(AMQChannel channel) throws AMQException - { - if (_closed) - { - throw new AMQException("Session is closed"); - } - - final int channelId = channel.getChannelId(); - - if (_closingChannelsList.contains(channelId)) - { - throw new AMQException("Session is marked awaiting channel close"); - } - - if (_channelMap.size() == _maxNoOfChannels) - { - String errorMessage = - toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels - + "); can't create channel"; - _logger.error(errorMessage); - throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); - } - else - { - _channelMap.put(channel.getChannelId(), channel); - } - - if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) - { - _cachedChannels[channelId] = channel; - } - - checkForNotification(); - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (channelsCount >= _maxNoOfChannels) - { - _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); - } - } - - public Long getMaximumNumberOfChannels() - { - return _maxNoOfChannels; - } - - public void setMaximumNumberOfChannels(Long value) - { - _maxNoOfChannels = value; - } - - public void commitTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.commit(); - } - } - - public void rollbackTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.rollback(); - } - } - - /** - * Close a specific channel. This will remove any resources used by the channel, including:

      • 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 = getChannel(channelId); - if (channel == null) - { - throw new IllegalArgumentException("Unknown channel id"); - } - else - { - try - { - channel.close(); - markChannelAwaitingCloseOk(channelId); - } - finally - { - removeChannel(channelId); - } - } - } - - public void closeChannelOk(int channelId) - { - // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler. - // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory. - // We do it from the Close Handler as we are sending the OK back to the client. - // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException - // will send a close-ok.. Where we should call removeChannel. - // However, due to the poor exception handling on the client. The client-user will be notified of the - // InvalidArgument and if they then decide to close the session/connection then the there will be time - // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. - //removeChannel(channelId); - _closingChannelsList.remove(new Integer(channelId)); - } - - private void markChannelAwaitingCloseOk(int channelId) - { - _closingChannelsList.add(channelId); - } - - /** - * In our current implementation this is used by the clustering code. - * - * @param channelId The channel to remove - */ - public void removeChannel(int channelId) - { - _channelMap.remove(channelId); - if ((channelId & CHANNEL_CACHE_SIZE) == channelId) - { - _cachedChannels[channelId] = null; - } - } - - /** - * Initialise heartbeats on the session. - * - * @param delay delay in seconds (not ms) - */ - public void initHeartbeats(int delay) - { - if (delay > 0) - { - _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); - _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, (int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay)); - } - } - - /** - * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. - * - * @throws AMQException if an error occurs while closing any channel - */ - private void closeAllChannels() throws AMQException - { - for (AMQChannel channel : _channelMap.values()) - { - channel.close(); - } - - _channelMap.clear(); - for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) - { - _cachedChannels[i] = null; - } - } - - /** This must be called when the session is _closed in order to free up any resources managed by the session. */ - public void closeSession() throws AMQException - { - if (!_closed) - { - _closed = true; - - if (_virtualHost != null) - { - _virtualHost.getConnectionRegistry().deregisterConnection(this); - } - - closeAllChannels(); - if (_managedObject != null) - { - _managedObject.unregister(); - } - - for (Task task : _taskList) - { - task.doTask(this); - } - } - } - - public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - markChannelAwaitingCloseOk(channelId); - closeSession(); - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(e.getCloseFrame(channelId)); - - if (closeProtocolSession) - { - closeProtocolSession(); - } - } - - public void closeProtocolSession() - { - closeProtocolSession(true); - } - - public void closeProtocolSession(boolean waitLast) - { - if (waitLast && (_lastWriteFuture != null)) - { - _logger.debug("Waiting for last write to join."); - _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); - } - - _logger.debug("REALLY Closing protocol session:" + _minaProtocolSession); - final CloseFuture future = _minaProtocolSession.close(); - future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); - - try - { - _stateManager.changeState(AMQState.CONNECTION_CLOSED); - } - catch (AMQException e) - { - _logger.info(e.getMessage()); - } - } - - public String toString() - { - return _minaProtocolSession.getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")"); - } - - public String dump() - { - return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; - } - - /** @return an object that can be used to identity */ - public Object getKey() - { - return _minaProtocolSession.getRemoteAddress(); - } - - /** - * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may - * be bound to multiple addresses this could vary depending on the acceptor this session was created from. - * - * @return a String FQDN - */ - public String getLocalFQDN() - { - SocketAddress address = _minaProtocolSession.getLocalAddress(); - // we use the vmpipe address in some tests hence the need for this rather ugly test. The host - // information is used by SASL primary. - if (address instanceof InetSocketAddress) - { - return ((InetSocketAddress) address).getHostName(); - } - else if (address instanceof VmPipeAddress) - { - return "vmpipe:" + ((VmPipeAddress) address).getPort(); - } - else - { - throw new IllegalArgumentException("Unsupported socket address class: " + address); - } - } - - public SaslServer getSaslServer() - { - return _saslServer; - } - - public void setSaslServer(SaslServer saslServer) - { - _saslServer = saslServer; - } - - public FieldTable getClientProperties() - { - return _clientProperties; - } - - public void setClientProperties(FieldTable clientProperties) - { - _clientProperties = clientProperties; - if (_clientProperties != null) - { - if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) - { - setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); - } - - if (_clientProperties.getString(ClientProperties.version.toString()) != null) - { - _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); - } - } - _sessionIdentifier = new ProtocolSessionIdentifier(this); - } - - private void setProtocolVersion(ProtocolVersion pv) - { - _protocolVersion = pv; - - _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); - _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion); - } - - public byte getProtocolMajorVersion() - { - return _protocolVersion.getMajorVersion(); - } - - public ProtocolVersion getProtocolVersion() - { - return _protocolVersion; - } - - public byte getProtocolMinorVersion() - { - return _protocolVersion.getMinorVersion(); - } - - public boolean isProtocolVersion(byte major, byte minor) - { - return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); - } - - public MethodRegistry getRegistry() - { - return getMethodRegistry(); - } - - public Object getClientIdentifier() - { - return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public void setVirtualHost(VirtualHost virtualHost) throws AMQException - { - _virtualHost = virtualHost; - - _virtualHost.getConnectionRegistry().registerConnection(this); - - _managedObject = createMBean(); - _managedObject.register(); - } - - public void addSessionCloseTask(Task task) - { - _taskList.add(task); - } - - public void removeSessionCloseTask(Task task) - { - _taskList.remove(task); - } - - public ProtocolOutputConverter getProtocolOutputConverter() - { - return _protocolOutputConverter; - } - - public void setAuthorizedID(Principal authorizedID) - { - _authorizedID = authorizedID; - } - - public Principal getAuthorizedID() - { - return _authorizedID; - } - - public MethodRegistry getMethodRegistry() - { - return MethodRegistry.getMethodRegistry(getProtocolVersion()); - } - - public MethodDispatcher getMethodDispatcher() - { - return _dispatcher; - } - - public ProtocolSessionIdentifier getSessionIdentifier() - { - return _sessionIdentifier; - } - - public String getClientVersion() - { - return (_clientVersion == null) ? null : _clientVersion.toString(); - } - - public void setSender(Sender sender) - { - // No-op, interface munging between this and AMQProtocolSession - } - - public void init() - { - // No-op, interface munging between this and AMQProtocolSession - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java deleted file mode 100644 index a7599a3e0d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to handle an AMQP method. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a - * Runtime. - */ -public class AMQNoMethodHandlerException extends AMQException -{ - public AMQNoMethodHandlerException(AMQMethodEvent evt) - { - super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java deleted file mode 100644 index 0dbefd8798..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoFilterChain; -import org.apache.mina.common.IoHandlerAdapter; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.ReadThrottleFilterBuilder; -import org.apache.mina.filter.SSLFilter; -import org.apache.mina.filter.WriteBufferLimitFilterBuilder; -import org.apache.mina.filter.codec.QpidProtocolCodecFilter; -import org.apache.mina.filter.executor.ExecutorFilter; -import org.apache.mina.util.SessionUtil; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQProtocolHeaderException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.ssl.SSLContextFactory; - -/** - * The protocol handler handles "protocol events" for all connections. The state - * associated with an individual connection is accessed through the protocol session. - * - * We delegate all frame (message) processing to the AMQProtocolSession which wraps - * the state for the connection. - */ -public class AMQPFastProtocolHandler extends IoHandlerAdapter -{ - private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); - - private final IApplicationRegistry _applicationRegistry; - - private final int BUFFER_READ_LIMIT_SIZE; - private final int BUFFER_WRITE_LIMIT_SIZE; - - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) - { - this(ApplicationRegistry.getInstance(applicationRegistryInstance)); - } - - public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) - { - _applicationRegistry = applicationRegistry; - - // Read the configuration from the application registry - BUFFER_READ_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferReadLimit(); - BUFFER_WRITE_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferWriteLimit(); - - _logger.debug("AMQPFastProtocolHandler created"); - } - - protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) - { - this(handler._applicationRegistry); - } - - public void sessionCreated(IoSession protocolSession) throws Exception - { - SessionUtil.initialize(protocolSession); - final AMQCodecFactory codecFactory = new AMQCodecFactory(true); - - createSession(protocolSession, _applicationRegistry, codecFactory); - _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); - - final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory); - final ServerConfiguration config = _applicationRegistry.getConfiguration(); - - String keystorePath = config.getKeystorePath(); - String keystorePassword = config.getKeystorePassword(); - String certType = config.getCertType(); - SSLContextFactory sslContextFactory = null; - boolean isSsl = false; - if (config.getEnableSSL() && isSSLClient(config, protocolSession)) - { - sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); - isSsl = true; - } - if (config.getEnableExecutorPool()) - { - if (isSsl) - { - protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); - } - else - { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); - if (isSsl) - { - protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - } - - if (ApplicationRegistry.getInstance().getConfiguration().getProtectIOEnabled()) - { - try - { -// //Add IO Protection Filters - IoFilterChain chain = protocolSession.getFilterChain(); - - - protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter()); - - ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); - readfilter.setMaximumConnectionBufferSize(BUFFER_READ_LIMIT_SIZE); - readfilter.attach(chain); - - WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); - writefilter.setMaximumConnectionBufferSize(BUFFER_WRITE_LIMIT_SIZE); - writefilter.attach(chain); - - protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder"); - _logger.info("Using IO Read/Write Filter Protection"); - } - catch (Exception e) - { - _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage()); - } - } - } - - /** Separated into its own, protected, method to allow easier reuse */ - protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException - { - new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); - } - - public void sessionOpened(IoSession protocolSession) throws Exception - { - _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); - } - - public void sessionClosed(IoSession protocolSession) throws Exception - { - _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - //fixme -- this can be null - if (amqProtocolSession != null) - { - try - { - amqProtocolSession.closeSession(); - } - catch (AMQException e) - { - _logger.error("Caught AMQException whilst closingSession:" + e); - } - } - } - - public void sessionIdle(IoSession session, IdleStatus status) throws Exception - { - _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); - if (IdleStatus.WRITER_IDLE.equals(status)) - { - //write heartbeat frame: - session.write(HeartbeatBody.FRAME); - } - else if (IdleStatus.READER_IDLE.equals(status)) - { - //failover: - throw new IOException("Timed out while waiting for heartbeat from peer."); - } - - } - - public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception - { - AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - if (throwable instanceof AMQProtocolHeaderException) - { - - protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - protocolSession.close(); - - _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); - } - else if (throwable instanceof IOException) - { - _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable); - } - else - { - _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); - - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(session.getProtocolVersion()); - ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); - - protocolSession.write(closeBody.generateFrame(0)); - - protocolSession.close(); - } - } - - /** - * Invoked when a message is received on a particular protocol session. Note that a - * protocol session is directly tied to a particular physical connection. - * - * @param protocolSession the protocol session that received the message - * @param message the message itself (i.e. a decoded frame) - * - * @throws Exception if the message cannot be processed - */ - public void messageReceived(IoSession protocolSession, Object message) throws Exception - { - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - - if (message instanceof AMQDataBlock) - { - amqProtocolSession.dataBlockReceived((AMQDataBlock) message); - - } - else if (message instanceof ByteBuffer) - { - throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); - } - else - { - throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); - } - } - - /** - * Called after a message has been sent out on a particular protocol session - * - * @param protocolSession the protocol session (i.e. connection) on which this - * message was sent - * @param object the message (frame) that was encoded and sent - * - * @throws Exception if we want to indicate an error - */ - public void messageSent(IoSession protocolSession, Object object) throws Exception - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Message sent: " + object); - } - } - - protected boolean isSSLClient(ServerConfiguration connectionConfig, - IoSession protocolSession) - { - InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); - return addr.getPort() == connectionConfig.getSSLPort(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java deleted file mode 100644 index 07c153bfe8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; - -/** - * The protocol provide's role is to encapsulate the initialisation of the protocol handler. - * - * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events - * such as connection closing or a frame being received. It can either do this directly - * or pass off to the protocol session in the cases where state information is required to - * deal with the event. - * - */ -public class AMQPProtocolProvider -{ - /** - * Handler for protocol events - */ - private AMQPFastProtocolHandler _handler; - - public AMQPProtocolProvider() - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - _handler = new AMQPFastProtocolHandler(registry); - } - - public AMQPFastProtocolHandler getHandler() - { - return _handler; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java deleted file mode 100644 index 1bac601225..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import javax.security.sasl.SaslServer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.security.Principal; - - -public interface AMQProtocolSession extends AMQVersionAwareProtocolSession -{ - - public static final class ProtocolSessionIdentifier - { - private final Object _sessionIdentifier; - private final Object _sessionInstance; - - ProtocolSessionIdentifier(AMQProtocolSession session) - { - _sessionIdentifier = session.getClientIdentifier(); - _sessionInstance = session.getClientProperties() == null ? null : session.getClientProperties().getObject(ClientProperties.instance.toAMQShortString()); - } - - public Object getSessionIdentifier() - { - return _sessionIdentifier; - } - - public Object getSessionInstance() - { - return _sessionInstance; - } - } - - public static interface Task - { - public void doTask(AMQProtocolSession session) throws AMQException; - } - - /** - * 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; - - /** - * Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC - * 6). - * - * @return the context key - */ - AMQShortString 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(AMQShortString 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) throws AMQException; - - /** - * 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; - - /** - * Markes the specific channel as closed. This will release the lock for that channel id so a new channel can be - * created on that id. - * - * @param channelId id of the channel to close - */ - void closeChannelOk(int channelId); - - /** - * Check to see if this chanel is closing - * - * @param channelId id to check - * @return boolean with state of channel awaiting closure - */ - boolean channelAwaitingClosure(int channelId); - - /** - * 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; - - /** This must be called to close the session in order to free up any resources managed by the session. */ - void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) 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); - - - FieldTable getClientProperties(); - - void setClientProperties(FieldTable clientProperties); - - Object getClientIdentifier(); - - VirtualHost getVirtualHost(); - - void setVirtualHost(VirtualHost virtualHost) throws AMQException; - - void addSessionCloseTask(Task task); - - void removeSessionCloseTask(Task task); - - public ProtocolOutputConverter getProtocolOutputConverter(); - - void setAuthorizedID(Principal authorizedID); - - /** @return a Principal that was used to authorized this session */ - Principal getAuthorizedID(); - - public MethodRegistry getMethodRegistry(); - - public MethodDispatcher getMethodDispatcher(); - - public ProtocolSessionIdentifier getSessionIdentifier(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java deleted file mode 100644 index 5dd3cc075a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; -import java.util.List; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; - -/** - * This MBean class implements the management interface. 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") -public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection -{ - private AMQMinaProtocolSession _session = null; - private String _name = null; - - // openmbean data types for representing the channel attributes - private static final String[] _channelAtttibuteNames = - { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; - private static final String[] _indexNames = { _channelAtttibuteNames[0] }; - private static final OpenType[] _channelAttributeTypes = - { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; - private static CompositeType _channelType = null; // represents the data type for channel data - private static TabularType _channelsType = null; // Data type for list of channels type - private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = - new AMQShortString("Broker Management Console has closed the connection."); - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException - { - super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); - _session = session; - String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); - init(); - } - - static - { - try - { - init(); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - /** - * initialises the openmbean data types - */ - private static void init() throws OpenDataException - { - _channelType = - new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, - _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); - } - - public String getClientId() - { - return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); - } - - public String getAuthorizedId() - { - return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; - } - - public String getVersion() - { - return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); - } - - public Date getLastIoTime() - { - return new Date(_session.getIOSession().getLastIoTime()); - } - - public String getRemoteAddress() - { - return _session.getIOSession().getRemoteAddress().toString(); - } - - public ManagedObject getParentObject() - { - return _session.getVirtualHost().getManagedObject(); - } - - public Long getWrittenBytes() - { - return _session.getIOSession().getWrittenBytes(); - } - - public Long getReadBytes() - { - return _session.getIOSession().getReadBytes(); - } - - public Long getMaximumNumberOfChannels() - { - return _session.getMaximumNumberOfChannels(); - } - - public void setMaximumNumberOfChannels(Long value) - { - _session.setMaximumNumberOfChannels(value); - } - - public String getObjectInstanceName() - { - return _name; - } - - /** - * commits transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if commit fails - */ - public void commitTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _session.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _session.commitTransactions(channel); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * rollsback the transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if rollback fails - */ - public void rollbackTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _session.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _session.rollbackTransactions(channel); - } - 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 channels() throws OpenDataException - { - TabularDataSupport channelsList = new TabularDataSupport(_channelsType); - List list = _session.getChannels(); - - for (AMQChannel channel : list) - { - Object[] itemValues = - { - channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, - channel.getUnacknowledgedMessageMap().size() - }; - - CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); - channelsList.put(channelData); - } - - return channelsList; - } - - /** - * closes the connection. The administrator can use this management operation to close connection to free up - * resources. - * @throws JMException - */ - public void closeConnection() throws JMException - { - - MethodRegistry methodRegistry = _session.getMethodRegistry(); - ConnectionCloseBody responseBody = - methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), - // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION, - // replyText, - 0, - 0); - - _session.writeFrame(responseBody.generateFrame(0)); - - try - { - _session.closeSession(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Channel count has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } - - public void notifyClients(String notificationMsg) - { - Notification n = - new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, - System.currentTimeMillis(), notificationMsg); - _broadcaster.sendNotification(n); - } - -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java deleted file mode 100644 index 2abcecb6de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeType; - -public class ExchangeInitialiser -{ - public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ - for (ExchangeType type : factory.getRegisteredTypes()) - { - define (registry, factory, type.getDefaultExchangeName(), type.getName()); - } - - define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); - registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); - } - - private void define(ExchangeRegistry r, ExchangeFactory f, - AMQShortString name, AMQShortString type) throws AMQException - { - if(r.getExchange(name)== null) - { - r.registerExchange(f.createExchange(name, type, true, false, 0)); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java deleted file mode 100644 index e75b09a0cb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.util.Date; -import java.security.Principal; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of Connections. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedConnection -{ - static final String TYPE = "Connection"; - static final int VERSION = 1; - - @MBeanAttribute(name = "ClientId", description = "Client Id") - String getClientId(); - - @MBeanAttribute(name = "AuthorizedId", description = "User Name") - String getAuthorizedId(); - - @MBeanAttribute(name = "Version", description = "Client Version") - String getVersion(); - - /** - * Tells the remote address of this connection. - * @return remote address - */ - @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") - String getRemoteAddress(); - - /** - * Tells the last time, the IO operation was done. - * @return last IO time. - */ - @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done") - Date getLastIoTime(); - - /** - * Tells the total number of bytes written till now. - * @return number of bytes written. - * - @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") - Long getWrittenBytes(); - */ - /** - * Tells the total number of bytes read till now. - * @return number of bytes read. - * - @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") - Long getReadBytes(); - */ - - /** - * Threshold high value for no of channels. This is useful in setting notifications or - * taking required action is there are more channels being created. - * @return threshold limit for no of channels - */ - Long getMaximumNumberOfChannels(); - - /** - * Sets the threshold high value for number of channels for a connection - * @param value - */ - @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") - void setMaximumNumberOfChannels(Long value); - - //********** Operations *****************// - - /** - * channel details of all the channels opened for this connection. - * @return general channel details - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="channels", description="Channel details for this connection") - TabularData channels() throws IOException, JMException; - - /** - * Commits the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="commitTransaction", - description="Commits the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Rollsback the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="rollbackTransactions", - description="Rollsback the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Closes all the related channels and unregisters this connection from managed objects. - */ - @MBeanOperation(name="closeConnection", - description="Closes this connection and all related channels", - impact= MBeanOperationInfo.ACTION) - void closeConnection() throws Exception; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java deleted file mode 100644 index 6e72aa062f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; - -/** - * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to cast a frame to its expected type. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would - * be better just to leave that as a ClassCastException. However, check the framing layer catches this error - * first. - */ -public class UnknnownMessageTypeException extends AMQException -{ - public UnknnownMessageTypeException(AMQDataBlock message) - { - super("Unknown message type: " + message.getClass().getName() + ": " + message); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java deleted file mode 100644 index 8dac12fe24..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.AMQDataBlock; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.AMQException; - -import java.util.Iterator; - -public interface AMQMessage -{ - //Get Content relating to this message - - Long getMessageId(); - - Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel); - - Iterator getContentBodyIterator(); - - ContentHeaderBody getContentHeaderBody(); - - ContentChunk getContentChunk(int index); - - Object getPublisherClientInstance(); - - Object getPublisherIdentifier(); - - MessagePublishInfo getMessagePublishInfo(); - - int getBodyCount(); - - long getSize(); - - long getArrivalTime(); - - - - //Check the status of this message - - /** Is this a persistent message - * - * @return true if the message is persistent - */ - boolean isPersistent(); - - - boolean isImmediate(); - - - void setClientIdentifier(AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier); - - /** - * This is called when all the content has been received. - * @param storeContext - *@param messagePublishInfo - * @param contentHeaderBody @throws org.apache.qpid.AMQException - */ - void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, ContentHeaderBody contentHeaderBody) - throws AMQException; - - void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) - throws AMQException; - - void recoverFromMessageMetaData(MessageMetaData mmd); - - void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException; - - - String toString(); - - String debugIdentity(); - - void setExpiration(long expiration); - - long getExpiration(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java deleted file mode 100644 index 00dec57ed5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ /dev/null @@ -1,77 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.subscription.SubscriptionList; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.AMQException; - -public class AMQPriorityQueue extends SimpleAMQQueue -{ - protected AMQPriorityQueue(final AMQShortString name, - final boolean durable, - final AMQShortString owner, - final boolean autoDelete, - final VirtualHost virtualHost, - int priorities) - throws AMQException - { - super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueEntryList.Factory(priorities)); - } - - public int getPriorities() - { - return ((PriorityQueueEntryList) _entries).getPriorities(); - } - - @Override - protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) - { - // check that all subscriptions are not in advance of the entry - SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator(); - while(subIter.advance() && !entry.isAcquired()) - { - final Subscription subscription = subIter.getNode().getSubscription(); - QueueEntry subnode = subscription.getLastSeenEntry(); - while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()) - { - if(subscription.setLastSeenEntry(subnode,entry)) - { - break; - } - else - { - subnode = subscription.getLastSeenEntry(); - } - } - - } - } - - @Override - public String getType() - { - return getClass().getSimpleName() + "[" + getName() + "][Priorities:" + getPriorities() + "]"; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java deleted file mode 100644 index fae219e320..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; - -import java.util.List; -import java.util.Set; - -public interface AMQQueue extends Managable, Comparable -{ - - AMQShortString getName(); - - boolean isDurable(); - - boolean isAutoDelete(); - - AMQShortString getOwner(); - - VirtualHost getVirtualHost(); - - - void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - List getExchangeBindings(); - - - void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; - - void unregisterSubscription(final Subscription subscription) throws AMQException; - - - int getConsumerCount(); - - int getActiveConsumerCount(); - - boolean isUnused(); - - boolean isEmpty(); - - boolean isFlowed(); - - int getMessageCount(); - - int getUndeliveredMessageCount(); - - - long getQueueDepth(); - - long getReceivedMessageCount(); - - long getOldestMessageArrivalTime(); - - boolean isDeleted(); - - int delete() throws AMQException; - - QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; - - void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; - - void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; - - boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - - void addQueueDeleteTask(final Task task); - - List getMessagesOnTheQueue(); - - List getMessagesOnTheQueue(long fromMessageId, long toMessageId); - - List getMessagesOnTheQueue(int num); - - List getMessagesOnTheQueue(int num, int offest); - - QueueEntry getMessageOnTheQueue(long messageId); - - - void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext); - - void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext); - - void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); - - long getMemoryUsageMaximum(); - - void setMemoryUsageMaximum(long maximumMemoryUsage); - - long getMemoryUsageMinimum(); - - void setMemoryUsageMinimum(long minimumMemoryUsage); - - long getMemoryUsageCurrent(); - - long getMaximumMessageSize(); - - void setMaximumMessageSize(long value); - - - long getMaximumMessageCount(); - - void setMaximumMessageCount(long value); - - - long getMaximumQueueDepth(); - - void setMaximumQueueDepth(long value); - - - long getMaximumMessageAge(); - - void setMaximumMessageAge(final long maximumMessageAge); - - - long getMinimumAlertRepeatGap(); - - void setMinimumAlertRepeatGap(long value); - - - void deleteMessageFromTop(StoreContext storeContext) throws AMQException; - - long clearQueue(StoreContext storeContext) throws AMQException; - - /** - * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. - * @throws AMQException - */ - void checkMessageStatus() throws AMQException; - - Set getNotificationChecks(); - - void flushSubscription(final Subscription sub) throws AMQException; - - void deliverAsync(final Subscription sub); - - void deliverAsync(); - - void stop(); - - /** - * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create a subscription, because an exclusive subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - static final class ExistingExclusiveSubscription extends AMQException - { - - public ExistingExclusiveSubscription() - { - super(""); - } - } - - /** - * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription - * already exists. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to create an exclusize subscription, as a subscription already exists. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Move to top level, used outside this class. - */ - static final class ExistingSubscriptionPreventsExclusive extends AMQException - { - public ExistingSubscriptionPreventsExclusive() - { - super(""); - } - } - - static interface Task - { - public void doTask(AMQQueue queue) throws AMQException; - } - - void configure(QueueConfiguration config); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java deleted file mode 100644 index b77a9d8f6a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class AMQQueueFactory -{ - public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); - public static final AMQShortString QPID_MAX_COUNT = new AMQShortString("qpid.max_count"); - public static final AMQShortString QPID_MAX_SIZE = new AMQShortString("qpid.max_size"); - public static final AMQShortString QPID_POLICY_TYPE = new AMQShortString("qpid.policy_type"); - public static final String QPID_FLOW_TO_DISK = "flow_to_disk"; - - public static AMQQueue createAMQQueueImpl(AMQShortString name, - boolean durable, - AMQShortString owner, - boolean autoDelete, - VirtualHost virtualHost, final FieldTable arguments) - throws AMQException - { - - int priorities = 1; - - if (arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) - { - Integer priority = arguments.getInteger(X_QPID_PRIORITIES); - - if (priority != null) - { - priorities = priority.intValue(); - } - else - { - throw new AMQException(AMQConstant.INVALID_ARGUMENT, - "Queue create request with non integer value for :" + X_QPID_PRIORITIES + "=" + arguments.get(X_QPID_PRIORITIES), null); - } - - } - - AMQQueue q = null; - if (priorities > 1) - { - q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); - } - else - { - q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); - } - - final String queuePolicyType = arguments == null ? null : - arguments.containsKey(QPID_POLICY_TYPE) ? arguments.getString(QPID_POLICY_TYPE) : null; - - if (queuePolicyType != null) - { - if (queuePolicyType.equals(QPID_FLOW_TO_DISK)) - { - if (arguments.containsKey(QPID_MAX_SIZE)) - { - - final long queueSize = arguments.getInteger(QPID_MAX_SIZE); - - if (queueSize < 0) - { - throw new AMQException(AMQConstant.INVALID_ARGUMENT, - "Queue create request with negative size:" + queueSize, null); - } - - q.setMemoryUsageMaximum(queueSize); - } - else - { - throw new AMQException(AMQConstant.INVALID_ARGUMENT, - "Queue create request with no qpid.max_size value,", null); - } - } - else - { - throw new AMQException(AMQConstant.NOT_IMPLEMENTED, - "Queue create request with unknown Policy Type:" + queuePolicyType, null); - } - - } - - //Register the new queue - virtualHost.getQueueRegistry().registerQueue(q); - return q; - } - - public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException - { - AMQShortString queueName = new AMQShortString(config.getName()); - - boolean durable = config.getDurable(); - boolean autodelete = config.getAutoDelete(); - AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null; - FieldTable arguments = null; - boolean priority = config.getPriority(); - int priorities = config.getPriorities(); - if (priority || priorities > 0) - { - if (arguments == null) - { - arguments = new FieldTable(); - } - if (priorities < 0) - { - priorities = 10; - } - arguments.put(new AMQShortString("x-qpid-priorities"), priorities); - } - - AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); - q.configure(config); - return q; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java deleted file mode 100644 index b46d6b6f12..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ /dev/null @@ -1,494 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; - -import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.OperationsException; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * AMQQueueMBean is the management bean for an {@link AMQQueue}. - * - *

      CRC Caption - * Responsibilities Collaborations - * - */ -@MBeanDescription("Management Interface for AMQQueue") -public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener -{ - /** Used for debugging purposes. */ - private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); - - private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); - - /** - * Since the MBean is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - private StoreContext _storeContext = new StoreContext(); - - private AMQQueue _queue = null; - private String _queueName = null; - // OpenMBean data types for viewMessages method - private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; - private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; - private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - // OpenMBean data types for viewMessageContent method - private static CompositeType _msgContentType = null; - private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; - private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; - private Notification _lastNotification = null; - - - - - @MBeanConstructor("Creates an MBean exposing an AMQQueue") - public AMQQueueMBean(AMQQueue queue) throws JMException - { - super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); - _queue = queue; - _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); - } - - public ManagedObject getParentObject() - { - return _queue.getVirtualHost().getManagedObject(); - } - - static - { - try - { - init(); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - /** - * initialises the openmbean data types - */ - private static void init() throws OpenDataException - { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = - new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, - _msgContentAttributeTypes); - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = - new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); - } - - public String getObjectInstanceName() - { - return _queueName; - } - - public String getName() - { - return _queueName; - } - - public boolean isDurable() - { - return _queue.isDurable(); - } - - public String getOwner() - { - return String.valueOf(_queue.getOwner()); - } - - public boolean isAutoDelete() - { - return _queue.isAutoDelete(); - } - - public Integer getMessageCount() - { - return _queue.getMessageCount(); - } - - public Long getMaximumMessageSize() - { - return _queue.getMaximumMessageSize(); - } - - public Long getMaximumMessageAge() - { - return _queue.getMaximumMessageAge(); - } - - public void setMaximumMessageAge(Long maximumMessageAge) - { - _queue.setMaximumMessageAge(maximumMessageAge); - } - - public void setMaximumMessageSize(Long value) - { - _queue.setMaximumMessageSize(value); - } - - public Integer getConsumerCount() - { - return _queue.getConsumerCount(); - } - - public Integer getActiveConsumerCount() - { - return _queue.getActiveConsumerCount(); - } - - public Long getReceivedMessageCount() - { - return _queue.getReceivedMessageCount(); - } - - public Long getMaximumMessageCount() - { - return _queue.getMaximumMessageCount(); - } - - public void setMaximumMessageCount(Long value) - { - _queue.setMaximumMessageCount(value); - } - - /** - * returns the maximum total size of messages(bytes) in the queue. - */ - public Long getMaximumQueueDepth() - { - return _queue.getMaximumQueueDepth(); - } - - public void setMaximumQueueDepth(Long value) - { - _queue.setMaximumQueueDepth(value); - } - - public Long getMemoryUsageMaximum() - { - return _queue.getMemoryUsageMaximum(); - } - - public void setMemoryUsageMaximum(Long maximumMemoryUsage) - { - _queue.setMemoryUsageMaximum(maximumMemoryUsage); - } - - public Long getMemoryUsageMinimum() - { - return _queue.getMemoryUsageMinimum(); - } - - public void setMemoryUsageMinimum(Long minimumMemoryUsage) - { - _queue.setMemoryUsageMinimum(minimumMemoryUsage); - } - - public Long getMemoryUsageCurrent() - { - return _queue.getMemoryUsageCurrent(); - } - - public boolean isFlowed() - { - return _queue.isFlowed(); - } - - /** - * returns the total size of messages(bytes) in the queue. - */ - public Long getQueueDepth() throws JMException - { - return _queue.getQueueDepth(); - } - - /** - * Checks if there is any notification to be send to the listeners - * @param queueEntry - */ - public void checkForNotification(QueueEntry queueEntry) throws AMQException - { - - final Set notificationChecks = _queue.getNotificationChecks(); - - if(!notificationChecks.isEmpty()) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - - for (NotificationCheck check : notificationChecks) - { - if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) - { - if (check.notifyIfNecessary(queueEntry, _queue, this)) - { - _lastNotificationTimes[check.ordinal()] = currentTime; - } - } - } - } - - } - - /** - * Sends the notification to the listeners - */ - public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) - { - // important : add log to the log file - monitoring tools may be looking for this - _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); - notificationMsg = notification.name() + " " + notificationMsg; - - _lastNotification = - new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, - System.currentTimeMillis(), notificationMsg); - - _broadcaster.sendNotification(_lastNotification); - } - - public Notification getLastNotification() - { - return _lastNotification; - } - - /** - * @see AMQQueue#deleteMessageFromTop - */ - public void deleteMessageFromTop() throws JMException - { - try - { - _queue.deleteMessageFromTop(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * @see AMQQueue#clearQueue - */ - public void clearQueue() throws JMException - { - try - { - _queue.clearQueue(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * returns message content as byte array and related attributes for the given message id. - */ - public CompositeData viewMessageContent(long msgId) throws JMException - { - QueueEntry entry = _queue.getMessageOnTheQueue(msgId); - - if (entry == null) - { - throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); - } - - AMQMessage msg = entry.getMessage(); - // get message content - Iterator cBodies = msg.getContentBodyIterator(); - List msgContent = new ArrayList(); - while (cBodies.hasNext()) - { - ContentChunk body = cBodies.next(); - if (body.getSize() != 0) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.getData().slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - } - - // Create header attributes list - CommonContentHeaderProperties headerProperties = - (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) - { - AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); - encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); - } - - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - - /** - * Returns the header contents of the messages stored in this queue in tabular form. - */ - public TabularData viewMessages(int beginIndex, int endIndex) throws JMException - { - if ((beginIndex > endIndex) || (beginIndex < 1)) - { - throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex - + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); - } - - List list = _queue.getMessagesOnTheQueue(); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - // Create the tabular list of message header contents - for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) - { - QueueEntry queueEntry = list.get(i - 1); - AMQMessage msg = queueEntry.getMessage(); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, - queueEntry.isRedelivered() }; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); - _messageList.put(messageData); - } - - return _messageList; - } - - private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) - { - List list = new ArrayList(); - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; - list.add("reply-to = " + headerProperties.getReplyToAsString()); - list.add("propertyFlags = " + headerProperties.getPropertyFlags()); - list.add("ApplicationID = " + headerProperties.getAppIdAsString()); - list.add("ClusterID = " + headerProperties.getClusterIdAsString()); - list.add("UserId = " + headerProperties.getUserIdAsString()); - list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); - list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); - - int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + - ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); - - list.add("JMSPriority = " + headerProperties.getPriority()); - list.add("JMSType = " + headerProperties.getType()); - - long longDate = headerProperties.getExpiration(); - String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; - list.add("JMSExpiration = " + strDate); - - longDate = headerProperties.getTimestamp(); - strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; - list.add("JMSTimestamp = " + strDate); - - return list.toArray(new String[list.size()]); - } - - /** - * @see ManagedQueue#moveMessages - * @param fromMessageId - * @param toMessageId - * @param toQueueName - * @throws JMException - */ - public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException - { - if ((fromMessageId > toMessageId) || (fromMessageId < 1)) - { - throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); - } - - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); - } - - /** - * returns Notifications sent by this MBean. - */ - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Either Message count or Queue depth or Message size has reached threshold high value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } - -} // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java deleted file mode 100644 index cbe9246f09..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class DefaultQueueRegistry implements QueueRegistry -{ - private ConcurrentMap _queueMap = new ConcurrentHashMap(); - - private final VirtualHost _virtualHost; - - public DefaultQueueRegistry(VirtualHost virtualHost) - { - _virtualHost = virtualHost; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public void registerQueue(AMQQueue queue) throws AMQException - { - _queueMap.put(queue.getName(), queue); - } - - public void unregisterQueue(AMQShortString name) throws AMQException - { - _queueMap.remove(name); - } - - public AMQQueue getQueue(AMQShortString name) - { - return _queueMap.get(name); - } - - public Collection getQueueNames() - { - return _queueMap.keySet(); - } - - public Collection getQueues() - { - return _queueMap.values(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java deleted file mode 100644 index a2fcab9e73..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; - -public class ExchangeBinding -{ - private final Exchange _exchange; - private final AMQShortString _routingKey; - private final FieldTable _arguments; - - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); - - ExchangeBinding(AMQShortString routingKey, Exchange exchange) - { - this(routingKey, exchange, EMPTY_ARGUMENTS); - } - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) - { - _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; - _exchange = exchange; - _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; - } - - void unbind(AMQQueue queue) throws AMQException - { - _exchange.deregisterQueue(_routingKey, queue, _arguments); - } - - public Exchange getExchange() - { - return _exchange; - } - - public AMQShortString getRoutingKey() - { - return _routingKey; - } - - public FieldTable getArguments() - { - return _arguments; - } - - public int hashCode() - { - return (_exchange == null ? 0 : _exchange.hashCode()) - + (_routingKey == null ? 0 : _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); - } -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java deleted file mode 100644 index fb839c1783..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; - -/** - * 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 -{ - 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(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); - } - - - public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); - } - - - /** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java deleted file mode 100644 index 6466e81dd2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * Signals that the dequeue of a message from a queue failed. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Indicates the a message could not be dequeued from a queue. - *
      - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Happens as a consequence of a message store failure, or reference counting error. Both of which migh become - * runtime exceptions, as unrecoverable conditions? In which case this one might be dropped too. - */ -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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java deleted file mode 100644 index b9d07d032b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStore.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.util.FileUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -public class FileQueueBackingStore implements QueueBackingStore -{ - private static final Logger _log = Logger.getLogger(FileQueueBackingStore.class); - - private String _flowToDiskLocation; - - public FileQueueBackingStore(String location) - { - _flowToDiskLocation = location; - } - - public AMQMessage load(Long messageId) - { - _log.info("Loading Message (ID:" + messageId + ")"); - - MessageMetaData mmd; - - File handle = getFileHandle(messageId); - - ObjectInputStream input = null; - - Exception error = null; - try - { - input = new ObjectInputStream(new FileInputStream(handle)); - - long arrivaltime = input.readLong(); - - final AMQShortString exchange = new AMQShortString(input.readUTF()); - final AMQShortString routingKey = new AMQShortString(input.readUTF()); - final boolean mandatory = input.readBoolean(); - final boolean immediate = input.readBoolean(); - - int bodySize = input.readInt(); - byte[] underlying = new byte[bodySize]; - - input.readFully(underlying, 0, bodySize); - - ByteBuffer buf = ByteBuffer.wrap(underlying); - - ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, bodySize); - - int chunkCount = input.readInt(); - - // There are WAY to many annonymous MPIs in the code this should be made concrete. - MessagePublishInfo info = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return exchange; - } - - public void setExchange(AMQShortString exchange) - { - - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return mandatory; - } - - public AMQShortString getRoutingKey() - { - return routingKey; - } - }; - - mmd = new MessageMetaData(info, chb, chunkCount); - mmd.setArrivalTime(arrivaltime); - - AMQMessage message; - if (((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == - BasicContentHeaderProperties.PERSISTENT) - { - message = new PersistentAMQMessage(messageId, null); - } - else - { - message = new TransientAMQMessage(messageId); - } - - message.recoverFromMessageMetaData(mmd); - - for (int chunk = 0; chunk < chunkCount; chunk++) - { - int length = input.readInt(); - - byte[] data = new byte[length]; - - input.readFully(data, 0, length); - - try - { - message.recoverContentBodyFrame(new RecoverDataBuffer(length, data), (chunk + 1 == chunkCount)); - } - catch (AMQException e) - { - //ignore as this will not occur. - // It is thrown by the _transactionLog method in load on PersistentAMQMessage - // but we have created the message with a null log and will never call that method. - } - } - - return message; - } - catch (Exception e) - { - error = e; - } - finally - { - try - { - if (input != null) - { - input.close(); - } - } - catch (IOException e) - { - _log.info("Unable to close input on message(" + messageId + ") recovery due to:" + e.getMessage()); - } - } - - throw new UnableToRecoverMessageException(error); - } - - /** - * Thread safety is ensured here by synchronizing on the message object. - * - * This is safe as load() calls will fail until the first thread through here has created the file on disk - * and fully written the content. - * - * After this point new AMQMessages can exist that reference the same data thus breaking the synchronisation. - * - * Thread safety is maintained here as the existence of the file is checked allowing then subsequent unload() calls - * to skip the writing. - * - * Multiple unload() calls will initially be blocked using the synchronization until the data exists on disk thus - * safely allowing any reference to the message to be cleared prompting a load call. - * - * @param message the message to unload - * @throws UnableToFlowMessageException - */ - public void unload(AMQMessage message) throws UnableToFlowMessageException - { - //Synchorize on the message to ensure that one only thread can unload at a time. - // If a second unload is attempted then it will block until the unload has completed. - synchronized (message) - { - long messageId = message.getMessageId(); - - File handle = getFileHandle(messageId); - - //If we have written the data once then we don't need to do it again. - if (handle.exists()) - { - if (_log.isDebugEnabled()) - { - _log.debug("Message(ID:" + messageId + ") already unloaded."); - } - return; - } - - if (_log.isInfoEnabled()) - { - _log.info("Unloading Message (ID:" + messageId + ")"); - } - - ObjectOutputStream writer = null; - Exception error = null; - - try - { - writer = new ObjectOutputStream(new FileOutputStream(handle)); - - writer.writeLong(message.getArrivalTime()); - - MessagePublishInfo mpi = message.getMessagePublishInfo(); - writer.writeUTF(String.valueOf(mpi.getExchange())); - writer.writeUTF(String.valueOf(mpi.getRoutingKey())); - writer.writeBoolean(mpi.isMandatory()); - writer.writeBoolean(mpi.isImmediate()); - ContentHeaderBody chb = message.getContentHeaderBody(); - - // write out the content header body - final int bodySize = chb.getSize(); - byte[] underlying = new byte[bodySize]; - ByteBuffer buf = ByteBuffer.wrap(underlying); - chb.writePayload(buf); - - writer.writeInt(bodySize); - writer.write(underlying, 0, bodySize); - - int bodyCount = message.getBodyCount(); - writer.writeInt(bodyCount); - - //WriteContentBody - for (int index = 0; index < bodyCount; index++) - { - ContentChunk chunk = message.getContentChunk(index); - int length = chunk.getSize(); - - byte[] chunk_underlying = new byte[length]; - - ByteBuffer chunk_buf = chunk.getData(); - - chunk_buf.duplicate().rewind().get(chunk_underlying); - - writer.writeInt(length); - writer.write(chunk_underlying, 0, length); - } - } - catch (FileNotFoundException e) - { - error = e; - } - catch (IOException e) - { - error = e; - } - finally - { - // In a FileNotFound situation writer will be null. - if (writer != null) - { - try - { - writer.flush(); - writer.close(); - } - catch (IOException e) - { - error = e; - } - } - } - - if (error != null) - { - _log.error("Unable to unload message(" + messageId + ") to disk, restoring state."); - handle.delete(); - throw new UnableToFlowMessageException(messageId, error); - } - } - } - - /** - * Use the messageId to calculate the file path on disk. - * - * Current implementation will give us 256 bins. - * Therefore the maximum messages that can be flowed before error/platform is: - * ext3 : 256 bins * 32000 = 8192000 - * FAT32 : 256 bins * 65534 = 16776704 - * Other FS have much greater limits than we need to worry about. - * - * @param messageId the Message we need a file Handle for. - * - * @return the File handle - */ - private File getFileHandle(long messageId) - { - // grab the 8 LSB to give us 256 bins - long bin = messageId & 0xFFL; - - String bin_path = _flowToDiskLocation + File.separator + bin; - File bin_dir = new File(bin_path); - - if (!bin_dir.exists()) - { - bin_dir.mkdirs(); - } - - String id = bin_path + File.separator + messageId; - - return new File(id); - } - - public void delete(Long messageId) - { - File handle = getFileHandle(messageId); - - if (handle.exists()) - { - if (_log.isInfoEnabled()) - { - _log.info("Message(" + messageId + ") delete flowToDisk."); - } - if (!handle.delete()) - { - throw new RuntimeException("Unable to delete flowToDisk data"); - } - } - } - - public void close() - { - _log.info("Closing Backing store at:" + _flowToDiskLocation); - if (!FileUtils.delete(new File(_flowToDiskLocation), true)) - { - // Attempting a second time appears to ensure that it is deleted. - if (!FileUtils.delete(new File(_flowToDiskLocation), true)) - { - _log.error("Unable to fully delete backing store location"); - } - } - } - - private class RecoverDataBuffer implements ContentChunk - { - private int _length; - private ByteBuffer _dataBuffer; - - public RecoverDataBuffer(int length, byte[] data) - { - _length = length; - _dataBuffer = ByteBuffer.wrap(data); - } - - public int getSize() - { - return _length; - } - - public ByteBuffer getData() - { - return _dataBuffer; - } - - public void reduceToFit() - { - - } - - } - -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java deleted file mode 100644 index 8981db0071..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FileQueueBackingStoreFactory.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.util.FileUtils; - -import java.io.File; - -public class FileQueueBackingStoreFactory implements QueueBackingStoreFactory -{ - private static final Logger _log = Logger.getLogger(FileQueueBackingStoreFactory.class); - - private String _flowToDiskLocation; - public static final String QUEUE_BACKING_DIR = "queueBacking"; - - public void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException - { - setFlowToDisk(virtualHost.getName(), config.getFlowToDiskLocation()); - } - - private void setFlowToDisk(String vHostName, String location) throws ConfigurationException - { - if (vHostName == null) - { - throw new ConfigurationException("Unable to setup to Flow to Disk as Virtualhost name was not specified"); - } - - if (location == null) - { - throw new ConfigurationException("Unable to setup to Flow to Disk as location was not specified."); - } - - _flowToDiskLocation = location; - - _flowToDiskLocation += File.separator + QUEUE_BACKING_DIR + File.separator + vHostName; - - //Check the location we will create QUEUE_BACKING_DIR in. - File root = new File(location); - if (!root.exists()) - { - throw new ConfigurationException("Specified Flow to Disk root does not exist:" + root.getAbsolutePath()); - } - else - { - - if (root.isFile()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified root is a file:" + - root.getAbsolutePath()); - } - - if (!root.canWrite()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store. Unable to write to specified root:" + - root.getAbsolutePath()); - } - - } - - // if we don't mark QUEUE_BAKCING_DIR as a deleteOnExit it will remain. - File backingDir = new File(location + File.separator + QUEUE_BACKING_DIR); - if (backingDir.exists()) - { - if (!FileUtils.delete(backingDir, true)) - { - throw new ConfigurationException("Unable to delete existing Flow to Disk root at:" - + backingDir.getAbsolutePath()); - } - - if (backingDir.isFile()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk root as specified location is a file:" + - backingDir.getAbsolutePath()); - } - } - - backingDir.deleteOnExit(); - if (!backingDir.mkdirs()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk root:" + location + File.separator + QUEUE_BACKING_DIR); - } - - - File store = new File(_flowToDiskLocation); - if (store.exists()) - { - if (!FileUtils.delete(store, true)) - { - throw new ConfigurationException("Unable to delete existing Flow to Disk store at:" - + store.getAbsolutePath()); - } - - if (store.isFile()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store as specified location is a file:" + - store.getAbsolutePath()); - } - - } - - _log.info("Creating Flow to Disk Store : " + store.getAbsolutePath()); - store.deleteOnExit(); - if (!store.mkdir()) - { - throw new ConfigurationException("Unable to create Temporary Flow to Disk store:" + store.getAbsolutePath()); - } - } - - public QueueBackingStore createBacking(AMQQueue queue) - { - return new FileQueueBackingStore(createStore(queue.getName().toString())); - } - - private String createStore(String name) - { - return createStore(name, 0); - } - - /** - * Returns a hash code for non-null Object x. - * Uses the same hash code spreader as most other java.util hash tables. - * - * Borrowed from the Apache Harmony project - * @param x the object serving as a key - * @return the hash code - */ - public static int hash(Object x) { - int h = x.hashCode(); - h += ~(h << 9); - h ^= (h >>> 14); - h += (h << 4); - h ^= (h >>> 10); - return h; - } - - private String createStore(String name, int index) - { - - int hash = hash(name); - - long bin = hash & 0xFFL; - - String store = _flowToDiskLocation + File.separator + bin + File.separator + name; - - if (index > 0) - { - store += "-" + index; - } - - //TODO ensure name is safe for the OS i.e. on OSX you can't have any ':' - // Does java take care of this? - - File storeFile = new File(store); - - if (storeFile.exists()) - { - return createStore(name, index + 1); - } - - // Ensure we report an error if we cannot create the backing store. - if (!storeFile.mkdirs()) - { - _log.error("Unable to create queue backing directory for queue:" + name); - throw new RuntimeException("Unable to create queue backing directory for queue:" + name); - } - - storeFile.deleteOnExit(); - - return store; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java deleted file mode 100644 index d38932bb61..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java +++ /dev/null @@ -1,33 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.AMQException; - -public interface Filterable -{ - ContentHeaderBody getContentHeaderBody() throws E; - - boolean isPersistent() throws E; - - boolean isRedelivered(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java deleted file mode 100644 index b252c7304e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FlowableBaseQueueEntryList.java +++ /dev/null @@ -1,550 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.pool.ReferenceCountingExecutorService; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -/** This is an abstract base class to handle */ -public abstract class FlowableBaseQueueEntryList implements QueueEntryList -{ - protected static final Logger _log = Logger.getLogger(FlowableBaseQueueEntryList.class); - - private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); - private final AtomicLong _atomicQueueSize = new AtomicLong(0L); - protected final AtomicLong _atomicQueueInMemory = new AtomicLong(0L); - /** The maximum amount of memory that is allocated to this queue. Beyond this the queue will flow to disk. */ - - protected long _memoryUsageMaximum = -1L; - - /** The minimum amount of memory that is allocated to this queue. If the queueDepth hits this level then more flowed data can be read in. */ - protected long _memoryUsageMinimum = 0; - private volatile AtomicBoolean _flowed; - private QueueBackingStore _backingStore; - protected AMQQueue _queue; - private Executor _inhaler; - private Executor _purger; - private AtomicBoolean _stopped; - private AtomicReference _asynchronousInhaler = new AtomicReference(null); - protected boolean _disableFlowToDisk; - private AtomicReference _asynchronousPurger = new AtomicReference(null); - private static final int BATCH_PROCESS_COUNT = 100; - protected FlowableBaseQueueEntryList _parentQueue; - - FlowableBaseQueueEntryList(AMQQueue queue) - { - _queue = queue; - _flowed = new AtomicBoolean(false); - VirtualHost vhost = queue.getVirtualHost(); - if (vhost != null) - { - _backingStore = vhost.getQueueBackingStoreFactory().createBacking(queue); - } - - _stopped = new AtomicBoolean(false); - _inhaler = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); - _purger = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); - _disableFlowToDisk = true; - } - - public void setFlowed(boolean flowed) - { - if (_flowed.get() != flowed) - { - _log.warn("Marking Queue(" + _queue.getName() + ") as flowed (" + flowed + ")"); - _flowed.set(flowed); - } - } - - protected void showUsage() - { - showUsage(""); - } - - protected void showUsage(String prefix) - { - if (_log.isTraceEnabled()) - { - _log.trace(prefix + " Queue(" + _queue.getName() + ") usage:" + memoryUsed() - + "/" + getMemoryUsageMinimum() + "<>" + getMemoryUsageMaximum() - + "/" + dataSize()); - } - } - - public boolean isFlowed() - { - if (_parentQueue != null) - { - return _parentQueue.isFlowed(); - } - else - { - return _flowed.get(); - } - } - - public int size() - { - return _atomicQueueCount.get(); - } - - public long dataSize() - { - return _atomicQueueSize.get(); - } - - public long memoryUsed() - { - return _atomicQueueInMemory.get(); - } - - public void setMemoryUsageMaximum(long maximumMemoryUsage) - { - _memoryUsageMaximum = maximumMemoryUsage; - - if (maximumMemoryUsage >= 0) - { - _disableFlowToDisk = false; - } - - // Don't attempt to start the inhaler/purger unless we have a minimum value specified. - if (_memoryUsageMaximum >= 0) - { - setMemoryUsageMinimum(_memoryUsageMaximum / 2); - - // if we have now have to much memory in use we need to purge. - if (_memoryUsageMaximum < _atomicQueueInMemory.get()) - { - setFlowed(true); - startPurger(); - } - } - else - { - if (_log.isInfoEnabled()) - { - _log.info("Disabling Flow to Disk for queue:" + _queue.getName()); - } - _disableFlowToDisk = true; - } - } - - public long getMemoryUsageMaximum() - { - return _memoryUsageMaximum; - } - - public void setMemoryUsageMinimum(long minimumMemoryUsage) - { - _memoryUsageMinimum = minimumMemoryUsage; - - // Don't attempt to start the inhaler unless we have a minimum value specified. - if (_memoryUsageMinimum > 0) - { - checkAndStartInhaler(); - } - } - - private void checkAndStartInhaler() - { - // If we've increased the minimum memory above what we have in memory then - // we need to inhale more if there is more - if (!_disableFlowToDisk && _atomicQueueInMemory.get() < _memoryUsageMinimum && _atomicQueueSize.get() > 0) - { - startInhaler(); - } - } - - private void startInhaler() - { - MessageInhaler inhaler = new MessageInhaler(); - - if (_asynchronousInhaler.compareAndSet(null, inhaler)) - { - _inhaler.execute(inhaler); - } - } - - private void startPurger() - { - MessagePurger purger = new MessagePurger(); - - if (_asynchronousPurger.compareAndSet(null, purger)) - { - _purger.execute(purger); - } - } - - public long getMemoryUsageMinimum() - { - return _memoryUsageMinimum; - } - - /** - * Only to be called by the QueueEntry - * - * @param queueEntry the entry to unload - */ - public void entryUnloadedUpdateMemory(QueueEntry queueEntry) - { - if (_parentQueue != null) - { - _parentQueue.entryUnloadedUpdateMemory(queueEntry); - } - else - { - if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) - { - _log.error("InMemory Count just went below 0:" + queueEntry.debugIdentity()); - } - - checkAndStartInhaler(); - } - } - - /** - * Only to be called from the QueueEntry - * - * @param queueEntry the entry to load - */ - public void entryLoadedUpdateMemory(QueueEntry queueEntry) - { - if (_parentQueue != null) - { - _parentQueue.entryLoadedUpdateMemory(queueEntry); - } - else - { - if (!_disableFlowToDisk && _atomicQueueInMemory.addAndGet(queueEntry.getSize()) > _memoryUsageMaximum) - { - _log.error("Loaded to much data!:" + _atomicQueueInMemory.get() + "/" + _memoryUsageMaximum); - setFlowed(true); - startPurger(); - } - } - } - - public void stop() - { - if (!_stopped.getAndSet(true)) - { - // The SimpleAMQQueue keeps running when stopped so we should just release the services - // rather than actively shutdown our threads. - //Shutdown thread for inhaler. - ReferenceCountingExecutorService.getInstance().releaseExecutorService(); - ReferenceCountingExecutorService.getInstance().releaseExecutorService(); - - _backingStore.close(); - } - } - - /** - * Mark this queue as part of another QueueEntryList for accounting purposes. - * - * All Calls from the QueueEntry to the QueueEntryList need to check if there is - * a parent QueueEntrylist upon which the action should take place. - * - * @param queueEntryList The parent queue that is performing accounting. - */ - public void setParentQueueEntryList(FlowableBaseQueueEntryList queueEntryList) - { - _parentQueue = queueEntryList; - } - - protected void incrementCounters(final QueueEntryImpl queueEntry) - { - if (_parentQueue != null) - { - _parentQueue.incrementCounters(queueEntry); - } - else - { - _atomicQueueCount.incrementAndGet(); - _atomicQueueSize.addAndGet(queueEntry.getSize()); - long inUseMemory = _atomicQueueInMemory.addAndGet(queueEntry.getSize()); - - if (!_disableFlowToDisk && inUseMemory > _memoryUsageMaximum) - { - setFlowed(true); - queueEntry.unload(); - } - } - } - - protected void dequeued(QueueEntryImpl queueEntry) - { - if (_parentQueue != null) - { - _parentQueue.dequeued(queueEntry); - } - else - { - _atomicQueueCount.decrementAndGet(); - _atomicQueueSize.addAndGet(-queueEntry.getSize()); - if (!queueEntry.isFlowed()) - { - if (_atomicQueueInMemory.addAndGet(-queueEntry.getSize()) < 0) - { - _log.error("InMemory Count just went below 0 on dequeue."); - } - } - } - } - - public QueueBackingStore getBackingStore() - { - return _backingStore; - } - - private class MessageInhaler implements Runnable - { - public void run() - { - String threadName = Thread.currentThread().getName(); - Thread.currentThread().setName("Inhaler-" + _queue.getVirtualHost().getName() + "-" + _queue.getName()); - try - { - inhaleList(this); - } - finally - { - Thread.currentThread().setName(threadName); - } - } - } - - private void inhaleList(MessageInhaler messageInhaler) - { - if (_log.isInfoEnabled()) - { - _log.info("Inhaler Running:" + _queue.getName()); - showUsage("Inhaler Running:" + _queue.getName()); - } - // If in memory count is at or over max then we can't inhale - if (_atomicQueueInMemory.get() >= _memoryUsageMaximum) - { - if (_log.isDebugEnabled()) - { - _log.debug("Unable to start inhaling as we are already over quota:" + - _atomicQueueInMemory.get() + ">=" + _memoryUsageMaximum); - } - return; - } - - _asynchronousInhaler.compareAndSet(messageInhaler, null); - int inhaled = 1; - - //Because we may not be able to totally fill up to _memoryUsageMaximum we need to be able to say we've done - // enough loading and this inhale process should stop - boolean finshedInhaling = false; - - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) // we havn't filled our max memory - && !finshedInhaling // Have we loaded all we can fit into memory - && (_atomicQueueInMemory.get() < _atomicQueueSize.get()) // we haven't loaded all that is available - && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do - && (inhaled > 0) // ensure we could inhale something - && _asynchronousInhaler.compareAndSet(null, messageInhaler)) // Ensure we are the running inhaler - { - inhaled = 0; - QueueEntryIterator iterator = iterator(); - - // If the inhaler is running and delivery rate picks up ensure that we just don't chase the delivery thread. - while ((_atomicQueueInMemory.get() < _memoryUsageMaximum) - && !iterator.getNode().isAvailable() && iterator.advance()) - { - //Find first AVAILABLE node - } - - // Because the above loop checks then moves on to the next entry a check for atTail will return true but - // we won't have checked the last entry to see if we can load it. So create atEndofList and update it based - // on the return from advance() which returns true if it can advance. - boolean atEndofList = false; - - while ((_atomicQueueInMemory.get() <= _memoryUsageMaximum) // we haven't filled our max memory - && !finshedInhaling // Have we loaded all we can fit into memory - && (inhaled < BATCH_PROCESS_COUNT) // limit the number of runs we do - && !atEndofList) // We have reached end of list QueueEntries - { - QueueEntry entry = iterator.getNode(); - - if (entry.isAvailable() && entry.isFlowed()) - { - if (_atomicQueueInMemory.get() + entry.getSize() > _memoryUsageMaximum) - { - // We don't have space for this message so we need to stop inhaling. - if (_log.isDebugEnabled()) - { - _log.debug("Entry won't fit in memory stopping inhaler:" + entry.debugIdentity()); - } - finshedInhaling = true; - } - else - { - entry.load(); - inhaled++; - } - } - - atEndofList = !iterator.advance(); - } - - if (iterator.atTail()) - { - setFlowed(false); - } - - _asynchronousInhaler.set(null); - } - - if (_log.isInfoEnabled()) - { - _log.info("Inhaler Stopping:" + _queue.getName()); - showUsage("Inhaler Stopping:" + _queue.getName()); - } - - //If we have become flowed or have more capacity since we stopped then schedule the thread to run again. - if (!finshedInhaling && _flowed.get() && _atomicQueueInMemory.get() < _memoryUsageMaximum) - { - if (_log.isInfoEnabled()) - { - _log.info("Rescheduling Inhaler:" + _queue.getName()); - } - _inhaler.execute(messageInhaler); - } - - } - - private class MessagePurger implements Runnable - { - public void run() - { - String threadName = Thread.currentThread().getName(); - Thread.currentThread().setName("Purger-" + _queue.getVirtualHost().getName() + "-" + _queue.getName()); - try - { - purgeList(this); - } - finally - { - Thread.currentThread().setName(threadName); - } - } - } - - private void purgeList(MessagePurger messagePurger) - { - // If in memory count is at or over max then we can't inhale - if (_atomicQueueInMemory.get() <= _memoryUsageMinimum) - { - if (_log.isDebugEnabled()) - { - _log.debug("Unable to start purging as we are already below our minimum cache level:" + - _atomicQueueInMemory.get() + "<=" + _memoryUsageMinimum); - } - return; - } - - if (_log.isInfoEnabled()) - { - _log.info("Purger Running:" + _queue.getName()); - showUsage("Purger Running:" + _queue.getName()); - } - - _asynchronousPurger.compareAndSet(messagePurger, null); - int purged = 0; - - while ((_atomicQueueInMemory.get() > _memoryUsageMaximum) - && purged < BATCH_PROCESS_COUNT - && _asynchronousPurger.compareAndSet(null, messagePurger)) - { - QueueEntryIterator iterator = iterator(); - - //There are potentially AQUIRED messages that can be purged but we can't purge the last AQUIRED message - // as it may have just become AQUIRED and not yet delivered. - - //To be safe only purge available messages. This should be fine as long as we have a small prefetch. - while (!iterator.getNode().isAvailable() && iterator.advance()) - { - //Find first AVAILABLE node - } - - // Count up the memory usage to find our minimum point - long memoryUsage = 0; - boolean atTail = false; - while ((memoryUsage < _memoryUsageMaximum) && !atTail) - { - QueueEntry entry = iterator.getNode(); - - if (entry.isAvailable() && !entry.isFlowed()) - { - memoryUsage += entry.getSize(); - // If this message is what puts us over the limit then break - // out of this loop as we need to purge this item. - if (memoryUsage > _memoryUsageMaximum) - { - break; - } - } - - atTail = !iterator.advance(); - } - - //Purge remainging mesages on queue - while (!atTail && (purged < BATCH_PROCESS_COUNT)) - { - QueueEntry entry = iterator.getNode(); - - if (entry.isAvailable() && !entry.isFlowed()) - { - entry.unload(); - purged++; - } - - atTail = !iterator.advance(); - } - - _asynchronousPurger.set(null); - } - - if (_log.isInfoEnabled()) - { - _log.info("Purger Stopping:" + _queue.getName()); - showUsage("Purger Stopping:" + _queue.getName()); - } - - //If we are still flowed and are over the minimum value then schedule to run again. - if (_flowed.get() && _atomicQueueInMemory.get() > _memoryUsageMaximum) - { - if (_log.isInfoEnabled()) - { - _log.info("Rescheduling Purger:" + _queue.getName()); - } - _purger.execute(messagePurger); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java deleted file mode 100644 index 36ca197fa6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.exchange.NoRouteException; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; - -import java.util.ArrayList; - -public class IncomingMessage implements Filterable -{ - - /** Used for debugging purposes. */ - private static final Logger _logger = Logger.getLogger(IncomingMessage.class); - - private static final boolean SYNCHED_CLOCKS = - ApplicationRegistry.getInstance().getConfiguration().getSynchedClocks(); - - private final MessagePublishInfo _messagePublishInfo; - private ContentHeaderBody _contentHeaderBody; - private AMQMessage _message; - private final TransactionalContext _txnContext; - - private static final boolean MSG_AUTH = - ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); - - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done - * by the message handle. - */ - private ArrayList _destinationQueues; - - private AMQProtocolSession _publisher; - private TransactionLog _messageStore; - private long _expiration; - - private Exchange _exchange; - private static MessageFactory MESSAGE_FACTORY = MessageFactory.getInstance(); - - public IncomingMessage(final MessagePublishInfo info, - final TransactionalContext txnContext, - final AMQProtocolSession publisher, - TransactionLog messasgeStore) - { - if (publisher == null) - { - throw new NullPointerException("Message Publisher cannot be null"); - } - _messagePublishInfo = info; - _txnContext = txnContext; - _publisher = publisher; - _messageStore = messasgeStore; - } - - public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException - { - _contentHeaderBody = contentHeaderBody; - _message = MESSAGE_FACTORY.createMessage(_messageStore, isPersistent()); - } - - public void setExpiration() - { - long expiration = - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getExpiration(); - long timestamp = - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getTimestamp(); - - if (SYNCHED_CLOCKS) - { - _expiration = expiration; - } - else - { - // Update TTL to be in broker time. - if (expiration != 0L) - { - if (timestamp != 0L) - { - // todo perhaps use arrival time - long diff = (System.currentTimeMillis() - timestamp); - - if ((diff > 1000L) || (diff < 1000L)) - { - _expiration = expiration + diff; - } - } - } - } - - } - - public void routingComplete(final TransactionLog transactionLog) throws AMQException - { - - if (isPersistent()) - { - _txnContext.beginTranIfNecessary(); - // enqueuing the messages ensure that if required the destinations are recorded to a - // persistent store - - if(_destinationQueues != null) - { - transactionLog.enqueueMessage(_txnContext.getStoreContext(), _destinationQueues, getMessageId()); - } - } - } - - public AMQMessage deliverToQueues() - throws AMQException - { - - // we get a reference to the destination queues now so that we can clear the - // transient message data as quickly as possible - if (_logger.isDebugEnabled()) - { - _logger.debug("Delivering message " + getMessageId() + " to " + _destinationQueues); - } - - - // 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 - _message.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), _messagePublishInfo, getContentHeaderBody()); - - - - _message.setExpiration(_expiration); - _message.setClientIdentifier(_publisher.getSessionIdentifier()); - - // 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()); - - AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; - - if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) - { - throw new UnauthorizedAccessException("Acccess Refused", _message); - } - - if ((_destinationQueues == null) || _destinationQueues.size() == 0) - { - - if (isMandatory() || isImmediate()) - { - throw new NoRouteException("No Route for message", _message); - - } - else - { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + _message); - } - } - else - { - int offset; - final int queueCount = _destinationQueues.size(); - if(queueCount == 1) - { - offset = 0; - } - else - { - offset = ((int)(_message.getMessageId().longValue())) % queueCount; - if(offset < 0) - { - offset = -offset; - } - } - for (int i = offset; i < queueCount; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), _message); - } - for (int i = 0; i < offset; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), _message); - } - } - - return _message; - - - - } - - public void addContentBodyFrame(final ContentChunk contentChunk) - throws AMQException - { - - _bodyLengthReceived += contentChunk.getSize(); - - _message.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); - - } - - public boolean allContentReceived() - { - return (_bodyLengthReceived == getContentHeaderBody().bodySize); - } - - public AMQShortString getExchange() throws AMQException - { - return _messagePublishInfo.getExchange(); - } - - public AMQShortString getRoutingKey() throws AMQException - { - return _messagePublishInfo.getRoutingKey(); - } - - public boolean isMandatory() throws AMQException - { - return _messagePublishInfo.isMandatory(); - } - - - public boolean isImmediate() throws AMQException - { - return _messagePublishInfo.isImmediate(); - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - - public boolean isPersistent() - { - return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == - BasicContentHeaderProperties.PERSISTENT; - } - - public boolean isRedelivered() - { - return false; - } - - /** - * The message ID will not be assigned until the ContentHeaderBody has arrived. - * @return - */ - public Long getMessageId() - { - return _message.getMessageId(); - } - - public void setExchange(final Exchange e) - { - _exchange = e; - } - - public void route() throws AMQException - { - _exchange.route(this); - } - - public void enqueue(final ArrayList queues) - { - _destinationQueues = queues; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java deleted file mode 100644 index d91d45a446..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of a queue. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedQueue -{ - static final String TYPE = "Queue"; - static final int VERSION = 2; - - /** - * Returns the Name of the ManagedQueue. - * @return the name of the managedQueue. - * @throws IOException - */ - @MBeanAttribute(name="Name", description = TYPE + " Name") - String getName() throws IOException; - - /** - * Total number of messages on the queue, which are yet to be delivered to the consumer(s). - * @return number of undelivered message in the Queue. - * @throws IOException - */ - @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") - Integer getMessageCount() throws IOException; - - /** - * Tells the total number of messages receieved by the queue since startup. - * @return total number of messages received. - * @throws IOException - */ - @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") - Long getReceivedMessageCount() throws IOException; - - /** - * Size of messages in the queue - * @return - * @throws IOException - */ - @MBeanAttribute(name="QueueDepth", description="The total size(Bytes) of messages in the queue") - Long getQueueDepth() throws IOException, JMException; - - /** - * Returns the total number of active subscribers to the queue. - * @return the number of active subscribers - * @throws IOException - */ - @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") - Integer getActiveConsumerCount() throws IOException; - - /** - * Returns the total number of subscribers to the queue. - * @return the number of subscribers. - * @throws IOException - */ - @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") - Integer getConsumerCount() throws IOException; - - /** - * Tells the Owner of the ManagedQueue. - * @return the owner's name. - * @throws IOException - */ - @MBeanAttribute(name="Owner", description = "Owner") - String getOwner() throws IOException; - - /** - * Tells whether this ManagedQueue is durable or not. - * @return true if this ManagedQueue is a durable queue. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the ManagedQueue is set to AutoDelete. - * @return true if the ManagedQueue is set to AutoDelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") - boolean isAutoDelete() throws IOException; - - /** - * Returns the maximum age of a message (expiration time) in milliseconds - * @return the maximum age - * @throws IOException - */ - Long getMaximumMessageAge() throws IOException; - - /** - * Sets the maximum age of a message in milliseconds - * @param age maximum age of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value(milliseconds) for message age") - void setMaximumMessageAge(Long age) throws IOException; - - /** - * Returns the maximum size of a message (in Bytes) allowed to be accepted by the - * ManagedQueue. This is useful in setting notifications or taking - * appropriate action, if the size of the message received is more than - * the allowed size. - * @return the maximum size of a message allowed to be aceepted by the - * ManagedQueue. - * @throws IOException - */ - Long getMaximumMessageSize() throws IOException; - - /** - * Sets the maximum size of the message (in Bytes) that is allowed to be - * accepted by the Queue. - * @param size maximum size of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(Bytes) for a message size") - void setMaximumMessageSize(Long size) throws IOException; - - /** - * Tells the maximum number of messages that can be stored in the queue. - * This is useful in setting the notifications or taking required - * action is the number of message increase this limit. - * @return maximum muber of message allowed to be stored in the queue. - * @throws IOException - */ - Long getMaximumMessageCount() throws IOException; - - /** - * Sets the maximum number of messages allowed to be stored in the queue. - * @param value the maximum number of messages allowed to be stored in the queue. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") - void setMaximumMessageCount(Long value) throws IOException; - - /** - * This is useful for setting notifications or taking required action if the size of messages - * stored in the queue increases over this limit. - * @return threshold high value for Queue Depth - * @throws IOException - */ - Long getMaximumQueueDepth() throws IOException; - - /** - * Sets the maximum size of all the messages together, that can be stored - * in the queue. - * @param value - * @throws IOException - */ - @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth") - void setMaximumQueueDepth(Long value) throws IOException; - - /** - * View the limit on the memory that this queue will utilise. - * - * Used by Flow to Disk. - * - * @return The maximum memory(B) that the queue will occuy. - */ - public Long getMemoryUsageMaximum(); - - /** - * Place a limit on the memory that this queue will utilise. - * - * Used by Flow to Disk - * - * @param maximumMemoryUsage The new maximum memory(B) to be used by this queue - */ - @MBeanAttribute(name="MemoryUsageMaximum", description="The maximum memory(Bytes) that the queue will occupy.") - public void setMemoryUsageMaximum(Long maximumMemoryUsage); - - /** - * View the minimum amount of memory that has been defined for this queue. - * - * Used by Flow to Disk - * - * @return The minimum amount of queue data(B) that the queue will attempt to keep in memory - */ - public Long getMemoryUsageMinimum(); - - /** - * Set the minimum amount of memory that has been defined for this queue. - * - * Used by Flow to Disk - * - * @param minimumMemoryUsage The new minimum memory(B) level to be used by this queue - */ - @MBeanAttribute(name="MemoryUsageMinimum", description="The minimum memory(Bytes) that the queue will occupy.") - public void setMemoryUsageMinimum(Long minimumMemoryUsage); - - /** - * View the amount of memory(B) that this queue is using. - * - * @return The current memory(B) usage of this queue. - */ - @MBeanAttribute(name="MemoryUsageCurrent", description="The current amount of memory(Bytes) used by this queue.") - public Long getMemoryUsageCurrent(); - - /** - * When a queue exceeds its MemoryUsageMaximum value then the Queue will start flowing to disk. - * - * This boolean is used to show that change in state. - * - * @return true if the Queue is currently flowing to disk - */ - @MBeanAttribute(name="isFlowed", description="true if the queue is currently flowing to disk.") - public boolean isFlowed(); - - - - //********** Operations *****************// - - - /** - * Returns a subset of all the messages stored in the queue. The messages - * are returned based on the given index numbers. - * @param fromIndex - * @param toIndex - * @return - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="viewMessages", - description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") - TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, - @MBeanOperationParameter(name="to index", description="to index")int toIndex) - throws IOException, JMException, AMQException; - - @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") - CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) - throws IOException, JMException; - - /** - * Deletes the first message from top. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", - impact= MBeanOperationInfo.ACTION) - void deleteMessageFromTop() throws IOException, JMException; - - /** - * Clears the queue by deleting all the undelivered messages from the queue. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="clearQueue", - description="Clears the queue by deleting all the undelivered messages from the queue", - impact= MBeanOperationInfo.ACTION) - void clearQueue() throws IOException, JMException; - - /** - * Moves the messages in given range of message Ids to given Queue. QPID-170 - * @param fromMessageId first in the range of message ids - * @param toMessageId last in the range of message ids - * @param toQueue where the messages are to be moved - * @throws IOException - * @throws JMException - * @throws AMQException - */ - @MBeanOperation(name="moveMessages", - description="You can move messages to another queue from this queue ", - impact= MBeanOperationInfo.ACTION) - void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, - @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, - @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) - throws IOException, JMException, AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java deleted file mode 100644 index 090096d3c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * MessageCleanupException represents the failure to perform reference counting on messages correctly. This should not - * happen, but there may be programming errors giving race conditions that cause the reference counting to go wrong. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Signals that the reference count of a message has gone below zero. - *
      Indicates that a message store has lost a message which is still referenced. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo The race conditions leading to this error should be cleaned up, and a runtime exception used instead. If the - * message store loses messages, then something is seriously wrong and it would be sensible to terminate the - * broker. This may be disguising out of memory errors. - */ -public class MessageCleanupException extends AMQException -{ - public MessageCleanupException(long messageId, AMQException e) - { - super("Failed to cleanup message with id " + messageId, e); - } - - public MessageCleanupException(String message) - { - super(message); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java deleted file mode 100644 index 10e7dca18f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageFactory.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.transactionlog.TransactionLog; - -import java.util.concurrent.atomic.AtomicLong; - -public class MessageFactory -{ - private AtomicLong _messageId; - private static MessageFactory INSTANCE; - - private enum State - { - RECOVER, - OPEN - } - - private State _state = State.RECOVER; - - private MessageFactory() - { - _messageId = new AtomicLong(0L); - } - - public void recoveryComplete() - { - _state = State.OPEN; - } - - /** - * Only to be used by tests as this will cause violate the principal that message IDs should not be reused. - */ - public void reset() - { - _state = State.RECOVER; - _messageId = new AtomicLong(0L); - } - - /** - * Normal message creation path - * @param transactionLog - * @param persistent - * @return - */ - public AMQMessage createMessage(TransactionLog transactionLog, boolean persistent) - { - if (_state != State.OPEN) - { - _state = State.OPEN; - } - - return createNextMessage(_messageId.incrementAndGet(), transactionLog, persistent); - } - - /** - * Used for message recovery only and so only creates persistent messages. - * @param messageId the id that this message must have - * @param transactionLog - * @return - */ - public AMQMessage createMessage(Long messageId, TransactionLog transactionLog) - { - if (_state != State.RECOVER) - { - throw new RuntimeException("Unable to create message by ID when not recovering"); - } - - if (messageId < 0L) - { - throw new RuntimeException("Message IDs can only be positive. Requested:" + messageId); - } - - _messageId.set((int)Math.max(messageId, _messageId.get())); - - return createNextMessage(messageId, transactionLog, true); - } - - private AMQMessage createNextMessage(Long messageId, TransactionLog transactionLog, boolean persistent) - { - if (persistent) - { - return new PersistentAMQMessage(messageId, transactionLog); - } - else - { - return new TransientAMQMessage(messageId); - } - } - - public static MessageFactory getInstance() - { - if (INSTANCE == null) - { - INSTANCE = new MessageFactory(); - } - - return INSTANCE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java deleted file mode 100644 index 6118a4c11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * Encapsulates a publish body and a content header. In the context of the message store these are treated as a - * single unit. - */ -public class MessageMetaData -{ - private MessagePublishInfo _messagePublishInfo; - - private ContentHeaderBody _contentHeaderBody; - - private int _contentChunkCount; - - private long _arrivalTime; - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) - { - this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); - } - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) - { - _contentHeaderBody = contentHeaderBody; - _messagePublishInfo = publishBody; - _contentChunkCount = contentChunkCount; - _arrivalTime = arrivalTime; - } - - public int getContentChunkCount() - { - return _contentChunkCount; - } - - public void setContentChunkCount(int contentChunkCount) - { - _contentChunkCount = contentChunkCount; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public void setArrivalTime(long arrivalTime) - { - _arrivalTime = arrivalTime; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java deleted file mode 100644 index d6fd1eec89..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate - * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is - * always used to report this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoConsumersException extends RequiredDeliveryException -{ - public NoConsumersException(AMQMessage message) - { - super("Immediate delivery is not possible.", message); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_CONSUMERS; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java deleted file mode 100644 index a83d661de2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 enum NotificationCheck -{ - - MESSAGE_COUNT_ALERT - { - boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) - { - int msgCount; - final long maximumMessageCount = queue.getMaximumMessageCount(); - if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) - { - listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); - return true; - } - return false; - } - }, - MESSAGE_SIZE_ALERT(true) - { - boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) - { - final long maximumMessageSize = queue.getMaximumMessageSize(); - if(maximumMessageSize != 0) - { - // Check for threshold message size - long messageSize = (queueEntry == null) ? 0 : queueEntry.getSize(); - - if (messageSize >= maximumMessageSize) - { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold (" + - maximumMessageSize + ") breached. [Message ID=" + - (queueEntry == null ? "null" : queueEntry.getMessageId()) + "]"); - return true; - } - } - return false; - } - - }, - QUEUE_DEPTH_ALERT - { - boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) - { - // Check for threshold queue depth in bytes - final long maximumQueueDepth = queue.getMaximumQueueDepth(); - - if(maximumQueueDepth != 0) - { - final long queueDepth = queue.getQueueDepth(); - - if (queueDepth >= maximumQueueDepth) - { - listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); - return true; - } - } - return false; - } - - }, - MESSAGE_AGE_ALERT - { - boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener) - { - - final long maxMessageAge = queue.getMaximumMessageAge(); - if(maxMessageAge != 0) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - maxMessageAge; - final long firstArrivalTime = queue.getOldestMessageArrivalTime(); - - if(firstArrivalTime < thresholdTime) - { - long oldestAge = currentTime - firstArrivalTime; - listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); - - return true; - } - } - return false; - - } - - } - ; - - private final boolean _messageSpecific; - - NotificationCheck() - { - this(false); - } - - NotificationCheck(boolean messageSpecific) - { - _messageSpecific = messageSpecific; - } - - public boolean isMessageSpecific() - { - return _messageSpecific; - } - - abstract boolean notifyIfNecessary(QueueEntry queueEntry, AMQQueue queue, QueueNotificationListener listener); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java deleted file mode 100644 index 9c644cc010..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PersistentAMQMessage.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.transactionlog.TransactionLog; - -public class PersistentAMQMessage extends TransientAMQMessage -{ - protected TransactionLog _transactionLog; - - public PersistentAMQMessage(Long messageId, TransactionLog transactionLog) - { - super(messageId); - _transactionLog = transactionLog; - } - - @Override - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) - throws AMQException - { - super.addContentBodyFrame(storeContext, contentChunk, isLastContentBody); - _transactionLog.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, - contentChunk, isLastContentBody); - } - - @Override - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - super.setPublishAndContentHeaderBody(storeContext, messagePublishInfo, contentHeaderBody); - MessageMetaData mmd = new MessageMetaData(messagePublishInfo, contentHeaderBody, - _contentBodies == null ? 0 : _contentBodies.size(), _arrivalTime); - - _transactionLog.storeMessageMetaData(storeContext, _messageId, mmd); - } - - @Override - public boolean isPersistent() - { - return true; - } - - @Override - public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - super.addContentBodyFrame(null, contentChunk, isLastContentBody); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java deleted file mode 100644 index 83c7ebb4f2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueEntryList.java +++ /dev/null @@ -1,178 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* 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.CommonContentHeaderProperties; - -public class PriorityQueueEntryList extends FlowableBaseQueueEntryList implements QueueEntryList -{ - private final AMQQueue _queue; - private final QueueEntryList[] _priorityLists; - private final int _priorities; - private final int _priorityOffset; - - public PriorityQueueEntryList(AMQQueue queue, int priorities) - { - super(queue); - _queue = queue; - _priorityLists = new QueueEntryList[priorities]; - _priorities = priorities; - _priorityOffset = 5 - ((priorities + 1) / 2); - for (int i = 0; i < priorities; i++) - { - _priorityLists[i] = new SimpleQueueEntryList(queue); - _priorityLists[i].setParentQueueEntryList(this); - } - - showUsage("Created:" + _queue.getName()); - } - - public int getPriorities() - { - return _priorities; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public QueueEntry add(AMQMessage message) - { - int index = ((CommonContentHeaderProperties) ((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if (index >= _priorities) - { - index = _priorities - 1; - } - else if (index < 0) - { - index = 0; - } - - return _priorityLists[index].add(message); - } - - - public QueueEntry next(QueueEntry node) - { - QueueEntryImpl nodeImpl = (QueueEntryImpl) node; - QueueEntry next = nodeImpl.getNext(); - - if (next == null) - { - QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); - int index; - for (index = _priorityLists.length - 1; _priorityLists[index] != nodeEntryList; index--) - { - ; - } - - while (next == null && index != 0) - { - index--; - next = ((QueueEntryImpl) _priorityLists[index].getHead()).getNext(); - } - - } - return next; - } - - private final class PriorityQueueEntryListIterator implements QueueEntryIterator - { - private final QueueEntryIterator[] _iterators = new QueueEntryIterator[_priorityLists.length]; - private QueueEntry _lastNode; - - PriorityQueueEntryListIterator() - { - for (int i = 0; i < _priorityLists.length; i++) - { - _iterators[i] = _priorityLists[i].iterator(); - } - _lastNode = _iterators[_iterators.length - 1].getNode(); - } - - public boolean atTail() - { - for (int i = 0; i < _iterators.length; i++) - { - if (!_iterators[i].atTail()) - { - return false; - } - } - return true; - } - - public QueueEntry getNode() - { - return _lastNode; - } - - public boolean advance() - { - for (int i = _iterators.length - 1; i >= 0; i--) - { - if (_iterators[i].advance()) - { - _lastNode = _iterators[i].getNode(); - return true; - } - } - return false; - } - } - - public QueueEntryIterator iterator() - { - return new PriorityQueueEntryListIterator(); - } - - public QueueEntry getHead() - { - return _priorityLists[_priorities - 1].getHead(); - } - - static class Factory implements QueueEntryListFactory - { - private final int _priorities; - - Factory(int priorities) - { - _priorities = priorities; - } - - public QueueEntryList createQueueEntryList(AMQQueue queue) - { - return new PriorityQueueEntryList(queue, _priorities); - } - } - - - @Override - public void stop() - { - super.stop(); - for (QueueEntryList queueEntryList : _priorityLists) - { - queueEntryList.stop(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java deleted file mode 100644 index 5c65cb6424..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStore.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.commons.configuration.ConfigurationException; - -public interface QueueBackingStore -{ - /** - * Retrieve the message with a given ID - * - * This method must be thread safe. - * - * Multiple calls to load with a given messageId DO NOT need to return the same object. - * - * @param messageId the id of the message to retreive. - * @return - */ - AMQMessage load(Long messageId); - - /** - * Store a message in the BackingStore. - * - * This method must be thread safe understanding that multiple message objects may be the same data. - * - * Allowing a thread to return from this method means that it is safe to call load() - * - * Implementer guide: - * Until the message has been loaded the message references will all be the same object. - * - * One appraoch as taken by the @see FileQueueBackingStore is to block aimulataneous calls to this method - * until the message is fully on disk. This can be done by synchronising on message as initially it is always the - * same object. Only after a load has taken place will there be a discrepency. - * - * - * @param message the message to unload - * @throws UnableToFlowMessageException - */ - void unload(AMQMessage message) throws UnableToFlowMessageException; - - void delete(Long messageId); - - void close(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java deleted file mode 100644 index 3dd23a2f40..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueBackingStoreFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.commons.configuration.ConfigurationException; - -public interface QueueBackingStoreFactory -{ - void configure(VirtualHost virtualHost, VirtualHostConfiguration config) throws ConfigurationException; - - public QueueBackingStore createBacking(AMQQueue queue); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java deleted file mode 100644 index fb23edb3c5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.Subscription; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public interface QueueEntry extends Comparable, Filterable -{ - public static enum State - { - AVAILABLE, - ACQUIRED, - EXPIRED, - DEQUEUED, - DELETED - } - - public static interface StateChangeListener - { - public void stateChanged(QueueEntry entry, State oldSate, State newState); - } - - public abstract class EntryState - { - private EntryState() - { - } - - public abstract State getState(); - } - - public final class AvailableState extends EntryState - { - - public State getState() - { - return State.AVAILABLE; - } - } - - public final class DequeuedState extends EntryState - { - - public State getState() - { - return State.DEQUEUED; - } - } - - public final class DeletedState extends EntryState - { - - public State getState() - { - return State.DELETED; - } - } - - public final class ExpiredState extends EntryState - { - - public State getState() - { - return State.EXPIRED; - } - } - - public final class NonSubscriptionAcquiredState extends EntryState - { - public State getState() - { - return State.ACQUIRED; - } - } - - public final class SubscriptionAcquiredState extends EntryState - { - private final Subscription _subscription; - - public SubscriptionAcquiredState(Subscription subscription) - { - _subscription = subscription; - } - - public State getState() - { - return State.ACQUIRED; - } - - public Subscription getSubscription() - { - return _subscription; - } - } - - final static EntryState AVAILABLE_STATE = new AvailableState(); - final static EntryState DELETED_STATE = new DeletedState(); - final static EntryState DEQUEUED_STATE = new DequeuedState(); - final static EntryState EXPIRED_STATE = new ExpiredState(); - final static EntryState NON_SUBSCRIPTION_ACQUIRED_STATE = new NonSubscriptionAcquiredState(); - - /** Flag to indicate that this message requires 'immediate' delivery. */ - - final static byte IMMEDIATE = 0x01; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - - final static byte DELIVERED_TO_CONSUMER = 0x02; - - - AMQQueue getQueue(); - - AMQMessage getMessage(); - - Long getMessageId(); - - long getSize(); - - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - boolean getDeliveredToConsumer(); - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @return true if the message has expire - * - * @throws org.apache.qpid.AMQException - */ - boolean expired() throws AMQException; - - public void setExpiration(final long expiration); - - boolean isAcquired(); - - boolean isAvailable(); - - boolean acquire(); - - boolean acquire(Subscription sub); - - boolean delete(); - - boolean isDeleted(); - - boolean acquiredBySubscription(); - - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - * - * This is now also used to unload the message if this entry is on a flowed queue. As a result this method should - * only be called after the message has been sent. - */ - void setDeliveredToSubscription(); - - void release(); - - String debugIdentity(); - - /** - * Called to enforce the 'immediate' flag. - * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer - */ - boolean immediateAndNotDelivered(); - - void setRedelivered(boolean b); - - Subscription getDeliveredSubscription(); - - void reject(); - - void reject(Subscription subscription); - - boolean isRejectedBy(Subscription subscription); - - void requeue(StoreContext storeContext) throws AMQException; - - void dequeue(final StoreContext storeContext) throws FailedDequeueException; - - /** - * Message has been ack so dequeueAndDelete it. - * If the message is persistent and this is the last QueueEntry that uses it then the data will be removed - * from the transaciton log - * - * @param storeContext the transactional Context in which to perform the deletion - * - * @throws FailedDequeueException - * @throws MessageCleanupException - */ - void dequeueAndDelete(StoreContext storeContext) throws FailedDequeueException; - - boolean isQueueDeleted(); - - void addStateChangeListener(StateChangeListener listener); - - boolean removeStateChangeListener(StateChangeListener listener); - - void unload(); - - AMQMessage load(); - - boolean isFlowed(); - -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java deleted file mode 100644 index e6223ef4ac..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ /dev/null @@ -1,568 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.ContentHeaderBody; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.Subscription; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -public class QueueEntryImpl implements QueueEntry -{ - - /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(QueueEntryImpl.class); - - private final SimpleQueueEntryList _queueEntryList; - - private AtomicReference _messageRef; - - private boolean _redelivered; - - private Set _rejectedBy = null; - - private volatile EntryState _state = AVAILABLE_STATE; - - private static final - AtomicReferenceFieldUpdater - _stateUpdater = - AtomicReferenceFieldUpdater.newUpdater - (QueueEntryImpl.class, EntryState.class, "_state"); - - private volatile Set _stateChangeListeners; - - private static final - AtomicReferenceFieldUpdater - _listenersUpdater = - AtomicReferenceFieldUpdater.newUpdater - (QueueEntryImpl.class, Set.class, "_stateChangeListeners"); - - private static final - AtomicLongFieldUpdater - _entryIdUpdater = - AtomicLongFieldUpdater.newUpdater - (QueueEntryImpl.class, "_entryId"); - - private volatile long _entryId; - - volatile QueueEntryImpl _next; - - private long _messageSize; - private QueueBackingStore _backingStore; - private AtomicBoolean _flowed; - private Long _messageId; - - private byte _flags = 0; - - private long _expiration; - - private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - private boolean _persistent; - private boolean _hasBeenUnloaded = false; - - QueueEntryImpl(SimpleQueueEntryList queueEntryList) - { - this(queueEntryList, null, Long.MIN_VALUE); - _state = DELETED_STATE; - } - - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) - { - this(queueEntryList, message); - - _entryIdUpdater.set(this, entryId); - } - - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) - { - _queueEntryList = queueEntryList; - _messageRef = new AtomicReference(message); - if (message != null) - { - _messageId = message.getMessageId(); - _messageSize = message.getSize(); - - if (message.isImmediate()) - { - _flags |= IMMEDIATE; - } - _expiration = message.getExpiration(); - _persistent = message.isPersistent(); - } - _backingStore = queueEntryList.getBackingStore(); - _flowed = new AtomicBoolean(false); - } - - protected void setEntryId(long entryId) - { - _entryIdUpdater.set(this, entryId); - } - - protected long getEntryId() - { - return _entryId; - } - - public AMQQueue getQueue() - { - return _queueEntryList.getQueue(); - } - - public AMQMessage getMessage() - { - return load(); - } - - public Long getMessageId() - { - return _messageId; - } - - public long getSize() - { - return _messageSize; - } - - public boolean getDeliveredToConsumer() - { - return (_flags & DELIVERED_TO_CONSUMER) != 0; - } - - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - * - * This is now also used to unload the message if this entry is on a flowed queue. As a result this method should - * only be called after the message has been sent. - */ - public void setDeliveredToSubscription() - { - _flags |= DELIVERED_TO_CONSUMER; - - // We have delivered this message so we can unload it if we are flowed. - if (_queueEntryList.isFlowed()) - { - unload(); - } - } - - public boolean expired() throws AMQException - { - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } - - return false; - } - - public void setExpiration(final long expiration) - { - _expiration = expiration; - } - - public boolean isAcquired() - { - return _state.getState() == State.ACQUIRED; - } - - public boolean isAvailable() - { - return _state.getState() == State.AVAILABLE; - } - - public boolean acquire() - { - return acquire(NON_SUBSCRIPTION_ACQUIRED_STATE); - } - - private boolean acquire(final EntryState state) - { - boolean acquired = _stateUpdater.compareAndSet(this, AVAILABLE_STATE, state); - if (acquired && _stateChangeListeners != null) - { - notifyStateChange(State.AVAILABLE, State.ACQUIRED); - } - - return acquired; - } - - public boolean acquire(Subscription sub) - { - return acquire(sub.getOwningState()); - } - - public boolean acquiredBySubscription() - { - - return (_state instanceof SubscriptionAcquiredState); - } - - public void release() - { - _stateUpdater.set(this, AVAILABLE_STATE); - } - - public String debugIdentity() - { - String entry = "[State:" + _state.getState().name() + "]"; - - AMQMessage message = _messageRef.get(); - - if (message == null) - { - return entry + "(Message Unloaded ID:" + _messageId + ")"; - } - else - { - - return entry + message.debugIdentity(); - } - } - - public boolean immediateAndNotDelivered() - { - return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; - } - - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - return getMessage().getContentHeaderBody(); - } - - public boolean isPersistent() throws AMQException - { - return _persistent; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - // todo - here we could record this message as redelivered on this queue in the transactionLog - // so we don't have to mark all messages on recover as redelivered. - } - - public Subscription getDeliveredSubscription() - { - EntryState state = _state; - if (state instanceof SubscriptionAcquiredState) - { - return ((SubscriptionAcquiredState) state).getSubscription(); - } - else - { - return null; - } - - } - - public void reject() - { - reject(getDeliveredSubscription()); - } - - public void reject(Subscription subscription) - { - if (subscription != null) - { - if (_rejectedBy == null) - { - _rejectedBy = new HashSet(); - } - - _rejectedBy.add(subscription); - } - else - { - _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); - } - } - - public boolean isRejectedBy(Subscription subscription) - { - - if (_rejectedBy != null) // We have subscriptions that rejected this message - { - return _rejectedBy.contains(subscription); - } - else // This messasge hasn't been rejected yet. - { - return false; - } - } - - public void requeue(final StoreContext storeContext) throws AMQException - { - getQueue().requeue(storeContext, this); - if (_stateChangeListeners != null) - { - notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); - } - } - - public void dequeue(final StoreContext storeContext) throws FailedDequeueException - { - EntryState state = _state; - - if ((state.getState() == State.ACQUIRED) && _stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) - { - if (state instanceof SubscriptionAcquiredState) - { - Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); - s.restoreCredit(this); - } - - _queueEntryList.dequeued(this); - - getQueue().dequeue(storeContext, this); - - if (_stateChangeListeners != null) - { - notifyStateChange(state.getState(), QueueEntry.State.DEQUEUED); - } - } - } - - private void notifyStateChange(final State oldState, final State newState) - { - for (StateChangeListener l : _stateChangeListeners) - { - l.stateChanged(this, oldState, newState); - } - } - - public void dequeueAndDelete(StoreContext storeContext) throws FailedDequeueException - { - //if the queue is null (i.e. queue.delete()'d) then the message is waiting to be acked, but has already be delete()'d; - if (getQueue() != null) - { - dequeue(storeContext); - } - - delete(); - } - - public boolean isQueueDeleted() - { - return getQueue().isDeleted(); - } - - public void addStateChangeListener(StateChangeListener listener) - { - Set listeners = _stateChangeListeners; - if (listeners == null) - { - _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet()); - listeners = _stateChangeListeners; - } - - listeners.add(listener); - } - - public boolean removeStateChangeListener(StateChangeListener listener) - { - Set listeners = _stateChangeListeners; - if (listeners != null) - { - return listeners.remove(listener); - } - - return false; - } - - public void unload() - { - //Get the currently loaded message - AMQMessage message = _messageRef.get(); - - // If we have a message in memory and we have a valid backingStore attempt to unload - if (message != null && _backingStore != null) - { - try - { - // The backingStore will now handle concurrent calls to unload and safely synchronize to ensure - // multiple initial unloads are unloads - _backingStore.unload(message); - _hasBeenUnloaded = true; - _messageRef.set(null); - - if (_log.isDebugEnabled()) - { - _log.debug("Unloaded:" + debugIdentity()); - } - - - // Clear the message reference if the loaded message is still the one we are processing. - - //Update the memoryState if this load call resulted in the message being purged from memory - if (!_flowed.getAndSet(true)) - { - _queueEntryList.entryUnloadedUpdateMemory(this); - } - - } - catch (UnableToFlowMessageException utfme) - { - // There is no recovery needed as the memory states remain unchanged. - if (_log.isDebugEnabled()) - { - _log.debug("Unable to Flow message:" + debugIdentity() + ", due to:" + utfme.getMessage()); - } - } - } - } - - public AMQMessage load() - { - // MessageId and Backing store are null in test scenarios, normally this is not the case. - if (_messageId != null && _backingStore != null) - { - // See if we have the message currently in memory to return - AMQMessage message = _messageRef.get(); - // if we don't then we need to start a load process. - if (message == null) - { - //Synchronize here to ensure only the first thread that attempts to load will perform the load from the - // backing store. - synchronized (this) - { - // Check again to see if someone else ahead of us loaded the message - message = _messageRef.get(); - // if we still don't have the message then we need to start a load process. - if (message == null) - { - // Load the message and keep a reference to it - message = _backingStore.load(_messageId); - // Set the message reference - _messageRef.set(message); - } - else - { - // If someone else loaded the message then we can jump out here as the Memory Updates will - // have been performed by the loading thread - return message; - } - } - - if (_log.isDebugEnabled()) - { - _log.debug("Loaded:" + debugIdentity()); - } - - //Update the memoryState if this load call resulted in the message comming in to memory - if (_flowed.getAndSet(false)) - { - _queueEntryList.entryLoadedUpdateMemory(this); - } - } - - // Return the message that was either already in memory or the value we just loaded. - return message; - } - // This can be null but only in the case where we have no messageId - // in the case where we have no backingStore then we will never have unloaded the message - return _messageRef.get(); - } - - public boolean isFlowed() - { - return _flowed.get(); - } - - public int compareTo(final QueueEntry o) - { - QueueEntryImpl other = (QueueEntryImpl) o; - return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0; - } - - public QueueEntryImpl getNext() - { - - QueueEntryImpl next = nextNode(); - while (next != null && next.isDeleted()) - { - - final QueueEntryImpl newNext = next.nextNode(); - if (newNext != null) - { - SimpleQueueEntryList._nextUpdater.compareAndSet(this, next, newNext); - next = nextNode(); - } - else - { - next = null; - } - - } - return next; - } - - QueueEntryImpl nextNode() - { - return _next; - } - - public boolean isDeleted() - { - return _state == DELETED_STATE; - } - - public boolean delete() - { - EntryState state = _state; - - if (state != DELETED_STATE && _stateUpdater.compareAndSet(this, state, DELETED_STATE)) - { - _queueEntryList.advanceHead(); - if (_backingStore != null && _hasBeenUnloaded) - { - _backingStore.delete(_messageId); - } - return true; - } - else - { - return false; - } - } - - public QueueEntryList getQueueEntryList() - { - return _queueEntryList; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java deleted file mode 100644 index c5c115a2d1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -public interface QueueEntryIterator -{ - boolean atTail(); - - QueueEntry getNode(); - - boolean advance(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java deleted file mode 100644 index 2bbdf610de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public interface QueueEntryList -{ - AMQQueue getQueue(); - - QueueEntry add(AMQMessage message); - - QueueEntry next(QueueEntry node); - - QueueEntryIterator iterator(); - - QueueEntry getHead(); - - void setFlowed(boolean flowed); - - boolean isFlowed(); - - int size(); - - long dataSize(); - - long memoryUsed(); - - void setMemoryUsageMaximum(long maximumMemoryUsage); - - long getMemoryUsageMaximum(); - - void setMemoryUsageMinimum(long minimumMemoryUsage); - - long getMemoryUsageMinimum(); - - /** - * Immediately update memory usage based on the unload of this queueEntry, potentially start inhaler. - * @param queueEntry the entry that has been unloaded - */ - void entryUnloadedUpdateMemory(QueueEntry queueEntry); - - /** - * Immediately update memory usage based on the load of this queueEntry - * @param queueEntry the entry that has been loaded - */ - void entryLoadedUpdateMemory(QueueEntry queueEntry); - - void stop(); - - /** - * Mark this queue as part of another QueueEntryList for accounting purposes. - * - * All Calls from the QueueEntry to the QueueEntryList need to check if there is - * a parent QueueEntrylist upon which the action should take place. - * - * @param queueEntryList The parent queue that is performing accounting. - */ - void setParentQueueEntryList(FlowableBaseQueueEntryList queueEntryList); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java deleted file mode 100644 index 4dbce45f67..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -interface QueueEntryListFactory -{ - public QueueEntryList createQueueEntryList(AMQQueue queue); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java deleted file mode 100644 index 959ca03c80..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - - -public interface QueueNotificationListener -{ - void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java deleted file mode 100644 index 1210f0e97c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Collection; - -public interface QueueRegistry -{ - VirtualHost getVirtualHost(); - - void registerQueue(AMQQueue queue) throws AMQException; - - void unregisterQueue(AMQShortString name) throws AMQException; - - AMQQueue getQueue(AMQShortString name); - - Collection getQueueNames(); - - Collection getQueues(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java deleted file mode 100644 index 6a19acddd7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ /dev/null @@ -1,1666 +0,0 @@ -package org.apache.qpid.server.queue; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -import javax.management.JMException; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.pool.ReadWriteRunnable; -import org.apache.qpid.pool.ReferenceCountingExecutorService; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionList; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener -{ - private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); - - private final AMQShortString _name; - - /** null means shared */ - private final AMQShortString _owner; - - private final boolean _durable; - - /** If true, this queue is deleted when the last subscriber is removed */ - private final boolean _autoDelete; - - private final VirtualHost _virtualHost; - - /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ - private final ExchangeBindings _bindings = new ExchangeBindings(this); - - private final AtomicBoolean _deleted = new AtomicBoolean(false); - - private final List _deleteTaskList = new CopyOnWriteArrayList(); - - private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); - - protected final SubscriptionList _subscriptionList = new SubscriptionList(this); - private final AtomicReference _lastSubscriptionNode = new AtomicReference(_subscriptionList.getHead()); - - private volatile Subscription _exclusiveSubscriber; - - protected final QueueEntryList _entries; - - private final AMQQueueMBean _managedObject; - private final Executor _asyncDelivery; - private final AtomicLong _totalMessagesReceived = new AtomicLong(); - - /** max allowed size(KB) of a single message */ - public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); - - /** max allowed number of messages on a queue. */ - public long _maximumMessageCount = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageCount(); - - /** max queue depth for the queue */ - public long _maximumQueueDepth = ApplicationRegistry.getInstance().getConfiguration().getMaximumQueueDepth(); - - /** maximum message age before alerts occur */ - public long _maximumMessageAge = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageAge(); - - /** the minimum interval between sending out consecutive alerts of the same type */ - public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); - - - private static final int MAX_ASYNC_DELIVERIES = 10; - - private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); - - private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); - private AtomicReference _asynchronousRunner = new AtomicReference(null); - private AtomicInteger _deliveredMessages = new AtomicInteger(); - private AtomicBoolean _stopped = new AtomicBoolean(false); - - protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException - { - this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); - } - - protected SimpleAMQQueue(AMQShortString name, - boolean durable, - AMQShortString owner, - boolean autoDelete, - VirtualHost virtualHost, - QueueEntryListFactory entryListFactory) - throws AMQException - { - - if (name == null) - { - throw new IllegalArgumentException("Queue name must not be null"); - } - - if (virtualHost == null) - { - throw new IllegalArgumentException("Virtual Host must not be null"); - } - - _name = name; - _durable = durable; - _owner = owner; - _autoDelete = autoDelete; - _virtualHost = virtualHost; - _entries = entryListFactory.createQueueEntryList(this); - - _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); - - try - { - _managedObject = new AMQQueueMBean(this); - _managedObject.register(); - } - catch (JMException e) - { - throw new AMQException("AMQQueue MBean creation has failed ", e); - } - - resetNotifications(); - } - - public void resetNotifications() - { - // This ensure that the notification checks for the configured alerts are created. - setMaximumMessageAge(_maximumMessageAge); - setMaximumMessageCount(_maximumMessageCount); - setMaximumMessageSize(_maximumMessageSize); - setMaximumQueueDepth(_maximumQueueDepth); - } - - // ------ Getters and Setters - - public AMQShortString getName() - { - return _name; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - public boolean isFlowed() - { - return _entries.isFlowed(); - } - - public AMQShortString getOwner() - { - return _owner; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - // ------ bind and unbind - - public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException - { - exchange.registerQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getRoutingTable().bindQueue(exchange, routingKey, this, arguments); - } - - _bindings.addBinding(routingKey, arguments, exchange); - } - - public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException - { - exchange.deregisterQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getRoutingTable().unbindQueue(exchange, routingKey, this, arguments); - } - - boolean removed = _bindings.remove(routingKey, arguments, exchange); - if (!removed) - { - _logger.error("Mismatch between queue bindings and exchange record of bindings"); - } - } - - public List getExchangeBindings() - { - return new ArrayList(_bindings.getExchangeBindings()); - } - - // ------ Manage Subscriptions - - public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException - { - - if (isExclusiveSubscriber()) - { - throw new ExistingExclusiveSubscription(); - } - - if (exclusive) - { - if (getConsumerCount() != 0) - { - throw new ExistingSubscriptionPreventsExclusive(); - } - else - { - _exclusiveSubscriber = subscription; - - } - } - - _activeSubscriberCount.incrementAndGet(); - subscription.setStateListener(this); - subscription.setLastSeenEntry(null, _entries.getHead()); - - if (!isDeleted()) - { - subscription.setQueue(this); - _subscriptionList.add(subscription); - if (isDeleted()) - { - subscription.queueDeleted(this); - } - } - else - { - // TODO - } - - deliverAsync(subscription); - - } - - public synchronized void unregisterSubscription(final Subscription subscription) throws AMQException - { - if (subscription == null) - { - throw new NullPointerException("subscription argument is null"); - } - - boolean removed = _subscriptionList.remove(subscription); - - if (removed) - { - subscription.close(); - // No longer can the queue have an exclusive consumer - setExclusiveSubscriber(null); - - QueueEntry lastSeen; - - while ((lastSeen = subscription.getLastSeenEntry()) != null) - { - subscription.setLastSeenEntry(lastSeen, null); - } - - // auto-delete queues must be deleted if there are no remaining subscribers - - if (_autoDelete && getConsumerCount() == 0) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Auto-deleteing queue:" + this); - } - - delete(); - - // 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 - subscription.queueDeleted(this); - } - } - - } - - // ------ Enqueue / Dequeue - - public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException - { - _totalMessagesReceived.incrementAndGet(); - - QueueEntry entry; - Subscription exclusiveSub = _exclusiveSubscriber; - - if (exclusiveSub != null) - { - exclusiveSub.getSendLock(); - - try - { - entry = _entries.add(message); - - deliverToSubscription(exclusiveSub, entry); - - // where there is more than one producer there's a reasonable chance that even though there is - // no "queueing" we do not deliver because we get an interleving of _entries.add and - // deliverToSubscription between threads. Therefore have one more try. - if (!(entry.isAcquired() || entry.isDeleted())) - { - deliverToSubscription(exclusiveSub, entry); - } - } - finally - { - exclusiveSub.releaseSendLock(); - } - } - else - { - entry = _entries.add(message); - /* - - iterate over subscriptions and if any is at the end of the queue and can deliver this message, then deliver the message - - */ - SubscriptionList.SubscriptionNode node = _lastSubscriptionNode.get(); - SubscriptionList.SubscriptionNode nextNode = node.getNext(); - if (nextNode == null) - { - nextNode = _subscriptionList.getHead().getNext(); - } - while (nextNode != null) - { - if (_lastSubscriptionNode.compareAndSet(node, nextNode)) - { - break; - } - else - { - node = _lastSubscriptionNode.get(); - nextNode = node.getNext(); - if (nextNode == null) - { - nextNode = _subscriptionList.getHead().getNext(); - } - } - } - - // always do one extra loop after we believe we've finished - // this catches the case where we *just* miss an update - int loops = 2; - - while (!(entry.isAcquired() || entry.isDeleted()) && loops != 0) - { - if (nextNode == null) - { - loops--; - nextNode = _subscriptionList.getHead(); - } - else - { - // if subscription at end, and active, offer - Subscription sub = nextNode.getSubscription(); - deliverToSubscription(sub, entry); - } - nextNode = nextNode.getNext(); - - } - } - - if (entry.immediateAndNotDelivered()) - { - //We acquire the message here to ensure that the dequeueAndDelete will correctly remove the content - // from the transactionLog. This saves us from having to have a custom dequeueAndDelete that checks - // for the AVAILABLE state of an entry rather than the ACQUIRED state that it currently uses. - entry.acquire(); - entry.dequeueAndDelete(storeContext); - } - else if (!(entry.isAcquired() || entry.isDeleted())) - { - checkSubscriptionsNotAheadOfDelivery(entry); - - deliverAsync(); - } - - _managedObject.checkForNotification(entry); - - return entry; - } - - private void deliverToSubscription(final Subscription sub, final QueueEntry entry) - throws AMQException - { - - sub.getSendLock(); - try - { - if (subscriptionReadyAndHasInterest(sub, entry) - && !sub.isSuspended()) - { - if (!sub.wouldSuspend(entry)) - { - if (!sub.isBrowser() && !entry.acquire(sub)) - { - // restore credit here that would have been taken away by wouldSuspend since we didn't manage - // to acquire the entry for this subscription - sub.restoreCredit(entry); - } - else - { - - deliverMessage(sub, entry); - - } - } - } - } - finally - { - sub.releaseSendLock(); - } - } - - protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) - { - // This method is only required for queues which mess with ordering - // Simple Queues don't :-) - } - - private void deliverMessage(final Subscription sub, final QueueEntry entry) - throws AMQException - { - _deliveredMessages.incrementAndGet(); - - sub.send(entry); - - } - - private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) - { - - // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no - // interest in. - QueueEntry node = sub.getLastSeenEntry(); - while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node))) - { - - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - node = null; - break; - } - - } - - if (node == entry) - { - // If the first entry that subscription can process is the one we are trying to deliver to it, then we are - // good - return true; - } - else - { - // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing - // no-one else has updated it to something furhter on in the list - //TODO - check - //updateLastSeenEntry(sub, entry); - return false; - } - - } - - private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry) - { - QueueEntry node = sub.getLastSeenEntry(); - - if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) - { - do - { - if (sub.setLastSeenEntry(node, entry)) - { - return; - } - else - { - node = sub.getLastSeenEntry(); - } - } - while (node != null && entry.compareTo(node) < 0); - } - - } - - public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException - { - - SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); - // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards - while (subscriberIter.advance()) - { - Subscription sub = subscriberIter.getNode().getSubscription(); - - // we don't make browsers send the same stuff twice - if (!sub.isBrowser()) - { - updateLastSeenEntry(sub, entry); - } - } - - deliverAsync(); - - } - - /** - * Only call from queue Entry - * @param storeContext - * @param entry - * @throws FailedDequeueException - */ - public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException - { - if (entry.acquiredBySubscription()) - { - _deliveredMessages.decrementAndGet(); - } - - try - { - if (entry.isPersistent()) - { - _virtualHost.getTransactionLog().dequeueMessage(storeContext, this, entry.getMessageId()); - } - - } - catch (MessageCleanupException e) - { - // Message was dequeued, but could not then be deleted - // though it is no longer referenced. This should be very - // rare and can be detected and cleaned up on recovery or - // done through some form of manual intervention. - _logger.error(e, e); - } - catch (AMQException e) - { - throw new FailedDequeueException(_name.toString(), e); - } - - } - - - public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException - { - /* TODO : This is wrong as the subscription may be suspended, we should instead change the state of the message - entry to resend and move back the subscription pointer. */ - - subscription.getSendLock(); - try - { - if (!subscription.isClosed()) - { - deliverMessage(subscription, entry); - return true; - } - else - { - return false; - } - } - finally - { - subscription.releaseSendLock(); - } - } - - public int getConsumerCount() - { - return _subscriptionList.size(); - } - - public int getActiveConsumerCount() - { - return _activeSubscriberCount.get(); - } - - public boolean isUnused() - { - return getConsumerCount() == 0; - } - - public boolean isEmpty() - { - return getMessageCount() == 0; - } - - public long getMemoryUsageCurrent() - { - return getQueueInMemory(); - } - - public int getMessageCount() - { - return getQueueCount(); - } - - public long getQueueDepth() - { - return getQueueSize(); - } - - public int getUndeliveredMessageCount() - { - int count = getMessageCount() - _deliveredMessages.get(); - if (count < 0) - { - return 0; - } - else - { - return count; - } - } - - public long getReceivedMessageCount() - { - return _totalMessagesReceived.get(); - } - - public long getOldestMessageArrivalTime() - { - QueueEntry entry = getOldestQueueEntry(); - return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); - } - - protected QueueEntry getOldestQueueEntry() - { - return _entries.next(_entries.getHead()); - } - - public boolean isDeleted() - { - return _deleted.get(); - } - - public List getMessagesOnTheQueue() - { - ArrayList entryList = new ArrayList(); - QueueEntryIterator queueListIterator = _entries.iterator(); - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (node != null && !node.isDeleted()) - { - entryList.add(node); - } - } - return entryList; - - } - - public void stateChange(Subscription sub, Subscription.State oldState, Subscription.State newState) - { - if (oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE) - { - _activeSubscriberCount.decrementAndGet(); - - } - else if (newState == Subscription.State.ACTIVE) - { - if (oldState != Subscription.State.ACTIVE) - { - _activeSubscriberCount.incrementAndGet(); - - } - deliverAsync(sub); - } - } - - public int compareTo(final AMQQueue o) - { - return _name.compareTo(o.getName()); - } - - public int getQueueCount() - { - return _entries.size(); - } - - public long getQueueSize() - { - return _entries.dataSize(); - } - - public long getQueueInMemory() - { - return _entries.memoryUsed(); - } - - private boolean isExclusiveSubscriber() - { - return _exclusiveSubscriber != null; - } - - private void setExclusiveSubscriber(Subscription exclusiveSubscriber) - { - _exclusiveSubscriber = exclusiveSubscriber; - } - - public static interface QueueEntryFilter - { - public boolean accept(QueueEntry entry); - - public boolean filterComplete(); - } - - public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) - { - return getMessagesOnTheQueue(new QueueEntryFilter() - { - - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessageId(); - return messageId >= fromMessageId && messageId <= toMessageId; - } - - public boolean filterComplete() - { - return false; - } - }); - } - - public QueueEntry getMessageOnTheQueue(final long messageId) - { - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - private boolean _complete; - - public boolean accept(QueueEntry entry) - { - _complete = entry.getMessageId() == messageId; - return _complete; - } - - public boolean filterComplete() - { - return _complete; - } - }); - return entries.isEmpty() ? null : entries.get(0); - } - - public List getMessagesOnTheQueue(QueueEntryFilter filter) - { - ArrayList entryList = new ArrayList(); - QueueEntryIterator queueListIterator = _entries.iterator(); - while (queueListIterator.advance() && !filter.filterComplete()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && filter.accept(node)) - { - entryList.add(node); - } - } - return entryList; - - } - - - public void moveMessagesToAnotherQueue(final long fromMessageId, - final long toMessageId, - String queueName, - StoreContext storeContext) - { - // The move is a two step process. First the messages are moved in the _transactionLog. - // That is persistent messages are moved queues on disk for recovery and the QueueEntries removed from the - // existing queue. - // This is done as Queue.enqueue() does not write the data to the transactionLog. In normal message delivery - // this is done as the message is recieved. - // So The final step is to enqueue the messages on the new queue. - - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - TransactionLog transactionLog = getVirtualHost().getTransactionLog(); - - if (toQueue.equals(this)) - { - //nothing to do here, message is already at the requested destination - return; - } - - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessageId(); - return (messageId >= fromMessageId) - && (messageId <= toMessageId) - && entry.acquire(); - } - - public boolean filterComplete() - { - return false; - } - }); - - try - { - transactionLog.beginTran(storeContext); - - // Move the messages in the transaction log. - for (QueueEntry entry : entries) - { - if (entry.isPersistent()) - { - //FIXME - //fixme - - // Creating a list with the destination queue AND the current queue. - // This is a hack to ensure a reference is kept in the TLog to the new destination when dequeing - // the old destination below, thus preventing incorrect removal of the message from the store - ArrayList list = new ArrayList(); - list.add(toQueue); - list.add(this); - transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); - } - // dequeue will remove the messages from the queue - entry.dequeue(storeContext); - } - - // Commit and flush the move transactions. - try - { - transactionLog.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on transaction log.", e); - } - } - catch (AMQException e) - { - try - { - transactionLog.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } - - try - { - // Add messages to new queue - for (QueueEntry entry : entries) - { - toQueue.enqueue(storeContext, entry.getMessage()); - // As we only did a dequeue above now that we have moved the message we should perform a delete. - // We cannot do this earlier as the message will be lost if flowed. - entry.delete(); - } - } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - - } - - public void copyMessagesToAnotherQueue(final long fromMessageId, - final long toMessageId, - String queueName, - final StoreContext storeContext) - { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - TransactionLog transactionLog = getVirtualHost().getTransactionLog(); - - if (toQueue.equals(this)) - { - //nothing to do here, message is already at the requested destination - return; - } - - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - - public boolean accept(QueueEntry entry) - { - final long messageId = entry.getMessageId(); - if ((messageId >= fromMessageId) - && (messageId <= toMessageId)) - { - if (!entry.isDeleted()) - { - return true; - } - } - - return false; - } - - public boolean filterComplete() - { - return false; - } - }); - - try - { - transactionLog.beginTran(storeContext); - - // Move the messages in on the transaction log. - for (QueueEntry entry : entries) - { - if (!entry.isDeleted() && entry.isPersistent()) - { - //fixme - //FIXME - - // Creating a list with the destination queue AND the current queue. - // This is a hack to ensure a reference is kept in the TLog to the old destination when enqueing - ArrayList list = new ArrayList(); - list.add(this); - list.add(toQueue); - transactionLog.enqueueMessage(storeContext, list, entry.getMessageId()); - } - } - - - // Commit and flush the move transcations. - try - { - transactionLog.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on transaction log.", e); - } - } - catch (AMQException e) - { - try - { - transactionLog.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } - - try - { - for (QueueEntry entry : entries) - { - if (!entry.isDeleted()) - { - toQueue.enqueue(storeContext, entry.getMessage()); - } - } - } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - - } - - public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) - { - - try - { - QueueEntryIterator queueListIterator = _entries.iterator(); - - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - - final long messageId = node.getMessageId(); - - if ((messageId >= fromMessageId) - && (messageId <= toMessageId) - && !node.isDeleted() - && node.acquire()) - { - node.dequeueAndDelete(storeContext); - } - - } - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - - } - - // ------ Management functions - - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException - { - QueueEntryIterator queueListIterator = _entries.iterator(); - boolean noDeletes = true; - - while (noDeletes && queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.acquire()) - { - node.dequeueAndDelete(storeContext); - noDeletes = false; - } - - } - } - - public long clearQueue(StoreContext storeContext) throws AMQException - { - - QueueEntryIterator queueListIterator = _entries.iterator(); - long count = 0; - - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.acquire()) - { - node.dequeueAndDelete(storeContext); - count++; - } - - } - return count; - - } - - public void addQueueDeleteTask(final Task task) - { - _deleteTaskList.add(task); - } - - public int delete() throws AMQException - { - if (!_deleted.getAndSet(true)) - { - - SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); - - while (subscriptionIter.advance()) - { - Subscription s = subscriptionIter.getNode().getSubscription(); - if (s != null) - { - s.queueDeleted(this); - } - } - - _bindings.deregister(); - _virtualHost.getQueueRegistry().unregisterQueue(_name); - - _managedObject.unregister(); - for (Task task : _deleteTaskList) - { - task.doTask(this); - } - - _deleteTaskList.clear(); - stop(); - } - return getMessageCount(); - - } - - public void stop() - { - if (!_stopped.getAndSet(true)) - { - ReferenceCountingExecutorService.getInstance().releaseExecutorService(); - _entries.stop(); - } - } - - public void deliverAsync() - { - _stateChangeCount.incrementAndGet(); - - Runner runner = new Runner(); - - if (_asynchronousRunner.compareAndSet(null, runner)) - { - _asyncDelivery.execute(runner); - } - } - - public void deliverAsync(Subscription sub) - { - _asyncDelivery.execute(new SubFlushRunner(sub)); - } - - private class Runner implements ReadWriteRunnable - { - public void run() - { - try - { - processQueue(this); - } - catch (AMQException e) - { - _logger.error(e); - } - - } - - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - } - - private class SubFlushRunner implements ReadWriteRunnable - { - private final Subscription _sub; - - public SubFlushRunner(Subscription sub) - { - _sub = sub; - } - - public void run() - { - boolean complete = false; - try - { - complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); - - } - catch (AMQException e) - { - _logger.error(e); - } - if (!complete && !_sub.isSuspended()) - { - _asyncDelivery.execute(this); - } - - } - - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - } - - public void flushSubscription(Subscription sub) throws AMQException - { - flushSubscription(sub, Long.MAX_VALUE); - } - - public boolean flushSubscription(Subscription sub, Long iterations) throws AMQException - { - boolean atTail = false; - - while (!sub.isSuspended() && !atTail && iterations != 0) - { - try - { - sub.getSendLock(); - atTail = attemptDelivery(sub); - if (atTail && sub.isAutoClose()) - { - unregisterSubscription(sub); - - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); - } - else if (!atTail) - { - iterations--; - } - } - finally - { - sub.releaseSendLock(); - } - } - - // if there's (potentially) more than one subscription the others will potentially not have been advanced to the - // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc - // which would give us memory "leak". - - if (!isExclusiveSubscriber()) - { - advanceAllSubscriptions(); - } - return atTail; - } - - private boolean attemptDelivery(Subscription sub) throws AMQException - { - boolean atTail = false; - boolean advanced = false; - boolean subActive = sub.isActive(); - if (subActive) - { - QueueEntry node = moveSubscriptionToNextNode(sub); - if (!(node.isAcquired() || node.isDeleted())) - { - if (!sub.isSuspended()) - { - if (sub.hasInterest(node)) - { - if (!sub.wouldSuspend(node)) - { - if (!sub.isBrowser() && !node.acquire(sub)) - { - sub.restoreCredit(node); - } - else - { - deliverMessage(sub, node); - - if (sub.isBrowser()) - { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - advanced = true; - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - } - } - - } - else // Not enough Credit for message and wouldSuspend - { - //QPID-1187 - Treat the subscription as suspended for this message - // and wait for the message to be removed to continue delivery. - subActive = false; - node.addStateChangeListener(new QueueEntryListener(sub, node)); - } - } - else - { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - } - } - } - - } - atTail = (_entries.next(node) == null) && !advanced; - } - return atTail || !subActive; - } - - protected void advanceAllSubscriptions() throws AMQException - { - SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); - while (subscriberIter.advance()) - { - SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); - Subscription sub = subNode.getSubscription(); - moveSubscriptionToNextNode(sub); - } - } - - private QueueEntry moveSubscriptionToNextNode(final Subscription sub) - throws AMQException - { - QueueEntry node = sub.getLastSeenEntry(); - - while (node != null && (node.isAcquired() || node.isDeleted() || node.expired())) - { - if (!node.isAcquired() && !node.isDeleted() && node.expired()) - { - if (node.acquire()) - { - // creating a new final store context per message seems wasteful. - final StoreContext reapingStoreContext = new StoreContext(); - node.dequeueAndDelete(reapingStoreContext); - } - } - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - break; - } - - } - return node; - } - - private void processQueue(Runnable runner) throws AMQException - { - long stateChangeCount; - long previousStateChangeCount = Long.MIN_VALUE; - boolean deliveryIncomplete = true; - - int extraLoops = 1; - Long iterations = new Long(MAX_ASYNC_DELIVERIES); - - _asynchronousRunner.compareAndSet(runner, null); - - while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) - { - // we want to have one extra loop after every subscription has reached the point where it cannot move - // further, just in case the advance of one subscription in the last loop allows a different subscription to - // move forward in the next iteration - - if (previousStateChangeCount != stateChangeCount) - { - extraLoops = 1; - } - - previousStateChangeCount = stateChangeCount; - deliveryIncomplete = _subscriptionList.size() != 0; - boolean done = true; - - SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); - //iterate over the subscribers and try to advance their pointer - while (subscriptionIter.advance()) - { - boolean closeConsumer = false; - Subscription sub = subscriptionIter.getNode().getSubscription(); - sub.getSendLock(); - try - { - if (sub != null) - { - - QueueEntry node = moveSubscriptionToNextNode(sub); - if (node != null) - { - done = attemptDelivery(sub); - } - } - if (done) - { - if (extraLoops == 0) - { - deliveryIncomplete = false; - if (sub.isAutoClose()) - { - unregisterSubscription(sub); - - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); - } - } - else - { - extraLoops--; - } - } - else - { - iterations--; - extraLoops = 1; - } - } - finally - { - sub.releaseSendLock(); - } - } - _asynchronousRunner.set(null); - } - - // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit - // therefore we should schedule this runner again (unless someone beats us to it :-) ). - if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner)) - { - _asyncDelivery.execute(runner); - } - } - - - public void checkMessageStatus() throws AMQException - { - - final StoreContext storeContext = new StoreContext(); - - QueueEntryIterator queueListIterator = _entries.iterator(); - - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.expired() && node.acquire()) - { - node.dequeueAndDelete(storeContext); - } - else - { - _managedObject.checkForNotification(node); - } - } - - } - - - public long getMemoryUsageMaximum() - { - return _entries.getMemoryUsageMaximum(); - } - - public void setMemoryUsageMaximum(long maximumMemoryUsage) - { - _entries.setMemoryUsageMaximum(maximumMemoryUsage); - } - - public long getMemoryUsageMinimum() - { - return _entries.getMemoryUsageMinimum(); - } - - public void setMemoryUsageMinimum(long minimumMemoryUsage) - { - _entries.setMemoryUsageMinimum(minimumMemoryUsage); - } - - public long getMinimumAlertRepeatGap() - { - return _minimumAlertRepeatGap; - } - - public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) - { - _minimumAlertRepeatGap = minimumAlertRepeatGap; - } - - public long getMaximumMessageAge() - { - return _maximumMessageAge; - } - - public void setMaximumMessageAge(long maximumMessageAge) - { - _maximumMessageAge = maximumMessageAge; - if (maximumMessageAge == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT); - } - } - - public long getMaximumMessageCount() - { - return _maximumMessageCount; - } - - public void setMaximumMessageCount(final long maximumMessageCount) - { - _maximumMessageCount = maximumMessageCount; - if (maximumMessageCount == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); - } - - } - - public long getMaximumQueueDepth() - { - return _maximumQueueDepth; - } - - // Sets the queue depth, the max queue size - public void setMaximumQueueDepth(final long maximumQueueDepth) - { - _maximumQueueDepth = maximumQueueDepth; - if (maximumQueueDepth == 0L) - { - _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT); - } - - } - - public long getMaximumMessageSize() - { - return _maximumMessageSize; - } - - public void setMaximumMessageSize(final long maximumMessageSize) - { - _maximumMessageSize = maximumMessageSize; - if (maximumMessageSize == 0L) - { - _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); - } - else - { - _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT); - } - } - - public Set getNotificationChecks() - { - return _notificationChecks; - } - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - private final class QueueEntryListener implements QueueEntry.StateChangeListener - { - private final QueueEntry _entry; - private final Subscription _sub; - - public QueueEntryListener(final Subscription sub, final QueueEntry entry) - { - _entry = entry; - _sub = sub; - } - - public boolean equals(Object o) - { - return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub; - } - - public int hashCode() - { - return System.identityHashCode(_entry) ^ System.identityHashCode(_sub); - } - - public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState) - { - entry.removeStateChangeListener(this); - deliverAsync(_sub); - } - } - - public List getMessagesOnTheQueue(int num) - { - return getMessagesOnTheQueue(num, 0); - } - - public List getMessagesOnTheQueue(int num, int offset) - { - ArrayList ids = new ArrayList(num); - QueueEntryIterator it = _entries.iterator(); - for (int i = 0; i < offset; i++) - { - it.advance(); - } - - for (int i = 0; i < num && !it.atTail(); i++) - { - it.advance(); - ids.add(it.getNode().getMessageId()); - } - return ids; - } - - - public String getType() - { - return getClass().getSimpleName() + "[" + getName() +"]"; - } - - public String toString() - { - return getType() + "[Owner:" + _owner + "][Durable:" + _durable + "]"; - } - - public void configure(QueueConfiguration config) - { - if (config != null) - { - setMaximumMessageAge(config.getMaximumMessageAge()); - setMaximumQueueDepth(config.getMaximumQueueDepth()); - setMaximumMessageSize(config.getMaximumMessageSize()); - setMaximumMessageCount(config.getMaximumMessageCount()); - setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); - setMemoryUsageMaximum(config.getMemoryUsageMaximum()); - setMemoryUsageMinimum(config.getMemoryUsageMinimum()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java deleted file mode 100644 index a10e332ef5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.apache.qpid.server.queue; - -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class SimpleQueueEntryList extends FlowableBaseQueueEntryList -{ - - private final QueueEntryImpl _head; - - private volatile QueueEntryImpl _tail; - - static final AtomicReferenceFieldUpdater - _tailUpdater = - AtomicReferenceFieldUpdater.newUpdater - (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail"); - - - private final AMQQueue _queue; - - static final AtomicReferenceFieldUpdater - _nextUpdater = - AtomicReferenceFieldUpdater.newUpdater - (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); - - public SimpleQueueEntryList(AMQQueue queue) - { - super(queue); - _queue = queue; - _head = new QueueEntryImpl(this); - _tail = _head; - } - - void advanceHead() - { - QueueEntryImpl head = _head.nextNode(); - while(head._next != null && head.isDeleted()) - { - - final QueueEntryImpl newhead = head.nextNode(); - if(newhead != null) - { - _nextUpdater.compareAndSet(_head,head, newhead); - } - head = _head.nextNode(); - } - } - - - public AMQQueue getQueue() - { - return _queue; - } - - - public QueueEntry add(AMQMessage message) - { - QueueEntryImpl node = new QueueEntryImpl(this, message); - - incrementCounters(node); - - for (;;) - { - QueueEntryImpl tail = _tail; - QueueEntryImpl next = tail.nextNode(); - if (tail == _tail) - { - if (next == null) - { - node.setEntryId(tail.getEntryId()+1); - if (_nextUpdater.compareAndSet(tail, null, node)) - { - _tailUpdater.compareAndSet(this, tail, node); - - return node; - } - } - else - { - _tailUpdater.compareAndSet(this,tail, next); - } - } - } - } - - - public QueueEntry next(QueueEntry node) - { - return ((QueueEntryImpl)node).getNext(); - } - - public class QueueEntryIteratorImpl implements QueueEntryIterator - { - - private QueueEntryImpl _lastNode; - - QueueEntryIteratorImpl(QueueEntryImpl startNode) - { - _lastNode = startNode; - } - - - public boolean atTail() - { - return _lastNode.nextNode() == null; - } - - public QueueEntry getNode() - { - - return _lastNode; - - } - - public boolean advance() - { - - if(!atTail()) - { - QueueEntryImpl nextNode = _lastNode.nextNode(); - while(nextNode.isDeleted() && nextNode.nextNode() != null) - { - nextNode = nextNode.nextNode(); - } - _lastNode = nextNode; - return true; - - } - else - { - return false; - } - - } - - } - - - public QueueEntryIterator iterator() - { - return new QueueEntryIteratorImpl(_head); - } - - - public QueueEntry getHead() - { - return _head; - } - - static class Factory implements QueueEntryListFactory - { - - public QueueEntryList createQueueEntryList(AMQQueue queue) - { - return new SimpleQueueEntryList(queue); - } - - } - - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java deleted file mode 100644 index 4c9fe81439..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientAMQMessage.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** A deliverable message. */ -public class TransientAMQMessage implements AMQMessage -{ - /** Used for debugging purposes. */ - protected static final Logger _log = Logger.getLogger(AMQMessage.class); - - protected ContentHeaderBody _contentHeaderBody; - - protected MessagePublishInfo _messagePublishInfo; - - protected List _contentBodies; - - protected long _arrivalTime; - - protected final Long _messageId; - - - private byte _flags = 0; - - private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; - private long _expiration; - - /** - * 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 AMQProtocolSession _protocolSession; - - private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - _channel = channel; - _protocolSession = protocolSession; - } - - public boolean hasNext() - { - return _index < (getBodyCount() - 1); - } - - public AMQDataBlock next() - { - AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(getContentChunk(++_index)); - - return new AMQFrame(_channel, cb); - } - - private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() - { - return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - private class BodyContentIterator implements Iterator - { - - private int _index = -1; - - public boolean hasNext() - { - return _index < (getBodyCount() - 1); - } - - public ContentChunk next() - { - return getContentChunk(++_index); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - /** - * Used by SimpleAMQQueueTest, TxAckTest.TestMessage, AbstractHeaderExchangeTestBase.Message - * These all need refactoring to some sort of MockAMQMessageFactory. - */ - @Deprecated - protected TransientAMQMessage(AMQMessage message) throws AMQException - { - _messageId = message.getMessageId(); - _flags = ((TransientAMQMessage) message)._flags; - _contentHeaderBody = message.getContentHeaderBody(); - _messagePublishInfo = message.getMessagePublishInfo(); - } - - /** - * Normal message creation via the MessageFactory uses this constructor - * Package scope limited as MessageFactory should be used - * - * @param messageId - * - * @see MessageFactory - */ - TransientAMQMessage(Long messageId) - { - _messageId = messageId; - } - - public String debugIdentity() - { - return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() +")"; - } - - public void setExpiration(long expiration) - { - _expiration = expiration; - } - - public long getExpiration() - { - return _expiration; - } - - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); - } - - public Iterator getContentBodyIterator() - { - return new BodyContentIterator(); - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public Long getMessageId() - { - return _messageId; - } - - - public long getSize() - { - return _contentHeaderBody.bodySize; - } - - public Object getPublisherClientInstance() - { - return _sessionIdentifier.getSessionInstance(); - } - - public Object getPublisherIdentifier() - { - return _sessionIdentifier.getSessionIdentifier(); - } - - public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) - { - _sessionIdentifier = sessionIdentifier; - } - - /** From AMQMessageHandle * */ - - public int getBodyCount() - { - return _contentBodies.size(); - } - - public ContentChunk getContentChunk(int index) - { - if (_contentBodies == null) - { - throw new RuntimeException("No ContentBody has been set"); - } - - if (index > _contentBodies.size() - 1 || index < 0) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - return _contentBodies.get(index); - } - - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) - throws AMQException - { - if (_contentBodies == null) - { - if (isLastContentBody) - { - _contentBodies = Collections.singletonList(contentChunk); - } - else - { - _contentBodies = new ArrayList(); - _contentBodies.add(contentChunk); - } - } - else - { - _contentBodies.add(contentChunk); - } - } - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public boolean isPersistent() - { - return false; - } - - public boolean isImmediate() - { - return _messagePublishInfo.isImmediate(); - } - - /** - * This is called when all the content has been received. - * - * @param storeContext - * @param messagePublishInfo - * @param contentHeaderBody @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - - if (contentHeaderBody == null) - { - throw new NullPointerException("HeaderBody cannot be null"); - } - - if (messagePublishInfo == null) - { - throw new NullPointerException("PublishInfo cannot be null"); - } - - _arrivalTime = System.currentTimeMillis(); - - - _contentHeaderBody = contentHeaderBody; - _messagePublishInfo = messagePublishInfo; - - updateHeaderAndFlags(); - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public void recoverFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = mmd.getContentHeaderBody(); - _messagePublishInfo = mmd.getMessagePublishInfo(); - - updateHeaderAndFlags(); - } - - private void updateHeaderAndFlags() - { - if (_contentHeaderBody.bodySize == 0) - { - _contentBodies = Collections.EMPTY_LIST; - } - } - - public void recoverContentBodyFrame(ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - addContentBodyFrame(null, contentChunk, isLastContentBody); - } - - - public String toString() - { - // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - // _taken + " by :" + _takenBySubcription; - - return "Message[" + debugIdentity() + "]: " + getMessageId() ; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java deleted file mode 100644 index b09283b11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * Contains data that is only used in AMQMessage transiently, e.g. while the content - * body fragments are arriving. - * - * Having this data stored in a separate class means that the AMQMessage class avoids - * the small overhead of numerous guaranteed-null references. - * - * @author Apache Software Foundation - */ -public class TransientMessageData -{ - /** - * Stored temporarily until the header has been received at which point it is used when - * constructing the handle - */ - private MessagePublishInfo _messagePublishInfo; - - /** - * Also stored temporarily. - */ - private ContentHeaderBody _contentHeaderBody; - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done - * by the message handle. - */ - private List _destinationQueues; - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public List getDestinationQueues() - { - return _destinationQueues == null ? (List) Collections.EMPTY_LIST : _destinationQueues; - } - - public void setDestinationQueues(List destinationQueues) - { - _destinationQueues = destinationQueues; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public long getBodyLengthReceived() - { - return _bodyLengthReceived; - } - - public void addBodyLength(int value) - { - _bodyLengthReceived += value; - } - - public boolean isAllContentReceived() throws AMQException - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public void addDestinationQueue(AMQQueue queue) - { - if(_destinationQueues == null) - { - _destinationQueues = new ArrayList(); - } - _destinationQueues.add(queue); - } - - public boolean isPersistent() - { - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == - BasicContentHeaderProperties.PERSISTENT; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java deleted file mode 100644 index 03cfed8533..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToFlowMessageException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public class UnableToFlowMessageException extends Exception -{ - public UnableToFlowMessageException(long messageId, Exception error) - { - super("Unable to Flow Message:"+messageId, error); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java deleted file mode 100644 index cae5bc6327..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnableToRecoverMessageException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public class UnableToRecoverMessageException extends RuntimeException -{ - public UnableToRecoverMessageException(Exception error) - { - super(error); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java deleted file mode 100644 index 295cb266b9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * UnauthorizedAccessException is a {@link RequiredDeliveryException} that represents the failure case where a message - * is published with a user id different from the one used when creating the connection . - * The AMQP status code, 403, is always used to report this condition. - * - */ - -public class UnauthorizedAccessException extends RequiredDeliveryException -{ - public UnauthorizedAccessException(String msg, AMQMessage amqMessage) - { - super(msg, amqMessage); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.ACCESS_REFUSED; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java deleted file mode 100644 index 22b4623ae1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.mina.common.IoAcceptor; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -/** - * 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 -{ - protected static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); - - private static Map _instanceMap = new HashMap(); - - private final Map, Object> _configuredObjects = new HashMap, Object>(); - - protected final ServerConfiguration _configuration; - - public static final int DEFAULT_INSTANCE = 1; - public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; - public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; - - protected final Map _acceptors = new HashMap(); - - protected ManagedObjectRegistry _managedObjectRegistry; - - protected AuthenticationManager _authenticationManager; - - protected VirtualHostRegistry _virtualHostRegistry; - - protected ACLManager _accessManager; - - protected PrincipalDatabaseManager _databaseManager; - - protected PluginManager _pluginManager; - - static - { - Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); - } - - private static class ShutdownService implements Runnable - { - public void run() - { - removeAll(); - } - } - - 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); - } - } - - /** - * Method to cleanly shutdown specified registry running in this JVM - * - * @param instanceID the instance to shutdown - */ - - public static void remove(int instanceID) - { - try - { - IApplicationRegistry instance = _instanceMap.get(instanceID); - if (instance != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); - } - instance.close(); - } - } - catch (Exception e) - { - _logger.error("Error shutting down Application Registry(" + instanceID + "): " + e, e); - } - finally - { - _instanceMap.remove(instanceID); - } - } - - /** Method to cleanly shutdown all registries currently running in this JVM */ - public static void removeAll() - { - Object[] keys = _instanceMap.keySet().toArray(); - for (Object k : keys) - { - remove((Integer) k); - } - } - - protected ApplicationRegistry(ServerConfiguration configuration) - { - _configuration = configuration; - } - - public static IApplicationRegistry getInstance() - { - return getInstance(DEFAULT_INSTANCE); - } - - public static IApplicationRegistry getInstance(int instanceID) - { - synchronized (IApplicationRegistry.class) - { - IApplicationRegistry instance = _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", e); - } - } - else - { - return instance; - } - } - } - - public void close() throws Exception - { - if (_logger.isInfoEnabled()) - { - _logger.info("Shutting down ApplicationRegistry:"+this); - } - - //Stop incomming connections - unbind(); - - //Shutdown virtualhosts - for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) - { - virtualHost.close(); - } - - // Replace above with this -// _virtualHostRegistry.close(); - -// _accessManager.close(); - -// _databaseManager.close(); - - _authenticationManager.close(); - -// _databaseManager.close(); - - // close the rmi registry(if any) started for management - if (_managedObjectRegistry != null) - { - _managedObjectRegistry.close(); - } - -// _pluginManager.close(); - } - - private void unbind() - { - synchronized (_acceptors) - { - for (InetSocketAddress bindAddress : _acceptors.keySet()) - { - IoAcceptor acceptor = _acceptors.get(bindAddress); - acceptor.unbind(bindAddress); - } - } - } - - public ServerConfiguration getConfiguration() - { - return _configuration; - } - - public void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor) - { - synchronized (_acceptors) - { - _acceptors.put(bindAddress, acceptor); - } - } - - public static void setDefaultApplicationRegistry(String clazz) - { - _APPLICATION_REGISTRY = clazz; - } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public ACLManager getAccessManager() throws ConfigurationException - { - return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); - } - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public PrincipalDatabaseManager getDatabaseManager() - { - return _databaseManager; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public PluginManager getPluginManager() - { - return _pluginManager; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java deleted file mode 100644 index 39164883f9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.io.File; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -public class ConfigurationFileApplicationRegistry extends ApplicationRegistry -{ - - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException - { - super(new ServerConfiguration(configurationURL)); - } - - public void initialise() throws Exception - { - initialiseManagedObjectRegistry(); - - _virtualHostRegistry = new VirtualHostRegistry(); - - _pluginManager = new PluginManager(_configuration.getPluginDirectory()); - - _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); - - _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _databaseManager.initialiseManagement(_configuration); - - _managedObjectRegistry.start(); - - initialiseVirtualHosts(); - - } - - private void initialiseVirtualHosts() throws Exception - { - for (String name : _configuration.getVirtualHosts()) - { - _virtualHostRegistry.registerVirtualHost(new VirtualHost(_configuration.getVirtualHostConfig(name))); - } - getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); - } - - private void initialiseManagedObjectRegistry() throws AMQException - { - if (_configuration.getManagementEnabled()) - { - _managedObjectRegistry = new JMXManagedObjectRegistry(); - } - else - { - _managedObjectRegistry = new NoopManagedObjectRegistry(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java deleted file mode 100644 index bbfda3addc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import java.util.Collection; -import java.net.InetSocketAddress; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.mina.common.IoAcceptor; - -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; - - /** - * Shutdown this Registry - * @throws Exception - //fixme needs to be made more specific - */ - void close() throws Exception; - - /** - * 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 - */ - ServerConfiguration getConfiguration(); - - ManagedObjectRegistry getManagedObjectRegistry(); - - PrincipalDatabaseManager getDatabaseManager(); - - AuthenticationManager getAuthenticationManager(); - - VirtualHostRegistry getVirtualHostRegistry(); - - ACLManager getAccessManager() throws ConfigurationException; - - PluginManager getPluginManager(); - - /** - * Register any acceptors for this registry - * @param bindAddress The address that the acceptor has been bound with - * @param acceptor The acceptor in use - */ - void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java deleted file mode 100644 index 883a41b55f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/routing/RoutingTable.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.routing; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.commons.configuration.Configuration; - -public interface RoutingTable -{ - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object. - * - * @throws Exception If any error occurs that means the store is unable to configure itself. - */ - Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws Exception If the close fails. - */ - void close() throws Exception; - - - /** - * Makes the specified exchange persistent. - * - * @param exchange The exchange to persist. - * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. - */ - void createExchange(Exchange exchange) throws AMQException; - - /** - * Removes the specified persistent exchange. - * - * @param exchange The exchange to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeExchange(Exchange exchange) throws AMQException; - - /** - * Binds the specified queue to an exchange with a routing key. - * - * @param exchange The exchange to bind to. - * @param routingKey The routing key to bind by. - * @param queue The queue to bind. - * @param args Additional parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Unbinds the specified from an exchange under a particular routing key. - * - * @param exchange The exchange to unbind from. - * @param routingKey The routing key to unbind. - * @param queue The queue to unbind. - * @param args Additonal parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue) throws AMQException; - - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * @param arguments The additional arguments to the binding - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; - - /** - * Removes the specified queue from the persistent store. - * - * @param queue The queue to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeQueue(final AMQQueue queue) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java deleted file mode 100644 index 6f7f66fad2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.SecurityConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.security.access.plugins.SimpleXML; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class ACLManager -{ - private static final Logger _logger = Logger.getLogger(ACLManager.class); - private PluginManager _pluginManager; - private Map _allSecurityPlugins = new HashMap(); - private Map _globalPlugins = new HashMap(); - private Map _hostPlugins = new HashMap(); - - public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException - { - this(configuration, manager, null); - } - - public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException - { - _pluginManager = manager; - - if (manager == null) // No plugin manager, no plugins - { - return; - } - - _allSecurityPlugins = _pluginManager.getSecurityPlugins(); - if (securityPlugin != null) - { - _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); - } - - _globalPlugins = configurePlugins(configuration); - } - - - public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - _hostPlugins = configurePlugins(hostConfig); - } - - public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - Configuration securityConfig = hostConfig.getConfiguration(); - Map plugins = new HashMap(); - Iterator keys = securityConfig.getKeys(); - Collection handledTags = new HashSet(); - while (keys.hasNext()) - { - // Splitting the string is necessary here because of the way that getKeys() returns only - // bottom level children - String tag = ((String) keys.next()).split("\\.", 2)[0]; - if (!handledTags.contains(tag)) - { - for (ACLPluginFactory plugin : _allSecurityPlugins.values()) - { - if (plugin.supportsTag(tag)) - { - _logger.warn("Plugin handling security section "+tag+" is "+plugin.getClass().getSimpleName()); - handledTags.add(tag); - plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); - } - } - } - if (!handledTags.contains(tag)) - { - _logger.warn("No plugin handled security section "+tag); - } - } - return plugins; - } - - public static Logger getLogger() - { - return _logger; - } - - private abstract class AccessCheck - { - abstract AuthzResult allowed(ACLPlugin plugin); - } - - private boolean checkAllPlugins(AccessCheck checker) - { - AuthzResult result = AuthzResult.ABSTAIN; - HashMap remainingPlugins = new HashMap(); - remainingPlugins.putAll(_globalPlugins); - for (Entry plugin : _hostPlugins.entrySet()) - { - result = checker.allowed(plugin.getValue()); - if (result == AuthzResult.DENIED) - { - // Something vetoed the access, we're done - return false; - } - else if (result == AuthzResult.ALLOWED) - { - // Remove plugin from global check list since - // host allow overrides global allow - remainingPlugins.remove(plugin.getKey()); - } - } - - for (ACLPlugin plugin : remainingPlugins.values()) - { - result = checker.allowed(plugin); - if (result == AuthzResult.DENIED) - { - return false; - } - } - return true; - } - - public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue, - final AMQShortString routingKey) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseBind(session, exch, queue, routingKey); - } - - }); - } - - public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConnect(session, virtualHost); - } - - }); - } - - public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, noAck, queue); - } - - }); - } - - public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck, - final boolean noLocal, final boolean nowait, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue); - } - - }); - } - - public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete, - final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, - final boolean passive, final AMQShortString exchangeType) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait, - passive, exchangeType); - } - - }); - } - - public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete, - final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, - final AMQShortString queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue); - } - - }); - } - - public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, queue); - } - - }); - } - - public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, exchange); - } - - }); - } - - public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory, - final AMQShortString routingKey, final Exchange e) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePublish(session, immediate, mandatory, routingKey, e); - } - - }); - } - - public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePurge(session, queue); - } - - }); - } - - public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch, - final AMQShortString routingKey, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseUnbind(session, exch, routingKey, queue); - } - - }); - } - - public void addHostPlugin(ACLPlugin aclPlugin) - { - _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java deleted file mode 100644 index 032184ec39..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public interface ACLPlugin -{ - public enum AuthzResult - { - ALLOWED, - DENIED, - ABSTAIN - } - - void setConfiguration(Configuration config) throws ConfigurationException; - - // These return true if the plugin thinks the action should be allowed, and false if not. - - AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); - - AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - - AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue); - - AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); - - AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); - - AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue); - - AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue); - - AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange); - - AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e); - - AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue); - - AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java deleted file mode 100644 index 256f093477..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -public interface ACLPluginFactory -{ - - public boolean supportsTag(String name); - - public ACLPlugin newInstance(Configuration config) throws ConfigurationException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java deleted file mode 100644 index d722da4ae0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessResult -{ - public enum AccessStatus - { - GRANTED, REFUSED - } - - private String _authorizer; - private AccessStatus _status; - - public AccessResult(ACLPlugin authorizer, AccessStatus status) - { - _status = status; - _authorizer = authorizer.getClass().getSimpleName(); - } - - public void setAuthorizer(ACLPlugin authorizer) - { - _authorizer += authorizer.getClass().getSimpleName(); - } - - public String getAuthorizer() - { - return _authorizer; - } - - public void setStatus(AccessStatus status) - { - _status = status; - } - - public AccessStatus getStatus() - { - return _status; - } - - public void addAuthorizer(ACLPlugin accessManager) - { - _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer; - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java deleted file mode 100644 index 1b79a5a0e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessRights -{ - public enum Rights - { - ANY, - READ, - WRITE, - READWRITE - } - - Rights _right; - - public AccessRights(Rights right) - { - _right = right; - } - - public boolean allows(Rights rights) - { - switch (_right) - { - case ANY: - return (rights.equals(Rights.WRITE) - || rights.equals(Rights.READ) - || rights.equals(Rights.READWRITE) - || rights.equals(Rights.ANY)); - case READ: - return rights.equals(Rights.READ) || rights.equals(Rights.ANY); - case WRITE: - return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); - case READWRITE: - return true; - } - return false; - } - - public Rights getRights() - { - return _right; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java deleted file mode 100644 index f51cf24caa..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public interface Accessable -{ - void setAccessableName(String name); - String getAccessableName(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java deleted file mode 100644 index 9527120f30..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.apache.qpid.server.security.access; - -public class AuthorizationManager -{ - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java deleted file mode 100644 index b65b0cdc6c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; - -public enum Permission -{ - CONSUME, - PUBLISH, - CREATEQUEUE, - CREATEEXCHANGE, - ACCESS, - BIND, - UNBIND, - DELETE, - PURGE -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java deleted file mode 100755 index f852514444..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.QueueBindBody; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.ExchangeDeclareBody; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.exchange.Exchange; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class PrincipalPermissions -{ - - private static final Object CONSUME_QUEUES_KEY = new Object(); - private static final Object CONSUME_TEMPORARY_KEY = new Object(); - private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object(); - - private static final Object CREATE_QUEUES_KEY = new Object(); - private static final Object CREATE_EXCHANGES_KEY = new Object(); - - private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); - private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); - private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); - - private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object(); - private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); - - private static final int PUBLISH_EXCHANGES_KEY = 0; - - private Map _permissions; - - private String _user; - - - public PrincipalPermissions(String user) - { - _user = user; - _permissions = new ConcurrentHashMap(); - } - - /** - * - * @param permission the type of permission to check - * - * @param parameters vararg depending on what permission was passed in - * ACCESS: none - * BIND: none - * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly - * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey - * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class - * DELETE: none - * PUBLISH: Exchange exchange, AMQShortString routingKey - * PURGE: none - * UNBIND: none - */ - public void grant(Permission permission, Object... parameters) - { - switch (permission) - { - case ACCESS: - break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS - case BIND: - break; // All the details are currently included in the create setup. - case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly - Map consumeRights = (Map) _permissions.get(permission); - - if (consumeRights == null) - { - consumeRights = new ConcurrentHashMap(); - _permissions.put(permission, consumeRights); - } - - //if we have parametsre - if (parameters.length > 0) - { - AMQShortString queueName = (AMQShortString) parameters[0]; - Boolean temporary = (Boolean) parameters[1]; - Boolean ownQueueOnly = (Boolean) parameters[2]; - - if (temporary) - { - consumeRights.put(CONSUME_TEMPORARY_KEY, true); - } - else - { - consumeRights.put(CONSUME_TEMPORARY_KEY, false); - } - - if (ownQueueOnly) - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); - } - else - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); - } - - - LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); - if (queues == null) - { - queues = new LinkedList(); - consumeRights.put(CONSUME_QUEUES_KEY, queues); - } - - if (queueName != null) - { - queues.add(queueName); - } - } - - - break; - case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName - // , AMQShortString exchangeName , AMQShortString routingKey - - Map createRights = (Map) _permissions.get(permission); - - if (createRights == null) - { - createRights = new ConcurrentHashMap(); - _permissions.put(permission, createRights); - - } - - //The existence of the empty map mean permission to all. - if (parameters.length == 0) - { - return; - } - - Boolean temporary = (Boolean) parameters[0]; - - AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; - AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; - //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; - - // Get the queues map - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - if (create_queues == null) - { - create_queues = new ConcurrentHashMap(); - createRights.put(CREATE_QUEUES_KEY, create_queues); - } - - //Allow all temp queues to be created - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); - - //Create empty list of queues - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - if (create_queues_queues == null) - { - create_queues_queues = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); - } - - // We are granting CREATE rights to all temporary queues only - if (parameters.length == 1) - { - return; - } - - // if we have a queueName then we need to store any associated exchange / rk bindings - if (queueName != null) - { - Map queue = (Map) create_queues_queues.get(queueName); - if (queue == null) - { - queue = new ConcurrentHashMap(); - create_queues_queues.put(queueName, queue); - } - - if (exchangeName != null) - { - queue.put(exchangeName, routingKey); - } - - //If no exchange is specified then the presence of the queueName in the map says any exchange is ok - } - - // Store the exchange that we are being granted rights to. This will be used as part of binding - - //Lookup the list of exchanges - Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - if (create_queues_exchanges == null) - { - create_queues_exchanges = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); - } - - //if we have an exchange - if (exchangeName != null) - { - //Retrieve the list of permitted exchanges. - Map exchanges = (Map) create_queues_exchanges.get(exchangeName); - - if (exchanges == null) - { - exchanges = new ConcurrentHashMap(); - create_queues_exchanges.put(exchangeName, exchanges); - } - - //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY - exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); - - //Store the binding details of queue/rk for this exchange. - if (queueName != null) - { - //Retrieve the list of permitted routingKeys. - Map rKeys = (Map) exchanges.get(exchangeName); - - if (rKeys == null) - { - rKeys = new ConcurrentHashMap(); - exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); - } - - rKeys.put(queueName, routingKey); - } - } - break; - case CREATEEXCHANGE: - // Parameters AMQShortString exchangeName , AMQShortString Class - Map rights = (Map) _permissions.get(permission); - if (rights == null) - { - rights = new ConcurrentHashMap(); - _permissions.put(permission, rights); - } - - Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); - if (create_exchanges == null) - { - create_exchanges = new ConcurrentHashMap(); - rights.put(CREATE_EXCHANGES_KEY, create_exchanges); - } - - //Should perhaps error if parameters[0] is null; - AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; - AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); - - //Store the exchangeName / class mapping if the mapping is null - rights.put(name, className); - break; - case DELETE: - break; - - case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - publishRights = new ConcurrentHashMap(); - _permissions.put(permission, publishRights); - } - - if (parameters == null || parameters.length == 0) - { - //If we have no parameters then allow publish to all destinations - // this is signified by having a null value for publish_exchanges - } - else - { - Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - if (publish_exchanges == null) - { - publish_exchanges = new ConcurrentHashMap(); - publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); - } - - - HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); - - // Check to see if we have a routing key - if (parameters.length == 2) - { - if (routingKeys == null) - { - routingKeys = new HashSet(); - } - //Add routing key to permitted publish destinations - routingKeys.add(parameters[1]); - } - - // Add the updated routingkey list or null if all values allowed - publish_exchanges.put(parameters[0], routingKeys); - } - break; - case PURGE: - break; - case UNBIND: - break; - } - - } - - /** - * - * @param permission the type of permission to check - * - * @param parameters vararg depending on what permission was passed in - * ACCESS: none - * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey - * CONSUME: AMQQueue queue - * CREATEQUEUE: Boolean autodelete, AMQShortString name - * CREATEEXCHANGE: AMQShortString exchangeName - * DELETE: none - * PUBLISH: Exchange exchange, AMQShortString routingKey - * PURGE: none - * UNBIND: none - */ - public AuthzResult authorise(Permission permission, Object... parameters) - { - - switch (permission) - { - case ACCESS: - return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it. - // The existence of this user specific PP can be validated in the map SimpleXML maintains. - case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey - - Exchange exchange = (Exchange) parameters[1]; - - AMQQueue bind_queueName = (AMQQueue) parameters[2]; - AMQShortString routingKey = (AMQShortString) parameters[3]; - - //Get all Create Rights for this user - Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); - - //Look up the Queue Creation Rights - Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues - Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); - - // Check and see if we have a queue white list to check - if (bind_create_queues_queues != null) - { - //There a white list for queues - Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); - - if (exchangeDetails == null) //Then all queue can be bound to all exchanges. - { - return AuthzResult.ALLOWED; - } - - // Check to see if we have a white list of routingkeys to check - Map rkeys = (Map) exchangeDetails.get(exchange.getName()); - - // if keys is null then any rkey is allowed on this exchange - if (rkeys == null) - { - // There is no routingkey white list - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = rkeys.keySet().iterator(); - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - if (rkey.endsWith("*")) - { - matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); - } - else - { - matched = routingKey.equals(rkey); - } - } - - - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - - } - else - { - //There a is no white list for queues - - // So can allow all queues to be bound - // but we should first check and see if we have a temp queue and validate that we are allowed - // to bind temp queues. - - //Check to see if we have a temporary queue - if (bind_queueName.isAutoDelete()) - { - // Check and see if we have an exchange white list. - Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - // If the exchange exists then we must check to see if temporary queues are allowed here - if (bind_exchanges != null) - { - // Check to see if the requested exchange is allowed. - Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); - - return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - //no white list so all allowed, drop through to return true below. - } - - // not a temporary queue and no white list so all allowed. - return AuthzResult.ALLOWED; - } - - case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name - - Map createRights = (Map) _permissions.get(permission); - - // If there are no create rights then deny request - if (createRights == null) - { - return AuthzResult.DENIED; - } - - //Look up the Queue Creation Rights - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues allowed to be created - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - - AMQShortString queueName = (AMQShortString) parameters[1]; - Boolean autoDelete = (Boolean) parameters[0]; - - if (autoDelete)// we have a temporary queue - { - return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - // If there is a white list then check - if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } - - } - case CREATEEXCHANGE: - Map rights = (Map) _permissions.get(permission); - - AMQShortString exchangeName = (AMQShortString) parameters[0]; - - // If the exchange list is doesn't exist then all is allowed else - // check the valid exchanges - if (rights == null || rights.containsKey(exchangeName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } - case CONSUME: // Parameters : AMQQueue - - if (parameters.length == 1 && parameters[0] instanceof AMQQueue) - { - AMQQueue queue = ((AMQQueue) parameters[0]); - Map queuePermissions = (Map) _permissions.get(permission); - - List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); - - Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); - Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); - - // If user is allowed to publish to temporary queues and this is a temp queue then allow it. - if (temporayQueues) - { - if (queue.isAutoDelete()) - // This will allow consumption from any temporary queue including ones not owned by this user. - // Of course the exclusivity will not be broken. - { - // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } - - // if queues are white listed then ensure it is ok - if (queues != null) - { - // if no queues are listed then ALL are ok othereise it must be specified. - if (ownQueuesOnly) - { - if (queue.getOwner().equals(_user)) - { - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } - - // If we are - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - - // Can't authenticate without the right parameters - return AuthzResult.DENIED; - case DELETE: - break; - - case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - return AuthzResult.DENIED; - } - - Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - // Having no exchanges listed gives full publish rights to all exchanges - if (exchanges == null) - { - return AuthzResult.ALLOWED; - } - // Otherwise exchange must be listed in the white list - - // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) - { - return AuthzResult.DENIED; - } - else - { - - // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); - - // Having no routingKeys in the map then all are allowed. - if (routingKeys == null) - { - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = routingKeys.iterator(); - - - AMQShortString publishRKey = (AMQShortString)parameters[1]; - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - - if (rkey.endsWith("*")) - { - matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); - } - else - { - matched = publishRKey.equals(rkey); - } - } - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - case PURGE: - break; - case UNBIND: - break; - - } - - return AuthzResult.DENIED; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java deleted file mode 100644 index 13151a66b8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class VirtualHostAccess -{ - private String _vhost; - private AccessRights _rights; - - public VirtualHostAccess(String vhostaccess) - { - //format () - int hostend = vhostaccess.indexOf('('); - - if (hostend == -1) - { - throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); - } - - _vhost = vhostaccess.substring(0, hostend); - - String rights = vhostaccess.substring(hostend); - - if (rights.indexOf('r') != -1) - { - if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.READWRITE); - } - else - { - _rights = new AccessRights(AccessRights.Rights.READ); - } - } - else if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.WRITE); - } - } - - public AccessRights getAccessRights() - { - return _rights; - } - - public String getVirtualHost() - { - return _vhost; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java deleted file mode 100644 index 121f571abe..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.management; - -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.access.management.UserManagement; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; - -import javax.management.JMException; -import javax.management.remote.JMXPrincipal; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.auth.Subject; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.FileOutputStream; -import java.util.Properties; -import java.util.List; -import java.util.Enumeration; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.AccessControlContext; -import java.security.AccessController; - -/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ -@MBeanDescription("User Management Interface") -public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement -{ - - private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); - - private PrincipalDatabase _principalDatabase; - private Properties _accessRights; - private File _accessFile; - - private ReentrantLock _accessRightsUpdate = new ReentrantLock(); - - // Setup for the TabularType - static TabularType _userlistDataType; // Datatype for representing User Lists - - static CompositeType _userDataType; // Composite type for representing User - static String[] _userItemNames = {"Username", "read", "write", "admin"}; - - static - { - String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", - "Management Console Write Permission", "Management Console Admin Permission"}; - - OpenType[] userItemTypes = new OpenType[4]; // User item types. - userItemTypes[0] = SimpleType.STRING; // For Username - userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read - userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write - userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin - String[] userDataIndex = {_userItemNames[0]}; - - try - { - _userDataType = - new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); - - _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); - } - catch (OpenDataException e) - { - _logger.error("Tabular data setup for viewing users incorrect."); - _userlistDataType = null; - } - } - - - public AMQUserManagementMBean() throws JMException - { - super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); - } - - public String getObjectInstanceName() - { - return UserManagement.TYPE; - } - - public boolean setPassword(String username, char[] password) - { - try - { - //delegate password changes to the Principal Database - return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to set password of non-existant user'" + username + "'"); - return false; - } - } - - public boolean setRights(String username, boolean read, boolean write, boolean admin) - { - - Object oldRights = null; - if ((oldRights =_accessRights.get(username)) == null) - { - // If the user doesn't exist in the access rights file check that they at least have an account. - if (_principalDatabase.getUser(username) == null) - { - return false; - } - } - - try - { - _accessRightsUpdate.lock(); - - // Update the access rights - if (admin) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); - } - else - { - if (read | write) - { - if (read) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); - } - if (write) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); - } - } - else - { - _accessRights.remove(username); - } - } - - //save the rights file - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - - //the rights file was not successfully saved, restore user rights to previous value - _logger.warn("Reverting attempted rights update for user'" + username + "'"); - if (oldRights != null) - { - _accessRights.put(username, oldRights); - } - else - { - _accessRights.remove(username); - } - - return false; - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - - return true; - } - - public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) - { - if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) - { - if (!setRights(username, read, write, admin)) - { - //unable to set rights for user, remove account - try - { - _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); - } - catch (AccountNotFoundException e) - { - //ignore - } - return false; - } - else - { - return true; - } - } - - return false; - } - - public boolean deleteUser(String username) - { - try - { - if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) - { - try - { - _accessRightsUpdate.lock(); - - _accessRights.remove(username); - - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - return false; - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); - return false; - } - - return true; - } - - public boolean reloadData() - { - try - { - loadAccessFile(); - _principalDatabase.reload(); - } - catch (ConfigurationException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - catch (IOException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - // Reload successful - return true; - } - - - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") - public TabularData viewUsers() - { - // Table of users - // Username(string), Access rights Read,Write,Admin(bool,bool,bool) - - if (_userlistDataType == null) - { - _logger.warn("TabluarData not setup correctly"); - return null; - } - - List users = _principalDatabase.getUsers(); - - TabularDataSupport userList = new TabularDataSupport(_userlistDataType); - - try - { - // Create the tabular list of message header contents - for (Principal user : users) - { - // Create header attributes list - - String rights = (String) _accessRights.get(user.getName()); - - Boolean read = false; - Boolean write = false; - Boolean admin = false; - - if (rights != null) - { - read = rights.equals(MBeanInvocationHandlerImpl.READONLY) - || rights.equals(MBeanInvocationHandlerImpl.READWRITE); - write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); - admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); - } - - Object[] itemData = {user.getName(), read, write, admin}; - CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); - userList.put(messageData); - } - } - catch (OpenDataException e) - { - _logger.warn("Unable to create user list due to :" + e); - return null; - } - - return userList; - } - - /*** Broker Methods **/ - - /** - * setPrincipalDatabase - * - * @param database set The Database to use for user lookup - */ - public void setPrincipalDatabase(PrincipalDatabase database) - { - _principalDatabase = database; - } - - /** - * setAccessFile - * - * @param accessFile the file to use for updating. - * - * @throws java.io.IOException If the file cannot be accessed - * @throws org.apache.commons.configuration.ConfigurationException - * if checks on the file fail. - */ - public void setAccessFile(String accessFile) throws IOException, ConfigurationException - { - if (accessFile != null) - { - _accessFile = new File(accessFile); - if (!_accessFile.exists()) - { - throw new ConfigurationException("'" + _accessFile + "' does not exist"); - } - - if (!_accessFile.canRead()) - { - throw new ConfigurationException("Cannot read '" + _accessFile + "'."); - } - - if (!_accessFile.canWrite()) - { - _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); - } - - loadAccessFile(); - } - else - { - _logger.warn("Access rights file specified is null. Access rights not changed."); - } - } - - private void loadAccessFile() throws IOException, ConfigurationException - { - if(_accessFile == null) - { - _logger.error("No jmx access rights file has been specified."); - return; - } - - if(_accessFile.exists()) - { - try - { - _accessRightsUpdate.lock(); - - Properties accessRights = new Properties(); - accessRights.load(new FileInputStream(_accessFile)); - checkAccessRights(accessRights); - setAccessRights(accessRights); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - else - { - _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); - } - } - - private void checkAccessRights(Properties accessRights) - { - Enumeration values = accessRights.propertyNames(); - - while (values.hasMoreElements()) - { - String user = (String) values.nextElement(); - - if (_principalDatabase.getUser(user) == null) - { - _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); - } - } - } - - private void saveAccessFile() throws IOException - { - try - { - _accessRightsUpdate.lock(); - - // Create temporary file - File tmp = File.createTempFile(_accessFile.getName(), ".tmp"); - - FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); - output.close(); - - // Rename new file to main file - tmp.renameTo(_accessFile); - - // delete tmp - tmp.delete(); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - - } - - private String getCurrentJMXUser() - { - AccessControlContext acc = AccessController.getContext(); - - Subject subject = Subject.getSubject(acc); - if (subject == null) - { - return "Unknown user, authentication Subject was null"; - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - return "Unknown user principals were null"; - } - - Principal principal = principals.iterator().next(); - return principal.getName(); - } - - /** - * user=read user=write user=readwrite user=admin - * - * @param accessRights The properties list of access rights to process - */ - private void setAccessRights(Properties accessRights) - { - _logger.debug("Setting Access Rights:" + accessRights); - _accessRights = accessRights; - MBeanInvocationHandlerImpl.setAccessRights(_accessRights); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java deleted file mode 100644 index 9fcdd4cd17..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.management; - -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.AMQException; - -import javax.management.openmbean.TabularData; -import javax.management.openmbean.CompositeData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.io.IOException; - -public interface UserManagement -{ - - String TYPE = "UserManagement"; - int VERSION = 2; - - //********** Operations *****************// - /** - * set password for user - * - * @param username The username to create - * @param password The password for the user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setPassword", description = "Set password for user.", - impact = MBeanOperationInfo.ACTION) - boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password); - - /** - * set rights for users with given details - * - * @param username The username to create - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setRights", description = "Set access rights for user.", - impact = MBeanOperationInfo.ACTION) - boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * Create users with given details - * - * @param username The username to create - * @param password The password for the user - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "createUser", description = "Create new user from system.", - impact = MBeanOperationInfo.ACTION) - boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * View users returns all the users that are currently available to the system. - * - * @param username The user to delete - * - * @return The result of the operation - */ - @MBeanOperation(name = "deleteUser", description = "Delete user from system.", - impact = MBeanOperationInfo.ACTION) - boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); - - - /** - * Reload the date from disk - * - * @return The result of the operation - */ - @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", - impact = MBeanOperationInfo.ACTION) - boolean reloadData(); - - /** - * View users returns all the users that are currently available to the system. - * - * @return a table of users data (Username, read, write, admin) - */ - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", - impact = MBeanOperationInfo.INFO) - TabularData viewUsers(); - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java deleted file mode 100644 index 682135bc25..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHost; - -/** - * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. - */ -public abstract class AbstractACLPlugin implements ACLPlugin -{ - - private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; - - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, - AMQShortString routingKey) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) - { - // TODO Auto-generated method stub - return null; - } - - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, - boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, - AMQQueue queue) - { - return DEFAULT_ANSWER; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java deleted file mode 100644 index 4af178574b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -public class AllowAll extends BasicACLPlugin -{ - - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return false; - } - - public ACLPlugin newInstance(Configuration config) - { - return new AllowAll(); - } - }; - - public String getPluginName() - { - return this.getClass().getSimpleName(); - } - - @Override - protected AuthzResult getResult() - { - // Always allow - return AuthzResult.ALLOWED; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java deleted file mode 100644 index f7e537b02b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public abstract class BasicACLPlugin implements ACLPlugin -{ - - // Returns true or false if the plugin should authorise or deny the request - protected abstract AuthzResult getResult(); - - @Override - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, - AMQQueue queue, AMQShortString routingKey) - { - return getResult(); - } - - @Override - public AuthzResult authoriseConnect(AMQProtocolSession session, - VirtualHost virtualHost) - { - return getResult(); - } - - @Override - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, - AMQQueue queue) - { - return getResult(); - } - - @Override - public AuthzResult authoriseConsume(AMQProtocolSession session, - boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, - AMQQueue queue) - { - return getResult(); - } - - @Override - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, - boolean autoDelete, boolean durable, AMQShortString exchangeName, - boolean internal, boolean nowait, boolean passive, - AMQShortString exchangeType) - { - return getResult(); - } - - @Override - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, - boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue) - { - return getResult(); - } - - @Override - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) - { - return getResult(); - } - - @Override - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) - { - return getResult(); - } - - @Override - public AuthzResult authorisePublish(AMQProtocolSession session, - boolean immediate, boolean mandatory, AMQShortString routingKey, - Exchange e) - { - return getResult(); - } - - @Override - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) - { - return getResult(); - } - - @Override - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, - AMQShortString routingKey, AMQQueue queue) - { - return getResult(); - } - - @Override - public void setConfiguration(Configuration config) - { - // no-op - } - - public boolean supportsTag(String name) - { - // This plugin doesn't support any tags - return false; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java deleted file mode 100644 index 26a76c9af1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Permission; - -public class DenyAll extends BasicACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return false; - } - - public ACLPlugin newInstance(Configuration config) - { - return new DenyAll(); - } - }; - - public AccessResult authorise(AMQProtocolSession session, - Permission permission, AMQMethodBody body, Object... parameters) - throws AMQConnectionException - { - - if (ACLManager.getLogger().isInfoEnabled()) - { - ACLManager.getLogger().info( - "Denying user:" + session.getAuthorizedID()); - } - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, - "DenyAll Plugin"); - } - - public String getPluginName() - { - return getClass().getSimpleName(); - } - - @Override - protected AuthzResult getResult() - { - // Always deny - return AuthzResult.DENIED; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java deleted file mode 100644 index fc1bc048d4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import java.util.Collection; -import java.util.HashSet; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -/** - * - * Used to suppress warnings in legacy config files that have things in which aren't handled by a plugin directly. - * - */ -public class LegacyAccessPlugin extends BasicACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - private Collection maskedTags = new HashSet(); - { - maskedTags.add("principal-databases"); - maskedTags.add("access"); - maskedTags.add("msg-auth"); - maskedTags.add("false"); - maskedTags.add("jmx"); - } - - public boolean supportsTag(String name) - { - return maskedTags .contains(name); - } - - public ACLPlugin newInstance(Configuration config) - { - return new LegacyAccessPlugin(); - } - }; - - public String getPluginName() - { - return getClass().getSimpleName(); - } - - @Override - protected AuthzResult getResult() - { - // Always abstain - return AuthzResult.ABSTAIN; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java deleted file mode 100644 index 2cc0c530de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicPublishBody; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.security.access.PrincipalPermissions; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * This uses the default - */ -public class SimpleXML implements ACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return name.startsWith("access_control_list"); - } - - public ACLPlugin newInstance(Configuration config) - { - SimpleXML plugin = new SimpleXML(); - plugin.setConfiguration(config); - return plugin; - } - }; - - private Map _users; - private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); - - public SimpleXML() - { - _users = new ConcurrentHashMap(); - } - - public void setConfiguration(Configuration config) - { - processConfig(config); - } - - private void processConfig(Configuration config) - { - processPublish(config); - - processConsume(config); - - processCreate(config); - } - - /** - * Publish format takes Exchange + Routing Key Pairs - * - * @param config - * XML Configuration - */ - private void processPublish(Configuration config) - { - Configuration publishConfig = config.subset("access_control_list.publish"); - - // Process users that have full publish permission - String[] users = publishConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.PUBLISH, user); - } - - // Process exchange limited users - int exchangeCount = 0; - Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - // Get Exchange Name - AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); - - // Get Routing Keys - int keyCount = 0; - Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); - - while (!routingkeyConfig.isEmpty()) - { - // Get RoutingKey Value - AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); - - // Apply Exchange + RoutingKey permissions to Users - users = routingkeyConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); - } - - // Apply permissions to Groups - - // Check for more configs - keyCount++; - routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); - } - - // Apply Exchange wide permissions to Users - users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); - - for (String user : users) - { - grant(Permission.PUBLISH, user, exchangeName); - } - - // Apply permissions to Groups - exchangeCount++; - exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - } - - private void grant(Permission permission, String user, Object... parameters) - { - PrincipalPermissions permissions = _users.get(user); - - if (permissions == null) - { - permissions = new PrincipalPermissions(user); - } - - _users.put(user, permissions); - permissions.grant(permission, parameters); - } - - private void processConsume(Configuration config) - { - Configuration consumeConfig = config.subset("access_control_list.consume"); - - // Process queue limited users - int queueCount = 0; - Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); - - while (!queueConfig.isEmpty()) - { - // Get queue Name - AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); - // if there is no name then there may be a temporary element - boolean temporary = queueConfig.containsKey("temporary"); - boolean ownQueues = queueConfig.containsKey("own_queues"); - - // Process permissions for this queue - String[] users = queueConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.CONSUME, user, queueName, temporary, ownQueues); - } - - // See if we have another config - queueCount++; - queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); - } - - // Process users that have full consume permission - String[] users = consumeConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.CONSUME, user); - } - } - - private void processCreate(Configuration config) - { - Configuration createConfig = config.subset("access_control_list.create"); - - // Process create permissions for queue creation - int queueCount = 0; - Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); - - while (!queueConfig.isEmpty()) - { - // Get queue Name - AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); - - // if there is no name then there may be a temporary element - boolean temporary = queueConfig.containsKey("temporary"); - - int exchangeCount = 0; - Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - - AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); - AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); - - // Process permissions for this queue - String[] users = exchangeConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.CREATEEXCHANGE, user, exchange); - grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange - .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); - } - - // See if we have another config - exchangeCount++; - exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - - // Process users that are not bound to an exchange - String[] users = queueConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.CREATEQUEUE, user, temporary, queueName); - } - - // See if we have another config - queueCount++; - queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); - } - - // Process create permissions for exchange creation - int exchangeCount = 0; - Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); - AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); - - // Process permissions for this queue - String[] users = exchangeConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.CREATEEXCHANGE, user, exchange, clazz); - } - - // See if we have another config - exchangeCount++; - exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - - // Process users that have full create permission - String[] users = createConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.CREATEEXCHANGE, user); - grant(Permission.CREATEQUEUE, user); - } - - } - - public String getPluginName() - { - return "Simple"; - } - - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.BIND, null, exch, queue, routingKey); - } - } - - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.ACCESS); - } - } - - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CONSUME, queue); - } - } - - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue) - { - return authoriseConsume(session, noAck, queue); - } - - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CREATEEXCHANGE, exchangeName); - } - } - - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CREATEQUEUE, autoDelete, queue); - } - } - - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.DELETE); - } - } - - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.DELETE); - } - } - - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.PUBLISH, e, routingKey); - } - } - - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.PURGE); - } - } - - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.UNBIND); - } - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java deleted file mode 100644 index a1a399e5bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins.network; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -public class FirewallFactory implements ACLPluginFactory -{ - - @Override - public ACLPlugin newInstance(Configuration config) throws ConfigurationException - { - FirewallPlugin plugin = new FirewallPlugin(); - plugin.setConfiguration(config); - return plugin; - } - - @Override - public boolean supportsTag(String name) - { - return name.equals("firewall"); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java deleted file mode 100644 index 85026121ab..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins.network; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Pattern; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.util.NetMatcher; - -public class FirewallPlugin extends AbstractACLPlugin -{ - - public class FirewallPluginException extends Exception {} - - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return name.startsWith("firewall"); - } - - public ACLPlugin newInstance(Configuration config) throws ConfigurationException - { - FirewallPlugin plugin = new FirewallPlugin(); - plugin.setConfiguration(config); - return plugin; - } - }; - - public class FirewallRule - { - - private static final long DNS_TIMEOUT = 30000; - private AuthzResult _access; - private NetMatcher _network; - private Pattern[] _hostnamePatterns; - - public FirewallRule(String access, List networks, List hostnames) - { - _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - - if (networks != null && networks.size() > 0) - { - String[] networkStrings = objListToStringArray(networks); - _network = new NetMatcher(networkStrings); - } - - if (hostnames != null && hostnames.size() > 0) - { - int i = 0; - _hostnamePatterns = new Pattern[hostnames.size()]; - for (String hostname : objListToStringArray(hostnames)) - { - _hostnamePatterns[i++] = Pattern.compile(hostname); - } - } - - } - - private String[] objListToStringArray(List objList) - { - String[] networkStrings = new String[objList.size()]; - int i = 0; - for (Object network : objList) - { - networkStrings[i++] = (String) network; - } - return networkStrings; - } - - public boolean match(InetAddress remote) throws FirewallPluginException - { - if (_hostnamePatterns != null) - { - String hostname = getHostname(remote); - if (hostname == null) - { - throw new FirewallPluginException(); - } - for (Pattern pattern : _hostnamePatterns) - { - if (pattern.matcher(hostname).matches()) - { - return true; - } - } - return false; - } - else - { - return _network.matchInetNetwork(remote); - } - } - - /** - * @param remote the InetAddress to look up - * @return the hostname, null if not found or takes longer than 30s to find - */ - private String getHostname(final InetAddress remote) - { - final String[] hostname = new String[]{null}; - final AtomicBoolean done = new AtomicBoolean(false); - // Spawn thread - Thread thread = new Thread(new Runnable() - { - public void run() - { - hostname[0] = remote.getCanonicalHostName(); - done.getAndSet(true); - synchronized (done) - { - done.notifyAll(); - } - } - }); - - thread.run(); - long endTime = System.currentTimeMillis() + DNS_TIMEOUT; - - while (System.currentTimeMillis() < endTime && !done.get()) - { - try - { - synchronized (done) - { - done.wait(endTime - System.currentTimeMillis()); - } - } - catch (InterruptedException e) - { - // Check the time and if necessary sleep for a bit longer - } - } - return hostname[0]; - } - - public AuthzResult getAccess() - { - return _access; - } - - } - - private AuthzResult _default = AuthzResult.ABSTAIN; - private FirewallRule[] _rules; - - @Override - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) - { - if (!(session instanceof AMQMinaProtocolSession)) - { - return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which - // mean MINA right now - } - - InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session); - - if (addr == null) - { - return AuthzResult.ABSTAIN; // Not an Inet socket on the other end - } - - boolean match = false; - for (FirewallRule rule : _rules) - { - try - { - match = rule.match(addr); - } - catch (FirewallPluginException e) - { - return AuthzResult.DENIED; - } - if (match) - { - return rule.getAccess(); - } - } - return _default; - - } - - private InetAddress getInetAdressFromMinaSession(AMQMinaProtocolSession session) - { - SocketAddress remote = session.getIOSession().getRemoteAddress(); - if (remote instanceof InetSocketAddress) - { - return ((InetSocketAddress) remote).getAddress(); - } - else - { - return null; - } - } - - @Override - public void setConfiguration(Configuration config) throws ConfigurationException - { - // Get default action - String defaultAction = config.getString("[@default-action]"); - if (defaultAction == null) - { - _default = AuthzResult.ABSTAIN; - } - else if (defaultAction.toLowerCase().equals("allow")) - { - _default = AuthzResult.ALLOWED; - } - else - { - _default = AuthzResult.DENIED; - } - CompositeConfiguration finalConfig = new CompositeConfiguration(config); - - List subFiles = config.getList("firewall.xml[@fileName]"); - for (Object subFile : subFiles) - { - finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); - } - - // all rules must have an access attribute - int numRules = finalConfig.getList("rule[@access]").size(); - _rules = new FirewallRule[numRules]; - for (int i = 0; i < numRules; i++) - { - FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), finalConfig.getList("rule(" - + i + ")[@network]"), finalConfig.getList("rule(" + i + ")[@hostname]")); - _rules[i] = rule; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java deleted file mode 100644 index 3f846b9dd0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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; - -public class AuthenticationResult -{ - public enum AuthenticationStatus - { - SUCCESS, CONTINUE, ERROR - } - - public AuthenticationStatus status; - public byte[] challenge; - - private Exception cause; - - public AuthenticationResult(AuthenticationStatus status) - { - this(null, status, null); - } - - public AuthenticationResult(byte[] challenge, AuthenticationStatus status) - { - this(challenge, status, null); - } - - public AuthenticationResult(AuthenticationStatus error, Exception cause) - { - this(null, error, cause); - } - - public AuthenticationResult(byte[] challenge, AuthenticationStatus status, Exception cause) - { - this.status = status; - this.challenge = challenge; - this.cause = cause; - } - - public Exception getCause() - { - return cause; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java deleted file mode 100644 index 3c211746e3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; -import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; -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 Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map _saslServers; - - AMQUserManagementMBean _mbean; - public static final String DEFAULT_ENCODING = "utf-8"; - private Map _users = new HashMap(); - private ReentrantLock _userUpdate = new ReentrantLock(); - - public Base64MD5PasswordFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for MD5 Password file. - */ - - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); - cram.initialise(this); - _saslServers.put(cram.getMechanismName(), cram); - - //fixme The PDs should setup a PD Mangement MBean -// try -// { -// _mbean = new AMQUserManagementMBean(); -// _mbean.setPrincipalDatabase(this); -// } -// catch (JMException e) -// { -// _logger.warn("User management disabled as unable to create MBean:" + e); -// } - } - - public void setPasswordFile(String passwordFile) throws IOException - { - 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."); - } - - loadPasswordFile(); - } - - /** - * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile - * If you want to change the password for a user, use updatePassword instead. - * - * @param principal The Principal to set the password for - * @param callback The PasswordCallback to call setPassword on - * - * @throws AccountNotFoundException If the Principal cannont be found in this Database - */ - public void setPassword(Principal principal, PasswordCallback callback) throws 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); - } - } - - /** - * Used to verify that the presented Password is correct. Currently only used by Management Console - * - * @param principal The principal to authenticate - * @param password The password to check - * - * @return true if password is correct - * - * @throws AccountNotFoundException if the principal cannot be found - */ - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - char[] pwd = lookupPassword(principal); - - if (pwd == null) - { - throw new AccountNotFoundException("Unable to lookup the specfied users password"); - } - - byte[] byteArray = new byte[password.length]; - int index = 0; - for (char c : password) - { - byteArray[index++] = (byte) c; - } - - byte[] MD5byteArray; - try - { - MD5byteArray = HashedUser.getMD5(byteArray); - } - catch (Exception e1) - { - _logger.warn("Unable to hash password for user '" + principal + "' for comparison"); - return false; - } - - char[] hashedPassword = new char[MD5byteArray.length]; - - index = 0; - for (byte c : MD5byteArray) - { - hashedPassword[index++] = (char) c; - } - - return compareCharArray(pwd, hashedPassword); - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - /** - * Changes the password for the specified user - * - * @param principal to change the password for - * @param password plaintext password to set the password too - */ - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - HashedUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - try - { - _userUpdate.lock(); - char[] orig = user.getPassword(); - user.setPassword(password,false); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to save password file, password change for user'" - + principal + "' will revert at restart"); - //revert the password change - user.setPassword(orig,true); - return false; - } - return true; - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - catch (Exception e) - { - return false; - } - } - - public boolean createPrincipal(Principal principal, char[] password) - { - if (_users.get(principal.getName()) != null) - { - return false; - } - - HashedUser user; - try - { - user = new HashedUser(principal.getName(), password); - } - catch (Exception e1) - { - _logger.warn("Unable to create new user '" + principal.getName() + "'"); - return false; - } - - - try - { - _userUpdate.lock(); - _users.put(user.getName(), user); - - try - { - savePasswordFile(); - return true; - } - catch (IOException e) - { - //remove the use on failure. - _users.remove(user.getName()); - return false; - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - HashedUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - _userUpdate.lock(); - user.delete(); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); - return false; - } - - _users.remove(user.getName()); - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - - return true; - } - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(_users.values()); - } - - public Principal getUser(String username) - { - if (_users.containsKey(username)) - { - return new UsernamePrincipal(username); - } - return null; - } - - /** - * 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 The principal name to lookup - * - * @return a char[] for use in SASL. - */ - private char[] lookupPassword(String name) - { - HashedUser user = _users.get(name); - if (user == null) - { - return null; - } - else - { - return user.getPassword(); - } - } - - private void loadPasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - _users.clear(); - - 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 || result[0].startsWith("#")) - { - continue; - } - - HashedUser user = new HashedUser(result); - _logger.info("Created user:" + user); - _users.put(user.getName(), user); - } - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - private void savePasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); - - try - { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - continue; - } - - HashedUser user = _users.get(result[0]); - - if (user == null) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else if (!user.isDeleted()) - { - if (!user.isModified()) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else - { - try - { - byte[] encodedPassword = user.getEncodedPassword(); - - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to encode new password reverting to old password."); - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - } - } - } - - for (HashedUser user : _users.values()) - { - if (user.isModified()) - { - byte[] encodedPassword; - try - { - encodedPassword = user.getEncodedPassword(); - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); - } - } - } - } - finally - { - if (reader != null) - { - reader.close(); - } - - if (writer != null) - { - writer.close(); - } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - _passwordFile.renameTo(old); - tmp.renameTo(_passwordFile); - tmp.delete(); - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - public void reload() throws IOException - { - loadPasswordFile(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java deleted file mode 100644 index e0d4c49af1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -import org.apache.log4j.Logger; - -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.configuration.PropertyException; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; -import org.apache.qpid.AMQException; - -import javax.management.JMException; - -public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager -{ - private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); - - Map _databases; - - public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception - { - _logger.info("Initialising PrincipleDatabase authentication manager"); - _databases = initialisePrincipalDatabases(_configuration); - } - - private Map initialisePrincipalDatabases(ServerConfiguration _configuration) throws Exception - { - List databaseNames = _configuration.getPrincipalDatabaseNames(); - List databaseClasses = _configuration.getPrincipalDatabaseClass(); - Map databases = new HashMap(); - - if (databaseNames.size() == 0) - { - _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); - } - - 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, _configuration, 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 not permitted"); - } - - _logger.info("Initialised principal database '" + name + "' successfully"); - databases.put(name, (PrincipalDatabase) o); - } - - return databases; - } - - private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, ServerConfiguration _configuration, int index) - throws FileNotFoundException, ConfigurationException - { - List argumentNames = _configuration.getPrincipalDatabaseAttributeNames(index); - List argumentValues = _configuration.getPrincipalDatabaseAttributeValues(index); - for (int i = 0; i < argumentNames.size(); i++) - { - String argName = argumentNames.get(i); - if ((argName == null) || (argName.length() == 0)) - { - throw new ConfigurationException("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 = null; - try - { - method = principalDatabase.getClass().getMethod(methodName, String.class); - } - catch (Exception e) - { - // do nothing.. as on error method will be null - } - - if (method == null) - { - throw new ConfigurationException("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"); - } - - try - { - method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); - } - catch (Exception ite) - { - if (ite instanceof ConfigurationException) - { - throw(ConfigurationException) ite; - } - else - { - throw new ConfigurationException(ite.getMessage(), ite); - } - } - } - } - - public Map getDatabases() - { - return _databases; - } - - public void initialiseManagement(ServerConfiguration config) throws ConfigurationException - { - try - { - AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); - - List principalDBs = config.getManagementPrincipalDBs(); - - if (principalDBs.size() == 0) - { - throw new ConfigurationException("No principal-database specified for jmx security"); - } - - String databaseName = principalDBs.get(0); - - PrincipalDatabase database = getDatabases().get(databaseName); - - if (database == null) - { - throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); - } - - _mbean.setPrincipalDatabase(database); - - List jmxaccesslist = config.getManagementAccessList(); - - if (jmxaccesslist.size() == 0) - { - throw new ConfigurationException("No access control files specified for jmx security"); - } - - String jmxaccesssFile = null; - - try - { - jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); - } - catch (PropertyException e) - { - throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); - } - - try - { - _mbean.setAccessFile(jmxaccesssFile); - } - catch (IOException e) - { - _logger.warn("Unable to load access file:" + jmxaccesssFile); - } - - try - { - _mbean.register(); - } - catch (AMQException e) - { - _logger.warn("Unable to register user management MBean"); - } - } - catch (JMException e) - { - _logger.warn("User management disabled as unable to create MBean:" + e); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java deleted file mode 100644 index 3690e7f92a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java +++ /dev/null @@ -1,169 +0,0 @@ -/* -* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; - -public class HashedUser implements Principal -{ - private static final Logger _logger = Logger.getLogger(HashedUser.class); - - String _name; - char[] _password; - byte[] _encodedPassword = null; - private boolean _modified = false; - private boolean _deleted = false; - - HashedUser(String[] data) throws UnsupportedEncodingException - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be length 2, username, password"); - } - - _name = data[0]; - - byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); - - Base64 b64 = new Base64(); - byte[] decoded = b64.decode(encoded_password); - - _encodedPassword = encoded_password; - - _password = new char[decoded.length]; - - int index = 0; - for (byte c : decoded) - { - _password[index++] = (char) c; - } - } - - public HashedUser(String name, char[] password) throws UnsupportedEncodingException, NoSuchAlgorithmException - { - _name = name; - setPassword(password,false); - } - - public static byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException - { - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - return md.digest(); - } - - public String getName() - { - return _name; - } - - public String toString() - { - return _name; - } - - char[] getPassword() - { - return _password; - } - - void setPassword(char[] password, boolean alreadyHashed) throws UnsupportedEncodingException, NoSuchAlgorithmException - { - if(alreadyHashed){ - _password = password; - } - else - { - byte[] byteArray = new byte[password.length]; - int index = 0; - for (char c : password) - { - byteArray[index++] = (byte) c; - } - - byte[] MD5byteArray = getMD5(byteArray); - - _password = new char[MD5byteArray.length]; - - index = 0; - for (byte c : MD5byteArray) - { - _password[index++] = (char) c; - } - } - - _modified = true; - _encodedPassword = null; - } - - byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - if (_encodedPassword == null) - { - encodePassword(); - } - return _encodedPassword; - } - - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - _encodedPassword = (new Base64()).encode(byteArray); - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java deleted file mode 100644 index 5e4678a63b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; -import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; -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 PlainPasswordFilePrincipalDatabase implements PrincipalDatabase -{ - public static final String DEFAULT_ENCODING = "utf-8"; - - private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map _saslServers; - - private Map _users = new HashMap(); - private ReentrantLock _userUpdate = new ReentrantLock(); - - public PlainPasswordFilePrincipalDatabase() - { - _saslServers = new HashMap(); - - /** - * Create Authenticators for Plain Password file. - */ - - // Accept AMQPlain incomming and compare it to the file. - AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); - amqplain.initialise(this); - - // Accept Plain incomming and compare it to the file. - PlainInitialiser plain = new PlainInitialiser(); - plain.initialise(this); - - // Accept MD5 incomming and Hash file value for comparison - CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); - cram.initialise(this); - - _saslServers.put(amqplain.getMechanismName(), amqplain); - _saslServers.put(plain.getMechanismName(), plain); - _saslServers.put(cram.getMechanismName(), cram); - } - - public void setPasswordFile(String passwordFile) throws IOException - { - File f = new File(passwordFile); - _logger.info("PlainPasswordFile 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."); - } - - loadPasswordFile(); - } - - /** - * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile - * If you want to change the password for a user, use updatePassword instead. - * - * @param principal The Principal to set the password for - * @param callback The PasswordCallback to call setPassword on - * - * @throws AccountNotFoundException If the Principal cannot be found in this Database - */ - public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException - { - if (_passwordFile == null) - { - 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); - } - } - - /** - * Used to verify that the presented Password is correct. Currently only used by Management Console - * - * @param principal The principal to authenticate - * @param password The plaintext password to check - * - * @return true if password is correct - * - * @throws AccountNotFoundException if the principal cannot be found - */ - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - - char[] pwd = lookupPassword(principal); - - if (pwd == null) - { - throw new AccountNotFoundException("Unable to lookup the specfied users password"); - } - - return compareCharArray(pwd, password); - - } - - /** - * Changes the password for the specified user - * - * @param principal to change the password for - * @param password plaintext password to set the password too - */ - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - PlainUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - try - { - _userUpdate.lock(); - char[] orig = user.getPassword(); - user.setPassword(password); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to save password file, password change for user '" + principal + "' discarded"); - //revert the password change - user.setPassword(orig); - return false; - } - return true; - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - catch (Exception e) - { - return false; - } - } - - public boolean createPrincipal(Principal principal, char[] password) - { - if (_users.get(principal.getName()) != null) - { - return false; - } - - PlainUser user = new PlainUser(principal.getName(), password); - - try - { - _userUpdate.lock(); - _users.put(user.getName(), user); - - try - { - savePasswordFile(); - return true; - } - catch (IOException e) - { - //remove the use on failure. - _users.remove(user.getName()); - _logger.warn("Unable to create user '" + user.getName()); - return false; - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - PlainUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - _userUpdate.lock(); - user.delete(); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to remove user '" + user.getName() + "' from password file."); - return false; - } - - _users.remove(user.getName()); - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - - return true; - } - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(_users.values()); - } - - public Principal getUser(String username) - { - if (_users.containsKey(username)) - { - return new UsernamePrincipal(username); - } - return null; - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - - /** - * 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 The principal name to lookup - * - * @return a char[] for use in SASL. - */ - private char[] lookupPassword(String name) - { - PlainUser user = _users.get(name); - if (user == null) - { - return null; - } - else - { - return user.getPassword(); - } - } - - private void loadPasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - _users.clear(); - - 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 || result[0].startsWith("#")) - { - continue; - } - - PlainUser user = new PlainUser(result); - _logger.info("Created user:" + user); - _users.put(user.getName(), user); - } - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - private void savePasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); - - try - { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - continue; - } - - PlainUser user = _users.get(result[0]); - - if (user == null) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else if (!user.isDeleted()) - { - if (!user.isModified()) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else - { - byte[] password = user.getPasswordBytes(); - - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(password); - writer.println(); - - user.saved(); - } - } - } - - for (PlainUser user : _users.values()) - { - if (user.isModified()) - { - byte[] password; - password = user.getPasswordBytes(); - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(password); - writer.println(); - user.saved(); - } - } - } - finally - { - if (reader != null) - { - reader.close(); - } - - if (writer != null) - { - writer.close(); - } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - _passwordFile.renameTo(old); - tmp.renameTo(_passwordFile); - tmp.delete(); - } - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } - } - - public void reload() throws IOException - { - loadPasswordFile(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java deleted file mode 100644 index 46a78a55aa..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java +++ /dev/null @@ -1,106 +0,0 @@ -/* -* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.log4j.Logger; - -import java.security.Principal; - -public class PlainUser implements Principal -{ - private String _name; - private char[] _password; - private boolean _modified = false; - private boolean _deleted = false; - - PlainUser(String[] data) - { - if (data.length != 2) - { - throw new IllegalArgumentException("User Data should be length 2, username, password"); - } - - _name = data[0]; - - _password = data[1].toCharArray(); - - } - - public PlainUser(String name, char[] password) - { - _name = name; - _password = password; - _modified = true; - } - - public String getName() - { - return _name; - } - - public String toString() - { - return _name; - } - - char[] getPassword() - { - return _password; - } - - byte[] getPasswordBytes() - { - byte[] byteArray = new byte[_password.length]; - int index = 0; - for (char c : _password) - { - byteArray[index++] = (byte) c; - } - return byteArray; - } - - void setPassword(char[] password) - { - _password = password; - _modified = true; - } - - public boolean isModified() - { - return _modified; - } - - public boolean isDeleted() - { - return _deleted; - } - - public void delete() - { - _deleted = true; - } - - public void saved() - { - _modified = false; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java deleted file mode 100644 index ef37e043a6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.util.Map; -import java.util.List; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -/** 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; - - /** - * Used to verify that the presented Password is correct. Currently only used by Management Console - * @param principal The principal to authenticate - * @param password The password to check - * @return true if password is correct - * @throws AccountNotFoundException if the principal cannot be found - */ - boolean verifyPassword(String principal, char[] password) - throws AccountNotFoundException; - - /** - * Update(Change) the password for the given principal - * @param principal Who's password is to be changed - * @param password The new password to use - * @return True if change was successful - * @throws AccountNotFoundException If the given principal doesn't exist in the Database - */ - boolean updatePassword(Principal principal, char[] password) - throws AccountNotFoundException; - - /** - * Create a new principal in the database - * @param principal The principal to create - * @param password The password to set for the principal - * @return True on a successful creation - */ - boolean createPrincipal(Principal principal, char[] password); - - /** - * Delete a principal - * @param principal The principal to delete - * @return True on a successful creation - * @throws AccountNotFoundException If the given principal doesn't exist in the Database - */ - boolean deletePrincipal(Principal principal) - throws AccountNotFoundException; - - /** - * Get the principal from the database with the given username - * @param username of the principal to lookup - * @return The Principal object for the given username or null if not found. - */ - Principal getUser(String username); - - /** - * Reload the database to its ensure contents are up to date - * @throws IOException If there was an error reloading the database - */ - void reload() throws IOException; - - public Map getMechanisms(); - - - List getUsers(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java deleted file mode 100644 index f9882f8810..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -import java.util.Map; - -public interface PrincipalDatabaseManager -{ - public Map getDatabases(); - - public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java deleted file mode 100644 index ff8851306f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.util.Properties; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.security.Principal; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -public class PropertiesPrincipalDatabase implements PrincipalDatabase -{ - private Properties _users; - - private Map _saslServers; - - public PropertiesPrincipalDatabase(Properties users) - { - _users = users; - - _saslServers = new HashMap(); - - /** - * Create Authenticators for Properties Principal Database. - */ - - // Accept MD5 incomming and use plain comparison with the file - PlainInitialiser cram = new PlainInitialiser(); - cram.initialise(this); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); - plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); - - _saslServers.put(plain.getMechanismName(), cram); - _saslServers.put(cram.getMechanismName(), plain); - } - - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException - { - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - - - - final String pwd = _users.getProperty(principal.getName()); - - if (pwd != null) - { - callback.setPassword(pwd.toCharArray()); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } - - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - //fixme this is not correct as toCharArray is not safe based on the type of string. - char[] pwd = _users.getProperty(principal).toCharArray(); - - return compareCharArray(pwd, password); - } - - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - return false; // updates denied - } - - public boolean createPrincipal(Principal principal, char[] password) - { - return false; // updates denied - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - return false; // updates denied - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - private char[] convertPassword(String password) throws UnsupportedEncodingException - { - byte[] passwdBytes = password.getBytes("utf-8"); - - char[] passwd = new char[passwdBytes.length]; - - int index = 0; - - for (byte b : passwdBytes) - { - passwd[index++] = (char) b; - } - - return passwd; - } - - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(); //todo - } - - public Principal getUser(String username) - { - if (_users.getProperty(username) != null) - { - return new UsernamePrincipal(username); - } - else - { - return null; - } - } - - public void reload() throws IOException - { - //No file to update from, so do nothing. - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java deleted file mode 100644 index 4efe381a8b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.database; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.ServerConfiguration; - -import java.util.Map; -import java.util.Properties; -import java.util.HashMap; - -public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager -{ - - Map _databases = new HashMap(); - - public PropertiesPrincipalDatabaseManager(String name, Properties users) - { - _databases.put(name, new PropertiesPrincipalDatabase(users)); - } - - public Map getDatabases() - { - return _databases; - } - - @Override - public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException - { - //todo - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java deleted file mode 100644 index d1803124a7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.manager; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.AuthenticationResult; - -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); - - void close(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java deleted file mode 100644 index 98c060599a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.manager; - -import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.JCAProvider; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.AuthenticationResult; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.Sasl; -import java.util.Map; -import java.util.HashMap; -import java.util.TreeMap; -import java.security.Security; - -public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager -{ - private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.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>(); - - private AuthenticationManager _default = null; - /** The name for the required SASL Server mechanisms */ - public static final String PROVIDER_NAME= "AMQSASLProvider-Server"; - - public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception - { - _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") - + " PrincipleDatabase authentication manager."); - - // Fixme This should be done per Vhost but allowing global hack isn't right but ... - // required as authentication is done before Vhost selection - - Map> providerMap = new TreeMap>(); - - - if (name == null || hostConfig == null) - { - initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); - } - else - { - String databaseName = hostConfig.getAuthenticationDatabase(); - - if (databaseName == null) - { - - _default = ApplicationRegistry.getInstance().getAuthenticationManager(); - return; - } - else - { - PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); - - if (database == null) - { - throw new ConfigurationException("Requested database:" + databaseName + " was not found"); - } - - initialiseAuthenticationMechanisms(providerMap, database); - } - } - - if (providerMap.size() > 0) - { - // Ensure we are used before the defaults - if (Security.insertProviderAt(new JCAProvider(PROVIDER_NAME, providerMap), 1) == -1) - { - _logger.error("Unable to load custom SASL providers. Qpid custom SASL authenticators unavailable."); - } - else - { - _logger.info("Additional SASL providers successfully registered."); - } - - } - else - { - _logger.warn("No additional SASL providers registered."); - } - - } - - - private void initialiseAuthenticationMechanisms(Map> providerMap, Map databases) throws Exception - { - if (databases.size() > 1) - { - _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); - } - - for (Map.Entry entry : databases.entrySet()) - { - // fixme As the database now provide the mechanisms they support, they will ... - // overwrite each other in the map. There should only be one database per vhost. - // But currently we must have authentication before vhost definition. - initialiseAuthenticationMechanisms(providerMap, entry.getValue()); - } - } - - private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception - { - if (database == null || database.getMechanisms().size() == 0) - { - _logger.warn("No Database or no mechanisms to initialise authentication"); - return; - } - - for (Map.Entry mechanism : database.getMechanisms().entrySet()) - { - initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); - } - } - - private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, - Map> providerMap) - throws Exception - { - 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); - } - _logger.info("Initialised " + mechanism + " SASL provider successfully"); - } - - public String getMechanisms() - { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.getMechanisms(); - } - else - { - return _mechanisms; - } - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.createSaslServer(mechanism, localFQDN); - } - else - { - return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), - _callbackHandlerMap.get(mechanism)); - } - - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - // Use the default AuthenticationManager if present - if (_default != null) - { - return _default.authenticate(server, 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, e); - } - } - - public void close() - { - Security.removeProvider(PROVIDER_NAME); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java deleted file mode 100644 index 77040e896c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.rmi; - -import java.util.Collections; - -import javax.management.remote.JMXAuthenticator; -import javax.management.remote.JMXPrincipal; -import javax.security.auth.Subject; -import javax.security.auth.login.AccountNotFoundException; - -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -public class RMIPasswordAuthenticator implements JMXAuthenticator -{ - static final String UNABLE_TO_LOOKUP = "The broker was unable to lookup the user details"; - static final String SHOULD_BE_STRING_ARRAY = "User details should be String[]"; - static final String SHOULD_HAVE_2_ELEMENTS = "User details should have 2 elements, username, password"; - static final String SHOULD_BE_NON_NULL = "Supplied username and password should be non-null"; - static final String INVALID_CREDENTIALS = "Invalid user details supplied"; - static final String CREDENTIALS_REQUIRED = "User details are required. " + - "Please ensure you are using an up to date management console to connect."; - - private PrincipalDatabase _db = null; - - public RMIPasswordAuthenticator() - { - } - - public void setPrincipalDatabase(PrincipalDatabase pd) - { - this._db = pd; - } - - public Subject authenticate(Object credentials) throws SecurityException - { - // Verify that credential's are of type String[]. - if (!(credentials instanceof String[])) - { - if (credentials == null) - { - throw new SecurityException(CREDENTIALS_REQUIRED); - } - else - { - throw new SecurityException(SHOULD_BE_STRING_ARRAY); - } - } - - // Verify that required number of credential's. - final String[] userCredentials = (String[]) credentials; - if (userCredentials.length != 2) - { - throw new SecurityException(SHOULD_HAVE_2_ELEMENTS); - } - - String username = (String) userCredentials[0]; - String password = (String) userCredentials[1]; - - // Verify that all required credential's are actually present. - if (username == null || password == null) - { - throw new SecurityException(SHOULD_BE_NON_NULL); - } - - // Verify that a PD has been set. - if (_db == null) - { - throw new SecurityException(UNABLE_TO_LOOKUP); - } - - boolean authenticated = false; - - // Perform authentication - try - { - if (_db.verifyPassword(username, password.toCharArray())) - { - authenticated = true; - } - } - catch (AccountNotFoundException e) - { - throw new SecurityException(INVALID_CREDENTIALS); - } - - if (authenticated) - { - //credential's check out, return the appropriate JAAS Subject - return new Subject(true, - Collections.singleton(new JMXPrincipal(username)), - Collections.EMPTY_SET, - Collections.EMPTY_SET); - } - else - { - throw new SecurityException(INVALID_CREDENTIALS); - } - } - -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java deleted file mode 100644 index 89e545d6f5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -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 - * @throws Exception needs refined Exception is too broad. - */ - void initialise(String baseConfigPath, Configuration configuration, - Map principalDatabases) throws Exception; - - /** - * Initialise the authentication provider. - * @param db The principal database to initialise with - */ - void initialise(PrincipalDatabase db); - - - /** - * @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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java deleted file mode 100644 index d6a09d8217..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.security.Provider; -import java.security.Security; -import java.util.Map; - -import javax.security.sasl.SaslServerFactory; - -public final class JCAProvider extends Provider -{ - public JCAProvider(String name, Map> providerMap) - { - super(name, 1.0, "A JCA provider that registers all " + - "AMQ SASL providers that want to be registered"); - register(providerMap); - } - - private void register(Map> providerMap) - { - for (Map.Entry> me : - providerMap.entrySet()) - { - put("SaslServerFactory." + me.getKey(), me.getValue().getName()); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java deleted file mode 100644 index dd0bd096c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -import java.io.IOException; -import java.security.Principal; -import java.util.Map; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; - -import org.apache.commons.configuration.Configuration; - -import org.apache.log4j.Logger; - -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; - -public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser -{ - protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); - - 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 - IOException ioe = new IOException("Error looking up user " + e); - ioe.initCause(e); - throw ioe; - } - } - 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); - - initialise(db); - } - - public void initialise(PrincipalDatabase db) - { - if (db == null) - { - throw new NullPointerException("Cannot initialise with a null Principal database."); - } - - _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java deleted file mode 100644 index d7c8383690..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl; - -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; - } - - public String toString() - { - return _name; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java deleted file mode 100644 index 7acc6322d1..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; - -public class AmqPlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "AMQPLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return AmqPlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java deleted file mode 100644 index 9f56b8521a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; - -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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.getString("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.getString("PASSWORD"); - AuthorizeCallback authzCb = new AuthorizeCallback(username, username); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - String storedPwd = new String(passwordCb.getPassword()); - if (storedPwd.equals(pwd)) - { - _complete = true; - } - if (authzCb.isAuthorized() && _complete) - { - _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java deleted file mode 100644 index 67d20136bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.amqplain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java deleted file mode 100644 index 97f9a4e91a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -import javax.security.sasl.SaslServerFactory; -import java.util.Map; - -public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return CRAMMD5HashedSaslServer.MECHANISM; - } - - public Class getServerFactoryClassForJCARegistration() - { - return CRAMMD5HashedServerFactory.class; - } - - public void initialise(PrincipalDatabase passwordFile) - { - super.initialise(passwordFile); - } - - public Map getProperties() - { - return null; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java deleted file mode 100644 index f6cab084ea..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslServerFactory; -import javax.security.auth.callback.CallbackHandler; -import java.util.Enumeration; -import java.util.Map; - -public class CRAMMD5HashedSaslServer implements SaslServer -{ - public static final String MECHANISM = "CRAM-MD5-HASHED"; - - private SaslServer _realServer; - - public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - Enumeration factories = Sasl.getSaslServerFactories(); - - while (factories.hasMoreElements()) - { - SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); - - if (factory instanceof CRAMMD5HashedServerFactory) - { - continue; - } - - String[] mechs = factory.getMechanismNames(props); - - for (String mech : mechs) - { - if (mech.equals("CRAM-MD5")) - { - _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); - return; - } - } - } - - throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - return _realServer.evaluateResponse(response); - } - - public boolean isComplete() - { - return _realServer.isComplete(); - } - - public String getAuthorizationID() - { - return _realServer.getAuthorizationID(); - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - return _realServer.unwrap(incoming, offset, len); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - return _realServer.wrap(outgoing, offset, len); - } - - public Object getNegotiatedProperty(String propName) - { - return _realServer.getNegotiatedProperty(propName); - } - - public void dispose() throws SaslException - { - _realServer.dispose(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java deleted file mode 100644 index 5298b5cc63..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5HashedServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) - { - return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); - } - else - { - return null; - } - } - - public String[] getMechanismNames(Map props) - { - if (props != null) - { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) - { - // returned array must be non null according to interface documentation - return new String[0]; - } - } - - return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java deleted file mode 100644 index 264832888d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.crammd5; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; - -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5Initialiser extends UsernamePasswordInitialiser -{ - private HashDirection _hashDirection; - - public enum HashDirection - { - INCOMMING, PASSWORD_FILE - } - - - 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. - if (_hashDirection == HashDirection.PASSWORD_FILE) - { - return null; - } - else - { - //fixme we need a server that will correctly has the incomming plain text for comparison to file. - _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); - return null; - } - } - - public void initialise(PrincipalDatabase passwordFile) - { - initialise(passwordFile, HashDirection.PASSWORD_FILE); - } - - public void initialise(PrincipalDatabase passwordFile, HashDirection direction) - { - super.initialise(passwordFile); - - _hashDirection = direction; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java deleted file mode 100644 index 1d16cd8755..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; - -public class PlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "PLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return PlainSaslServerFactory.class; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java deleted file mode 100644 index 45fb9a4e42..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -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); - 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"); - AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - String storedPwd = new String(passwordCb.getPassword()); - if (storedPwd.equals(pwd)) - { - _complete = true; - } - if (authzCb.isAuthorized() && _complete) - { - _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java deleted file mode 100644 index f0dd9eeb6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.sasl.plain; - -import java.util.Map; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - -public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java deleted file mode 100644 index f427cc7206..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -/** - * States used in the AMQ protocol. Used by the finite state machine to determine - * valid responses. - */ -public enum AMQState -{ - CONNECTION_NOT_STARTED, - CONNECTION_NOT_AUTH, - CONNECTION_NOT_TUNED, - CONNECTION_NOT_OPENED, - CONNECTION_OPEN, - CONNECTION_CLOSING, - CONNECTION_CLOSED -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java deleted file mode 100644 index c5b3099f58..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.*; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.handler.BasicAckMethodHandler; -import org.apache.qpid.server.handler.BasicCancelMethodHandler; -import org.apache.qpid.server.handler.BasicConsumeMethodHandler; -import org.apache.qpid.server.handler.BasicGetMethodHandler; -import org.apache.qpid.server.handler.BasicPublishMethodHandler; -import org.apache.qpid.server.handler.BasicQosHandler; -import org.apache.qpid.server.handler.BasicRecoverMethodHandler; -import org.apache.qpid.server.handler.BasicRejectMethodHandler; -import org.apache.qpid.server.handler.ChannelCloseHandler; -import org.apache.qpid.server.handler.ChannelCloseOkHandler; -import org.apache.qpid.server.handler.ChannelFlowHandler; -import org.apache.qpid.server.handler.ChannelOpenHandler; -import org.apache.qpid.server.handler.ConnectionCloseMethodHandler; -import org.apache.qpid.server.handler.ConnectionCloseOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionOpenMethodHandler; -import org.apache.qpid.server.handler.ConnectionSecureOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionStartOkMethodHandler; -import org.apache.qpid.server.handler.ConnectionTuneOkMethodHandler; -import org.apache.qpid.server.handler.ExchangeBoundHandler; -import org.apache.qpid.server.handler.ExchangeDeclareHandler; -import org.apache.qpid.server.handler.ExchangeDeleteHandler; -import org.apache.qpid.server.handler.QueueBindHandler; -import org.apache.qpid.server.handler.QueueDeclareHandler; -import org.apache.qpid.server.handler.QueueDeleteHandler; -import org.apache.qpid.server.handler.QueuePurgeHandler; -import org.apache.qpid.server.handler.TxCommitHandler; -import org.apache.qpid.server.handler.TxRollbackHandler; -import org.apache.qpid.server.handler.TxSelectHandler; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -/** - * 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); - - private final VirtualHostRegistry _virtualHostRegistry; - private final AMQProtocolSession _protocolSession; - /** The current state */ - private AMQState _currentState; - - /** - * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of - * AMQFrame. - */ -/* private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = - new EnumMap, StateAwareMethodListener>>( - AMQState.class); - */ - - - private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - - public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) - { - - _virtualHostRegistry = virtualHostRegistry; - _protocolSession = protocolSession; - _currentState = AMQState.CONNECTION_NOT_STARTED; - - } - - /* - protected void registerListeners() - { - Map, StateAwareMethodListener> frame2handlerMap; - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_AUTH, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - _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>(); - ChannelOpenHandler.getInstance(); - ChannelCloseHandler.getInstance(); - ChannelCloseOkHandler.getInstance(); - ConnectionCloseMethodHandler.getInstance(); - ConnectionCloseOkMethodHandler.getInstance(); - ConnectionTuneOkMethodHandler.getInstance(); - ConnectionSecureOkMethodHandler.getInstance(); - ConnectionStartOkMethodHandler.getInstance(); - ExchangeDeclareHandler.getInstance(); - ExchangeDeleteHandler.getInstance(); - ExchangeBoundHandler.getInstance(); - BasicAckMethodHandler.getInstance(); - BasicRecoverMethodHandler.getInstance(); - BasicConsumeMethodHandler.getInstance(); - BasicGetMethodHandler.getInstance(); - BasicCancelMethodHandler.getInstance(); - BasicPublishMethodHandler.getInstance(); - BasicQosHandler.getInstance(); - QueueBindHandler.getInstance(); - QueueDeclareHandler.getInstance(); - QueueDeleteHandler.getInstance(); - QueuePurgeHandler.getInstance(); - ChannelFlowHandler.getInstance(); - TxSelectHandler.getInstance(); - TxCommitHandler.getInstance(); - TxRollbackHandler.getInstance(); - BasicRejectMethodHandler.getInstance(); - - _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - - _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(Exception e) - { - _logger.error("State manager received error notification[Current State:" + _currentState + "]: " + e, e); - for (StateListener l : _stateListeners) - { - l.error(e); - } - } - - public boolean methodReceived(AMQMethodEvent evt) throws AMQException - { - MethodDispatcher dispatcher = _protocolSession.getMethodDispatcher(); - - final int channelId = evt.getChannelId(); - B body = evt.getMethod(); - - if(channelId != 0 && _protocolSession.getChannel(channelId)== null) - { - - if(! ((body instanceof ChannelOpenBody) - || (body instanceof ChannelCloseOkBody) - || (body instanceof ChannelCloseBody))) - { - throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "channel is closed"); - } - - } - - return body.execute(dispatcher, channelId); - - } - - private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) - throws AMQException - { - if ((evt.getChannelId() != 0) && !(evt.getMethod() instanceof ChannelOpenBody) - && (protocolSession.getChannel(evt.getChannelId()) == null) - && !protocolSession.channelAwaitingClosure(evt.getChannelId())) - { - throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); - } - } - -/* - protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, - B frame) - // throws IllegalStateTransitionException - { - final Map, StateAwareMethodListener> classToHandlerMap = - _state2HandlersMap.get(currentState); - - final StateAwareMethodListener handler = - (classToHandlerMap == null) ? null : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); - - if (handler == null) - { - _logger.debug("No state transition handler defined for receiving frame " + frame); - - return null; - } - else - { - return handler; - } - } -*/ - - public void addStateListener(StateListener listener) - { - _logger.debug("Adding state listener"); - _stateListeners.add(listener); - } - - public void removeStateListener(StateListener listener) - { - _stateListeners.remove(listener); - } - - public VirtualHostRegistry getVirtualHostRegistry() - { - return _virtualHostRegistry; - } - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java deleted file mode 100644 index cec67a8a6d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -/** - * @todo Not an AMQP exception as no status code. - * - * @todo Not used! Delete. - */ -public class IllegalStateTransitionException extends AMQException -{ - private AMQState _originalState; - - private Class _frame; - - public IllegalStateTransitionException(AMQState originalState, Class frame) - { - super("No valid state transition defined for receiving frame " + frame + " from state " + originalState); - _originalState = originalState; - _frame = frame; - } - - public AMQState getOriginalState() - { - return _originalState; - } - - public Class getFrameClass() - { - return _frame; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java deleted file mode 100644 index 3c11bb8a9c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQMethodEvent; - -/** - * 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, B evt, int channelId) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java deleted file mode 100644 index 00fc09867b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -public interface StateListener -{ - void stateChanged(AMQState oldState, AMQState newState) throws AMQException; - - void error(Throwable t); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java deleted file mode 100644 index 157418d806..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ /dev/null @@ -1,1461 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.store; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.QueueRegistry; - -import org.apache.qpid.server.queue.MessageFactory; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.transactionlog.BaseTransactionLog; -import org.apache.qpid.server.routing.RoutingTable; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; - -import java.io.File; -import java.io.ByteArrayInputStream; -import java.sql.DriverManager; -import java.sql.Driver; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Blob; -import java.sql.Types; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.HashMap; -import java.util.TreeMap; - - -public class DerbyMessageStore implements TransactionLog, RoutingTable -{ - - private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); - - private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; - - - private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; - - private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION"; - - private static final String EXCHANGE_TABLE_NAME = "QPID_EXCHANGE"; - private static final String QUEUE_TABLE_NAME = "QPID_QUEUE"; - private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS"; - private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY"; - private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA"; - private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; - - private static final int DB_VERSION = 1; - - - - private VirtualHost _virtualHost; - private static Class DRIVER_CLASS; - - private final AtomicLong _messageId = new AtomicLong(1); - private AtomicBoolean _closed = new AtomicBoolean(false); - - private String _connectionURL; - - MessageFactory _messageFactory; - - private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; - private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; - private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; - private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; - private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; - private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; - private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; - private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; - private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; - private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; - private static final String SELECT_FROM_BINDINGS = - "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; - private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; - private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; - private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; - private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; - private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; - private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; - private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; - private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; - private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; - private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; - private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; - private static final String SELECT_FROM_MESSAGE_META_DATA = - "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String SELECT_FROM_MESSAGE_CONTENT = - "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; - private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; - private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; - - - private enum State - { - INITIAL, - CONFIGURING, - RECOVERING, - STARTED, - CLOSING, - CLOSED - } - - private State _state = State.INITIAL; - - - public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - //Only initialise when loaded with the old 'store' confing ignore the new 'RoutingTable' config - if (base.equals("store")) - { - stateTransition(State.INITIAL, State.CONFIGURING); - - initialiseDriver(); - - _virtualHost = virtualHost; - - _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - final String databasePath = config.getStoreConfiguration().getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); - - File environmentPath = new File(databasePath); - if (!environmentPath.exists()) - { - if (!environmentPath.mkdirs()) - { - throw new IllegalArgumentException("Environment path " + environmentPath + " could not be read or created. " - + "Ensure the path is correct and that the permissions are correct."); - } - } - - createOrOpenDatabase(databasePath); - - // this recovers durable queues and persistent messages - - _messageFactory = MessageFactory.getInstance(); - - recover(); - - stateTransition(State.RECOVERING, State.STARTED); - return new BaseTransactionLog(this); - } - return null; - } - - private static synchronized void initialiseDriver() throws ClassNotFoundException - { - if(DRIVER_CLASS == null) - { - DRIVER_CLASS = (Class) Class.forName(SQL_DRIVER_NAME); - } - } - - private void createOrOpenDatabase(final String environmentPath) throws SQLException - { - _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; - - Connection conn = newConnection(); - - createVersionTable(conn); - createExchangeTable(conn); - createQueueTable(conn); - createBindingsTable(conn); - createQueueEntryTable(conn); - createMessageMetaDataTable(conn); - createMessageContentTable(conn); - - conn.close(); - } - - - - private void createVersionTable(final Connection conn) throws SQLException - { - if(!tableExists(DB_VERSION_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - - stmt.execute(CREATE_DB_VERSION_TABLE); - stmt.close(); - - PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); - pstmt.setInt(1, DB_VERSION); - pstmt.execute(); - pstmt.close(); - } - - } - - - private void createExchangeTable(final Connection conn) throws SQLException - { - if(!tableExists(EXCHANGE_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - - stmt.execute(CREATE_EXCHANGE_TABLE); - stmt.close(); - } - } - - private void createQueueTable(final Connection conn) throws SQLException - { - if(!tableExists(QUEUE_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_TABLE); - stmt.close(); - } - } - - private void createBindingsTable(final Connection conn) throws SQLException - { - if(!tableExists(BINDINGS_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - stmt.execute(CREATE_BINDINGS_TABLE); - - stmt.close(); - } - - } - - private void createQueueEntryTable(final Connection conn) throws SQLException - { - if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_ENTRY_TABLE); - - stmt.close(); - } - - } - - private void createMessageMetaDataTable(final Connection conn) throws SQLException - { - if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); - - stmt.close(); - } - - } - - - private void createMessageContentTable(final Connection conn) throws SQLException - { - if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) - { - Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); - - stmt.close(); - } - - } - - - - private boolean tableExists(final String tableName, final Connection conn) throws SQLException - { - PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); - stmt.setString(1, tableName); - ResultSet rs = stmt.executeQuery(); - boolean exists = rs.next(); - rs.close(); - stmt.close(); - return exists; - } - - public void recover() throws AMQException - { - stateTransition(State.CONFIGURING, State.RECOVERING); - - _logger.info("Recovering persistent state..."); - StoreContext context = new StoreContext(); - - try - { - Map queues = loadQueues(); - - recoverExchanges(); - - try - { - - beginTran(context); - - deliverMessages(context, queues); - _logger.info("Persistent state recovered successfully"); - commitTran(context); - - } - finally - { - if(inTran(context)) - { - abortTran(context); - } - } - } - catch (SQLException e) - { - - throw new AMQException("Error recovering persistent state: " + e, e); - } - - } - - private Map loadQueues() throws SQLException, AMQException - { - Connection conn = newConnection(); - - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); - Map queueMap = new HashMap(); - while(rs.next()) - { - String queueName = rs.getString(1); - String owner = rs.getString(2); - AMQShortString queueNameShortString = new AMQShortString(queueName); - AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, - null); - _virtualHost.getQueueRegistry().registerQueue(q); - queueMap.put(queueNameShortString,q); - - } - return queueMap; - } - - private void recoverExchanges() throws AMQException, SQLException - { - for (Exchange exchange : loadExchanges()) - { - recoverExchange(exchange); - } - } - - - private List loadExchanges() throws AMQException, SQLException - { - - List exchanges = new ArrayList(); - Connection conn = null; - try - { - conn = newConnection(); - - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); - - Exchange exchange; - while(rs.next()) - { - String exchangeName = rs.getString(1); - String type = rs.getString(2); - boolean autoDelete = rs.getShort(3) != 0; - - exchange = _virtualHost.getExchangeFactory().createExchange(new AMQShortString(exchangeName), new AMQShortString(type), true, autoDelete, 0); - _virtualHost.getExchangeRegistry().registerExchange(exchange); - exchanges.add(exchange); - - } - return exchanges; - - } - finally - { - if(conn != null) - { - conn.close(); - } - } - - } - - private void recoverExchange(Exchange exchange) throws AMQException, SQLException - { - _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "..."); - - QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); - - Connection conn = null; - try - { - conn = newConnection(); - - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString()); - - ResultSet rs = stmt.executeQuery(); - - - while(rs.next()) - { - String queueName = rs.getString(1); - String bindingKey = rs.getString(2); - Blob arguments = rs.getBlob(3); - - - AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) - { - _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getName()); - } - else - { - _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName - + ", Routing Key: " + bindingKey + ", Arguments: " + arguments - + ")"); - - FieldTable argumentsFT = null; - if(arguments != null) - { - byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length()); - ByteBuffer buf = ByteBuffer.wrap(argumentBytes); - argumentsFT = new FieldTable(buf,arguments.length()); - } - - queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); - - } - } - } - finally - { - if(conn != null) - { - conn.close(); - } - } - } - - public void close() throws Exception - { - _closed.getAndSet(true); - } - - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - - boolean localTx = getOrCreateTransaction(storeContext); - - Connection conn = getConnection(storeContext); - ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload(); - - - if (_logger.isDebugEnabled()) - { - _logger.debug("Message Id: " + messageId + " Removing"); - } - - // first we need to look up the header to get the chunk count - MessageMetaData mmd = getMessageMetaData(storeContext, messageId); - try - { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); - stmt.setLong(1,messageId); - wrapper.setRequiresCommit(); - int results = stmt.executeUpdate(); - - if (results == 0) - { - if (localTx) - { - abortTran(storeContext); - } - - throw new AMQException("Message metadata not found for message id " + messageId); - } - stmt.close(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Deleted metadata for message " + messageId); - } - - stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - results = stmt.executeUpdate(); - - if(results != mmd.getContentChunkCount()) - { - if (localTx) - { - abortTran(storeContext); - } - throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results); - - } - - if (localTx) - { - commitTran(storeContext); - } - } - catch (SQLException e) - { - if ((conn != null) && localTx) - { - abortTran(storeContext); - } - - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); - } - - } - - public void createExchange(Exchange exchange) throws AMQException - { - if (_state != State.RECOVERING) - { - try - { - Connection conn = null; - - try - { - conn = newConnection(); - - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); - stmt.setString(2, exchange.getType().toString()); - stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); - stmt.execute(); - stmt.close(); - conn.commit(); - - } - finally - { - if(conn != null) - { - conn.close(); - } - } - } - catch (SQLException e) - { - throw new AMQException("Error writing Exchange with name " + exchange.getName() + " to database: " + e, e); - } - } - - } - - public void removeExchange(Exchange exchange) throws AMQException - { - Connection conn = null; - - try - { - conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); - int results = stmt.executeUpdate(); - if(results == 0) - { - throw new AMQException("Exchange " + exchange.getName() + " not found"); - } - else - { - conn.commit(); - stmt.close(); - } - } - catch (SQLException e) - { - throw new AMQException("Error writing deleting with name " + exchange.getName() + " from database: " + e, e); - } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - throws AMQException - { - if (_state != State.RECOVERING) - { - Connection conn = null; - - - try - { - conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); - stmt.setString(3, routingKey == null ? null : routingKey.toString()); - if(args != null) - { - /* This would be the Java 6 way of setting a Blob - Blob blobArgs = conn.createBlob(); - blobArgs.setBytes(0, args.getDataAsBytes()); - stmt.setBlob(4, blobArgs); - */ - byte[] bytes = args.getDataAsBytes(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - stmt.setBinaryStream(4, bis, bytes.length); - } - else - { - stmt.setNull(4, Types.BLOB); - } - - stmt.executeUpdate(); - conn.commit(); - stmt.close(); - } - catch (SQLException e) - { - throw new AMQException("Error writing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " to database: " + e, e); - } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } - - } - - - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - throws AMQException - { - Connection conn = null; - - - try - { - conn = newConnection(); - // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); - stmt.setString(3, routingKey == null ? null : routingKey.toString()); - - - if(stmt.executeUpdate() != 1) - { - throw new AMQException("Queue binding for queue with name " + queue.getName() + " to exchange " - + exchange.getName() + " not found"); - } - conn.commit(); - stmt.close(); - } - catch (SQLException e) - { - throw new AMQException("Error removing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " in database: " + e, e); - } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } - - - } - - public void createQueue(AMQQueue queue) throws AMQException - { - createQueue(queue, null); - } - - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException - { - _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); - - if (_state != State.RECOVERING) - { - try - { - Connection conn = newConnection(); - - PreparedStatement stmt = - conn.prepareStatement(INSERT_INTO_QUEUE); - - stmt.setString(1, queue.getName().toString()); - stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); - - stmt.execute(); - - stmt.close(); - - conn.commit(); - - conn.close(); - } - catch (SQLException e) - { - throw new AMQException("Error writing AMQQueue with name " + queue.getName() + " to database: " + e, e); - } - } - } - - private Connection newConnection() throws SQLException - { - final Connection connection = DriverManager.getConnection(_connectionURL); - return connection; - } - - public void removeQueue(final AMQQueue queue) throws AMQException - { - AMQShortString name = queue.getName(); - _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); - Connection conn = null; - - - try - { - conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); - stmt.setString(1, name.toString()); - int results = stmt.executeUpdate(); - - - if (results == 0) - { - throw new AMQException("Queue " + name + " not found"); - } - - conn.commit(); - stmt.close(); - } - catch (SQLException e) - { - throw new AMQException("Error writing deleting with name " + name + " from database: " + e, e); - } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } - - - } - - public void enqueueMessage(StoreContext context, ArrayList queues, Long messageId) throws AMQException - { - for (AMQQueue q : queues) - { - if (q.isDurable()) - { - enqueueMessage(context,q,messageId); - } - } - } - - void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException - { - AMQShortString name = queue.getName(); - - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - try - { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); - stmt.setString(1,name.toString()); - stmt.setLong(2,messageId); - stmt.executeUpdate(); - connWrapper.requiresCommit(); - - if(localTx) - { - commitTran(context); - } - - - - if (_logger.isDebugEnabled()) - { - _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - _logger.error("Failed to enqueue: " + e, e); - throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name - + " to database", e); - } - - } - - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException - { - AMQShortString name = queue.getName(); - - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - try - { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); - stmt.setString(1,name.toString()); - stmt.setLong(2,messageId); - int results = stmt.executeUpdate(); - - connWrapper.requiresCommit(); - - if(results != 1) - { - throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); - } - - if(localTx) - { - commitTran(context); - } - - - - if (_logger.isDebugEnabled()) - { - _logger.debug("Dequeuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - _logger.error("Failed to dequeue: " + e, e); - throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name - + " from database", e); - } - - } - - private static final class ConnectionWrapper - { - private final Connection _connection; - private boolean _requiresCommit; - - public ConnectionWrapper(Connection conn) - { - _connection = conn; - } - - public void setRequiresCommit() - { - _requiresCommit = true; - } - - public boolean requiresCommit() - { - return _requiresCommit; - } - - public Connection getConnection() - { - return _connection; - } - } - - public void beginTran(StoreContext context) throws AMQException - { - if (context.getPayload() != null) - { - throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: " - + context.getPayload()); - } - else - { - try - { - Connection conn = newConnection(); - - - context.setPayload(new ConnectionWrapper(conn)); - } - catch (SQLException e) - { - throw new AMQException("Error starting transaction: " + e, e); - } - } - } - - public void commitTran(StoreContext context) throws AMQException - { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - if (connWrapper == null) - { - throw new AMQException("Fatal internal error: transactional context is empty at commitTran"); - } - - try - { - Connection conn = connWrapper.getConnection(); - if(connWrapper.requiresCommit()) - { - conn.commit(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("commit tran completed"); - } - - } - conn.close(); - } - catch (SQLException e) - { - throw new AMQException("Error commit tx: " + e, e); - } - finally - { - context.setPayload(null); - } - } - - public void abortTran(StoreContext context) throws AMQException - { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - if (connWrapper == null) - { - throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("abort tran called: " + connWrapper.getConnection()); - } - - try - { - Connection conn = connWrapper.getConnection(); - if(connWrapper.requiresCommit()) - { - conn.rollback(); - } - - conn.close(); - } - catch (SQLException e) - { - throw new AMQException("Error aborting transaction: " + e, e); - } - finally - { - context.setPayload(null); - } - } - - public boolean inTran(StoreContext context) - { - return context.getPayload() != null; - } - - public Long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public void storeContentBodyChunk(StoreContext context, - Long messageId, - int index, - ContentChunk contentBody, - boolean lastContentBody) throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - try - { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - byte[] chunkData = new byte[contentBody.getSize()]; - contentBody.getData().duplicate().get(chunkData); - /* this would be the Java 6 way of doing things - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, chunkData); - stmt.setBlob(3, dataAsBlob); - */ - ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); - stmt.setBinaryStream(3, bis, chunkData.length); - stmt.executeUpdate(); - connWrapper.requiresCommit(); - - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); - } - - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd) - throws AMQException - { - - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - try - { - - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); - stmt.setLong(1,messageId); - stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); - stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); - stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0); - stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0); - - ContentHeaderBody headerBody = mmd.getContentHeaderBody(); - final int bodySize = headerBody.getSize(); - byte[] underlying = new byte[bodySize]; - ByteBuffer buf = ByteBuffer.wrap(underlying); - headerBody.writePayload(buf); -/* - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, underlying); - stmt.setBlob(6, dataAsBlob); -*/ - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(6,bis,underlying.length); - - stmt.setInt(7, mmd.getContentChunkCount()); - - stmt.executeUpdate(); - connWrapper.requiresCommit(); - - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); - } - - - } - - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - - - try - { - - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); - stmt.setLong(1,messageId); - ResultSet rs = stmt.executeQuery(); - - if(rs.next()) - { - final AMQShortString exchange = new AMQShortString(rs.getString(1)); - final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); - final boolean mandatory = (rs.getShort(3) != (short)0); - final boolean immediate = (rs.getShort(4) != (short)0); - MessagePublishInfo info = new MessagePublishInfoImpl(exchange,immediate,mandatory,routingKey); - - Blob dataAsBlob = rs.getBlob(5); - - byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); - ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); - - ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length); - - if(localTx) - { - commitTran(context); - } - - return new MessageMetaData(info, chb, rs.getInt(6)); - - } - else - { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Metadata not found for message with id " + messageId); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); - } - - - } - - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - - - try - { - - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - ResultSet rs = stmt.executeQuery(); - - if(rs.next()) - { - Blob dataAsBlob = rs.getBlob(1); - - final int size = (int) dataAsBlob.length(); - byte[] dataAsBytes = dataAsBlob.getBytes(1, size); - final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); - - ContentChunk cb = new ContentChunk() - { - - public int getSize() - { - return size; - } - - public ByteBuffer getData() - { - return buf; - } - - public void reduceToFit() - { - - } - }; - - if(localTx) - { - commitTran(context); - } - - return cb; - - } - else - { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Message not found for message with id " + messageId); - } - } - catch (SQLException e) - { - if(localTx) - { - abortTran(context); - } - - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); - } - - - - } - - public boolean isPersistent() - { - return true; - } - - private void checkNotClosed() throws MessageStoreClosedException - { - if (_closed.get()) - { - throw new MessageStoreClosedException(); - } - } - - - private static final class ProcessAction - { - private final AMQQueue _queue; - private final StoreContext _context; - private final AMQMessage _message; - - public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message) - { - _queue = queue; - _context = context; - _message = message; - } - - public void process() throws AMQException - { - _queue.enqueue(_context, _message); - - } - - } - - - private void deliverMessages(final StoreContext context, Map queues) - throws SQLException, AMQException - { - Map msgMap = new HashMap(); - List actions = new ArrayList(); - - Map queueRecoveries = new TreeMap(); - - final boolean inLocaltran = inTran(context); - Connection conn = null; - try - { - - if(inLocaltran) - { - conn = getConnection(context); - } - else - { - conn = newConnection(); - } - - long maxId = 1; - - TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); - - - while (rs.next()) - { - - - - AMQShortString queueName = new AMQShortString(rs.getString(1)); - - - AMQQueue queue = queues.get(queueName); - if (queue == null) - { - queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); - - _virtualHost.getQueueRegistry().registerQueue(queue); - queues.put(queueName, queue); - } - - long messageId = rs.getLong(2); - maxId = Math.max(maxId, messageId); - AMQMessage message = msgMap.get(messageId); - - if(message != null) - { - //todo must enqueue message to build reference table -// message.incrementReference(1); - } - else - { - message = _messageFactory.createMessage(messageId, this); - - _logger.error("todo must do message recovery now."); - //todo must do message recovery now. - - msgMap.put(messageId,message); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); - } - - if (_logger.isInfoEnabled()) - { - Integer count = queueRecoveries.get(queueName); - if (count == null) - { - count = 0; - } - - queueRecoveries.put(queueName, ++count); - - } - - actions.add(new ProcessAction(queue, context, message)); - - } - - for(ProcessAction action : actions) - { - action.process(); - } - - _messageId.set(maxId + 1); - } - catch (SQLException e) - { - _logger.error("Error: " + e, e); - throw e; - } - finally - { - if (inLocaltran && conn != null) - { - conn.close(); - } - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Recovered message counts: " + queueRecoveries); - } - } - - private Connection getConnection(final StoreContext context) - { - return ((ConnectionWrapper)context.getPayload()).getConnection(); - } - - private boolean getOrCreateTransaction(StoreContext context) throws AMQException - { - - ConnectionWrapper tx = (ConnectionWrapper) context.getPayload(); - if (tx == null) - { - beginTran(context); - return true; - } - - return false; - } - - private synchronized void stateTransition(State requiredState, State newState) throws AMQException - { - if (_state != requiredState) - { - throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState - + "; currently in state: " + _state); - } - - _state = newState; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java deleted file mode 100644 index f5819716cb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.routing.RoutingTable; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.transactionlog.BaseTransactionLog; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -/** - * A simple message store that stores the messages in a threadsafe structure in memory. - * - * NOTE: Now that we have removed the MessageStore interface and are using a TransactionLog - * - * This class really should have no storage unless we want to do inMemory Recovery. - */ -public class MemoryMessageStore implements TransactionLog, RoutingTable -{ - protected 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); - private AtomicBoolean _closed = new AtomicBoolean(false); - - public TransactionLog configure() - { - _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); - _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); - _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); - return new BaseTransactionLog(this); - } - - public TransactionLog configure(String base, VirtualHostConfiguration config) - { - //Only initialise when called with current 'store' configs i.e. don't reinit when used as a 'RoutingTable' - if (base.equals("store")) - { - int hashtableCapacity = config.getStoreConfiguration().getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); - _log.info("Using capacity " + hashtableCapacity + " for hash tables"); - _metaDataMap = new ConcurrentHashMap(hashtableCapacity); - _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); - return new BaseTransactionLog(this); - } - return null; - } - - public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - return configure(base, config); - } - - public void close() throws Exception - { - _closed.getAndSet(true); - if (_metaDataMap != null) - { - _metaDataMap.clear(); - _metaDataMap = null; - } - if (_contentBodyMap != null) - { - _contentBodyMap.clear(); - _contentBodyMap = null; - } - } - - public void removeMessage(StoreContext context, Long messageId) throws AMQException - { - checkNotClosed(); - if (_log.isDebugEnabled()) - { - _log.debug("Removing message with id " + messageId); - } - _metaDataMap.remove(messageId); - _contentBodyMap.remove(messageId); - } - - public void createExchange(Exchange exchange) throws AMQException - { - - } - - public void removeExchange(Exchange exchange) throws AMQException - { - - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - - } - - public void createQueue(AMQQueue queue) throws AMQException - { - // Not requred to do anything - } - - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException - { - // Not required to do anything - } - - public void removeQueue(final AMQQueue queue) throws AMQException - { - // Not required to do anything - } - - public void enqueueMessage(StoreContext context, final ArrayList queues, Long messageId) throws AMQException - { - // Not required to do anything - } - - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException - { - // Not required to do anything - } - - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException - { - // Not required to do anything - } - - public void beginTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void commitTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void abortTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public boolean inTran(StoreContext context) - { - return false; - } - - public List createQueues() throws AMQException - { - return null; - } - - public Long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) - throws AMQException - { - checkNotClosed(); - List bodyList = _contentBodyMap.get(messageId); - - if (bodyList == null && lastContentBody) - { - _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); - } - else - { - if (bodyList == null) - { - bodyList = new ArrayList(); - _contentBodyMap.put(messageId, bodyList); - } - - bodyList.add(index, contentBody); - } - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) - throws AMQException - { - checkNotClosed(); - _metaDataMap.put(messageId, messageMetaData); - } - - - public boolean isPersistent() - { - return false; - } - - protected void checkNotClosed() throws MessageStoreClosedException - { - if (_closed.get()) - { - throw new MessageStoreClosedException(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java deleted file mode 100644 index 3d1538c7eb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.apache.qpid.server.store; - -import org.apache.qpid.AMQException;/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * NOTE: this class currently extends AMQException but - * we should be using AMQExceptions internally in the code base for Protocol errors hence - * the message store interface should throw a different super class which this should be - * moved to reflect - */ -public class MessageStoreClosedException extends AMQException -{ - public MessageStoreClosedException() - { - super("Message store closed"); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java deleted file mode 100644 index eb28d83d92..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQQueue; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import java.util.Collections; - -/** - * A context that the store can use to associate with a transactional context. For example, it could store - * some kind of txn id. - * - * @author Apache Software Foundation - */ -public class StoreContext -{ - private static final Logger _logger = Logger.getLogger(StoreContext.class); - - private static final String DEFAULT_NAME = "StoreContext"; - private String _name; - private Object _payload; - private Map> _dequeueMap; - private boolean _async; - private boolean _inTransaction; - - public StoreContext() - { - this(DEFAULT_NAME); - } - - public StoreContext(String name) - { - this(name, false); - } - - /** - * @param name The name of this Transaction - * @param asynchrouous Is this Transaction Asynchronous - */ - public StoreContext(String name, boolean asynchrouous) - { - _name = name; - _async = asynchrouous; - _inTransaction = false; - _dequeueMap = new HashMap>(); - } - - public StoreContext(boolean asynchronous) - { - this(DEFAULT_NAME, asynchronous); - } - - public Object getPayload() - { - return _payload; - } - - public void setPayload(Object payload) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("public void setPayload(Object payload = " + payload + "): called"); - } - _payload = payload; - } - - /** - * Prints out the transactional context as a string, mainly for debugging purposes. - * - * @return The transactional context as a string. - */ - public String toString() - { - return "<_name = " + _name + ", _payload = " + _payload + ">"; - } - - public Map> getDequeueMap() - { - return _dequeueMap; - } - - /** - * Record the dequeue for processing after the commit - * - * @param queue - * @param messageId - * - * @throws AMQException - */ - public void dequeueMessage(AMQQueue queue, Long messageId) throws AMQException - { - List dequeues = _dequeueMap.get(messageId); - - if (dequeues == null) - { - dequeues = new ArrayList(); - _dequeueMap.put(messageId, dequeues); - } - - dequeues.add(queue); - if (_logger.isInfoEnabled()) - { - _logger.info("Added (" + messageId + ") to dequeues:" + dequeues); - } - } - - public void beginTransaction() throws AMQException - { - _inTransaction = true; - } - - public void commitTransaction() throws AMQException - { - _dequeueMap.clear(); - _inTransaction = false; - } - - public void abortTransaction() throws AMQException - { - _dequeueMap.clear(); - _inTransaction = false; - } - - public boolean inTransaction() - { - return _inTransaction; - } - - public boolean isAsync() - { - return _async; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java deleted file mode 100644 index fbc8b3af7d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.AMQException; - -public interface ClientDeliveryMethod -{ - void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java deleted file mode 100644 index e2ed4104de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.server.queue.QueueEntry; - -public interface RecordDeliveryMethod -{ - void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java deleted file mode 100644 index 9419572399..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; - -public interface Subscription -{ - - - public static enum State - { - ACTIVE, - SUSPENDED, - CLOSED - } - - public static interface StateListener - { - public void stateChange(Subscription sub, State oldState, State newState); - } - - AMQQueue getQueue(); - - QueueEntry.SubscriptionAcquiredState getOwningState(); - - void setQueue(AMQQueue queue); - - AMQChannel getChannel(); - - AMQShortString getConsumerTag(); - - boolean isSuspended(); - - boolean hasInterest(QueueEntry msg); - - boolean isAutoClose(); - - boolean isClosed(); - - boolean isBrowser(); - - void close(); - - boolean filtersMessages(); - - void send(QueueEntry msg) throws AMQException; - - void queueDeleted(AMQQueue queue); - - - boolean wouldSuspend(QueueEntry msg); - - void getSendLock(); - void releaseSendLock(); - - void resend(final QueueEntry entry) throws AMQException; - - void restoreCredit(final QueueEntry queueEntry); - - void setStateListener(final StateListener listener); - - public State getState(); - - QueueEntry getLastSeenEntry(); - - boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); - - - boolean isActive(); - - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java deleted file mode 100644 index ce0362d73f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.AMQChannel; - -/** - * 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, - AMQShortString consumerTag, - boolean acks, - FieldTable filters, - boolean noLocal, FlowCreditManager creditManager) throws AMQException; - - - Subscription createSubscription(AMQChannel channel, - AMQProtocolSession protocolSession, - AMQShortString consumerTag, - boolean acks, - FieldTable filters, - boolean noLocal, - FlowCreditManager creditManager, - ClientDeliveryMethod clientMethod, - RecordDeliveryMethod recordMethod - ) - throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java deleted file mode 100644 index 5badbad642..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactory; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.common.AMQPFilterTypes; - -public class SubscriptionFactoryImpl implements SubscriptionFactory -{ - - /* private SubscriptionFactoryImpl() - { - - }*/ - - public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession, - AMQShortString consumerTag, boolean acks, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager) throws AMQException - { - AMQChannel channel = protocolSession.getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); - } - ClientDeliveryMethod clientMethod = channel.getClientDeliveryMethod(); - RecordDeliveryMethod recordMethod = channel.getRecordDeliveryMethod(); - - - return createSubscription(channel, protocolSession, consumerTag, acks, filters, - noLocal, - creditManager, - clientMethod, - recordMethod - ); - } - - public Subscription createSubscription(final AMQChannel channel, - final AMQProtocolSession protocolSession, - final AMQShortString consumerTag, - final boolean acks, - final FieldTable filters, - final boolean noLocal, - final FlowCreditManager creditManager, - final ClientDeliveryMethod clientMethod, - final RecordDeliveryMethod recordMethod - ) - throws AMQException - { - boolean isBrowser; - - if (filters != null) - { - Boolean isBrowserObj = (Boolean) filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); - isBrowser = (isBrowserObj != null) && isBrowserObj.booleanValue(); - } - else - { - isBrowser = false; - } - - if(isBrowser) - { - return new SubscriptionImpl.BrowserSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); - } - else if(acks) - { - return new SubscriptionImpl.AckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); - } - else - { - return new SubscriptionImpl.NoAckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); - } - } - - - public static final SubscriptionFactoryImpl INSTANCE = new SubscriptionFactoryImpl(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java deleted file mode 100644 index 043caa53ae..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.subscription; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.filter.FilterManager; -import org.apache.qpid.server.filter.FilterManagerFactory; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; - -/** - * Encapsulation of a supscription to a queue.

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

      - */ -public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener -{ - - private StateListener _stateListener = new StateListener() - { - - public void stateChange(Subscription sub, State oldState, State newState) - { - - } - }; - - - private final AtomicReference _state = new AtomicReference(State.ACTIVE); - private final AtomicReference _queueContext = new AtomicReference(null); - private final ClientDeliveryMethod _deliveryMethod; - private final RecordDeliveryMethod _recordMethod; - - private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); - private final Lock _stateChangeLock; - - static final class BrowserSubscription extends SubscriptionImpl - { - public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); - } - - - public boolean isBrowser() - { - return true; - } - - /** - * 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 The message to send - * @throws AMQException - */ - @Override - public void send(QueueEntry msg) throws AMQException - { - // We don't decrement the reference here as we don't want to consume the message - // but we do want to send it to the client. - - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); - sendToClient(msg, deliveryTag); - } - - } - - @Override - public boolean wouldSuspend(QueueEntry msg) - { - return false; - } - - } - - public static class NoAckSubscription extends SubscriptionImpl - { - public NoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); - } - - - public boolean isBrowser() - { - return false; - } - - /** - * 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 entry The message to send - * @throws AMQException - */ - @Override - public void send(QueueEntry entry) throws AMQException - { - - StoreContext storeContext = getChannel().getStoreContext(); - try - { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - entry.dequeueAndDelete(storeContext); - - - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); - - sendToClient(entry, deliveryTag); - - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - entry.setDeliveredToSubscription(); - } - } - - @Override - public boolean wouldSuspend(QueueEntry msg) - { - return false; - } - - } - - static final class AckSubscription extends SubscriptionImpl - { - public AckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); - } - - - public boolean isBrowser() - { - return false; - } - - - /** - * 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 entry The message to send - * @throws AMQException - */ - @Override - public void send(QueueEntry entry) throws AMQException - { - - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); - - - recordMessageDelivery(entry, deliveryTag); - sendToClient(entry, deliveryTag); - - - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - entry.setDeliveredToSubscription(); - } - } - - - } - - - private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); - - private final AMQChannel _channel; - - private final AMQShortString _consumerTag; - - - private final boolean _noLocal; - - private final FlowCreditManager _creditManager; - - private FilterManager _filters; - - private final Boolean _autoClose; - - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - private AMQQueue _queue; - private final AtomicBoolean _deleted = new AtomicBoolean(false); - - - - - public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable arguments, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - - _channel = channel; - _consumerTag = consumerTag; - - _creditManager = creditManager; - creditManager.addStateListener(this); - - _noLocal = noLocal; - - - _filters = FilterManagerFactory.createManager(arguments); - - _deliveryMethod = deliveryMethod; - _recordMethod = recordMethod; - - - _stateChangeLock = new ReentrantLock(); - - - if (arguments != null) - { - Object autoClose = arguments.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); - if (autoClose != null) - { - _autoClose = (Boolean) autoClose; - } - else - { - _autoClose = false; - } - } - else - { - _autoClose = false; - } - - _logger.info(debugIdentity()+" Created subscription:"); - } - - - - public synchronized void setQueue(AMQQueue queue) - { - if(getQueue() != null) - { - throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); - } - _queue = queue; - } - - public String toString() - { - String subscriber = "[channel=" + _channel + - ", consumerTag=" + _consumerTag + - ", session=" + getProtocolSession().getKey() ; - - return subscriber + "]"; - } - - /** - * 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 The message to send - * @throws AMQException - */ - abstract public void send(QueueEntry msg) throws AMQException; - - - public boolean isSuspended() - { - return !isActive() || _channel.isSuspended() || _deleted.get(); - } - - /** - * Callback indicating that a queue has been deleted. - * - * @param queue The queue to delete - */ - public void queueDeleted(AMQQueue queue) - { - _deleted.set(true); -// _channel.queueDeleted(queue); - } - - public boolean filtersMessages() - { - return _filters != null || _noLocal; - } - - public boolean hasInterest(QueueEntry entry) - { - //check that the message hasn't been rejected - if (entry.isRejectedBy(this)) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); - } -// return false; - } - - - - //todo - client id should be recoreded and this test removed but handled below - if (_noLocal) - { - //todo getPublisherClientInstance should be moved to QueueEntryImpl - final Object publisherId = entry.getMessage().getPublisherClientInstance(); - - // We don't want local messages so check to see if message is one we sent - Object localInstance; - - if (publisherId != null && (getProtocolSession().getClientProperties() != null) && - (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) - { - if(publisherId.equals(localInstance)) - { - return false; - } - } - else - { - - localInstance = getProtocolSession().getClientIdentifier(); - //todo - client id should be recoreded and this test removed but handled here - - - //todo getPublisherIdentifier should be moved to QueueEntryImpl - if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) - { - return false; - } - } - - - } - - - if (_logger.isDebugEnabled()) - { - _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity()); - } - return checkFilters(entry); - - } - - private String id = String.valueOf(System.identityHashCode(this)); - - private String debugIdentity() - { - return id; - } - - private boolean checkFilters(QueueEntry msg) - { - return (_filters == null) || _filters.allAllow(msg); - } - - public boolean isAutoClose() - { - return _autoClose; - } - - public FlowCreditManager getCreditManager() - { - return _creditManager; - } - - - public void close() - { - boolean closed = false; - State state = getState(); - - _stateChangeLock.lock(); - try - { - while(!closed && state != State.CLOSED) - { - closed = _state.compareAndSet(state, State.CLOSED); - if(!closed) - { - state = getState(); - } - else - { - _stateListener.stateChange(this,state, State.CLOSED); - } - } - _creditManager.removeListener(this); - } - finally - { - _stateChangeLock.unlock(); - } - - - if (closed) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Called close() on a closed subscription"); - } - - return; - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing subscription (" + debugIdentity() + "):" + this); - } - } - - public boolean isClosed() - { - return getState() == State.CLOSED; - } - - - public boolean wouldSuspend(QueueEntry queueEntry) - { - return !_creditManager.useCreditForMessage(queueEntry); - } - - public void getSendLock() - { - _stateChangeLock.lock(); - } - - public void releaseSendLock() - { - _stateChangeLock.unlock(); - } - - public void resend(final QueueEntry entry) throws AMQException - { - _queue.resend(entry, this); - } - - public AMQChannel getChannel() - { - return _channel; - } - - public AMQShortString getConsumerTag() - { - return _consumerTag; - } - - public AMQProtocolSession getProtocolSession() - { - return _channel.getProtocolSession(); - } - - public AMQQueue getQueue() - { - return _queue; - } - - public void restoreCredit(final QueueEntry queueEntry) - { - _creditManager.addCredit(1, queueEntry.getSize()); - } - - - public void creditStateChanged(boolean hasCredit) - { - - if(hasCredit) - { - if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) - { - _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); - } - else - { - // this is a hack to get round the issue of increasing bytes credit - _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE); - } - } - else - { - if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) - { - _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); - } - } - } - - public State getState() - { - return _state.get(); - } - - - public void setStateListener(final StateListener listener) - { - _stateListener = listener; - } - - - public QueueEntry getLastSeenEntry() - { - return _queueContext.get(); - } - - public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) - { - return _queueContext.compareAndSet(expected,newvalue); - } - - - protected void sendToClient(final QueueEntry entry, final long deliveryTag) - throws AMQException - { - if(_logger.isDebugEnabled()) - { - _logger.debug("Sending Message(" + entry + ") DTag:" + deliveryTag + " to subscription:" + debugIdentity()); - } - _deliveryMethod.deliverToClient(this,entry,deliveryTag); - } - - - protected void recordMessageDelivery(final QueueEntry entry, final long deliveryTag) - { - _recordMethod.recordMessageDelivery(this,entry,deliveryTag); - } - - - public boolean isActive() - { - return getState() == State.ACTIVE; - } - - public QueueEntry.SubscriptionAcquiredState getOwningState() - { - return _owningState; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java deleted file mode 100644 index 3fbb6bfa4a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java +++ /dev/null @@ -1,247 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.subscription; - -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.subscription.Subscription; - -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.nio.ByteBuffer; - -public class SubscriptionList -{ - - private final SubscriptionNode _head = new SubscriptionNode(); - - private AtomicReference _tail = new AtomicReference(_head); - private final AMQQueue _queue; - private AtomicInteger _size = new AtomicInteger(); - - - public final class SubscriptionNode - { - private final AtomicBoolean _deleted = new AtomicBoolean(); - private final AtomicReference _next = new AtomicReference(); - private final Subscription _sub; - - - public SubscriptionNode() - { - - _sub = null; - _deleted.set(true); - } - - public SubscriptionNode(final Subscription sub) - { - _sub = sub; - } - - - public SubscriptionNode getNext() - { - - SubscriptionNode next = nextNode(); - while(next != null && next.isDeleted()) - { - - final SubscriptionNode newNext = next.nextNode(); - if(newNext != null) - { - _next.compareAndSet(next, newNext); - next = nextNode(); - } - else - { - next = null; - } - - } - return next; - } - - private SubscriptionNode nextNode() - { - return _next.get(); - } - - public boolean isDeleted() - { - return _deleted.get(); - } - - - public boolean delete() - { - if(_deleted.compareAndSet(false,true)) - { - _size.decrementAndGet(); - advanceHead(); - return true; - } - else - { - return false; - } - } - - - public Subscription getSubscription() - { - return _sub; - } - } - - - public SubscriptionList(AMQQueue queue) - { - _queue = queue; - } - - private void advanceHead() - { - SubscriptionNode head = _head.nextNode(); - while(head._next.get() != null && head.isDeleted()) - { - - final SubscriptionNode newhead = head.nextNode(); - if(newhead != null) - { - _head._next.compareAndSet(head, newhead); - } - head = _head.nextNode(); - } - } - - - public SubscriptionNode add(Subscription sub) - { - SubscriptionNode node = new SubscriptionNode(sub); - for (;;) - { - SubscriptionNode tail = _tail.get(); - SubscriptionNode next = tail.nextNode(); - if (tail == _tail.get()) - { - if (next == null) - { - if (tail._next.compareAndSet(null, node)) - { - _tail.compareAndSet(tail, node); - _size.incrementAndGet(); - return node; - } - } - else - { - _tail.compareAndSet(tail, next); - } - } - } - - } - - public boolean remove(Subscription sub) - { - SubscriptionNode node = _head.getNext(); - while(node != null) - { - if(sub.equals(node._sub) && node.delete()) - { - return true; - } - node = node.getNext(); - } - return false; - } - - - public class SubscriptionNodeIterator - { - - private SubscriptionNode _lastNode; - - SubscriptionNodeIterator(SubscriptionNode startNode) - { - _lastNode = startNode; - } - - - public boolean atTail() - { - return _lastNode.nextNode() == null; - } - - public SubscriptionNode getNode() - { - - return _lastNode; - - } - - public boolean advance() - { - - if(!atTail()) - { - SubscriptionNode nextNode = _lastNode.nextNode(); - while(nextNode.isDeleted() && nextNode.nextNode() != null) - { - nextNode = nextNode.nextNode(); - } - _lastNode = nextNode; - return true; - - } - else - { - return false; - } - - } - - } - - - public SubscriptionNodeIterator iterator() - { - return new SubscriptionNodeIterator(_head); - } - - - public SubscriptionNode getHead() - { - return _head; - } - - public int size() - { - return _size.get(); - } - - - -} - - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java deleted file mode 100644 index 9c8cad4240..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/BaseTransactionLog.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transactionlog; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.Collections; -import java.util.List; - -public class BaseTransactionLog implements TransactionLog -{ - private static final Logger _logger = Logger.getLogger(BaseTransactionLog.class); - - TransactionLog _delegate; - protected Map> _idToQueues = Collections.synchronizedMap(new HashMap>()); - - public BaseTransactionLog(TransactionLog delegate) - { - _delegate = delegate; - } - - public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - return _delegate.configure(virtualHost, base, config); - } - - public void close() throws Exception - { - _delegate.close(); - } - - public void enqueueMessage(StoreContext context, ArrayList queues, Long messageId) throws AMQException - { - if (queues.size() > 1) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Recording Enqueue of (" + messageId + ") on queue:" + queues); - } - - //variable to hold which new queues to enqueue the message on - ArrayList toEnqueueList = null; - - List enqueuedList = _idToQueues.get(messageId); - if (enqueuedList != null) - { - //There are previous enqueues for this messageId - //create new empty list to hold additions - toEnqueueList = new ArrayList(); - - synchronized (enqueuedList) - { - for(AMQQueue queue : queues) - { - if(!enqueuedList.contains(queue)) - { - //update the old list. - enqueuedList.add(queue); - //keep track of new enqueues to be made - toEnqueueList.add(queue); - } - } - } - - if(toEnqueueList.isEmpty()) - { - //no new queues to enqueue message on - return; - } - } - else - { - //No existing list, add all provided queues (cloning toEnqueueList in case someone else changes original). - toEnqueueList = queues; - _idToQueues.put(messageId, Collections.synchronizedList((ArrayList)toEnqueueList.clone())); - } - - _delegate.enqueueMessage(context, toEnqueueList, messageId); - } - else - { - _delegate.enqueueMessage(context, queues, messageId); - } - } - - public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - context.dequeueMessage(queue, messageId); - - _delegate.dequeueMessage(context, queue, messageId); - - if (!context.inTransaction()) - { - processDequeues(context.getDequeueMap()); - } - } - - /** - * This should not be called from main broker code. - * // Perhaps we need a new interface: - * - * Broker <->TransactionLog - * Broker <->BaseTransactionLog<->(Log with removeMessage()) - */ - public void removeMessage(StoreContext context, Long messageId) throws AMQException - { - _delegate.removeMessage(context, messageId); - } - - public void beginTran(StoreContext context) throws AMQException - { - context.beginTransaction(); - _delegate.beginTran(context); - } - - public void commitTran(StoreContext context) throws AMQException - { - - Map> messageMap = context.getDequeueMap(); - - //For each Message ID that is in the map check - Set messageIDs = messageMap.keySet(); - - if (_logger.isInfoEnabled()) - { - _logger.info("Pre-Processing single dequeue of:" + messageIDs); - } - - Iterator iterator = messageIDs.iterator(); - - while (iterator.hasNext()) - { - Long messageID = (Long) iterator.next(); - //If we don't have a gloabl reference for this message then there - // is only a single enqueue can check here to see if this is the - // last reference? - if (_idToQueues.get(messageID) == null) - { - // Add the removal of the message to this transaction - _delegate.removeMessage(context, messageID); - // Remove this message ID as we have processed it so we don't - // reprocess after the main commmit - iterator.remove(); - } - } - - //Perform real commit of current data - _delegate.commitTran(context); - - processDequeues(context.getDequeueMap()); - - //Commit the recorded state for this transaction. - context.commitTransaction(); - } - - public void abortTran(StoreContext context) throws AMQException - { - //Abort the recorded state for this transaction. - context.abortTransaction(); - - _delegate.abortTran(context); - } - - private void processDequeues(Map> messageMap) - throws AMQException - { - // Check we have dequeues to process then process them - if (messageMap == null || messageMap.isEmpty()) - { - return; - } - - // Process any enqueues to bring our model up to date. - Set messageIDs = messageMap.keySet(); - - //Create a new Asynchronous Context. - StoreContext removeContext = new StoreContext(true); - - //Batch Process the Dequeues on the delegate - _delegate.beginTran(removeContext); - removeContext.beginTransaction(); - - try - { - //For each Message ID Decrement the reference for each of the queues it was on. - - if (_logger.isInfoEnabled()) - { - _logger.info("Processing Dequeue for:" + messageIDs); - } - - Iterator messageIDIterator = messageIDs.iterator(); - - while(messageIDIterator.hasNext()) - { - Long messageID = messageIDIterator.next(); - List queueList = messageMap.get(messageID); - - //Remove this message from our DequeueMap as we are processing it. - messageIDIterator.remove(); - - // For each of the queues decrement the reference - for (AMQQueue queue : queueList) - { - List enqueuedList = _idToQueues.get(messageID); - - if (_logger.isInfoEnabled()) - { - _logger.info("Dequeue message:" + messageID + " from :" + queue); - } - - - // If we have no mapping then this message was only enqueued on a single queue - // This will be the case when we are not in a larger transaction - if (enqueuedList == null) - { - _delegate.removeMessage(removeContext, messageID); - } - else - { - //When a message is on more than one queue it is possible that this code section is exectuted - // by one thread per enqueue. - // It is however, thread safe because there is only removes being performed and so the - // last thread that does the remove will see the empty queue and remove the message - // At this stage there is nothing that is going to cause this operation to abort. So we don't - // need to worry about any potential adds. - // The message will no longer be enqueued as that operation has been committed before now so - // this is clean up of the data. - - //Must synchronize here as this list may have been extracted from _idToQueues in many threads - // and we must ensure only one of them update the list at a time. - synchronized (enqueuedList) - { - // Update the enqueued list but if the queue is not in the list then we are trying - // to dequeue something that is not there anymore, or was never there. - if (!enqueuedList.remove(queue)) - { - throw new UnableToDequeueException(messageID, queue); - } - - // If the list is now empty then remove the message - if (enqueuedList.isEmpty()) - { - _delegate.removeMessage(removeContext, messageID); - //Remove references list - _idToQueues.remove(messageID); - } - } - } - } - } - //Commit the removes on the delegate. - _delegate.commitTran(removeContext); - // Mark this context as committed. - removeContext.commitTransaction(); - } - finally - { - if (removeContext.inTransaction()) - { - _delegate.abortTran(removeContext); - } - } - } - - public boolean inTran(StoreContext context) - { - return _delegate.inTran(context); - } - - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException - { - _delegate.storeContentBodyChunk(context, messageId, index, contentBody, lastContentBody); - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException - { - _delegate.storeMessageMetaData(context, messageId, messageMetaData); - } - - public boolean isPersistent() - { - return _delegate.isPersistent(); - } - - public TransactionLog getDelegate() - { - return _delegate; - } - - private class UnableToDequeueException extends RuntimeException - { - Long _messageID; - AMQQueue _queue; - - public UnableToDequeueException(Long messageID, AMQQueue queue) - { - super("Unable to dequeue message(" + messageID + ") from queue " + - "(" + queue + ") it is not/nolonger enqueued on it."); - _messageID = messageID; - _queue = queue; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java deleted file mode 100644 index b2054c3436..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transactionlog/TransactionLog.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transactionlog; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.store.StoreContext; - -import java.util.ArrayList; - -/** - * TransactionLog defines the interface for performing transactions. - * This is used to preserve the state of messages, queues - * and exchanges in a transactional manner. - * - *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which - * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single - * transaction. - * - *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. - * - *

      - *
      CRC Card
      Responsibilities - *
      Accept transaction boundary demarcations: Begin, Commit, Abort. - *
      Store and remove queues. - *
      Store and remove exchanges. - *
      Store and remove messages. - *
      Bind and unbind queues to exchanges. - *
      Enqueue and dequeue messages to queues. - *
      Generate message identifiers. - *
      - */ -public interface TransactionLog -{ - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config The apache commons configuration object. - * - * @throws Exception If any error occurs that means the store is unable to configure itself. - */ - Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * - * @throws Exception If the close fails. - */ - void close() throws Exception; - - /** - * Places a message onto a specified queue, in a given transactional context. - * - * This method need not be thread safe as it is only called by the message delivery thread - * - * @param context The transactional context for the operation. - * @param queues - *@param messageId The message to enqueue. @throws AMQException If the operation fails for any reason. @throws org.apache.qpid.AMQException - */ - void enqueueMessage(StoreContext context, final ArrayList queues, Long messageId) throws AMQException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * This method MUST be thread safe as dequeue will be called by multiple threads, ack, requeue, delivery thread - * - * @param context The transactional context for the operation. - * @param queue - * @param messageId The message to dequeue. @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Remove the specified message from the log - * - * This method MUST be thread safe as dequeue will be called by multiple threads, ack, requeue, delivery thread - * - * @param context The transactional context for the operation - * @param messageId The message to remove - * @throws AMQException - */ - void removeMessage(StoreContext context, Long messageId) throws AMQException; - - /** - * Begins a transactional context. - * - * @param context The transactional context to begin. - * @throws AMQException If the operation fails for any reason. - */ - void beginTran(StoreContext context) throws AMQException; - - /** - * Commits all operations performed within a given transactional context. - * - * @param context The transactional context to commit all operations for. - * - * @throws AMQException If the operation fails for any reason. - */ - void commitTran(StoreContext context) throws AMQException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @param context The transactional context to abandon. - * - * @throws AMQException If the operation fails for any reason. - */ - void abortTran(StoreContext context) throws AMQException; - - /** - * Tests a transactional context to see if it has been begun but not yet committed or aborted. - * - * @param context The transactional context to test. - * - * @return true if the transactional context is live, false otherwise. - */ - boolean inTran(StoreContext context); - - - /** - * Stores a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param index The index of the data chunk. - * @param contentBody The content of the data chunk. - * @param lastContentBody Flag to indicate that this is the last such chunk for the message. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, - boolean lastContentBody) throws AMQException; - - /** - * Stores message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param messageMetaData The message meta data to store. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; -// -// /** -// * Retrieves message meta-data. -// * -// * @param context The transactional context for the operation. -// * @param messageId The message to get the meta-data for. -// * -// * @return The message meta data. -// * -// * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. -// */ -// MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; -// -// /** -// * Retrieves a chunk of message data. -// * -// * @param context The transactional context for the operation. -// * @param messageId The message to get the data chunk for. -// * @param index The offset index of the data chunk within the message. -// * -// * @return A chunk of message data. -// * -// * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. -// */ -// ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; - - /** - * Is this store capable of persisting the data - * - * @return true if this store is capable of persisting data - */ - boolean isPersistent(); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java deleted file mode 100644 index bdd27f2d1c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ /dev/null @@ -1,705 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoFilterAdapter; -import org.apache.mina.common.IoHandler; -import org.apache.mina.common.IoSession; -import org.apache.mina.util.BlockingQueue; -import org.apache.mina.util.ByteBufferUtil; -import org.apache.mina.util.IdentityHashSet; -import org.apache.mina.util.Queue; -import org.apache.mina.util.Stack; - -/** - * 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); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java deleted file mode 100644 index abfb60c5bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.StoreContext; - -import java.util.List; -import java.util.ArrayList; - -/** A transactional context that only supports local transactions. */ -public class LocalTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); - - private final TxnBuffer _txnBuffer = new TxnBuffer(); - - private final List _postCommitDeliveryList = new ArrayList(); - - /** - * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are - * consolidated into a single operation - */ - private TxAck _ackOp; - - private boolean _inTran = false; - - /** Are there messages to deliver. NOT Has the message been delivered */ - private boolean _messageDelivered = false; - private final AMQChannel _channel; - - private abstract class DeliveryAction - { - - abstract public void process() throws AMQException; - - } - - private class RequeueAction extends DeliveryAction - { - public QueueEntry entry; - - public RequeueAction(QueueEntry entry) - { - this.entry = entry; - } - - public void process() throws AMQException - { - entry.requeue(getStoreContext()); - } - } - - private class PublishAction extends DeliveryAction - { - private final AMQQueue _queue; - private final AMQMessage _message; - - public PublishAction(final AMQQueue queue, final AMQMessage message) - { - _queue = queue; - _message = message; - } - - public void process() throws AMQException - { - - QueueEntry entry = _queue.enqueue(getStoreContext(),_message); - - if(entry.immediateAndNotDelivered()) - { - getReturnMessages().add(new NoConsumersException(_message)); - } - } - } - - public LocalTransactionalContext(final AMQChannel channel) - { - _channel = channel; - } - - public StoreContext getStoreContext() - { - return _channel.getStoreContext(); - } - - public List getReturnMessages() - { - return _channel.getReturnMessages(); - } - - public TransactionLog getTransactionLog() - { - return _channel.getTransactionLog(); - } - - - public void rollback() throws AMQException - { - _txnBuffer.rollback(getStoreContext()); - // Hack to deal with uncommitted non-transactional writes - if (getTransactionLog().inTran(getStoreContext())) - { - getTransactionLog().abortTran(getStoreContext()); - _inTran = false; - } - - _postCommitDeliveryList.clear(); - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - // A publication will result in the enlisting of several - // TxnOps. The first is an op that will store the message. - // Following that (and ordering is important), an op will - // be added for every queue onto which the message is - // enqueued. - _postCommitDeliveryList.add(new PublishAction(queue, message)); - _messageDelivered = true; - - } - - public void requeue(QueueEntry entry) throws AMQException - { - _postCommitDeliveryList.add(new RequeueAction(entry)); - _messageDelivered = true; - - } - - - private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - - public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - // check that the tag exists to give early failure - if (!multiple || (deliveryTag > 0)) - { - checkAck(deliveryTag, unacknowledgedMessageMap); - } - // we use a single txn op for all acks and update this op - // as new acks come in. If this is the first ack in the txn - // we will need to create and enlist the op. - if (_ackOp == null) - { - _ackOp = new TxAck(unacknowledgedMessageMap); - _txnBuffer.enlist(_ackOp); - } - // update the op to include this ack request - if (multiple && (deliveryTag == 0)) - { - // if have signalled to ack all, that refers only - // to all at this time - _ackOp.update(lastDeliveryTag, multiple); - } - else - { - _ackOp.update(deliveryTag, multiple); - } - if(!_inTran && _ackOp.checkPersistent()) - { - beginTranIfNecessary(); - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - // Not required in this transactional context - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - // Not required in this transactional context - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - if (_log.isDebugEnabled()) - { - _log.debug("Starting transaction on message store: " + this); - } - - getTransactionLog().beginTran(getStoreContext()); - _inTran = true; - } - } - - public void commit() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing transactional context: " + this); - } - - if (_ackOp != null) - { - - _messageDelivered = true; - _ackOp.consolidate(); - // already enlisted, after commit will reset regardless of outcome - _ackOp = null; - } - - if (_messageDelivered && _inTran) - { - _txnBuffer.enlist(new StoreMessageOperation(getTransactionLog())); - } - // fixme fail commit here ... QPID-440 - try - { - _txnBuffer.commit(getStoreContext()); - } - finally - { - _messageDelivered = false; - _inTran = getTransactionLog().inTran(getStoreContext()); - } - - try - { - postCommitDelivery(); - } - catch (AMQException e) - { - // OK so what do we do now...? - _log.error("Failed to deliver messages following txn commit: " + e, e); - } - } - - private void postCommitDelivery() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Performing post commit delivery"); - } - - try - { - for (DeliveryAction dd : _postCommitDeliveryList) - { - dd.process(); - } - } - finally - { - _postCommitDeliveryList.clear(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java deleted file mode 100644 index 9a90dd4bb2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.StoreContext; - -/** @author Apache Software Foundation */ -public class NonTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - - /** Channel is useful for logging */ - private final AMQChannel _channel; - - /** Where to put undeliverable messages */ - private final List _returnMessages; - - - - private final TransactionLog _transactionLog; - - private final StoreContext _storeContext; - - /** Whether we are in a transaction */ - private boolean _inTran; - - public NonTransactionalContext(TransactionLog transactionLog, StoreContext storeContext, AMQChannel channel, - List returnMessages) - { - _channel = channel; - _storeContext = storeContext; - _returnMessages = returnMessages; - _transactionLog = transactionLog; - - } - - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _transactionLog.beginTran(_storeContext); - _inTran = true; - } - } - - public void commit() throws AMQException - { - // Does not apply to this context - } - - public void rollback() throws AMQException - { - // Does not apply to this context - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - QueueEntry entry = queue.enqueue(_storeContext, message); - - //following check implements the functionality - //required by the 'immediate' flag: - if(entry.immediateAndNotDelivered()) - { - _returnMessages.add(new NoConsumersException(entry.getMessage())); - } - - } - - public void requeue(QueueEntry entry) throws AMQException - { - entry.requeue(_storeContext); - } - - public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, - boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) - throws AMQException - { - - final boolean debug = _log.isDebugEnabled(); - ; - if (multiple) - { - if (deliveryTag == 0) - { - - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, - // tells the server to acknowledge all outstanding mesages. - _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + - unacknowledgedMessageMap.size()); - unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(final long deliveryTag, QueueEntry queueEntry) throws AMQException - { - if (debug) - { - _log.debug("Discarding message: " + queueEntry.getMessageId()); - } - if(queueEntry.isPersistent()) - { - beginTranIfNecessary(); - } - //Message has been ack so dequeueAndDelete it. - queueEntry.dequeueAndDelete(_storeContext); - - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } - else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - - unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext); - } - } - else - { - QueueEntry queueEntry; - queueEntry = unacknowledgedMessageMap.remove(deliveryTag); - - if (debug) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag); - } - - if (queueEntry == null) - { - _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - } - - if (debug) - { - _log.debug("Discarding message: " + queueEntry.getMessageId()); - } - if(queueEntry.isPersistent()) - { - beginTranIfNecessary(); - } - - //Message has been ack so dequeueAndDelete it. - // If the message is persistent and this is the last QueueEntry that uses it then the data will be removed - // from the transaciton log - queueEntry.dequeueAndDelete(_storeContext); - - } - if(_inTran) - { - _transactionLog.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - if (persistent) - { - _transactionLog.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - _channel.processReturns(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java deleted file mode 100644 index f1fbca2e28..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.transactionlog.TransactionLog; - -/** - * 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 TransactionLog _transactionLog; - - public StoreMessageOperation(TransactionLog transactionLog) - { - _transactionLog = transactionLog; - } - - public void prepare(StoreContext context) throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit(StoreContext context) throws AMQException - { - _transactionLog.commitTran(context); - } - - public void rollback(StoreContext context) throws AMQException - { - _transactionLog.abortTran(context); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java deleted file mode 100644 index 647ba66fb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -/** - * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. - * Different levels of transactional support for the delivery of messages may be provided by different implementations - * of this interface. - * - *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. - * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} - * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. - * - *

      - *
      CRC Card
      Responsibilities - *
      Explicitly accept a transaction start notification. - *
      Commit all pending operations in a transaction. - *
      Rollback all pending operations in a transaction. - *
      Deliver a message to a queue as part of a transaction. - *
      Redeliver a message to a queue as part of a transaction. - *
      Mark a message as acknowledged as part of a transaction. - *
      Accept notification that a message has been completely received as part of a transaction. - *
      Accept notification that a message has been fully processed as part of a transaction. - *
      Associate a message store context with this transaction context. - *
      - * - * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional - * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them - * somewhere else, a seperate interface for example. - * - * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides - * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any - * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean - * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be - * conceptually neater. - * - * For example: - *

      - * public interface Transactional
      - * {
      - *    public void commit();
      - *    public void rollback();
      - * }
      - *
      - * public interface TransactionalQueue extends Transactional, SizeableQueue
      - * {}
      - *
      - * public class Queues
      - * {
      - *    ...
      - *    // For transactional messaging, take a transactional view onto the queue.
      - *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      - *
      - *    // For non-transactional messaging, take a non-transactional view onto the queue.
      - *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      - * }
      - * 
      - */ -public interface TransactionalContext -{ - /** - * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} - * should automatically begin the next transaction in the chain. - * - * @throws AMQException If the transaction cannot be started for any reason. - */ - void beginTranIfNecessary() throws AMQException; - - /** - * Makes all pending operations on the transaction permanent and visible. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void commit() throws AMQException; - - /** - * Erases all pending operations on the transaction. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void rollback() throws AMQException; - - /** - * Delivers the specified message to the specified queue. - * - *

      This is an 'enqueue' operation. - * - * @param queue - * @param message The message to deliver - * @throws AMQException If the message cannot be delivered for any reason. - */ - void deliver(final AMQQueue queue, AMQMessage message) throws AMQException; - - /** - * Requeues the specified message entry (message queue pair) - * - * - * @param queueEntry The message,queue pair - * - * @throws AMQException If the message cannot be delivered for any reason. - */ - void requeue(QueueEntry queueEntry) throws AMQException; - - - /** - * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by - * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' - * flag is set, in which case an acknowledgement up to the latest delivered message should be done. - * - *

      This is a 'dequeue' operation. - * - * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement - * up to the latest message. - * @param lastDeliveryTag The latest message delivered. - * @param multiple true if all message ids up the acknowledged one or latest delivered, are - * to be acknowledged, false otherwise. - * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message - * from. - * - * @throws AMQException If the message cannot be acknowledged for any reason. - */ - void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - - /** - * Notifies the transactional context that a message has been fully received. The actual message that was received - * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, - * flushing its data to disk. - * - * @param persistent true if the received message is persistent, false otherwise. - * - * @throws AMQException If the fully received event cannot be processed for any reason. - */ - void messageFullyReceived(boolean persistent) throws AMQException; - - /** - * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual - * message that was delivered is not specified. This event may be used to trigger a process related to the - * outcome of the delivery of the message, for example, cleaning up failed deliveries. - * - * @param protocolSession The protocol session of the deliverable message. - * - * @throws AMQException If the message processed event cannot be handled for any reason. - */ - void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; - - /** - * Gets the message store context associated with this transactional context. - * - * @return The message store context associated with this transactional context. - */ - StoreContext getStoreContext(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java deleted file mode 100644 index 46a68b6a23..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** Holds a list of TxnOp instance representing transactional operations. */ -public class TxnBuffer -{ - private final List _ops = new ArrayList(); - private static final Logger _log = Logger.getLogger(TxnBuffer.class); - - public TxnBuffer() - { - } - - public void commit(StoreContext context) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); - } - - if (prepare(context)) - { - for (TxnOp op : _ops) - { - op.commit(context); - } - } - _ops.clear(); - } - - private boolean prepare(StoreContext context) throws AMQException - { - for (int i = 0; i < _ops.size(); i++) - { - TxnOp op = _ops.get(i); - try - { - op.prepare(context); - } - catch (AMQException e) - { - undoPrepare(i); - throw e; - } - catch (RuntimeException e) - { - undoPrepare(i); - throw e; - } - } - return true; - } - - private void undoPrepare(int lastPrepared) - { - //compensate previously prepared ops - for (int j = 0; j < lastPrepared; j++) - { - _ops.get(j).undoPrepare(); - } - } - - - - public void rollback(StoreContext context) throws AMQException - { - for (TxnOp op : _ops) - { - op.rollback(context); - } - _ops.clear(); - } - - public void enlist(TxnOp op) - { - _ops.add(op); - } - - public void cancel(TxnOp op) - { - _ops.remove(op); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java deleted file mode 100644 index 919c078cf0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** - * This provides the abstraction of an individual operation within a - * transaction. It is used by the TxnBuffer class. - */ -public interface TxnOp -{ - /** - * Do the part of the operation that updates persistent state - */ - public void prepare(StoreContext context) throws AMQException; - /** - * Complete the operation started by prepare. Can now update in - * memory state or make netork transfers. - */ - public void commit(StoreContext context) throws AMQException; - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback(StoreContext context) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java deleted file mode 100644 index e730e2f3c3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Iterator; - -import org.apache.log4j.Logger; - -public class CircularBuffer implements Iterable -{ - - private static final Logger _logger = Logger.getLogger(CircularBuffer.class); - - 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) - { - _logger.info(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); - _logger.info(buffer); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java deleted file mode 100644 index cf5e71a6e2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue -{ - public int size() - { - if (isEmpty()) - { - return 0; - } - else - { - return 1; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java deleted file mode 100644 index eda97e0ed2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; - -/** - * Dynamic proxy that records invocations in a fixed size circular buffer, - * dumping details on hitting an exception. - *

      - * Useful in debugging. - *

      - */ -public class LoggingProxy implements InvocationHandler -{ - private final Object _target; - private final CircularBuffer _log; - - public LoggingProxy(Object target, int size) - { - _target = target; - _log = new CircularBuffer(size); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - try - { - entered(method, args); - Object result = method.invoke(_target, args); - returned(method, result); - return result; - } - catch(InvocationTargetException e) - { - dump(); - throw e.getTargetException(); - } - } - - void dump() - { - _log.dump(); - } - - CircularBuffer getBuffer() - { - return _log; - } - - private synchronized void entered(Method method, Object[] args) - { - if (args == null) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); - } - } - - private synchronized void returned(Method method, Object result) - { - if (method.getReturnType() == Void.TYPE) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); - } - } - - public Object getProxy(Class... c) - { - return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); - } - - public int getBufferSize() { - return _log.size(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java deleted file mode 100644 index eda2d3a94e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Properties; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.MapConfiguration; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.plugins.AllowAll; -import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -public class NullApplicationRegistry extends ApplicationRegistry -{ - public NullApplicationRegistry() throws ConfigurationException - { - super(new ServerConfiguration(new PropertiesConfiguration())); - } - - public void initialise() throws Exception - { - _logger.info("Initialising NullApplicationRegistry"); - - _configuration.setHousekeepingExpiredMessageCheckPeriod(200); - - Properties users = new Properties(); - - users.put("guest", "guest"); - - _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); - - _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _managedObjectRegistry = new NoopManagedObjectRegistry(); - _virtualHostRegistry = new VirtualHostRegistry(); - PropertiesConfiguration vhostProps = new PropertiesConfiguration(); - VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); - VirtualHost dummyHost = new VirtualHost(hostConfig); - _virtualHostRegistry.registerVirtualHost(dummyHost); - _virtualHostRegistry.setDefaultVirtualHostName("test"); - _pluginManager = new PluginManager(""); - - } - - public Collection getVirtualHostNames() - { - String[] hosts = {"test"}; - return Arrays.asList(hosts); - } -} - - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java deleted file mode 100644 index f4c81fbbb8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; - -/** - * The management interface exposed to allow management of an Exchange. - * @version 0.1 - */ -public interface ManagedVirtualHost -{ - static final String TYPE = "VirtualHost"; - static final int VERSION = 1; - - /** - * Returns the name of the managed virtualHost. - * @return the name of the exchange. - * @throws java.io.IOException - */ - @MBeanAttribute(name="Name", description= TYPE + " Name") - String getName() throws IOException; - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java deleted file mode 100644 index dc12d97557..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ /dev/null @@ -1,597 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.configuration.ExchangeConfiguration; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.connection.ConnectionRegistry; -import org.apache.qpid.server.connection.IConnectionRegistry; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.FileQueueBackingStoreFactory; -import org.apache.qpid.server.queue.QueueBackingStoreFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.routing.RoutingTable; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.transactionlog.TransactionLog; -import org.apache.qpid.server.transactionlog.BaseTransactionLog; - -import javax.management.NotCompliantMBeanException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -public class VirtualHost implements Accessable -{ - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - private final String _name; - - private ConnectionRegistry _connectionRegistry; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private TransactionLog _transactionLog; - - private RoutingTable _routingTable; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private ACLManager _accessManager; - - private final Timer _houseKeepingTimer; - - private VirtualHostConfiguration _configuration; - private QueueBackingStoreFactory _queueBackingStoreFactory; - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - public IConnectionRegistry getConnectionRegistry() - { - return _connectionRegistry; - } - - public RoutingTable getRoutingTable() - { - return _routingTable; - } - - public VirtualHostConfiguration getConfiguration() - { - return _configuration; - } - - public QueueBackingStoreFactory getQueueBackingStoreFactory() - { - return _queueBackingStoreFactory; - } - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - } // End of MBean class - - /** - * Normal Constructor - * - * @param hostConfig - * - * @throws Exception - */ - public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception - { - this(hostConfig, null); - } - - public VirtualHost(VirtualHostConfiguration hostConfig, TransactionLog transactionLog) throws Exception - { - _configuration = hostConfig; - _name = hostConfig.getName(); - - if (_name == null || _name.length() == 0) - { - throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); - } - - _virtualHostMBean = new VirtualHostMBean(); - - _connectionRegistry = new ConnectionRegistry(this); - - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); - - _queueRegistry = new DefaultQueueRegistry(this); - - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - - _exchangeRegistry = new DefaultExchangeRegistry(this); - - _queueBackingStoreFactory = new FileQueueBackingStoreFactory(); - _queueBackingStoreFactory.configure(this, hostConfig); - - //Create a temporary RT to store the durable entries from the config file - // so we can replay them in to the real _RT after it has been loaded. - /// This should be removed after the _RT has been fully split from the the TL - - StartupRoutingTable configFileRT = new StartupRoutingTable(); - - _routingTable = configFileRT; - - // This needs to be after the RT has been defined as it creates the default durable exchanges. - _exchangeRegistry.initialise(); - initialiseModel(hostConfig); - - if (transactionLog != null) - { - _transactionLog = transactionLog; - if (_transactionLog instanceof RoutingTable) - { - _routingTable = (RoutingTable) _transactionLog; - } - else if (_transactionLog instanceof BaseTransactionLog) - { - TransactionLog delegate = ((BaseTransactionLog) _transactionLog).getDelegate(); - if (delegate instanceof RoutingTable) - { - _routingTable = (RoutingTable) delegate; - } - } - } - else - { - initialiseTransactionLog(hostConfig); - initialiseRoutingTable(hostConfig); - } - - //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config - // file and write them in to the new routing Table. - for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) - { - _routingTable.createQueue(cqt.queue, cqt.arguments); - } - - for (Exchange exchange : configFileRT.exchange) - { - _routingTable.createExchange(exchange); - } - - for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) - { - _routingTable.bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - } - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); - - _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); - } - - private void initialiseHouseKeeping(long period) - { - /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if (period != 0L) - { - class RemoveExpiredMessagesTask extends TimerTask - { - public void run() - { - for (AMQQueue q : _queueRegistry.getQueues()) - { - - try - { - q.checkMessageStatus(); - } - catch (AMQException e) - { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); - throw new RuntimeException(e); - } - } - } - } - - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); - } - } - - //todo we need to move from store.class to transactionlog.class - private void initialiseTransactionLog(VirtualHostConfiguration config) throws Exception - { - String transactionLogClass = config.getTransactionLogClass(); - - Class clazz = Class.forName(transactionLogClass); - Object o = clazz.newInstance(); - - if (!(o instanceof TransactionLog)) - { - throw new ClassCastException("TransactionLog class must implement " + TransactionLog.class + ". Class " + clazz + - " does not."); - } - _transactionLog = (TransactionLog) o; - - // If a TransactionLog uses the BaseTransactionLog then it will return this object. - _transactionLog = (TransactionLog) _transactionLog.configure(this, "store", config); - - //Assign RoutingTable as old MessageStores converted to TransactionLog will require the _routingTable. - if (_transactionLog instanceof RoutingTable) - { - _routingTable = (RoutingTable) _transactionLog; - } - else if (_transactionLog instanceof BaseTransactionLog) - { - TransactionLog delegate = ((BaseTransactionLog) _transactionLog).getDelegate(); - if (delegate instanceof RoutingTable) - { - _routingTable = (RoutingTable) delegate; - } - } - - } - - //todo we need to move from store.class to transactionlog.class - private void initialiseRoutingTable(VirtualHostConfiguration hostConfig) throws Exception - { - String transactionLogClass = hostConfig.getRoutingTableClass(); - - if (transactionLogClass != null) - { - Class clazz = Class.forName(transactionLogClass); - Object o = clazz.newInstance(); - - if (!(o instanceof RoutingTable)) - { - throw new ClassCastException("RoutingTable class must implement " + RoutingTable.class + ". Class " + clazz + - " does not."); - } - _routingTable = (RoutingTable) o; - _routingTable.configure(this, "routingtable", hostConfig); - } - else - { - if (_routingTable == null) - { - throw new RuntimeException("No Routing Table configured unable to startup."); - } - } - } - - private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException - { - _logger.debug("Loading configuration for virtualhost: " + config.getName()); - - List exchangeNames = config.getExchanges(); - - for (Object exchangeNameObj : exchangeNames) - { - String exchangeName = String.valueOf(exchangeNameObj); - configureExchange(config.getExchangeConfiguration(exchangeName)); - } - - String[] queueNames = config.getQueueNames(); - - for (Object queueNameObj : queueNames) - { - String queueName = String.valueOf(queueNameObj); - configureQueue(config.getQueueConfiguration(queueName)); - } - } - - private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException - { - AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); - - Exchange exchange; - exchange = _exchangeRegistry.getExchange(exchangeName); - if (exchange == null) - { - - AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); - boolean durable = exchangeConfiguration.getDurable(); - boolean autodelete = exchangeConfiguration.getAutoDelete(); - - Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); - _exchangeRegistry.registerExchange(newExchange); - } - } - - private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException - { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); - - if (queue.isDurable()) - { - _routingTable.createQueue(queue); - } - - String exchangeName = queueConfiguration.getExchange(); - - Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - - if (exchange == null) - { - exchange = _exchangeRegistry.getDefaultExchange(); - } - - if (exchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); - } - - List routingKeys = queueConfiguration.getRoutingKeys(); - if (routingKeys == null || routingKeys.isEmpty()) - { - routingKeys = Collections.singletonList(queue.getName()); - } - - for (Object routingKeyNameObj : routingKeys) - { - AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - if (_logger.isInfoEnabled()) - { - _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); - } - queue.bind(exchange, routingKey, null); - } - - if (exchange != _exchangeRegistry.getDefaultExchange()) - { - queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); - } - } - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - - public TransactionLog getTransactionLog() - { - return _transactionLog; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public ACLManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - - //Stop Connections - _connectionRegistry.close(); - - //Stop Housekeeping - if (_houseKeepingTimer != null) - { - _houseKeepingTimer.cancel(); - } - - //Stop the Queues processing - if (_queueRegistry != null) - { - for (AMQQueue queue : _queueRegistry.getQueues()) - { - queue.stop(); - } - } - - //Close TransactionLog - if (_transactionLog != null) - { - _transactionLog.close(); - } - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } - - /** - * Temporary Startup RT class to record the creation of persistent queues / exchanges. - * - * - * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. - * This should be removed after the _RT has been fully split from the the TL - */ - private class StartupRoutingTable implements RoutingTable - { - public List exchange = new LinkedList(); - public List queue = new LinkedList(); - public List bindings = new LinkedList(); - - public Object configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - return null; - } - - public void close() throws Exception - { - } - - public void createExchange(Exchange exchange) throws AMQException - { - if (exchange.isDurable()) - { - this.exchange.add(exchange); - } - } - - public void removeExchange(Exchange exchange) throws AMQException - { - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - if (exchange.isDurable() && queue.isDurable()) - { - bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); - } - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - } - - public void createQueue(AMQQueue queue) throws AMQException - { - createQueue(queue, null); - } - - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException - { - if (queue.isDurable()) - { - this.queue.add(new CreateQueueTuple(queue, arguments)); - } - } - - public void removeQueue(AMQQueue queue) throws AMQException - { - } - - private class CreateQueueTuple - { - public AMQQueue queue; - public FieldTable arguments; - - public CreateQueueTuple(AMQQueue queue, FieldTable arguments) - { - this.queue = queue; - this.arguments = arguments; - } - } - - private class CreateBindingTuple - { - public AMQQueue queue; - public FieldTable arguments; - public Exchange exchange; - public AMQShortString routingKey; - - public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - { - this.exchange = exchange; - this.routingKey = routingKey; - this.queue = queue; - arguments = args; - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java deleted file mode 100644 index 27917fac8a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -public class VirtualHostRegistry -{ - private final Map _registry = new ConcurrentHashMap(); - - - private String _defaultVirtualHostName; - - public synchronized void registerVirtualHost(VirtualHost host) throws Exception - { - if(_registry.containsKey(host.getName())) - { - throw new Exception("Virtual Host with name " + host.getName() + " already registered."); - } - _registry.put(host.getName(),host); - } - - public VirtualHost getVirtualHost(String name) - { - if(name == null || name.trim().length() == 0 ) - { - name = getDefaultVirtualHostName(); - } - - return _registry.get(name); - } - - private String getDefaultVirtualHostName() - { - return _defaultVirtualHostName; - } - - public void setDefaultVirtualHostName(String defaultVirtualHostName) - { - _defaultVirtualHostName = defaultVirtualHostName; - } - - - public Collection getVirtualHosts() - { - return new ArrayList(_registry.values()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java deleted file mode 100644 index a6e060e793..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore; - -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.tools.messagestore.commands.Clear; -import org.apache.qpid.tools.messagestore.commands.Command; -import org.apache.qpid.tools.messagestore.commands.Copy; -import org.apache.qpid.tools.messagestore.commands.Dump; -import org.apache.qpid.tools.messagestore.commands.Help; -import org.apache.qpid.tools.messagestore.commands.List; -import org.apache.qpid.tools.messagestore.commands.Load; -import org.apache.qpid.tools.messagestore.commands.Quit; -import org.apache.qpid.tools.messagestore.commands.Select; -import org.apache.qpid.tools.messagestore.commands.Show; -import org.apache.qpid.tools.messagestore.commands.Move; -import org.apache.qpid.tools.messagestore.commands.Purge; -import org.apache.qpid.tools.utils.CommandParser; -import org.apache.qpid.tools.utils.Console; -import org.apache.qpid.tools.utils.SimpleCommandParser; -import org.apache.qpid.tools.utils.SimpleConsole; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * MessageStoreTool. - */ -public class MessageStoreTool -{ - /** Text outputted at the start of each console.*/ - private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; - - /** I/O Wrapper. */ - protected Console _console; - - /** Batch mode flag. */ - protected boolean _batchMode; - - /** Internal State object. */ - private State _state = new State(); - - private HashMap _commands = new HashMap(); - - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); - - /** Loaded configuration file. */ - private Configuration _config; - - /** Control used for main run loop. */ - private boolean _running = true; - private boolean _initialised = false; - - //---------------------------------------------------------------------------------------------------/ - - public static void main(String[] args) throws Configuration.InitException - { - - MessageStoreTool tool = new MessageStoreTool(args); - - tool.start(); - } - - - public MessageStoreTool(String[] args) throws Configuration.InitException - { - this(args, System.in, System.out); - } - - public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException - { - BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); - BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); - - Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); - _batchMode = false; - - _console = new SimpleConsole(consoleWriter, consoleReader); - - _config = new Configuration(); - - setOptions(); - _config.processCommandline(args); - } - - - private void setOptions() - { - 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 By " - + "default looks for a file named " - + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) - .withLongOpt("config") - .create("c"); - - _config.setOption(help); - _config.setOption(version); - _config.setOption(configFile); - } - - public State getState() - { - return _state; - } - - public Map getCommands() - { - return _commands; - } - - public void setConfigurationFile(String configfile) throws Configuration.InitException - { - _config.loadConfig(new File(configfile)); - setup(); - } - - public Console getConsole() - { - return _console; - } - - public void setConsole(Console console) - { - _console = console; - } - - /** - * Simple ShutdownHook to cleanly shutdown the databases - */ - class ShutdownHook implements Runnable - { - MessageStoreTool _tool; - - ShutdownHook(MessageStoreTool messageStoreTool) - { - _tool = messageStoreTool; - } - - public void run() - { - _tool.quit(); - } - } - - public void quit() - { - _running = false; - - if (_initialised) - { - ApplicationRegistry.remove(1); - } - - _console.println("...exiting"); - - _console.close(); - } - - public void setBatchMode(boolean batchmode) - { - _batchMode = batchmode; - } - - /** - * Main loop - */ - protected void start() - { - setup(); - - if (!_initialised) - { - System.exit(1); - } - - _console.println(""); - - _console.println(BOILER_PLATE); - - runCLI(); - } - - private void setup() - { - loadDefaultVirtualHosts(); - - loadCommands(); - - _state.clearAll(); - } - - private void loadCommands() - { - _commands.clear(); - //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands - _commands.put("close", new Clear(this)); - _commands.put("copy", new Copy(this)); - _commands.put("dump", new Dump(this)); - _commands.put("help", new Help(this)); - _commands.put("list", new List(this)); - _commands.put("load", new Load(this)); - _commands.put("move", new Move(this)); - _commands.put("purge", new Purge(this)); - _commands.put("quit", new Quit(this)); - _commands.put("select", new Select(this)); - _commands.put("show", new Show(this)); - } - - private void loadDefaultVirtualHosts() - { - final File configFile = _config.getConfigFile(); - - loadVirtualHosts(configFile); - } - - private void loadVirtualHosts(File configFile) - { - - if (!configFile.exists()) - { - _devlog.error("Config file not found:" + configFile.getAbsolutePath()); - return; - } - else - { - _devlog.debug("using config file :" + configFile.getAbsolutePath()); - } - - try - { - ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); - - ApplicationRegistry.remove(1); - - ApplicationRegistry.initialise(registry); - - checkMessageStores(); - _initialised = true; - } - catch (ConfigurationException e) - { - _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); - e.printStackTrace(); - } - catch (Exception e) - { - _console.println("Unable to load configuration due to: " + e.getMessage()); - e.printStackTrace(); - } - - - } - - private void checkMessageStores() - { - Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); - - boolean warning = false; - for (VirtualHost vhost : vhosts) - { - if (vhost.getTransactionLog() instanceof MemoryMessageStore) - { - _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " - + "Changes will not persist."); - warning = true; - } - } - - if (warning) - { - _console.println(""); - _console.println("Please ensure you are using the correct config file currently using '" - + _config.getConfigFile().getAbsolutePath() + "'"); - _console.println("New config file can be specifed by 'load ' or -c on the commandline."); - _console.println(""); - } - } - - private void runCLI() - { - while (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - String[] args = _console.readCommand(); - - while (args != null) - { - exec(args); - - if (_running) - { - if (!_batchMode) - { - printPrompt(); - } - - args = _console.readCommand(); - } - } - } - } - - private void printPrompt() - { - _console.print(prompt()); - } - - - /** - * Execute a script (batch mode). - * - * @param script The file script - */ - protected void runScripts(String script) - { - //Store Current State - boolean oldBatch = _batchMode; - CommandParser oldParser = _console.getCommandParser(); - setBatchMode(true); - - try - { - _devlog.debug("Running script '" + script + "'"); - - _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); - - start(); - } - catch (java.io.FileNotFoundException e) - { - _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); - } - - //Restore previous state - _console.setCommandParser(oldParser); - setBatchMode(oldBatch); - } - - public String prompt() - { - String state = _state.toString(); - if (state != null && state.length() != 0) - { - return state + ":bdb$ "; - } - else - { - return "bdb$ "; - } - } - - /** - * Execute the command. - * - * @param args [command, arg0, arg1...]. - */ - protected void exec(String[] args) - { - // Comment lines start with a # - if (args.length == 0 || args[0].startsWith("#")) - { - return; - } - - final String command = args[0]; - - Command cmd = _commands.get(command); - - if (cmd == null) - { - _console.println("Command not understood: " + command); - } - else - { - cmd.execute(args); - } - } - - - /** - * Displays usage info. - */ - protected static void help() - { - System.out.println(BOILER_PLATE); - System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); - System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); - } - - - /** - * This class is used to store the current state of the tool. - * - * This is then interrogated by the various commands to augment their behaviour. - * - * - */ - public class State - { - private VirtualHost _vhost = null; - private AMQQueue _queue = null; - private Exchange _exchange = null; - private java.util.List _msgids = null; - - public State() - { - } - - public void setQueue(AMQQueue queue) - { - _queue = queue; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public void setVhost(VirtualHost vhost) - { - _vhost = vhost; - } - - public VirtualHost getVhost() - { - return _vhost; - } - - public Exchange getExchange() - { - return _exchange; - } - - public void setExchange(Exchange exchange) - { - _exchange = exchange; - } - - public String toString() - { - StringBuilder status = new StringBuilder(); - - if (_vhost != null) - { - status.append(_vhost.getName()); - - if (_exchange != null) - { - status.append("["); - status.append(_exchange.getName()); - status.append("]"); - - if (_queue != null) - { - status.append("->'"); - status.append(_queue.getName()); - status.append("'"); - - if (_msgids != null) - { - status.append(printMessages()); - } - } - } - } - - return status.toString(); - } - - - public String printMessages() - { - StringBuilder sb = new StringBuilder(); - - Long previous = null; - - Long start = null; - for (Long id : _msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(id); - start = null; - } - else - { - sb.append(","); - sb.append(previous); - } - } - } - - previous = id; - } - - if (start != null) - { - sb.append(","); - sb.append(start); - sb.append("-"); - sb.append(_msgids.get(_msgids.size() - 1)); - } - else - { - sb.append(","); - sb.append(previous); - } - - // surround list in () - sb.replace(0, 1, "("); - sb.append(")"); - return sb.toString(); - } - - public void clearAll() - { - _vhost = null; - clearExchange(); - } - - public void clearExchange() - { - _exchange = null; - clearQueue(); - } - - public void clearQueue() - { - _queue = null; - clearMessages(); - } - - public void clearMessages() - { - _msgids = null; - } - - /** - * A common location to provide parsing of the message id string - * utilised by a number of the commands. - * The String is comma separated list of ids that can be individual ids - * or a range (4-10) - * - * @param msgString string of msg ids to parse 1,2,4-10 - */ - public void setMessages(String msgString) - { - StringTokenizer tok = new StringTokenizer(msgString, ","); - - if (tok.hasMoreTokens()) - { - _msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - _msgids.add(l); - } - } - } - else - { - _msgids.add(Long.parseLong(next)); - } - } - - } - - public void setMessages(java.util.List msgids) - { - _msgids = msgids; - } - - public java.util.List getMessages() - { - return _msgids; - } - }//Class State - -}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java deleted file mode 100644 index 5444197cb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -public abstract class AbstractCommand implements Command -{ - protected Console _console; - protected MessageStoreTool _tool; - - public AbstractCommand(MessageStoreTool tool) - { - _console = tool.getConsole(); - _tool = tool; - } - - public void setOutput(Console out) - { - _console = out; - } - - protected void commandError(String message, String[] args) - { - _console.print(getCommand() + " : " + message); - - if (args != null) - { - for (int i = 1; i < args.length; i++) - { - _console.print(args[i]); - } - } - _console.println(""); - _console.println(help()); - } - - - public abstract String help(); - - public abstract String usage(); - - public abstract String getCommand(); - - - public abstract void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java deleted file mode 100644 index b0006b3fe6..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Clear extends AbstractCommand -{ - public Clear(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Clears any selection."; - } - - public String usage() - { - return "clear [ all | virtualhost | exchange | queue | msgs ]"; - } - - public String getCommand() - { - return "clear"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 1) - { - doClose("all"); - } - else - { - doClose(args[1]); - } - } - - private void doClose(String type) - { - if (type.equals("virtualhost") - || type.equals("all")) - { - _tool.getState().clearAll(); - } - - if (type.equals("exchange")) - { - _tool.getState().clearExchange(); - } - - if (type.equals("queue")) - { - _tool.getState().clearQueue(); - } - - if (type.equals("msgs")) - { - _tool.getState().clearMessages(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java deleted file mode 100644 index bfa775a34a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.utils.Console; - -public interface Command -{ - public void setOutput(Console out); - - public String help(); - - public abstract String usage(); - - String getCommand(); - - public void execute(String... args); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java deleted file mode 100644 index 0869d9a497..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.server.queue.AMQQueue; - -public class Copy extends Move -{ - public Copy(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Copy messages between queues.";/*\n" + - "The currently selected message set will be copied to the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; */ - } - - public String usage() - { - return "copy to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "copy"; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) - { - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java deleted file mode 100644 index 731f6140f9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.commons.codec.binary.Hex; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntryImpl; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.io.UnsupportedEncodingException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -public class Dump extends Show -{ - private static final int LINE_SIZE = 8; - private static final String DEFAULT_ENCODING = "utf-8"; - private static final boolean SPACE_BYTES = true; - private static final String BYTE_SPACER = " "; - private static final String NON_PRINTING_ASCII_CHAR = "?"; - - protected boolean _content = true; - - public Dump(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Dump selected message content. Default: show=content"; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; - } - - public String getCommand() - { - return "dump"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _content = arg.contains("content") || arg.contains("all"); - } - } - - parseArgs(args); - } - - performShow(); - } - - - protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - List display = new LinkedList(); - - List hex = new LinkedList(); - List ascii = new LinkedList(); - display.add(hex); - display.add(ascii); - - for (QueueEntry entry : messages) - { - AMQMessage msg = entry.getMessage(); - if (!includeMsg(msg, msgids)) - { - continue; - } - - //Add divider between messages - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - // Show general message information - hex.add(Show.Columns.ID.name()); - ascii.add(msg.getMessageId().toString()); - - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - if (showRouting) - { - addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); - } - if (showHeaders) - { - addShowInformation(hex, ascii, msg, "Headers", false, true, false); - } - if (showMessageHeaders) - { - addShowInformation(hex, ascii, msg, null, false, false, true); - } - - // Add Content Body seciont - hex.add("Content Body"); - ascii.add(""); - hex.add(Console.ROW_DIVIDER); - ascii.add(Console.ROW_DIVIDER); - - Iterator bodies = msg.getContentBodyIterator(); - if (bodies.hasNext()) - { - - hex.add("Hex"); - hex.add(Console.ROW_DIVIDER); - - - ascii.add("ASCII"); - ascii.add(Console.ROW_DIVIDER); - - while (bodies.hasNext()) - { - ContentChunk chunk = (ContentChunk) bodies.next(); - - //Duplicate so we don't destroy original data :) - ByteBuffer hexBuffer = chunk.getData().duplicate(); - - ByteBuffer charBuffer = hexBuffer.duplicate(); - - Hex hexencoder = new Hex(); - - while (hexBuffer.hasRemaining()) - { - byte[] line = new byte[LINE_SIZE]; - - int bufsize = hexBuffer.remaining(); - if (bufsize < LINE_SIZE) - { - hexBuffer.get(line, 0, bufsize); - } - else - { - bufsize = line.length; - hexBuffer.get(line); - } - - byte[] encoded = hexencoder.encode(line); - - try - { - String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); - String hexLine = ""; - - int strKength = encStr.length(); - for (int c = 0; c < strKength; c++) - { - hexLine += encStr.charAt(c); - - if (c % 2 == 1 && SPACE_BYTES) - { - hexLine += BYTE_SPACER; - } - } - - hex.add(hexLine); - } - catch (UnsupportedEncodingException e) - { - _console.println(e.getMessage()); - return null; - } - } - - while (charBuffer.hasRemaining()) - { - String asciiLine = ""; - - for (int pos = 0; pos < LINE_SIZE; pos++) - { - if (charBuffer.hasRemaining()) - { - byte ch = charBuffer.get(); - - if (isPrintable(ch)) - { - asciiLine += (char) ch; - } - else - { - asciiLine += NON_PRINTING_ASCII_CHAR; - } - - if (SPACE_BYTES) - { - asciiLine += BYTE_SPACER; - } - } - else - { - break; - } - } - - ascii.add(asciiLine); - } - } - } - else - { - List result = new LinkedList(); - - display.add(result); - result.add("No ContentBodies"); - } - } - - // if hex is empty then we have no data to display - if (hex.size() == 0) - { - return null; - } - - return display; - } - - private void addShowInformation(List column1, List column2, AMQMessage msg, - String title, boolean routing, boolean headers, boolean messageHeaders) - { - List single = new LinkedList(); - single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE)); - - List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); - - //Reformat data - if (title != null) - { - column1.add(title); - column2.add(""); - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - // look at all columns in the routing Data - for (List item : routingData) - { - // the item should be: - // Title - // *divider - // value - // otherwise we can't reason about the correct value - if (item.size() == 3) - { - //Filter out the columns we are not interested in. - - String columnName = item.get(0).toString(); - - if (!(columnName.equals(Show.Columns.ID.name()) - || columnName.equals(Show.Columns.Size.name()))) - { - column1.add(columnName); - column2.add(item.get(2).toString()); - } - } - } - column1.add(Console.ROW_DIVIDER); - column2.add(Console.ROW_DIVIDER); - } - - private boolean isPrintable(byte c) - { - return c > 31 && c < 127; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java deleted file mode 100644 index 0f9546541b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.Map; - -public class Help extends AbstractCommand -{ - public Help(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Provides detailed help on commands."; - } - - public String getCommand() - { - return "help"; - } - - public String usage() - { - return "help []"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - Command command = _tool.getCommands().get(args[1]); - if (command != null) - { - _console.println(command.help()); - _console.println("Usage:" + command.usage()); - } - else - { - commandError("Command not found: ", args); - } - } - else - { - java.util.List data = new LinkedList(); - - java.util.List commandName = new LinkedList(); - java.util.List commandDescription = new LinkedList(); - - data.add(commandName); - data.add(commandDescription); - - //Set up Headers - commandName.add("Command"); - commandDescription.add("Description"); - - commandName.add(Console.ROW_DIVIDER); - commandDescription.add(Console.ROW_DIVIDER); - - //Add current Commands with descriptions - Map commands = _tool.getCommands(); - - for (Command command : commands.values()) - { - commandName.add(command.getCommand()); - commandDescription.add(command.help()); - } - - _console.printMap("Available Commands", data); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java deleted file mode 100644 index df8b59ec19..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.Collection; -import java.util.LinkedList; - -public class List extends AbstractCommand -{ - - public List(MessageStoreTool tool) - { - super(tool); - } - - public void setOutput(Console out) - { - _console = out; - } - - public String help() - { - return "list available items."; - } - - public String usage() - { - return "list queues [] | exchanges | bindings [] | all"; - } - - public String getCommand() - { - return "list"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 1) - { - if ((args[1].equals("exchanges")) - || (args[1].equals("queues")) - || (args[1].equals("bindings")) - || (args[1].equals("all"))) - { - if (args.length == 2) - { - doList(args[1]); - } - else if (args.length == 3) - { - doList(args[1], args[2]); - } - } - else - { - commandError("Unknown options. ", args); - } - } - else if (args.length < 2) - { - doList("all"); - } - else - { - doList(args[1]); - } - } - - private void doList(String... listItem) - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - listVirtualHosts(); - return; - } - - VirtualHost vhost = _tool.getState().getVhost(); - - java.util.List data = null; - - if (listItem[0].equals("queues")) - { - if (listItem.length > 1) - { - data = listQueues(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - data = listQueues(vhost, exchange); - } - } - - if (listItem[0].equals("exchanges")) - { - data = listExchanges(vhost); - } - - if (listItem[0].equals("bindings")) - { - - if (listItem.length > 1) - { - data = listBindings(vhost, new AMQShortString(listItem[1])); - } - else - { - Exchange exchange = _tool.getState().getExchange(); - - data = listBindings(vhost, exchange); - } - } - - if (data != null) - { - if (data.size() == 1) - { - _console.println("No '" + listItem[0] + "' to display,"); - } - else - { - _console.displayList(true, data.toArray(new String[0])); - } - } - - - if (listItem[0].equals("all")) - { - - boolean displayed = false; - Exchange exchange = _tool.getState().getExchange(); - - //Do the display here for each one so that they are pretty printed - data = listQueues(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (exchange == null) - { - data = listExchanges(vhost); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - } - - data = listBindings(vhost, exchange); - if (data != null) - { - displayed = true; - _console.displayList(true, data.toArray(new String[0])); - } - - if (!displayed) - { - _console.println("Nothing to list"); - } - } - } - - private void listVirtualHosts() - { - Collection vhosts = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHosts(); - - String[] data = new String[vhosts.size() + 1]; - - data[0] = "Available VirtualHosts"; - - int index = 1; - for (VirtualHost vhost : vhosts) - { - data[index] = vhost.getName(); - index++; - } - - _console.displayList(true, data); - } - - private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) - { - return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listBindings(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueueNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Current Bindings"); - - for (AMQShortString queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.toString()); - } - } - else - { - data.add(queue.toString()); - } - } - - return data; - } - - private java.util.List listExchanges(VirtualHost vhost) - { - Collection queues = vhost.getExchangeRegistry().getExchangeNames(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Exchanges"); - - for (AMQShortString queue : queues) - { - data.add(queue.toString()); - } - - return data; - } - - private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) - { - return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); - } - - private java.util.List listQueues(VirtualHost vhost, Exchange exchange) - { - Collection queues = vhost.getQueueRegistry().getQueues(); - - if (queues == null || queues.size() == 0) - { - return null; - } - - java.util.List data = new LinkedList(); - - data.add("Available Queues"); - - for (AMQQueue queue : queues) - { - if (exchange != null) - { - if (exchange.isBound(queue)) - { - data.add(queue.getName().toString()); - } - } - else - { - data.add(queue.getName().toString()); - } - } - - if (exchange != null) - { - if (queues.size() == 1) - { - return null; - } - } - - return data; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java deleted file mode 100644 index 244a311c30..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.configuration.Configuration; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Load extends AbstractCommand -{ - public Load(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Loads specified broker configuration file."; - } - - public String usage() - { - return "load "; - } - - public String getCommand() - { - return "load"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length > 2) - { - _console.print("load " + args[1] + ": additional options not understood:"); - for (int i = 2; i < args.length; i++) - { - _console.print(args[i] + " "); - } - _console.println(""); - } - else if (args.length < 2) - { - _console.println("Enter Configuration file."); - String input = _console.readln(); - if (input != null) - { - doLoad(input); - } - else - { - _console.println("Did not recognise config file."); - } - } - else - { - doLoad(args[1]); - } - } - - private void doLoad(String configfile) - { - _console.println("Loading Configuration:" + configfile); - - try - { - _tool.setConfigurationFile(configfile); - } - catch (Configuration.InitException e) - { - _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java deleted file mode 100644 index 7fe16062fc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.QueueEntryImpl; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.LinkedList; -import java.util.List; - -public class Move extends AbstractCommand -{ - - /** - * Since the Coopy command is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - protected StoreContext _storeContext = new StoreContext(); - - public Move(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Move messages between queues.";/*\n" + - "The currently selected message set will be moved to the specifed queue.\n" + - "Alternatively the values can be provided on the command line.";*/ - } - - public String usage() - { - return "move to= [from=] [msgids=]"; - } - - public String getCommand() - { - return "move"; - } - - public void execute(String... args) - { - AMQQueue toQueue = null; - AMQQueue fromQueue = _tool.getState().getQueue(); - java.util.List msgids = _tool.getState().getMessages(); - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("to=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("from=")) - { - String queueName = arg.substring(arg.indexOf("=") + 1); - fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - } - - if (arg.startsWith("msgids=")) - { - String msgidStr = arg.substring(arg.indexOf("=") + 1); - - // Record the current message selection - java.util.List currentIDs = _tool.getState().getMessages(); - - // Use the ToolState class to perform the messasge parsing - _tool.getState().setMessages(msgidStr); - msgids = _tool.getState().getMessages(); - - // Reset the original selection of messages - _tool.getState().setMessages(currentIDs); - } - } - } - - if (!checkRequirements(fromQueue, toQueue, msgids)) - { - return; - } - - processIDs(fromQueue, toQueue, msgids); - } - - private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - Long previous = null; - Long start = null; - - if (msgids == null) - { - msgids = allMessageIDs(fromQueue); - } - - if (msgids == null || msgids.size() == 0) - { - _console.println("No Messages to move."); - return; - } - - for (long id : msgids) - { - if (previous != null) - { - if (id == previous + 1) - { - if (start == null) - { - start = previous; - } - } - else - { - if (start != null) - { - //move a range of ids - doCommand(fromQueue, start, id, toQueue); - start = null; - } - else - { - //move a single id - doCommand(fromQueue, id, id, toQueue); - } - } - } - - previous = id; - } - - if (start != null) - { - //move a range of ids - doCommand(fromQueue, start, previous, toQueue); - } - } - - private List allMessageIDs(AMQQueue fromQueue) - { - List ids = new LinkedList(); - - if (fromQueue != null) - { - List messages = fromQueue.getMessagesOnTheQueue(); - if (messages != null) - { - for (QueueEntry msg : messages) - { - ids.add(msg.getMessageId()); - } - } - } - - return ids; - } - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) - { - if (toQueue == null) - { - _console.println("Destination queue not specifed."); - _console.println(usage()); - return false; - } - - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) - { - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java deleted file mode 100644 index 5e99997863..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.server.queue.AMQQueue; - -public class Purge extends Move -{ - public Purge(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Purge messages from a queue.\n" + - "The currently selected message set will be purged from the specifed queue.\n" + - "Alternatively the values can be provided on the command line."; - } - - public String usage() - { - return "purge from= [msgids=]"; - } - - public String getCommand() - { - return "purge"; - } - - - protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) - { - if (fromQueue == null) - { - _console.println("Source queue not specifed."); - _console.println(usage()); - return false; - } - - return true; - } - - protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) - { - fromQueue.removeMessagesFromQueue(start, end, _storeContext); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java deleted file mode 100644 index a81bc07c38..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -public class Quit extends AbstractCommand -{ - public Quit(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Quit the tool."; - } - - public String usage() - { - return "quit"; - } - - public String getCommand() - { - return "quit"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals("quit"); - - _tool.quit(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java deleted file mode 100644 index ff59568374..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.tools.messagestore.MessageStoreTool; - -import java.util.LinkedList; -import java.util.StringTokenizer; - -public class Select extends AbstractCommand -{ - - public Select(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Perform a selection."; - } - - public String usage() - { - return "select virtualhost |exchange |queue | msg id="; - } - - public String getCommand() - { - return "select"; - } - - public void execute(String... args) - { - assert args.length > 2; - assert args[0].equals("select"); - - if (args.length < 3) - { - if (args[1].equals("show")) - { - doSelect(args[1], null); - } - else - { - _console.print("select : unknown command:"); - _console.println(help()); - } - } - else - { - if (args[1].equals("virtualhost") - || args[1].equals("vhost") - || args[1].equals("exchange") - || args[1].equals("queue") - || args[1].equals("msg") - ) - { - doSelect(args[1], args[2]); - } - else - { - _console.println(help()); - } - } - } - - private void doSelect(String type, String item) - { - if (type.equals("virtualhost")) - { - - VirtualHost vhost = ApplicationRegistry.getInstance() - .getVirtualHostRegistry().getVirtualHost(item); - - if (vhost == null) - { - _console.println("Virtualhost '" + item + "' not found."); - } - else - { - _tool.getState().setVhost(vhost); - } - } - - if (type.equals("exchange")) - { - - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - - Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); - - if (exchange == null) - { - _console.println("Exchange '" + item + "' not found."); - } - else - { - _tool.getState().setExchange(exchange); - } - - if (_tool.getState().getQueue() != null) - { - if (!exchange.isBound(_tool.getState().getQueue())) - { - _tool.getState().setQueue(null); - } - } - } - - if (type.equals("queue")) - { - VirtualHost vhost = _tool.getState().getVhost(); - - if (vhost == null) - { - _console.println("No Virtualhost open. Open a Virtualhost first."); - return; - } - - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); - - if (queue == null) - { - _console.println("Queue '" + item + "' not found."); - } - else - { - _tool.getState().setQueue(queue); - - if (_tool.getState().getExchange() == null) - { - for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) - { - Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); - if (exchange.isBound(queue)) - { - _tool.getState().setExchange(exchange); - break; - } - } - } - - //remove the message selection - _tool.getState().setMessages((java.util.List) null); - } - } - - if (type.equals("msg")) - { - if (item.startsWith("id=")) - { - StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); - - java.util.List msgids = null; - - if (tok.hasMoreTokens()) - { - msgids = new LinkedList(); - } - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - if (next.contains("-")) - { - Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); - Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); - - if (end >= start) - { - for (long l = start; l <= end; l++) - { - msgids.add(l); - } - } - } - else - { - msgids.add(Long.parseLong(next)); - } - } - - _tool.getState().setMessages(msgids); - } - - } - - if (type.equals("show")) - { - _console.println(_tool.getState().toString()); - if (_tool.getState().getMessages() != null) - { - _console.print("Msgs:"); - for (Long l : _tool.getState().getMessages()) - { - _console.print(" " + l); - } - _console.println(""); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java deleted file mode 100644 index 49afcb1340..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.messagestore.commands; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.tools.messagestore.MessageStoreTool; -import org.apache.qpid.tools.utils.Console; - -import java.util.LinkedList; -import java.util.List; - -public class Show extends AbstractCommand -{ - protected boolean _amqHeaders = false; - protected boolean _routing = false; - protected boolean _msgHeaders = false; - - public Show(MessageStoreTool tool) - { - super(tool); - } - - public String help() - { - return "Shows the messages headers."; - } - - public String usage() - { - return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; - } - - public String getCommand() - { - return "show"; - } - - public void execute(String... args) - { - assert args.length > 0; - assert args[0].equals(getCommand()); - - if (args.length < 2) - { - parseArgs("all"); - } - else - { - parseArgs(args); - } - - performShow(); - } - - protected void parseArgs(String... args) - { - List msgids = null; - - if (args.length >= 2) - { - for (String arg : args) - { - if (arg.startsWith("show=")) - { - _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); - _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); - _routing = arg.contains("routing") || arg.contains("all"); - } - - if (arg.startsWith("id=")) - { - _tool.getState().setMessages(msgids); - } - }//for args - }// if args > 2 - } - - protected void performShow() - { - if (_tool.getState().getVhost() == null) - { - _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); - return; - } - - AMQQueue _queue = _tool.getState().getQueue(); - - List msgids = _tool.getState().getMessages(); - - if (_queue != null) - { - List messages = _queue.getMessagesOnTheQueue(); - if (messages == null || messages.size() == 0) - { - _console.println("No messages on queue"); - return; - } - - List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); - if (data != null) - { - _console.printMap(null, data); - } - else - { - String message = "No data to display."; - if (msgids != null) - { - message += " Is message selection correct? " + _tool.getState().printMessages(); - } - _console.println(message); - } - - } - else - { - _console.println("No Queue specified to show."); - } - } - - /** - * Create the list data for display from the messages. - * - * @param msgids The list of message ids to display - * @param messages A list of messages to format and display. - * @param showHeaders should the header info be shown - * @param showRouting show the routing info be shown - * @param showMessageHeaders show the msg headers be shown - * @return the formated data lists for printing - */ - protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, - boolean showMessageHeaders) - { - - // Currenly exposed message properties -// //Printing the content Body -// msg.getContentBodyIterator(); -// //Print the Headers -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); -// -// //Print out all the property names -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); -// -// msg.getMessageId(); -// msg.getSize(); -// msg.getArrivalTime(); - -// msg.getDeliveredSubscription(); -// msg.getDeliveredToConsumer(); -// msg.getMessageHandle(); -// msg.getMessageId(); -// msg.getMessagePublishInfo(); -// msg.getPublisher(); - -// msg.getStoreContext(); -// msg.isAllContentReceived(); -// msg.isPersistent(); -// msg.isRedelivered(); -// msg.isRejectedBy(); -// msg.isTaken(); - - //Header setup - - List data = new LinkedList(); - - List id = new LinkedList(); - data.add(id); - id.add(Columns.ID.name()); - id.add(Console.ROW_DIVIDER); - - List exchange = new LinkedList(); - List routingkey = new LinkedList(); - List immediate = new LinkedList(); - List mandatory = new LinkedList(); - if (showRouting) - { - data.add(exchange); - exchange.add(Columns.Exchange.name()); - exchange.add(Console.ROW_DIVIDER); - - data.add(routingkey); - routingkey.add(Columns.RoutingKey.name()); - routingkey.add(Console.ROW_DIVIDER); - - data.add(immediate); - immediate.add(Columns.isImmediate.name()); - immediate.add(Console.ROW_DIVIDER); - - data.add(mandatory); - mandatory.add(Columns.isMandatory.name()); - mandatory.add(Console.ROW_DIVIDER); - } - - List size = new LinkedList(); - List appid = new LinkedList(); - List clusterid = new LinkedList(); - List contenttype = new LinkedList(); - List correlationid = new LinkedList(); - List deliverymode = new LinkedList(); - List encoding = new LinkedList(); - List arrival = new LinkedList(); - List expiration = new LinkedList(); - List priority = new LinkedList(); - List propertyflag = new LinkedList(); - List replyto = new LinkedList(); - List timestamp = new LinkedList(); - List type = new LinkedList(); - List userid = new LinkedList(); - List ispersitent = new LinkedList(); - List isredelivered = new LinkedList(); - List isdelivered = new LinkedList(); - - data.add(size); - size.add(Columns.Size.name()); - size.add(Console.ROW_DIVIDER); - - if (showHeaders) - { - data.add(ispersitent); - ispersitent.add(Columns.isPersistent.name()); - ispersitent.add(Console.ROW_DIVIDER); - - data.add(isredelivered); - isredelivered.add(Columns.isRedelivered.name()); - isredelivered.add(Console.ROW_DIVIDER); - - data.add(isdelivered); - isdelivered.add(Columns.isDelivered.name()); - isdelivered.add(Console.ROW_DIVIDER); - - data.add(appid); - appid.add(Columns.App_ID.name()); - appid.add(Console.ROW_DIVIDER); - - data.add(clusterid); - clusterid.add(Columns.Cluster_ID.name()); - clusterid.add(Console.ROW_DIVIDER); - - data.add(contenttype); - contenttype.add(Columns.Content_Type.name()); - contenttype.add(Console.ROW_DIVIDER); - - data.add(correlationid); - correlationid.add(Columns.Correlation_ID.name()); - correlationid.add(Console.ROW_DIVIDER); - - data.add(deliverymode); - deliverymode.add(Columns.Delivery_Mode.name()); - deliverymode.add(Console.ROW_DIVIDER); - - data.add(encoding); - encoding.add(Columns.Encoding.name()); - encoding.add(Console.ROW_DIVIDER); - - data.add(arrival); - expiration.add(Columns.Arrival.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(expiration); - expiration.add(Columns.Expiration.name()); - expiration.add(Console.ROW_DIVIDER); - - data.add(priority); - priority.add(Columns.Priority.name()); - priority.add(Console.ROW_DIVIDER); - - data.add(propertyflag); - propertyflag.add(Columns.Property_Flag.name()); - propertyflag.add(Console.ROW_DIVIDER); - - data.add(replyto); - replyto.add(Columns.ReplyTo.name()); - replyto.add(Console.ROW_DIVIDER); - - data.add(timestamp); - timestamp.add(Columns.Timestamp.name()); - timestamp.add(Console.ROW_DIVIDER); - - data.add(type); - type.add(Columns.Type.name()); - type.add(Console.ROW_DIVIDER); - - data.add(userid); - userid.add(Columns.UserID.name()); - userid.add(Console.ROW_DIVIDER); - } - - List msgHeaders = new LinkedList(); - if (showMessageHeaders) - { - data.add(msgHeaders); - msgHeaders.add(Columns.MsgHeaders.name()); - msgHeaders.add(Console.ROW_DIVIDER); - } - - //Add create the table of data - for (QueueEntry entry : messages) - { - AMQMessage msg = entry.getMessage(); - if (!includeMsg(msg, msgids)) - { - continue; - } - - id.add(msg.getMessageId().toString()); - - size.add("" + msg.getSize()); - - arrival.add("" + msg.getArrivalTime()); - - ispersitent.add(msg.isPersistent() ? "true" : "false"); - - isredelivered.add(entry.isRedelivered() ? "true" : "false"); - - isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false"); - - BasicContentHeaderProperties headers = null; - - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); - - if (headers != null) - { - String appidS = headers.getAppIdAsString(); - appid.add(appidS == null ? "null" : appidS); - - String clusterS = headers.getClusterIdAsString(); - clusterid.add(clusterS == null ? "null" : clusterS); - - String contentS = headers.getContentTypeAsString(); - contenttype.add(contentS == null ? "null" : contentS); - - String correlationS = headers.getCorrelationIdAsString(); - correlationid.add(correlationS == null ? "null" : correlationS); - - deliverymode.add("" + headers.getDeliveryMode()); - - AMQShortString encodeSS = headers.getEncoding(); - encoding.add(encodeSS == null ? "null" : encodeSS.toString()); - - expiration.add("" + headers.getExpiration()); - - FieldTable headerFT = headers.getHeaders(); - msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); - - priority.add("" + headers.getPriority()); - propertyflag.add("" + headers.getPropertyFlags()); - - AMQShortString replytoSS = headers.getReplyTo(); - replyto.add(replytoSS == null ? "null" : replytoSS.toString()); - - timestamp.add("" + headers.getTimestamp()); - - AMQShortString typeSS = headers.getType(); - type.add(typeSS == null ? "null" : typeSS.toString()); - - AMQShortString useridSS = headers.getUserId(); - userid.add(useridSS == null ? "null" : useridSS.toString()); - - MessagePublishInfo info = msg.getMessagePublishInfo(); - - if (info != null) - { - AMQShortString exchangeSS = info.getExchange(); - exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); - - AMQShortString routingkeySS = info.getRoutingKey(); - routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); - - immediate.add(info.isImmediate() ? "true" : "false"); - mandatory.add(info.isMandatory() ? "true" : "false"); - } - -// msg.getPublisher(); -- only used in clustering -// msg.getStoreContext(); -// msg.isAllContentReceived(); - - }// if headers!=null - -// need to access internal map and do lookups. -// msg.isTaken(); -// msg.getDeliveredSubscription(); -// msg.isRejectedBy(); - - } - - // if id only had the header and the divider in it then we have no data to display - if (id.size() == 2) - { - return null; - } - return data; - } - - protected boolean includeMsg(AMQMessage msg, List msgids) - { - if (msgids == null) - { - return true; - } - - Long msgid = msg.getMessageId(); - - boolean found = false; - - if (msgids != null) - { - //check msgid is in msgids - for (Long l : msgids) - { - if (l.equals(msgid)) - { - found = true; - break; - } - } - } - return found; - } - - public enum Columns - { - ID, - Size, - Exchange, - RoutingKey, - isImmediate, - isMandatory, - isPersistent, - isRedelivered, - isDelivered, - App_ID, - Cluster_ID, - Content_Type, - Correlation_ID, - Delivery_Mode, - Encoding, - Arrival, - Expiration, - Priority, - Property_Flag, - ReplyTo, - Timestamp, - Type, - UserID, - MsgHeaders - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java deleted file mode 100644 index c27c52eb8e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.security; - -import org.apache.commons.codec.binary.Base64; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; - -public class Passwd -{ - public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException - { - if (args.length != 2) - { - System.out.println("Passwd "); - System.exit(0); - } - - byte[] data = args[1].getBytes("utf-8"); - - MessageDigest md = MessageDigest.getInstance("MD5"); - - for (byte b : data) - { - md.update(b); - } - - byte[] digest = md.digest(); - - Base64 b64 = new Base64(); - - byte[] encoded = b64.encode(digest); - - output(args[0], encoded); - } - - private static void output(String user, byte[] encoded) throws IOException - { - -// File passwdFile = new File("qpid.passwd"); - - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java deleted file mode 100644 index 986fea32cc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -public interface CommandParser -{ - /** - * If there is more than one command received on the last parse request. - * - * Subsequent calls to parse will utilise this input rather than reading new data from the input source - * @return boolean - */ - boolean more(); - - /** - * True if the currently parsed command has been requested as a background operation - * - * @return boolean - */ - boolean isBackground(); - - /** - * Parses user commands, and groups tokens in the - * String[] format that all Java main's love. - * - * If more than one command is provided in one input line then the more() method will return true. - * A subsequent call to parse() will continue to parse that input line before reading new input. - * - * @return input split in args[] format; null if eof. - * @throws java.io.IOException if there is a problem reading from the input stream - */ - String[] parse() throws java.io.IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java deleted file mode 100644 index cf457d1ea5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.util.List; - -public interface Console -{ - public enum CellFormat - { - CENTRED, LEFT, RIGHT - } - - public static String ROW_DIVIDER = "*divider"; - - public void print(String... message); - - public void println(String... message); - - public String readln(); - - /** - * Reads and parses the command line. - * - * - * @return The next command or null - */ - public String[] readCommand(); - - public CommandParser getCommandParser(); - - public void setCommandParser(CommandParser parser); - - /** - * - * Prints the list of String nicely. - * - * +-------------+ - * | Heading | - * +-------------+ - * | Item 1 | - * | Item 2 | - * | Item 3 | - * +-------------+ - * - * @param hasTitle should list[0] be used as a heading - * @param list The list of Strings to display - */ - public void displayList(boolean hasTitle, String... list); - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * +----------------------------+ (*divider) - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - void printMap(String title, List entries); - - - public void close(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java deleted file mode 100644 index 09444ccdd7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.StringTokenizer; - -public class SimpleCommandParser implements CommandParser -{ - private static final String COMMAND_SEPERATOR = ";"; - - /** Input source of commands */ - protected BufferedReader _reader; - - /** The next list of commands from the command line */ - private StringBuilder _nextCommand = null; - - public SimpleCommandParser(BufferedReader reader) - { - _reader = reader; - } - - public boolean more() - { - return _nextCommand != null; - } - - public boolean isBackground() - { - return false; - } - - public String[] parse() throws IOException - { - String[] commands = null; - - String input = null; - - if (_nextCommand == null) - { - input = _reader.readLine(); - } - else - { - input = _nextCommand.toString(); - _nextCommand = null; - } - - if (input == null) - { - return null; - } - - StringTokenizer tok = new StringTokenizer(input, " "); - - int tokenCount = tok.countTokens(); - int index = 0; - - if (tokenCount > 0) - { - commands = new String[tokenCount]; - boolean commandComplete = false; - - while (tok.hasMoreTokens()) - { - String next = tok.nextToken(); - - if (next.equals(COMMAND_SEPERATOR)) - { - commandComplete = true; - _nextCommand = new StringBuilder(); - continue; - } - - if (commandComplete) - { - _nextCommand.append(next); - _nextCommand.append(" "); - } - else - { - commands[index] = next; - index++; - } - } - - } - - //Reduce the String[] if not all the tokens were used in this command. - // i.e. there is more than one command on the line. - if (index != tokenCount) - { - String[] shortCommands = new String[index]; - System.arraycopy(commands, 0, shortCommands, 0, index); - return shortCommands; - } - else - { - return commands; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java deleted file mode 100644 index ec080a4611..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.tools.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -public class SimpleConsole implements Console -{ - /** SLF4J Logger. */ - private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); - - /** Console Writer. */ - protected static BufferedWriter _consoleWriter; - - /** Console Reader. */ - protected static BufferedReader _consoleReader; - - /** Parser for command-line input. */ - protected CommandParser _parser; - - public SimpleConsole(BufferedWriter writer, BufferedReader reader) - { - _consoleWriter = writer; - _consoleReader = reader; - _parser = new SimpleCommandParser(_consoleReader); - } - - public void print(String... message) - { - try - { - for (String s : message) - { - _consoleWriter.write(s); - } - _consoleWriter.flush(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); - } - - } - - public void println(String... message) - { - print(message); - print(System.getProperty("line.separator")); - } - - - public String readln() - { - try - { - return _consoleReader.readLine(); - } - catch (IOException e) - { - _devlog.debug("Unable to read input due to:" + e.getMessage()); - return null; - } - } - - public String[] readCommand() - { - try - { - return _parser.parse(); - } - catch (IOException e) - { - _devlog.error("Error reading command:" + e.getMessage()); - return new String[0]; - } - } - - public CommandParser getCommandParser() - { - return _parser; - } - - public void setCommandParser(CommandParser parser) - { - _parser = parser; - } - - public void displayList(boolean hasTitle, String... list) - { - java.util.List data = new LinkedList(); - - java.util.List values = new LinkedList(); - - data.add(values); - - for (String value : list) - { - values.add(value); - } - - if (hasTitle) - { - values.add(1, "*divider"); - } - - printMap(null, data); - } - - /** - * - * Prints the list of String nicely. - * - * +----------------------------+ - * | Heading | - * +----------------------------+ - * | title | title | .. - * +----------------------------+ - * | Item 2 | value 2 | .. - * | Item 3 | value 2 | .. - * +----------------------------+ - * - * @param title The title to display if any - * @param entries the entries to display in a map. - */ - public void printMap(String title, java.util.List entries) - { - try - { - int columns = entries.size(); - - int[] columnWidth = new int[columns]; - - // calculate row count - int rowMax = 0; - - //the longest item - int itemMax = 0; - - for (int i = 0; i < columns; i++) - { - int columnIRowMax = entries.get(i).size(); - - if (columnIRowMax > rowMax) - { - rowMax = columnIRowMax; - } - for (Object values : entries.get(i)) - { - if (values.toString().equals(Console.ROW_DIVIDER)) - { - continue; - } - - int itemLength = values.toString().length(); - - //note for single width - if (itemLength > itemMax) - { - itemMax = itemLength; - } - - //note for mulit width - if (itemLength > columnWidth[i]) - { - columnWidth[i] = itemLength; - } - - } - } - - int tableWidth = 0; - - - for (int i = 0; i < columns; i++) - { - // plus 2 for the space padding - columnWidth[i] += 2; - } - for (int size : columnWidth) - { - tableWidth += size; - } - tableWidth += (columns - 1); - - if (title != null) - { - if (title.length() > tableWidth) - { - tableWidth = title.length(); - } - - printCellRow("+", "-", tableWidth); - - printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); - _consoleWriter.newLine(); - - } - - //put top line | or bottom of title - printCellRow("+", "-", tableWidth); - - //print the table data - int row = 0; - - for (; row < rowMax; row++) - { - for (int i = 0; i < columns; i++) - { - java.util.List columnData = entries.get(i); - - String value; - // does this column have a value for this row - if (columnData.size() > row) - { - value = " " + columnData.get(row).toString() + " "; - } - else - { - value = " "; - } - - if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) - { - printCellRow("+", "-", tableWidth); - //move on to the next row - break; - } - else - { - printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); - } - - // if it is the last row then do a new line. - if (i == columns - 1) - { - _consoleWriter.newLine(); - } - } - } - - printCellRow("+", "-", tableWidth); - - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to write."); - } - } - - public void close() - { - - try - { - _consoleReader.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); - } - - try - { - - _consoleWriter.close(); - } - catch (IOException e) - { - _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); - } - - } - - private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException - { - int pad = cellWidth - cell.length(); - - if (column == 0) - { - _consoleWriter.write(edge); - } - - switch (format) - { - case CENTRED: - printPad(" ", pad / 2); - break; - case RIGHT: - printPad(" ", pad); - break; - } - - _consoleWriter.write(cell); - - - switch (format) - { - case CENTRED: - // if pad isn't even put the extra one on the right - if (pad % 2 == 0) - { - printPad(" ", pad / 2); - } - else - { - printPad(" ", (pad / 2) + 1); - } - break; - case LEFT: - printPad(" ", pad); - break; - } - - - _consoleWriter.write(edge); - - } - - private void printCellRow(String edge, String mid, int cellWidth) throws IOException - { - _consoleWriter.write(edge); - - printPad(mid, cellWidth); - - _consoleWriter.write(edge); - _consoleWriter.newLine(); - } - - private void printPad(String padChar, int count) throws IOException - { - for (int i = 0; i < count; i++) - { - _consoleWriter.write(padChar); - } - } - - -} -- cgit v1.2.1 From ab8ba0dfc8979ac2fbba266b42e16f71c52276fe Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 14 Apr 2009 15:54:16 +0000 Subject: QPID-1807 : Add 0.5-fix broker and update SlowMessageStore to use MessageStores rather than TransactionLogs git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@764850 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 1007 ++++++++++++ .../apache/qpid/configuration/Configuration.java | 188 +++ .../apache/qpid/server/AMQBrokerManagerMBean.java | 235 +++ .../java/org/apache/qpid/server/AMQChannel.java | 909 +++++++++++ .../qpid/server/ConsumerTagNotUniqueException.java | 25 + .../qpid/server/ExtractResendAndRequeue.java | 108 ++ .../src/main/java/org/apache/qpid/server/Main.java | 509 +++++++ .../org/apache/qpid/server/ManagedChannel.java | 68 + .../qpid/server/RequiredDeliveryException.java | 79 + .../java/org/apache/qpid/server/ack/TxAck.java | 148 ++ .../qpid/server/ack/UnacknowledgedMessageMap.java | 81 + .../server/ack/UnacknowledgedMessageMapImpl.java | 232 +++ .../configuration/ExchangeConfiguration.java | 58 + .../server/configuration/QueueConfiguration.java | 111 ++ .../configuration/SecurityConfiguration.java | 41 + .../server/configuration/ServerConfiguration.java | 519 +++++++ .../configuration/VirtualHostConfiguration.java | 169 +++ .../management/ConfigurationManagement.java | 43 + .../management/ConfigurationManagementMBean.java | 49 + .../qpid/server/connection/ConnectionRegistry.java | 73 + .../server/connection/IConnectionRegistry.java | 38 + .../qpid/server/exchange/AbstractExchange.java | 211 +++ .../server/exchange/DefaultExchangeFactory.java | 114 ++ .../server/exchange/DefaultExchangeRegistry.java | 139 ++ .../qpid/server/exchange/DirectExchange.java | 251 +++ .../org/apache/qpid/server/exchange/Exchange.java | 98 ++ .../qpid/server/exchange/ExchangeFactory.java | 41 + .../server/exchange/ExchangeInUseException.java | 45 + .../qpid/server/exchange/ExchangeRegistry.java | 51 + .../apache/qpid/server/exchange/ExchangeType.java | 35 + .../qpid/server/exchange/FanoutExchange.java | 224 +++ .../qpid/server/exchange/HeadersBinding.java | 219 +++ .../qpid/server/exchange/HeadersExchange.java | 350 +++++ .../org/apache/qpid/server/exchange/Index.java | 99 ++ .../qpid/server/exchange/ManagedExchange.java | 99 ++ .../apache/qpid/server/exchange/MessageRouter.java | 41 + .../qpid/server/exchange/NoRouteException.java | 49 + .../apache/qpid/server/exchange/TopicExchange.java | 670 ++++++++ .../qpid/server/exchange/headers/HeaderKey.java | 40 + .../exchange/headers/HeaderKeyDictionary.java | 50 + .../exchange/headers/HeaderMatcherResult.java | 25 + .../exchange/headers/HeadersMatcherDFAState.java | 339 +++++ .../server/exchange/headers/HeadersParser.java | 439 ++++++ .../exchange/topic/TopicMatcherDFAState.java | 295 ++++ .../server/exchange/topic/TopicMatcherResult.java | 25 + .../qpid/server/exchange/topic/TopicParser.java | 613 ++++++++ .../qpid/server/exchange/topic/TopicWord.java | 54 + .../server/exchange/topic/TopicWordDictionary.java | 63 + .../qpid/server/filter/ArithmeticExpression.java | 275 ++++ .../qpid/server/filter/BinaryExpression.java | 106 ++ .../qpid/server/filter/BooleanExpression.java | 41 + .../qpid/server/filter/ComparisonExpression.java | 601 ++++++++ .../qpid/server/filter/ConstantExpression.java | 211 +++ .../org/apache/qpid/server/filter/Expression.java | 38 + .../apache/qpid/server/filter/FilterManager.java | 39 + .../qpid/server/filter/FilterManagerFactory.java | 67 + .../qpid/server/filter/JMSSelectorFilter.java | 56 + .../apache/qpid/server/filter/LogicExpression.java | 122 ++ .../apache/qpid/server/filter/MessageFilter.java | 30 + .../qpid/server/filter/NoConsumerFilter.java | 42 + .../qpid/server/filter/PropertyExpression.java | 268 ++++ .../qpid/server/filter/SimpleFilterManager.java | 77 + .../apache/qpid/server/filter/UnaryExpression.java | 369 +++++ .../apache/qpid/server/filter/XPathExpression.java | 127 ++ .../qpid/server/filter/XQueryExpression.java | 58 + .../qpid/server/filter/XalanXPathEvaluator.java | 103 ++ .../server/flow/AbstractFlowCreditManager.java | 62 + .../qpid/server/flow/BytesOnlyCreditManager.java | 77 + .../apache/qpid/server/flow/FlowCreditManager.java | 44 + .../qpid/server/flow/LimitlessCreditManager.java | 44 + .../server/flow/MessageAndBytesCreditManager.java | 79 + .../qpid/server/flow/MessageOnlyCreditManager.java | 76 + .../qpid/server/flow/Pre0_10CreditManager.java | 185 +++ .../qpid/server/handler/AccessRequestHandler.java | 61 + .../qpid/server/handler/BasicAckMethodHandler.java | 67 + .../server/handler/BasicCancelMethodHandler.java | 74 + .../server/handler/BasicConsumeMethodHandler.java | 173 +++ .../qpid/server/handler/BasicGetMethodHandler.java | 190 +++ .../server/handler/BasicPublishMethodHandler.java | 106 ++ .../qpid/server/handler/BasicQosHandler.java | 58 + .../server/handler/BasicRecoverMethodHandler.java | 73 + .../handler/BasicRecoverSyncMethodHandler.java | 75 + .../server/handler/BasicRejectMethodHandler.java | 125 ++ .../qpid/server/handler/ChannelCloseHandler.java | 77 + .../qpid/server/handler/ChannelCloseOkHandler.java | 53 + .../qpid/server/handler/ChannelFlowHandler.java | 66 + .../qpid/server/handler/ChannelOpenHandler.java | 103 ++ .../handler/ConnectionCloseMethodHandler.java | 72 + .../handler/ConnectionCloseOkMethodHandler.java | 63 + .../handler/ConnectionOpenMethodHandler.java | 102 ++ .../handler/ConnectionSecureOkMethodHandler.java | 126 ++ .../handler/ConnectionStartOkMethodHandler.java | 163 ++ .../handler/ConnectionTuneOkMethodHandler.java | 54 + .../qpid/server/handler/ExchangeBoundHandler.java | 178 +++ .../server/handler/ExchangeDeclareHandler.java | 122 ++ .../qpid/server/handler/ExchangeDeleteHandler.java | 75 + .../server/handler/OnCurrentThreadExecutor.java | 34 + .../qpid/server/handler/QueueBindHandler.java | 143 ++ .../qpid/server/handler/QueueDeclareHandler.java | 203 +++ .../qpid/server/handler/QueueDeleteHandler.java | 127 ++ .../qpid/server/handler/QueuePurgeHandler.java | 122 ++ .../qpid/server/handler/QueueUnbindHandler.java | 137 ++ .../server/handler/ServerMethodDispatcherImpl.java | 566 +++++++ .../handler/ServerMethodDispatcherImpl_0_9.java | 164 ++ .../handler/ServerMethodDispatcherImpl_8_0.java | 86 ++ .../qpid/server/handler/TxCommitHandler.java | 78 + .../qpid/server/handler/TxRollbackHandler.java | 77 + .../qpid/server/handler/TxSelectHandler.java | 63 + .../server/handler/UnexpectedMethodException.java | 33 + .../logging/management/LoggingManagement.java | 136 ++ .../logging/management/LoggingManagementMBean.java | 674 +++++++++ .../qpid/server/management/AMQManagedObject.java | 97 ++ .../server/management/DefaultManagedObject.java | 200 +++ .../management/JMXManagedObjectRegistry.java | 371 +++++ .../qpid/server/management/MBeanAttribute.java | 41 + .../qpid/server/management/MBeanConstructor.java | 39 + .../qpid/server/management/MBeanDescription.java | 38 + .../qpid/server/management/MBeanIntrospector.java | 388 +++++ .../management/MBeanInvocationHandlerImpl.java | 257 ++++ .../qpid/server/management/MBeanOperation.java | 43 + .../server/management/MBeanOperationParameter.java | 37 + .../apache/qpid/server/management/Managable.java | 34 + .../qpid/server/management/ManagedBroker.java | 98 ++ .../qpid/server/management/ManagedObject.java | 58 + .../server/management/ManagedObjectRegistry.java | 51 + .../management/NoopManagedObjectRegistry.java | 60 + .../server/output/ProtocolOutputConverter.java | 57 + .../output/ProtocolOutputConverterRegistry.java | 61 + .../amqp0_8/ProtocolOutputConverterImpl.java | 284 ++++ .../amqp0_9/ProtocolOutputConverterImpl.java | 391 +++++ .../org/apache/qpid/server/plugins/Activator.java | 44 + .../apache/qpid/server/plugins/PluginManager.java | 176 +++ .../server/protocol/AMQMinaProtocolSession.java | 859 +++++++++++ .../protocol/AMQNoMethodHandlerException.java | 46 + .../server/protocol/AMQPFastProtocolHandler.java | 284 ++++ .../qpid/server/protocol/AMQPProtocolProvider.java | 52 + .../qpid/server/protocol/AMQProtocolSession.java | 207 +++ .../server/protocol/AMQProtocolSessionMBean.java | 304 ++++ .../qpid/server/protocol/ExchangeInitialiser.java | 51 + .../qpid/server/protocol/ManagedConnection.java | 136 ++ .../protocol/UnknnownMessageTypeException.java | 46 + .../org/apache/qpid/server/queue/AMQMessage.java | 482 ++++++ .../apache/qpid/server/queue/AMQMessageHandle.java | 79 + .../apache/qpid/server/queue/AMQPriorityQueue.java | 70 + .../org/apache/qpid/server/queue/AMQQueue.java | 220 +++ .../apache/qpid/server/queue/AMQQueueFactory.java | 86 ++ .../apache/qpid/server/queue/AMQQueueMBean.java | 478 ++++++ .../qpid/server/queue/DefaultQueueRegistry.java | 71 + .../apache/qpid/server/queue/ExchangeBinding.java | 84 + .../apache/qpid/server/queue/ExchangeBindings.java | 82 + .../qpid/server/queue/FailedDequeueException.java | 50 + .../org/apache/qpid/server/queue/Filterable.java | 33 + .../qpid/server/queue/InMemoryMessageHandle.java | 157 ++ .../apache/qpid/server/queue/IncomingMessage.java | 319 ++++ .../org/apache/qpid/server/queue/ManagedQueue.java | 245 +++ .../qpid/server/queue/MessageCleanupException.java | 52 + .../qpid/server/queue/MessageHandleFactory.java | 46 + .../apache/qpid/server/queue/MessageMetaData.java | 92 ++ .../qpid/server/queue/NoConsumersException.java | 47 + .../qpid/server/queue/NotificationCheck.java | 138 ++ .../qpid/server/queue/PriorityQueueList.java | 169 +++ .../org/apache/qpid/server/queue/QueueEntry.java | 184 +++ .../apache/qpid/server/queue/QueueEntryImpl.java | 388 +++++ .../qpid/server/queue/QueueEntryIterator.java | 30 + .../apache/qpid/server/queue/QueueEntryList.java | 34 + .../qpid/server/queue/QueueEntryListFactory.java | 26 + .../server/queue/QueueNotificationListener.java | 27 + .../apache/qpid/server/queue/QueueRegistry.java | 43 + .../apache/qpid/server/queue/SimpleAMQQueue.java | 1600 ++++++++++++++++++++ .../qpid/server/queue/SimpleQueueEntryList.java | 178 +++ .../qpid/server/queue/TransientMessageData.java | 127 ++ .../server/queue/UnauthorizedAccessException.java | 45 + .../server/queue/WeakReferenceMessageHandle.java | 219 +++ .../qpid/server/registry/ApplicationRegistry.java | 290 ++++ .../ConfigurationFileApplicationRegistry.java | 87 ++ .../qpid/server/registry/IApplicationRegistry.java | 79 + .../qpid/server/security/access/ACLManager.java | 322 ++++ .../qpid/server/security/access/ACLPlugin.java | 70 + .../server/security/access/ACLPluginFactory.java | 33 + .../qpid/server/security/access/AccessResult.java | 65 + .../qpid/server/security/access/AccessRights.java | 63 + .../qpid/server/security/access/Accessable.java | 27 + .../security/access/AuthorizationManager.java | 6 + .../qpid/server/security/access/Permission.java | 38 + .../security/access/PrincipalPermissions.java | 612 ++++++++ .../server/security/access/VirtualHostAccess.java | 68 + .../access/management/AMQUserManagementMBean.java | 501 ++++++ .../security/access/management/UserManagement.java | 121 ++ .../security/access/plugins/AbstractACLPlugin.java | 99 ++ .../server/security/access/plugins/AllowAll.java | 54 + .../security/access/plugins/BasicACLPlugin.java | 129 ++ .../server/security/access/plugins/DenyAll.java | 75 + .../access/plugins/LegacyAccessPlugin.java | 71 + .../server/security/access/plugins/SimpleXML.java | 432 ++++++ .../access/plugins/network/FirewallFactory.java | 45 + .../access/plugins/network/FirewallPlugin.java | 264 ++++ .../server/security/auth/AuthenticationResult.java | 63 + .../Base64MD5PasswordFilePrincipalDatabase.java | 541 +++++++ .../ConfigurationFilePrincipalDatabaseManager.java | 232 +++ .../server/security/auth/database/HashedUser.java | 169 +++ .../PlainPasswordFilePrincipalDatabase.java | 491 ++++++ .../server/security/auth/database/PlainUser.java | 106 ++ .../security/auth/database/PrincipalDatabase.java | 105 ++ .../auth/database/PrincipalDatabaseManager.java | 35 + .../auth/database/PropertiesPrincipalDatabase.java | 169 +++ .../PropertiesPrincipalDatabaseManager.java | 50 + .../auth/manager/AuthenticationManager.java | 38 + .../PrincipalDatabaseAuthenticationManager.java | 237 +++ .../auth/rmi/RMIPasswordAuthenticator.java | 119 ++ .../sasl/AuthenticationProviderInitialiser.java | 76 + .../server/security/auth/sasl/JCAProvider.java | 46 + .../auth/sasl/UsernamePasswordInitialiser.java | 123 ++ .../security/auth/sasl/UsernamePrincipal.java | 44 + .../auth/sasl/amqplain/AmqPlainInitialiser.java | 38 + .../auth/sasl/amqplain/AmqPlainSaslServer.java | 132 ++ .../sasl/amqplain/AmqPlainSaslServerFactory.java | 60 + .../sasl/crammd5/CRAMMD5HashedInitialiser.java | 50 + .../auth/sasl/crammd5/CRAMMD5HashedSaslServer.java | 105 ++ .../sasl/crammd5/CRAMMD5HashedServerFactory.java | 61 + .../auth/sasl/crammd5/CRAMMD5Initialiser.java | 71 + .../security/auth/sasl/plain/PlainInitialiser.java | 38 + .../security/auth/sasl/plain/PlainSaslServer.java | 151 ++ .../auth/sasl/plain/PlainSaslServerFactory.java | 60 + .../org/apache/qpid/server/state/AMQState.java | 36 + .../apache/qpid/server/state/AMQStateManager.java | 263 ++++ .../state/IllegalStateTransitionException.java | 52 + .../server/state/StateAwareMethodListener.java | 35 + .../apache/qpid/server/state/StateListener.java | 30 + .../qpid/server/store/DerbyMessageStore.java | 1464 ++++++++++++++++++ .../qpid/server/store/MemoryMessageStore.java | 235 +++ .../org/apache/qpid/server/store/MessageStore.java | 277 ++++ .../server/store/MessageStoreClosedException.java | 36 + .../org/apache/qpid/server/store/StoreContext.java | 71 + .../server/subscription/ClientDeliveryMethod.java | 29 + .../server/subscription/RecordDeliveryMethod.java | 28 + .../qpid/server/subscription/Subscription.java | 96 ++ .../server/subscription/SubscriptionFactory.java | 59 + .../subscription/SubscriptionFactoryImpl.java | 103 ++ .../qpid/server/subscription/SubscriptionImpl.java | 617 ++++++++ .../qpid/server/subscription/SubscriptionList.java | 247 +++ .../qpid/server/transport/ThreadPoolFilter.java | 705 +++++++++ .../qpid/server/txn/LocalTransactionalContext.java | 293 ++++ .../qpid/server/txn/NonTransactionalContext.java | 213 +++ .../qpid/server/txn/StoreMessageOperation.java | 58 + .../qpid/server/txn/TransactionalContext.java | 179 +++ .../java/org/apache/qpid/server/txn/TxnBuffer.java | 109 ++ .../java/org/apache/qpid/server/txn/TxnOp.java | 55 + .../apache/qpid/server/util/CircularBuffer.java | 131 ++ .../server/util/ConcurrentLinkedQueueNoSize.java | 38 + .../org/apache/qpid/server/util/LoggingProxy.java | 105 ++ .../qpid/server/util/NullApplicationRegistry.java | 86 ++ .../server/virtualhost/ManagedVirtualHost.java | 45 + .../qpid/server/virtualhost/VirtualHost.java | 593 ++++++++ .../server/virtualhost/VirtualHostRegistry.java | 70 + .../qpid/tools/messagestore/MessageStoreTool.java | 652 ++++++++ .../messagestore/commands/AbstractCommand.java | 66 + .../qpid/tools/messagestore/commands/Clear.java | 85 ++ .../qpid/tools/messagestore/commands/Command.java | 36 + .../qpid/tools/messagestore/commands/Copy.java | 55 + .../qpid/tools/messagestore/commands/Dump.java | 302 ++++ .../qpid/tools/messagestore/commands/Help.java | 98 ++ .../qpid/tools/messagestore/commands/List.java | 314 ++++ .../qpid/tools/messagestore/commands/Load.java | 94 ++ .../qpid/tools/messagestore/commands/Move.java | 206 +++ .../qpid/tools/messagestore/commands/Purge.java | 67 + .../qpid/tools/messagestore/commands/Quit.java | 54 + .../qpid/tools/messagestore/commands/Select.java | 233 +++ .../qpid/tools/messagestore/commands/Show.java | 515 +++++++ .../org/apache/qpid/tools/security/Passwd.java | 81 + .../org/apache/qpid/tools/utils/CommandParser.java | 51 + .../java/org/apache/qpid/tools/utils/Console.java | 90 ++ .../qpid/tools/utils/SimpleCommandParser.java | 121 ++ .../org/apache/qpid/tools/utils/SimpleConsole.java | 363 +++++ 273 files changed, 44978 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java new file mode 100644 index 0000000000..7e0c4defe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -0,0 +1,1007 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.log4j; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.GZIPOutputStream; + +import org.apache.log4j.helpers.CountingQuietWriter; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.spi.LoggingEvent; + +/** + *

      CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender
      It can function as either + * or do both at the same time (making size based rolling files like RollingFileAppender until a data/time boundary is + * crossed at which time it rolls all of those files as per the DailyRollingFileAppender) based on the setting for + * rollingStyle.

      To use CompositeRollingAppender to roll log files as they reach a certain size + * (like RollingFileAppender), set rollingStyle=1 (@see config.size)
      To use CompositeRollingAppender to roll log + * files at certain time intervals (daily for example), set rollingStyle=2 and a datePattern (@see config.time)
      To + * have CompositeRollingAppender roll log files at a certain size AND rename those according to time intervals, set + * rollingStyle=3 (@see config.composite)
      + * + *

      A of few additional optional features have been added:
      -- Attach date pattern for current log file (@see + * staticLogFileName)
      -- Backup number increments for newer files (@see countDirection)
      -- Infinite number of + * backups by file size (@see maxSizeRollBackups)

      A few notes and warnings: For large or infinite number of + * backups countDirection > 0 is highly recommended, with staticLogFileName = false if time based rolling is also used + * -- this will reduce the number of file renamings to few or none. Changing staticLogFileName or countDirection + * without clearing the directory could have nasty side effects. If Date/Time based rolling is enabled, + * CompositeRollingAppender will attempt to roll existing files in the directory without a date/time tag based on the + * last modified date of the base log files last modification.

      A maximum number of backups based on + * date/time boundries would be nice but is not yet implemented.
      + * + * @author Kevin Steppe + * @author Heinz Richter + * @author Eirik Lygre + * @author Ceki Gülcü + * @author Martin Ritchie + */ +public class QpidCompositeRollingAppender extends FileAppender +{ + // The code assumes that the following 'time' constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE = -1; + static final int TOP_OF_MINUTE = 0; + static final int TOP_OF_HOUR = 1; + static final int HALF_DAY = 2; + static final int TOP_OF_DAY = 3; + static final int TOP_OF_WEEK = 4; + static final int TOP_OF_MONTH = 5; + + /** Style of rolling to use */ + static final int BY_SIZE = 1; + static final int BY_DATE = 2; + static final int BY_COMPOSITE = 3; + + // Not currently used + static final String S_BY_SIZE = "Size"; + static final String S_BY_DATE = "Date"; + static final String S_BY_COMPOSITE = "Composite"; + + /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ + private String datePattern = "'.'yyyy-MM-dd"; + + /** + * The actual formatted filename that is currently being written to or will be the file transferred to on roll over + * (based on staticLogFileName). + */ + private String scheduledFilename = null; + + /** The timestamp when we shall next recompute the filename. */ + private long nextCheck = System.currentTimeMillis() - 1; + + /** Holds date of last roll over */ + Date now = new Date(); + + SimpleDateFormat sdf; + + /** Helper class to determine next rollover time */ + RollingCalendar rc = new RollingCalendar(); + + /** Current period for roll overs */ + int checkPeriod = TOP_OF_TROUBLE; + + /** The default maximum file size is 10MB. */ + protected long maxFileSize = 10 * 1024 * 1024; + + /** There is zero backup files by default. */ + protected int maxSizeRollBackups = 0; + /** How many sized based backups have been made so far */ + protected int curSizeRollBackups = 0; + + /** not yet implemented */ + protected int maxTimeRollBackups = -1; + protected int curTimeRollBackups = 0; + + /** + * By default newer files have lower numbers. (countDirection < 0) ie. log.1 is most recent, log.5 is the 5th + * backup, etc... countDirection > 0 does the opposite ie. log.1 is the first backup made, log.5 is the 5th backup + * made, etc. For infinite backups use countDirection > 0 to reduce rollOver costs. + */ + protected int countDirection = -1; + + /** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */ + protected int rollingStyle = BY_COMPOSITE; + protected boolean rollDate = true; + protected boolean rollSize = true; + + /** + * By default file.log is always the current file. Optionally file.log.yyyy-mm-dd for current formated datePattern + * can by the currently logging file (or file.log.curSizeRollBackup or even file.log.yyyy-mm-dd.curSizeRollBackup) + * This will make time based roll overs with a large number of backups much faster -- it won't have to rename all + * the backups! + */ + protected boolean staticLogFileName = true; + + /** FileName provided in configuration. Used for rolling properly */ + protected String baseFileName; + + /** Do we want to .gz our backup files. */ + protected boolean compress = false; + + /** Do we want to use a second thread when compressing our backup files. */ + protected boolean compressAsync = false; + + /** Do we want to start numbering files at zero. */ + protected boolean zeroBased = false; + + /** Path provided in configuration. Used for moving backup files to */ + protected String backupFilesToPath = null; + private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); + private AtomicBoolean _compressing = new AtomicBoolean(false); + + /** The default constructor does nothing. */ + public QpidCompositeRollingAppender() + { } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The + * opened filename will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern) throws IOException + { + this(layout, filename, datePattern, true); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + * + *

      If the append parameter is true, the file will be appended to. Otherwise, the file desginated by + * filename will be truncated before being opened. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, boolean append) throws IOException + { + super(layout, filename, append); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the ouput destination for this appender. + */ + public QpidCompositeRollingAppender(Layout layout, String filename, String datePattern, boolean append) + throws IOException + { + super(layout, filename, append); + this.datePattern = datePattern; + activateOptions(); + } + + /** + * Instantiate a CompositeRollingAppender and open the file designated by filename. The opened filename + * will become the output destination for this appender. + * + *

      The file will be appended to. DatePattern is default. + */ + public QpidCompositeRollingAppender(Layout layout, String filename) throws IOException + { + super(layout, filename); + } + + /** + * The DatePattern takes a string in the same format as expected by {@link java.text.SimpleDateFormat}. This + * options determines the rollover schedule. + */ + public void setDatePattern(String pattern) + { + datePattern = pattern; + } + + /** Returns the value of the DatePattern option. */ + public String getDatePattern() + { + return datePattern; + } + + /** Returns the value of the maxSizeRollBackups option. */ + public int getMaxSizeRollBackups() + { + return maxSizeRollBackups; + } + + /** + * Get the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + * @since 1.1 + */ + public long getMaximumFileSize() + { + return maxFileSize; + } + + /** + *

      Set the maximum number of backup files to keep around based on file size. + * + *

      The MaxSizeRollBackups option determines how many backup files are kept before the oldest is erased. + * This option takes an integer value. If set to zero, then there will be no backup files and the log file will be + * truncated when it reaches MaxFileSize. If a negative number is supplied then no deletions will be + * made. Note that this could result in very slow performance as a large number of files are rolled over unless + * {@link #setCountDirection} up is used. + * + *

      The maximum applys to -each- time based group of files and -not- the total. Using a daily roll the maximum + * total files would be (#days run) * (maxSizeRollBackups) + */ + public void setMaxSizeRollBackups(int maxBackups) + { + maxSizeRollBackups = maxBackups; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaxFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter + * taking a long argument from the setter taking a String argument by the JavaBeans {@link + * java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaximumFileSize(long maxFileSize) + { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being rolled over to backup files. + * + *

      In configuration files, the MaxFileSize option takes an long integer in the range 0 - 2^63. You can + * specify the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed + * respectively in kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240. + */ + public void setMaxFileSize(String value) + { + maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); + } + + protected void setQWForFiles(Writer writer) + { + qw = new CountingQuietWriter(writer, errorHandler); + } + + // Taken verbatum from DailyRollingFileAppender + int computeCheckPeriod() + { + RollingCalendar c = new RollingCalendar(); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date(0); + if (datePattern != null) + { + for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) + { + String r0 = sdf.format(epoch); + c.setType(i); + Date next = new Date(c.getNextCheckMillis(epoch)); + String r1 = sdf.format(next); + // LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if ((r0 != null) && (r1 != null) && !r0.equals(r1)) + { + return i; + } + } + } + + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + // Now for the new stuff + /** + * Handles append time behavior for CompositeRollingAppender. This checks if a roll over either by date (checked + * first) or time (checked second) is need and then appends to the file last. + */ + protected void subAppend(LoggingEvent event) + { + + if (rollDate) + { + long n = System.currentTimeMillis(); + if (n >= nextCheck) + { + now.setTime(n); + nextCheck = rc.getNextCheckMillis(now); + + rollOverTime(); + } + } + + if (rollSize) + { + if ((fileName != null) && (((CountingQuietWriter) qw).getCount() >= maxFileSize)) + { + rollOverSize(); + } + } + + super.subAppend(event); + } + + public void setFile(String file) + { + baseFileName = file.trim(); + fileName = file.trim(); + } + + /** + * Creates and opens the file for logging. If staticLogFileName is false then the fully qualified name + * is determined and used. + */ + public synchronized void setFile(String fileName, boolean append) throws IOException + { + if (!staticLogFileName) + { + scheduledFilename = fileName = fileName.trim() + sdf.format(now); + if (countDirection > 0) + { + scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); + } + } + + super.setFile(fileName, append, bufferedIO, bufferSize); + + if (append) + { + File f = new File(fileName); + ((CountingQuietWriter) qw).setCount(f.length()); + } + } + + public int getCountDirection() + { + return countDirection; + } + + public void setCountDirection(int direction) + { + countDirection = direction; + } + + public int getRollingStyle() + { + return rollingStyle; + } + + public void setRollingStyle(int style) + { + rollingStyle = style; + switch (rollingStyle) + { + + case BY_SIZE: + rollDate = false; + rollSize = true; + break; + + case BY_DATE: + rollDate = true; + rollSize = false; + break; + + case BY_COMPOSITE: + rollDate = true; + rollSize = true; + break; + + default: + errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)"); + } + } + + /* + public void setRollingStyle(String style) { + if (style == S_BY_SIZE) { + rollingStyle = BY_SIZE; + } + else if (style == S_BY_DATE) { + rollingStyle = BY_DATE; + } + else if (style == S_BY_COMPOSITE) { + rollingStyle = BY_COMPOSITE; + } + } + */ + public boolean getStaticLogFileName() + { + return staticLogFileName; + } + + public void setStaticLogFileName(boolean s) + { + staticLogFileName = s; + } + + public void setStaticLogFileName(String value) + { + setStaticLogFileName(OptionConverter.toBoolean(value, true)); + } + + public boolean getCompressBackupFiles() + { + return compress; + } + + public void setCompressBackupFiles(boolean c) + { + compress = c; + } + + public boolean getCompressAsync() + { + return compressAsync; + } + + public void setCompressAsync(boolean c) + { + compressAsync = c; + if (compressAsync) + { + executor = Executors.newFixedThreadPool(1); + + compressor = new Compressor(); + } + } + + public boolean getZeroBased() + { + return zeroBased; + } + + public void setZeroBased(boolean z) + { + zeroBased = z; + } + + public String getBackupFilesToPath() + { + return backupFilesToPath; + } + + public void setbackupFilesToPath(String path) + { + File td = new File(path); + if (!td.exists()) + { + td.mkdirs(); + } + + backupFilesToPath = path; + } + + /** + * Initializes based on exisiting conditions at time of activateOptions. The following is done:
      + *
      A) determine curSizeRollBackups
      B) determine curTimeRollBackups (not implemented)
      C) initiates a + * roll over if needed for crossing a date boundary since the last run. + */ + protected void existingInit() + { + + if (zeroBased) + { + curSizeRollBackups = -1; + } + + curTimeRollBackups = 0; + + // part A starts here + String filter; + if (staticLogFileName || !rollDate) + { + filter = baseFileName + ".*"; + } + else + { + filter = scheduledFilename + ".*"; + } + + File f = new File(baseFileName); + f = f.getParentFile(); + if (f == null) + { + f = new File("."); + } + + LogLog.debug("Searching for existing files in: " + f); + String[] files = f.list(); + + if (files != null) + { + for (int i = 0; i < files.length; i++) + { + if (!files[i].startsWith(baseFileName)) + { + continue; + } + + int index = files[i].lastIndexOf("."); + + if (staticLogFileName) + { + int endLength = files[i].length() - index; + if ((baseFileName.length() + endLength) != files[i].length()) + { + // file is probably scheduledFilename + .x so I don't care + continue; + } + } + + try + { + int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); + LogLog.debug("From file: " + files[i] + " -> " + backup); + if (backup > curSizeRollBackups) + { + curSizeRollBackups = backup; + } + } + catch (Exception e) + { + // this happens when file.log -> file.log.yyyy-mm-dd which is normal + // when staticLogFileName == false + LogLog.debug("Encountered a backup file not ending in .x " + files[i]); + } + } + } + + LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); + // part A ends here + + // part B not yet implemented + + // part C + if (staticLogFileName && rollDate) + { + File old = new File(baseFileName); + if (old.exists()) + { + Date last = new Date(old.lastModified()); + if (!(sdf.format(last).equals(sdf.format(now)))) + { + scheduledFilename = baseFileName + sdf.format(last); + LogLog.debug("Initial roll over to: " + scheduledFilename); + rollOverTime(); + } + } + } + + LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups); + // part C ends here + + } + + /** + * Sets initial conditions including date/time roll over information, first check, scheduledFilename, and calls + * existingInit to initialize the current # of backups. + */ + public void activateOptions() + { + + // REMOVE removed rollDate from boolean to enable Alex's change + if (datePattern != null) + { + now.setTime(System.currentTimeMillis()); + sdf = new SimpleDateFormat(datePattern); + int type = computeCheckPeriod(); + // printPeriodicity(type); + rc.setType(type); + // next line added as this removes the name check in rollOver + nextCheck = rc.getNextCheckMillis(now); + } + else + { + if (rollDate) + { + LogLog.error("Either DatePattern or rollingStyle options are not set for [" + name + "]."); + } + } + + existingInit(); + + if (rollDate && (fileName != null) && (scheduledFilename == null)) + { + scheduledFilename = fileName + sdf.format(now); + } + + try + { + this.setFile(fileName, true); + } + catch (IOException e) + { + errorHandler.error("Cannot set file name:" + fileName); + } + + super.activateOptions(); + } + + /** + * Rollover the file(s) to date/time tagged file(s). Opens the new file (through setFile) and resets + * curSizeRollBackups. + */ + protected void rollOverTime() + { + + curTimeRollBackups++; + + this.closeFile(); // keep windows happy. + + // delete the old stuff here + + if (staticLogFileName) + { + /* Compute filename, but only if datePattern is specified */ + if (datePattern == null) + { + errorHandler.error("Missing DatePattern option in rollOver()."); + + return; + } + + // is the new file name equivalent to the 'current' one + // something has gone wrong if we hit this -- we should only + // roll over if the new file will be different from the old + String dateFormat = sdf.format(now); + if (scheduledFilename.equals(fileName + dateFormat)) + { + errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); + + return; + } + + // close current file, and rename it to datedFilename + this.closeFile(); + + // we may have to roll over a large number of backups here + String from, to; + for (int i = 1; i <= curSizeRollBackups; i++) + { + from = fileName + '.' + i; + to = scheduledFilename + '.' + i; + rollFile(from, to, false); + } + + rollFile(fileName, scheduledFilename, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new + + // new scheduled name + scheduledFilename = fileName + sdf.format(now); + this.setFile(baseFileName, false); + } + catch (IOException e) + { + errorHandler.error("setFile(" + fileName + ", false) call failed."); + } + + } + + /** + * Renames file from to file to. It also checks for existence of target file and deletes + * if it does. + */ + protected void rollFile(String from, String to, boolean compress) + { + if (from.equals(to)) + { + if (compress) + { + LogLog.debug("Attempting to compress file with same output name."); + } + + return; + } + + File target = new File(to); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + File file = new File(from); + if (compress) + { + compress(file, target); + } + else + { + if (!file.getPath().equals(target.getPath())) + { + file.renameTo(target); + } + } + + LogLog.debug(from + " -> " + to); + } + + protected void compress(String file) + { + File f = new File(file); + compress(f, f); + } + + private void compress(File from, File target) + { + if (compressAsync) + { + synchronized (_compress) + { + _compress.offer(new CompressJob(from, target)); + } + + startCompression(); + } + else + { + doCompress(from, target); + } + } + + private void startCompression() + { + if (_compressing.compareAndSet(false, true)) + { + executor.execute(compressor); + } + } + + /** Delete's the specified file if it exists */ + protected static void deleteFile(String fileName) + { + File file = new File(fileName); + if (file.exists()) + { + file.delete(); + } + } + + /** + * Implements roll overs base on file size. + * + *

      If the maximum number of size based backups is reached (curSizeRollBackups == maxSizeRollBackups If + * countDirection < 0, then files {File.1, ..., File.curSizeRollBackups -1} + * are renamed to {File.2, ..., File.curSizeRollBackups}. Moreover, File is + * renamed File.1 and closed.
      + * + * A new file is created to receive further log output. + * + *

      If maxSizeRollBackups is equal to zero, then the File is truncated with no backup + * files created. + * + *

      If maxSizeRollBackups < 0, then File is renamed if needed and no files are deleted. + */ + + // synchronization not necessary since doAppend is alreasy synched + protected void rollOverSize() + { + File file; + + this.closeFile(); // keep windows happy. + + LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount()); + LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups); + LogLog.debug("curSizeRollBackups = " + curSizeRollBackups); + LogLog.debug("countDirection = " + countDirection); + + // If maxBackups <= 0, then there is no file renaming to be done. + if (maxSizeRollBackups != 0) + { + + if (countDirection < 0) + { + // Delete the oldest file, to keep Windows happy. + if (curSizeRollBackups == maxSizeRollBackups) + { + deleteFile(fileName + '.' + maxSizeRollBackups); + curSizeRollBackups--; + } + + // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} + for (int i = curSizeRollBackups; i >= 1; i--) + { + rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); + } + + curSizeRollBackups++; + // Rename fileName to fileName.1 + rollFile(fileName, fileName + ".1", compress); + + } // REMOVE This code branching for Alexander Cerna's request + else if (countDirection == 0) + { + // rollFile based on date pattern + curSizeRollBackups++; + now.setTime(System.currentTimeMillis()); + scheduledFilename = fileName + sdf.format(now); + rollFile(fileName, scheduledFilename, compress); + } + else + { // countDirection > 0 + if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) + { + // delete the first and keep counting up. + int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + deleteFile(fileName + '.' + oldestFileIndex); + } + + if (staticLogFileName) + { + curSizeRollBackups++; + rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); + } + else + { + if (compress) + { + compress(fileName); + } + } + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(baseFileName, false); + } + catch (IOException e) + { + LogLog.error("setFile(" + fileName + ", false) call failed.", e); + } + } + + protected synchronized void doCompress(File from, File to) + { + String toFile; + if (backupFilesToPath == null) + { + toFile = to.getPath() + ".gz"; + } + else + { + toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; + } + + File target = new File(toFile); + if (target.exists()) + { + LogLog.debug("deleting existing target file: " + target); + target.delete(); + } + + try + { + // Create the GZIP output stream + GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); + + // Open the input file + FileInputStream in = new FileInputStream(from); + + // Transfer bytes from the input file to the GZIP output stream + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + + in.close(); + + // Complete the GZIP file + out.finish(); + out.close(); + // Remove old file. + from.delete(); + } + catch (IOException e) + { + if (target.exists()) + { + target.delete(); + } + + rollFile(from.getPath(), to.getPath(), false); + } + } + + private class CompressJob + { + File _from, _to; + + CompressJob(File from, File to) + { + _from = from; + _to = to; + } + + File getFrom() + { + return _from; + } + + File getTo() + { + return _to; + } + } + + Compressor compressor = null; + + Executor executor; + + private class Compressor implements Runnable + { + public void run() + { + boolean running = true; + while (running) + { + CompressJob job = _compress.poll(); + + doCompress(job.getFrom(), job.getTo()); + + synchronized (_compress) + { + if (_compress.isEmpty()) + { + running = false; + _compressing.set(false); + } + } + } + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java new file mode 100644 index 0000000000..40ff590a0a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.configuration; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class Configuration +{ + public static final String QPID_HOME = "QPID_HOME"; + + final String QPIDHOME = System.getProperty(QPID_HOME); + + private static Logger _devlog = LoggerFactory.getLogger(Configuration.class); + + public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + protected final Options _options = new Options(); + protected CommandLine _commandLine; + protected File _configFile; + + + public Configuration() + { + + } + + public void processCommandline(String[] args) throws InitException + { + try + { + _commandLine = new PosixParser().parse(_options, args); + } + catch (ParseException e) + { + throw new InitException("Unable to parse commmandline", e); + } + + final File defaultConfigFile = new File(QPIDHOME, DEFAULT_CONFIG_FILE); + setConfig(new File(_commandLine.getOptionValue("c", defaultConfigFile.getPath()))); + } + + public void setConfig(File file) + { + _configFile = file; + } + + /** + * @param option The option to set. + */ + public void setOption(Option option) + { + _options.addOption(option); + } + + /** + * getOptionValue from the configuration + * @param option variable argument, first string is option to get, second if present is the default value. + * @return the String for the given option or null if not present (if default value not specified) + */ + public String getOptionValue(String... option) + { + if (option.length == 1) + { + return _commandLine.getOptionValue(option[0]); + } + else if (option.length == 2) + { + return _commandLine.getOptionValue(option[0], option[1]); + } + return null; + } + + public void loadConfig(File file) throws InitException + { + setConfig(file); + loadConfig(); + } + + private void loadConfig() throws InitException + { + 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, null); + } + else + { + _devlog.debug("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); +// } + } + + +// private void configureLogging(File logConfigFile, String logWatchConfig) +// { +// int logWatchTime = 0; +// try +// { +// logWatchTime = Integer.parseInt(logWatchConfig); +// } +// catch (NumberFormatException e) +// { +// _devlog.error("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()) +// { +// _devlog.info("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); +// if (logWatchTime > 0) +// { +// _devlog.info("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(); +// } +// } + + public File getConfigFile() + { + return _configFile; + } + + + public class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java new file mode 100644 index 0000000000..11d2c27eab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -0,0 +1,235 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedBroker; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * This MBean 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") +public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBroker +{ + private final QueueRegistry _queueRegistry; + private final ExchangeRegistry _exchangeRegistry; + private final ExchangeFactory _exchangeFactory; + private final MessageStore _messageStore; + + private final VirtualHost.VirtualHostMBean _virtualHostMBean; + + @MBeanConstructor("Creates the Broker Manager MBean") + public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException + { + super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); + + _virtualHostMBean = virtualHostMBean; + VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); + + _queueRegistry = virtualHost.getQueueRegistry(); + _exchangeRegistry = virtualHost.getExchangeRegistry(); + _messageStore = virtualHost.getMessageStore(); + _exchangeFactory = virtualHost.getExchangeFactory(); + } + + public String getObjectInstanceName() + { + return _virtualHostMBean.getVirtualHost().getName(); + } + + /** + * Creates new exchange and registers it with the registry. + * + * @param exchangeName + * @param type + * @param durable + * @throws JMException + */ + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException + { + try + { + synchronized (_exchangeRegistry) + { + Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); + if (exchange == null) + { + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), + durable, false, 0); + _exchangeRegistry.registerExchange(exchange); + } + else + { + throw new JMException("The exchange \"" + exchangeName + "\" already exists."); + } + } + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in creating exchange " + exchangeName); + } + } + + /** + * Unregisters the exchange from registry. + * + * @param exchangeName + * @throws JMException + */ + public void unregisterExchange(String exchangeName) throws JMException + { + // TODO + // Check if the exchange is in use. + // boolean inUse = false; + // Check if there are queue-bindings with the exchange and unregister + // when there are no bindings. + try + { + _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); + } + } + + /** + * 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 + * @throws JMException + */ + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue != null) + { + throw new JMException("The queue \"" + queueName + "\" already exists."); + } + + try + { + AMQShortString ownerShortString = null; + if (owner != null) + { + ownerShortString = new AMQShortString(owner); + } + + queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost(), + null); + if (queue.isDurable() && !queue.isAutoDelete()) + { + _messageStore.createQueue(queue); + } + + _queueRegistry.registerQueue(queue); + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in creating queue " + queueName); + } + } + + private VirtualHost getVirtualHost() + { + return _virtualHostMBean.getVirtualHost(); + } + + /** + * Deletes the queue from queue registry and persistant storage. + * + * @param queueName + * @throws JMException + */ + public void deleteQueue(String queueName) throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("The Queue " + queueName + " is not a registerd queue."); + } + + try + { + queue.delete(); + _messageStore.removeQueue(queue); + + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in deleting queue " + queueName); + } + } + + public ManagedObject getParentObject() + { + return _virtualHostMBean; + } + + // This will have a single instance for a virtual host, so not having the name property in the ObjectName + public ObjectName getObjectName() throws MalformedObjectNameException + { + return getObjectNameForSingleInstanceMBean(); + } +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java new file mode 100644 index 0000000000..aa390d6c26 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -0,0 +1,909 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.NoRouteException; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.Pre0_10CreditManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.UnauthorizedAccessException; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.LocalTransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.txn.TransactionalContext; + +public class AMQChannel +{ + public static final int DEFAULT_PREFETCH = 5000; + + private static final Logger _log = Logger.getLogger(AMQChannel.class); + + private final int _channelId; + + + private final Pre0_10CreditManager _creditManager = new Pre0_10CreditManager(0l,0l); + + /** + * 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 long _deliveryTag = 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 IncomingMessage _currentMessage; + + /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */ + protected final Map _tag2SubscriptionMap = new HashMap(); + + private final MessageStore _messageStore; + + private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); + + private final AtomicBoolean _suspended = new AtomicBoolean(false); + + private TransactionalContext _txnContext; + + /** + * A context used by the message store enabling it to track context for a given channel even across thread + * boundaries + */ + private final StoreContext _storeContext; + + private final List _returnMessages = new LinkedList(); + + private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + + // Why do we need this reference ? - ritchiem + private final AMQProtocolSession _session; + private boolean _closing; + + public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) + throws AMQException + { + _session = session; + _channelId = channelId; + _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); + + + _messageStore = messageStore; + + // by default the session is non-transactional + _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + + /** Sets this channel to be part of a local transaction */ + public void setLocalTransactional() + { + _txnContext = new LocalTransactionalContext(this); + } + + public boolean isTransactional() + { + // this does not look great but there should only be one "non-transactional" + // transactional context, while there could be several transactional ones in + // theory + return !(_txnContext instanceof NonTransactionalContext); + } + + public int getChannelId() + { + return _channelId; + } + + public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException + { + + _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session); + _currentMessage.setMessageStore(_messageStore); + _currentMessage.setExchange(e); + } + + public void publishContentHeader(ContentHeaderBody contentHeaderBody) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content header without previously receiving a BasicPublish frame"); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("Content header received on channel " + _channelId); + } + + _currentMessage.setContentHeaderBody(contentHeaderBody); + + _currentMessage.setExpiration(); + + routeCurrentMessage(); + + _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + + deliverCurrentMessageIfComplete(); + + } + } + + private void deliverCurrentMessageIfComplete() + throws AMQException + { + // check and deliver if header says body length is zero + if (_currentMessage.allContentReceived()) + { + try + { + _currentMessage.deliverToQueues(); + } + catch (NoRouteException e) + { + _returnMessages.add(e); + } + catch(UnauthorizedAccessException ex) + { + _returnMessages.add(ex); + } + finally + { + // callback to allow the context to do any post message processing + // primary use is to allow message return processing in the non-tx case + _txnContext.messageProcessed(_session); + _currentMessage = null; + } + } + + } + + public void publishContentBody(ContentBody contentBody) throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content body without previously receiving a JmsPublishBody"); + } + + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + "Content body received on channel " + _channelId); + } + + try + { + + // returns true iff the message was delivered (i.e. if all data was + // received + _currentMessage.addContentBodyFrame( + _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( + contentBody)); + + deliverCurrentMessageIfComplete(); + } + 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 + { + try + { + _currentMessage.route(); + } + catch (NoRouteException e) + { + //_currentMessage.incrementReference(); + _returnMessages.add(e); + } + } + + public long getNextDeliveryTag() + { + return ++_deliveryTag; + } + + 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 acks Are acks enabled for this subscriber + * @param filters Filters to apply to this subscriber + * + * @param noLocal Flag stopping own messages being receivied. + * @param exclusive Flag requesting exclusive access to the queue + * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests + * + * @throws ConsumerTagNotUniqueException if the tag is not unique + * @throws AMQException if something goes wrong + */ + public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks, + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + { + if (tag == null) + { + tag = new AMQShortString("sgen_" + getNextConsumerTag()); + } + + if (_tag2SubscriptionMap.containsKey(tag)) + { + throw new ConsumerTagNotUniqueException(); + } + + Subscription subscription = + SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager); + + + // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. + // We add before we register as the Async Delivery process may AutoClose the subscriber + // so calling _cT2QM.remove before we have done put which was after the register succeeded. + // So to keep things straight we put before the call and catch all exceptions from the register and tidy up. + + _tag2SubscriptionMap.put(tag, subscription); + + try + { + queue.registerSubscription(subscription, exclusive); + } + catch (AMQException e) + { + _tag2SubscriptionMap.remove(tag); + throw e; + } + return tag; + } + + /** + * Unsubscribe a consumer from a queue. + * @param consumerTag + * @return true if the consumerTag had a mapped queue that could be unregistered. + * @throws AMQException + */ + public boolean unsubscribeConsumer(AMQShortString consumerTag) throws AMQException + { + + Subscription sub = _tag2SubscriptionMap.remove(consumerTag); + if (sub != null) + { + try + { + sub.getSendLock(); + sub.getQueue().unregisterSubscription(sub); + } + finally + { + sub.releaseSendLock(); + } + return true; + } + else + { + _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); + } + return false; + } + + /** + * Called from the protocol session to close this channel and clean up. T + * + * @throws AMQException if there is an error during closure + */ + public void close() throws AMQException + { + _txnContext.rollback(); + unsubscribeAllConsumers(); + try + { + requeue(); + } + catch (AMQException e) + { + _log.error("Caught AMQException whilst attempting to reque:" + e); + } + + setClosing(true); + } + + private void setClosing(boolean closing) + { + _closing = closing; + } + + private void unsubscribeAllConsumers() throws AMQException + { + if (_log.isInfoEnabled()) + { + if (!_tag2SubscriptionMap.isEmpty()) + { + _log.info("Unsubscribing all consumers on channel " + toString()); + } + else + { + _log.info("No consumers to unsubscribe on channel " + toString()); + } + } + + for (Map.Entry me : _tag2SubscriptionMap.entrySet()) + { + if (_log.isInfoEnabled()) + { + _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); + } + + Subscription sub = me.getValue(); + + try + { + sub.getSendLock(); + sub.getQueue().unregisterSubscription(sub); + } + finally + { + sub.releaseSendLock(); + } + + } + + _tag2SubscriptionMap.clear(); + } + + /** + * Add a message to the channel-based list of unacknowledged messages + * + * @param entry the record of the message on the queue that was delivered + * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the + * delivery tag) + * @param subscription The consumer that is to acknowledge this message. + */ + public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription) + { + if (_log.isDebugEnabled()) + { + if (entry.getQueue() == null) + { + _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity()); + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + + ") with a queue(" + entry.getQueue() + ") for " + subscription); + } + } + } + + _unacknowledgedMessageMap.add(deliveryTag, entry); + + } + + private final String id = "(" + System.identityHashCode(this) + ")"; + + public String debugIdentity() + { + return _channelId + id; + } + + /** + * Called to attempt re-delivery 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(); + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext = null; + + if (!messagesToBeDelivered.isEmpty()) + { + if (_log.isInfoEnabled()) + { + _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + } + + if (!(_txnContext instanceof NonTransactionalContext)) + { + + deliveryContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + else + { + deliveryContext = _txnContext; + } + } + + for (QueueEntry unacked : messagesToBeDelivered) + { + if (!unacked.isQueueDeleted()) + { + // Mark message redelivered + unacked.getMessage().setRedelivered(true); + + // Ensure message is released for redelivery + unacked.release(); + + // Deliver Message + deliveryContext.requeue(unacked); + + } + else + { + unacked.discard(_storeContext); + } + } + + } + + /** + * Requeue a single message + * + * @param deliveryTag The message to requeue + * + * @throws AMQException If something goes wrong. + */ + public void requeue(long deliveryTag) throws AMQException + { + QueueEntry unacked = _unacknowledgedMessageMap.remove(deliveryTag); + + if (unacked != null) + { + // Mark message redelivered + unacked.getMessage().setRedelivered(true); + + // Ensure message is released for redelivery + if (!unacked.isQueueDeleted()) + { + unacked.release(); + } + + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; + if (!(_txnContext instanceof NonTransactionalContext)) + { + + deliveryContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + + } + else + { + deliveryContext = _txnContext; + } + + if (!unacked.isQueueDeleted()) + { + // Redeliver the messages to the front of the queue + deliveryContext.requeue(unacked); + // Deliver increments the message count but we have already deliverted this once so don't increment it again + // this was because deliver did an increment changed this. + } + else + { + _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); + + unacked.discard(_storeContext); + } + } + else + { + _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + + _unacknowledgedMessageMap.size()); + + } + + } + + /** + * Called to resend all outstanding unacknowledged messages to this same channel. + * + * @param requeue Are the messages to be requeued or dropped. + * + * @throws AMQException When something goes wrong. + */ + public void resend(final boolean requeue) throws AMQException + { + + + final Map msgToRequeue = new LinkedHashMap(); + final Map msgToResend = new LinkedHashMap(); + + if (_log.isDebugEnabled()) + { + _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); + } + + // Process the Unacked-Map. + // Marking messages who still have a consumer for to be resent + // and those that don't to be requeued. + _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, + msgToResend, requeue, _storeContext)); + + + // Process Messages to Resend + if (_log.isDebugEnabled()) + { + if (!msgToResend.isEmpty()) + { + _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); + } + else + { + _log.debug("No message to resend."); + } + } + + for (Map.Entry entry : msgToResend.entrySet()) + { + QueueEntry message = entry.getValue(); + long deliveryTag = entry.getKey(); + + + + AMQMessage msg = message.getMessage(); + AMQQueue queue = message.getQueue(); + + // Our Java Client will always suspend the channel when resending! + // If the client has requested the messages be resent then it is + // their responsibility to ensure that thay are capable of receiving them + // i.e. The channel hasn't been server side suspended. + // if (isSuspended()) + // { + // _log.info("Channel is suspended so requeuing"); + // //move this message to requeue + // msgToRequeue.add(message); + // } + // else + // { + // release to allow it to be delivered + + // Without any details from the client about what has been processed we have to mark + // all messages in the unacked map as redelivered. + msg.setRedelivered(true); + + Subscription sub = message.getDeliveredSubscription(); + + if (sub != null) + { + + if(!queue.resend(message, sub)) + { + msgToRequeue.put(deliveryTag, message); + } + } + else + { + + if (_log.isInfoEnabled()) + { + _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + + ")to prevent loss"); + } + // move this message to requeue + msgToRequeue.put(deliveryTag, message); + } + } // for all messages + // } else !isSuspend + + if (_log.isInfoEnabled()) + { + if (!msgToRequeue.isEmpty()) + { + _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); + } + } + + // Deliver these messages out of the transaction as their delivery was never + // part of the transaction only the receive. + TransactionalContext deliveryContext; + if (!(_txnContext instanceof NonTransactionalContext)) + { + + deliveryContext = + new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + } + else + { + deliveryContext = _txnContext; + } + + // Process Messages to Requeue at the front of the queue + for (Map.Entry entry : msgToRequeue.entrySet()) + { + QueueEntry message = entry.getValue(); + long deliveryTag = entry.getKey(); + + message.release(); + message.setRedelivered(true); + + deliveryContext.requeue(message); + + _unacknowledgedMessageMap.remove(deliveryTag); + } + } + + /** + * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to + * remove the queue reference and also decrement any message reference counts, without actually removing the item + * since we may get an ack for a delivery tag that was generated from the deleted queue. + * + * @param queue the queue that has been deleted + * + */ + /* public void queueDeleted(final AMQQueue queue) + { + try + { + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) + { + if (message.getQueue() == queue) + { + try + { + message.discard(_storeContext); + message.setQueueDeleted(true); + + } + catch (AMQException e) + { + _log.error( + "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); + throw new RuntimeException(e); + } + } + + return false; + } + + public void visitComplete() + { + } + }); + } + catch (AMQException e) + { + _log.error("Unexpected Error while handling deletion of queue", e); + throw new RuntimeException(e); + } + + } +*/ + /** + * Acknowledge one or more messages. + * + * @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); + } + + /** + * Used only for testing purposes. + * + * @return the map of unacknowledged messages + */ + public UnacknowledgedMessageMap getUnacknowledgedMessageMap() + { + return _unacknowledgedMessageMap; + } + + + public void setSuspended(boolean suspended) + { + + + boolean wasSuspended = _suspended.getAndSet(suspended); + if (wasSuspended != suspended) + { + if (wasSuspended) + { + // may need to deliver queued messages + for (Subscription s : _tag2SubscriptionMap.values()) + { + s.getQueue().deliverAsync(s); + } + } + } + } + + public boolean isSuspended() + { + return _suspended.get(); + } + + public void commit() throws AMQException + { + if (!isTransactional()) + { + throw new AMQException("Fatal error: commit called on non-transactional channel"); + } + + _txnContext.commit(); + } + + public void rollback() throws AMQException + { + _txnContext.rollback(); + } + + public String toString() + { + return "["+_session.toString()+":"+_channelId+"]"; + } + + public void setDefaultQueue(AMQQueue queue) + { + _defaultQueue = queue; + } + + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public StoreContext getStoreContext() + { + return _storeContext; + } + + public void processReturns() throws AMQException + { + if (!_returnMessages.isEmpty()) + { + for (RequiredDeliveryException bouncedMessage : _returnMessages) + { + AMQMessage message = bouncedMessage.getAMQMessage(); + _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), + new AMQShortString(bouncedMessage.getMessage())); + + message.decrementReference(_storeContext); + } + + _returnMessages.clear(); + } + } + + + public TransactionalContext getTransactionalContext() + { + return _txnContext; + } + + public boolean isClosing() + { + return _closing; + } + + public AMQProtocolSession getProtocolSession() + { + return _session; + } + + public FlowCreditManager getCreditManager() + { + return _creditManager; + } + + public void setCredit(final long prefetchSize, final int prefetchCount) + { + _creditManager.setCreditLimits(prefetchSize, prefetchCount); + } + + public List getReturnMessages() + { + return _returnMessages; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod() + { + + public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) + throws AMQException + { + getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag()); + } + }; + + public ClientDeliveryMethod getClientDeliveryMethod() + { + return _clientDeliveryMethod; + } + + private final RecordDeliveryMethod _recordDeliveryMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) + { + addUnacknowledgedMessage(entry, deliveryTag, sub); + } + }; + + public RecordDeliveryMethod getRecordDeliveryMethod() + { + return _recordDeliveryMethod; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java new file mode 100644 index 0000000000..9a98af5689 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -0,0 +1,25 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +public class ConsumerTagNotUniqueException extends Exception +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java new file mode 100644 index 0000000000..29494c4118 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -0,0 +1,108 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import java.util.Map; + +public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor +{ + private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class); + + private Map _msgToRequeue; + private Map _msgToResend; + private boolean _requeueIfUnabletoResend; + private StoreContext _storeContext; + private UnacknowledgedMessageMap _unacknowledgedMessageMap; + + public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, + Map msgToRequeue, + Map msgToResend, + boolean requeueIfUnabletoResend, + StoreContext storeContext) + { + _unacknowledgedMessageMap = unacknowledgedMessageMap; + _msgToRequeue = msgToRequeue; + _msgToResend = msgToResend; + _requeueIfUnabletoResend = requeueIfUnabletoResend; + _storeContext = storeContext; + } + + public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException + { + + AMQMessage msg = message.getMessage(); + msg.setRedelivered(true); + final Subscription subscription = message.getDeliveredSubscription(); + if (subscription != null) + { + // Consumer exists + if (!subscription.isClosed()) + { + _msgToResend.put(deliveryTag, message); + } + else // consumer has gone + { + _msgToRequeue.put(deliveryTag, message); + } + } + else + { + // Message has no consumer tag, so was "delivered" to a GET + // or consumer no longer registered + // cannot resend, so re-queue. + if (!message.isQueueDeleted()) + { + if (_requeueIfUnabletoResend) + { + _msgToRequeue.put(deliveryTag, message); + } + else + { + message.discard(_storeContext); + _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); + } + } + else + { + message.discard(_storeContext); + _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); + } + } + + // false means continue processing + return false; + } + + public void visitComplete() + { + _unacknowledgedMessageMap.clear(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java new file mode 100644 index 0000000000..49619ac5b0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -0,0 +1,509 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.FixedSizeByteBufferAllocator; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; +import org.apache.mina.util.NewThreadExecutor; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; +import org.apache.qpid.server.logging.management.LoggingManagementMBean; +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; + +/** + * Main entry point for AMQPD. + * + */ +@SuppressWarnings({"AccessStaticViaInstance"}) +public class Main +{ + private static final Logger _logger = Logger.getLogger(Main.class); + public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); + + private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String QPID_HOME = "QPID_HOME"; + private static final int IPV4_ADDRESS_LENGTH = 4; + + private static final char IPV4_LITERAL_SEPARATOR = '.'; + + protected static class InitException extends Exception + { + InitException(String msg, Throwable cause) + { + super(msg, cause); + } + } + + 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 mport = + OptionBuilder.withArgName("mport").hasArg() + .withDescription("listen on the specified management port. Overrides any value in the config file") + .withLongOpt("mport").create("m"); + + + 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(mport); + 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 = QpidProperties.getVersionString(); + + StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: "); + + boolean first = true; + for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) + { + if (first) + { + first = false; + } + else + { + protocol.append(", "); + } + + protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); + + } + + System.out.println(ver + " (" + protocol + ")"); + } + else + { + try + { + startup(); + } + catch (InitException e) + { + System.out.println(e.getMessage()); + _brokerLogger.error("Initialisation Error : " + e.getMessage()); + shutdown(1); + } + catch (Throwable e) + { + System.out.println("Error initialising message broker: " + e); + _brokerLogger.error("Error initialising message broker: " + e); + e.printStackTrace(); + shutdown(1); + } + } + } + + protected void shutdown(int status) + { + ApplicationRegistry.removeAll(); + System.exit(status); + } + + protected void startup() throws Exception + { + final String QpidHome = System.getProperty(QPID_HOME); + final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE); + 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, null); + } + else + { + System.out.println("Using configuration file " + configFile.getAbsolutePath()); + } + + String logConfig = commandLine.getOptionValue("l"); + String logWatchConfig = commandLine.getOptionValue("w", "0"); + + int logWatchTime = 0; + try + { + logWatchTime = Integer.parseInt(logWatchConfig); + } + catch (NumberFormatException e) + { + System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + + "a non-negative integer. Using default of zero (no watching configured"); + } + + File logConfigFile; + if (logConfig != null) + { + logConfigFile = new File(logConfig); + configureLogging(logConfigFile, logWatchTime); + } + else + { + File configFileDirectory = configFile.getParentFile(); + logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); + configureLogging(logConfigFile, logWatchTime); + } + + ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile); + ServerConfiguration serverConfig = config.getConfiguration(); + updateManagementPort(serverConfig, commandLine.getOptionValue("m")); + + ApplicationRegistry.initialise(config); + + configureLoggingManagementMBean(logConfigFile, logWatchTime); + + ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); + configMBean.register(); + + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + // that are causing the broker build to pick up the wrong properties file and hence say + // Starting Qpid Client + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); + + ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); + + // 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 (!serverConfig.getEnablePooledAllocator()) + { + ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); + } + + if(serverConfig.getUseBiasedWrites()) + { + System.setProperty("org.apache.qpid.use_write_biased_pool","true"); + } + + int port = serverConfig.getPort(); + + String portStr = commandLine.getOptionValue("p"); + if (portStr != null) + { + try + { + port = Integer.parseInt(portStr); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + portStr, e); + } + } + + bind(port, serverConfig); + } + + /** + * Update the configuration data with the management port. + * @param configuration + * @param managementPort The string from the command line + */ + private void updateManagementPort(ServerConfiguration configuration, String managementPort) + { + if (managementPort != null) + { + try + { + configuration.setJMXManagementPort(Integer.parseInt(managementPort)); + } + catch (NumberFormatException e) + { + _logger.warn("Invalid management port: " + managementPort + " will use:" + configuration.getJMXManagementPort(), e); + } + } + } + + protected void bind(int port, ServerConfiguration config) throws BindException + { + String bindAddr = commandLine.getOptionValue("b"); + if (bindAddr == null) + { + bindAddr = config.getBind(); + } + + try + { + IoAcceptor acceptor; + + if (ApplicationRegistry.getInstance().getConfiguration().getQpidNIO()) + { + _logger.warn("Using Qpid Multithreaded IO Processing"); + acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(config.getProcessors(), new NewThreadExecutor()); + } + else + { + _logger.warn("Using Mina IO Processing"); + acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(config.getProcessors(), new NewThreadExecutor()); + } + + SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); + SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); + + sc.setReceiveBufferSize(config.getReceiveBufferSize()); + sc.setSendBufferSize(config.getWriteBufferSize()); + sc.setTcpNoDelay(config.getTcpNoDelay()); + + // if we do not use the executor pool threading model we get the default leader follower + // implementation provided by MINA + if (config.getEnableExecutorPool()) + { + sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); + } + + if (!config.getEnableSSL() || !config.getSSLOnly()) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + InetSocketAddress bindAddress; + if (bindAddr.equals("wildcard")) + { + bindAddress = new InetSocketAddress(port); + } + else + { + bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); + } + + bind(acceptor, bindAddress, handler, sconfig); + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); + } + + if (config.getEnableSSL()) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + try + { + + bind(acceptor, new InetSocketAddress(config.getSSLPort()), handler, sconfig); + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid.AMQP listening on SSL port " + config.getSSLPort()); + + } + catch (IOException e) + { + _brokerLogger.error("Unable to listen on SSL port: " + e, e); + } + } + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); + } + catch (Exception e) + { + _logger.error("Unable to bind service to registry: " + e, e); + //fixme this need tidying up + throw new BindException(e.getMessage()); + } + } + + /** + * Ensure that any bound Acceptors are recorded in the registry so they can be closed later. + * + * @param acceptor + * @param bindAddress + * @param handler + * @param sconfig + * + * @throws IOException from the acceptor.bind command + */ + private void bind(IoAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException + { + acceptor.bind(bindAddress, handler, sconfig); + + ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor); + } + + public static void main(String[] args) + { + + new Main(args); + } + + private byte[] parseIP(String address) throws Exception + { + char[] literalBuffer = address.toCharArray(); + int byteCount = 0; + int currByte = 0; + byte[] ip = new byte[IPV4_ADDRESS_LENGTH]; + for (int i = 0; i < literalBuffer.length; i++) + { + char currChar = literalBuffer[i]; + if ((currChar >= '0') && (currChar <= '9')) + { + currByte = (currByte * 10) + (Character.digit(currChar, 10) & 0xFF); + } + + if (currChar == IPV4_LITERAL_SEPARATOR || (i + 1 == literalBuffer.length)) + { + ip[byteCount++] = (byte) currByte; + currByte = 0; + } + } + + if (byteCount != 4) + { + throw new Exception("Invalid IP address: " + address); + } + return ip; + } + + private void configureLogging(File logConfigFile, int logWatchTime) + { + 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 configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception + { + LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); + + try + { + blm.register(); + } + catch (AMQException e) + { + throw new InitException("Unable to initialise the Logging Management MBean: ", e); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java new file mode 100644 index 0000000000..e76f9c3f6c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server; + +import java.io.IOException; + +import javax.management.JMException; + +/** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java new file mode 100644 index 0000000000..3f1947d65a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the + * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. + * + *

      The failed message is associated with this error condition, by taking a reference to it. This enables the + * correct compensating action to be taken against the message, for example, bouncing it back to the sender. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      Associate the failed message with the error condition. {@link AMQMessage} + *
      + */ +public abstract class RequiredDeliveryException extends AMQException +{ + private AMQMessage _amqMessage; + + public RequiredDeliveryException(String message, AMQMessage payload) + { + super(message); + + setMessage(payload); + } + + + public RequiredDeliveryException(String message) + { + super(message); + } + + public void setMessage(final AMQMessage payload) + { + + // Increment the reference as this message is in the routing phase + // and so will have the ref decremented as routing fails. + // we need to keep this message around so we can return it in the + // handler. So increment here. + _amqMessage = payload.takeReference(); + + } + + public AMQMessage getAMQMessage() + { + return _amqMessage; + } + + public AMQConstant getErrorCode() + { + return getReplyCode(); + } + + public abstract AMQConstant getReplyCode(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java new file mode 100644 index 0000000000..db3a05eb52 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -0,0 +1,148 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TxnOp; +import org.apache.qpid.server.queue.QueueEntry; + +/** + * A TxnOp implementation for handling accumulated acks + */ +public class TxAck implements TxnOp +{ + private final UnacknowledgedMessageMap _map; + private final Map _unacked = new HashMap(); + private List _individual; + private long _deliveryTag; + private boolean _multiple; + + public TxAck(UnacknowledgedMessageMap map) + { + _map = map; + } + + public void update(long deliveryTag, boolean multiple) + { + _unacked.clear(); + if (!multiple) + { + if(_individual == null) + { + _individual = new ArrayList(); + } + //have acked a single message that is not part of + //the previously acked region so record + //individually + _individual.add(deliveryTag);//_multiple && !multiple + } + else if (deliveryTag > _deliveryTag) + { + //have simply moved the last acked message on a + //bit + _deliveryTag = deliveryTag; + _multiple = true; + } + } + + public void consolidate() + { + if(_unacked.isEmpty()) + { + //lookup all the unacked messages that have been acked in this transaction + if (_multiple) + { + //get all the unacked messages for the accumulated + //multiple acks + _map.collect(_deliveryTag, true, _unacked); + } + if(_individual != null) + { + //get any unacked messages for individual acks outside the + //range covered by multiple acks + for (long tag : _individual) + { + if(_deliveryTag < tag) + { + _map.collect(tag, false, _unacked); + } + } + } + } + } + + public boolean checkPersistent() throws AMQException + { + consolidate(); + //if any of the messages in unacked are persistent the txn + //buffer must be marked as persistent: + for (QueueEntry msg : _unacked.values()) + { + if (msg.getMessage().isPersistent()) + { + return true; + } + } + return false; + } + + public void prepare(StoreContext storeContext) throws AMQException + { + //make persistent changes, i.e. dequeue and decrementReference + for (QueueEntry msg : _unacked.values()) + { + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(storeContext); + + } + } + + public void undoPrepare() + { + //decrementReference is annoyingly untransactional (due to + //in memory counter) so if we failed in prepare for full + //txn, this op will have to compensate by fixing the count + //in memory (persistent changes will be rolled back by store) + for (QueueEntry msg : _unacked.values()) + { + msg.getMessage().takeReference(); + } + } + + public void commit(StoreContext storeContext) + { + //remove the unacked messages from the channels map + _map.remove(_unacked); + } + + public void rollback(StoreContext storeContext) + { + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java new file mode 100644 index 0000000000..c80a96f967 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -0,0 +1,81 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.Map; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; + +public interface UnacknowledgedMessageMap +{ + public interface Visitor + { + /** + * @param deliveryTag + *@param message the message being iterated over @return true to stop iteration, false to continue + * @throws AMQException + */ + boolean callback(final long deliveryTag, QueueEntry message) throws AMQException; + + void visitComplete(); + } + + void visit(Visitor visitor) throws AMQException; + + void add(long deliveryTag, QueueEntry message); + + void collect(long deliveryTag, boolean multiple, Map msgs); + + boolean contains(long deliveryTag) throws AMQException; + + void remove(Map msgs); + + QueueEntry remove(long deliveryTag); + + public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException; + + Collection cancelAllMessages(); + + void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; + + int size(); + + void clear(); + + QueueEntry get(long deliveryTag); + + /** + * Get the set of delivery tags that are outstanding. + * + * @return a set of delivery tags + */ + Set getDeliveryTags(); + + public long getUnacknowledgeBytes(); +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java new file mode 100644 index 0000000000..c567387662 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -0,0 +1,232 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.server.store.StoreContext; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.txn.TransactionalContext; + +public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap +{ + private final Object _lock = new Object(); + + private long _unackedSize; + + private Map _map; + + private long _lastDeliveryTag; + + private final int _prefetchLimit; + + public UnacknowledgedMessageMapImpl(int prefetchLimit) + { + _prefetchLimit = prefetchLimit; + _map = new LinkedHashMap(prefetchLimit); + } + + public void collect(long deliveryTag, boolean multiple, Map msgs) + { + if (multiple) + { + collect(deliveryTag, msgs); + } + else + { + msgs.put(deliveryTag, get(deliveryTag)); + } + + } + + public boolean contains(long deliveryTag) throws AMQException + { + synchronized (_lock) + { + return _map.containsKey(deliveryTag); + } + } + + public void remove(Map msgs) + { + synchronized (_lock) + { + for (Long deliveryTag : msgs.keySet()) + { + remove(deliveryTag); + } + } + } + + public QueueEntry remove(long deliveryTag) + { + synchronized (_lock) + { + + QueueEntry message = _map.remove(deliveryTag); + if(message != null) + { + _unackedSize -= message.getMessage().getSize(); + + } + + return message; + } + } + + public void visit(Visitor visitor) throws AMQException + { + synchronized (_lock) + { + Set> currentEntries = _map.entrySet(); + for (Map.Entry entry : currentEntries) + { + visitor.callback(entry.getKey().longValue(), entry.getValue()); + } + visitor.visitComplete(); + } + } + + public void add(long deliveryTag, QueueEntry message) + { + synchronized (_lock) + { + _map.put(deliveryTag, message); + _unackedSize += message.getMessage().getSize(); + _lastDeliveryTag = deliveryTag; + } + } + + public Collection cancelAllMessages() + { + synchronized (_lock) + { + Collection currentEntries = _map.values(); + _map = new LinkedHashMap(_prefetchLimit); + _unackedSize = 0l; + 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(); + _unackedSize = 0l; + } + } + + public void drainTo(long deliveryTag, StoreContext storeContext) 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()); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + unacked.getValue().discard(storeContext); + + it.remove(); + + _unackedSize -= unacked.getValue().getMessage().getSize(); + + + if (unacked.getKey() == deliveryTag) + { + break; + } + } + } + } + + public QueueEntry get(long key) + { + synchronized (_lock) + { + return _map.get(key); + } + } + + public Set getDeliveryTags() + { + synchronized (_lock) + { + return _map.keySet(); + } + } + + private void collect(long key, Map msgs) + { + synchronized (_lock) + { + for (Map.Entry entry : _map.entrySet()) + { + msgs.put(entry.getKey(),entry.getValue()); + if (entry.getKey() == key) + { + break; + } + } + } + } + + public long getUnacknowledgeBytes() + { + return _unackedSize; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java new file mode 100644 index 0000000000..c7cf0c0892 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; + + +public class ExchangeConfiguration +{ + + private Configuration _config; + private String _name; + + public ExchangeConfiguration(String exchName, Configuration subset) + { + _name = exchName; + _config = subset; + } + + public String getName() + { + return _name; + } + + public String getType() + { + return _config.getString("type","direct"); + } + + public boolean getDurable() + { + return _config.getBoolean("durable", false); + } + + public boolean getAutoDelete() + { + return _config.getBoolean("autodelete",false); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java new file mode 100644 index 0000000000..74bb7ee969 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -0,0 +1,111 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import java.util.List; + +import org.apache.commons.configuration.Configuration; + +public class QueueConfiguration +{ + + private Configuration _config; + private String _name; + private VirtualHostConfiguration _vHostConfig; + + public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) + { + _vHostConfig = virtualHostConfiguration; + _config = config; + _name = name; + } + + public VirtualHostConfiguration getVirtualHostConfiguration() + { + return _vHostConfig; + } + + public boolean getDurable() + { + return _config.getBoolean("durable" ,false); + } + + public boolean getAutoDelete() + { + return _config.getBoolean("autodelete", false); + } + + public String getOwner() + { + return _config.getString("owner", null); + } + + public boolean getPriority() + { + return _config.getBoolean("priority", false); + } + + public int getPriorities() + { + return _config.getInt("priorities", -1); + } + + public String getExchange() + { + return _config.getString("exchange", null); + } + + public List getRoutingKeys() + { + return _config.getList("routingKey"); + } + + public String getName() + { + return _name; + } + + public int getMaximumMessageAge() + { + return _config.getInt("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); + } + + public long getMaximumQueueDepth() + { + return _config.getLong("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth()); + } + + public long getMaximumMessageSize() + { + return _config.getLong("maximumMessageSize", _vHostConfig.getMaximumMessageSize()); + } + + public long getMaximumMessageCount() + { + return _config.getLong("maximumMessageCount", _vHostConfig.getMaximumMessageCount()); + } + + public long getMinimumAlertRepeatGap() + { + return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java new file mode 100644 index 0000000000..5d080f8df1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; + +public class SecurityConfiguration +{ + + private Configuration _conf; + + public SecurityConfiguration(Configuration configuration) + { + _conf = configuration; + } + + public Configuration getConfiguration() + { + return _conf; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java new file mode 100644 index 0000000000..28a07e7ebf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -0,0 +1,519 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConfigurationFactory; +import org.apache.commons.configuration.SystemConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sun.misc.Signal; +import sun.misc.SignalHandler; + +public class ServerConfiguration implements SignalHandler +{ + + private static Configuration _config; + + private static final int DEFAULT_FRAME_SIZE = 65536; + private static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; + private static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; + private static final int DEFAULT_PORT = 5672; + private static final int DEFAUL_SSL_PORT = 8672; + private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; + private static final int DEFAULT_JMXPORT = 8999; + + private static int _jmxPort = DEFAULT_JMXPORT; + + private Map _virtualHosts = new HashMap(); + private SecurityConfiguration _securityConfiguration = null; + + private File _configFile; + + private Logger _log = LoggerFactory.getLogger(this.getClass()); + + private ConfigurationManagementMBean _mbean; + + + // Map of environment variables to config items + private static final Map envVarMap = new HashMap(); + + { + envVarMap.put("QPID_PORT", "connector.port"); + envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers"); + envVarMap.put("QPID_SSLPORT", "connector.ssl.port"); + envVarMap.put("QPID_NIO", "connector.qpidnio"); + envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool"); + envVarMap.put("QPID_JMXPORT", "management.jmxport"); + envVarMap.put("QPID_FRAMESIZE", "advanced.framesize"); + envVarMap.put("QPID_MSGAUTH", "security.msg-auth"); + envVarMap.put("QPID_AUTOREGISTER", "auto_register"); + envVarMap.put("QPID_MANAGEMENTENABLED", "management.enabled"); + envVarMap.put("QPID_HEARTBEATDELAY", "heartbeat.delay"); + envVarMap.put("QPID_HEARTBEATTIMEOUTFACTOR", "heartbeat.timeoutFactor"); + envVarMap.put("QPID_MAXIMUMMESSAGEAGE", "maximumMessageAge"); + envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount"); + envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth"); + envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize"); + envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap"); + envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer"); + envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer"); + envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay"); + envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator"); + } + + public ServerConfiguration(File configurationURL) throws ConfigurationException + { + this(parseConfig(configurationURL)); + _configFile = configurationURL; + sun.misc.Signal.handle(new sun.misc.Signal("HUP"), this); + } + + public ServerConfiguration(Configuration conf) throws ConfigurationException + { + _config = conf; + + substituteEnvironmentVariables(); + + _jmxPort = _config.getInt("management.jmxport", 8999); + _securityConfiguration = new SecurityConfiguration(conf.subset("security")); + + setupVirtualHosts(conf); + + } + + private void setupVirtualHosts(Configuration conf) throws ConfigurationException + { + List vhosts = conf.getList("virtualhosts"); + Iterator i = vhosts.iterator(); + while (i.hasNext()) + { + Object thing = i.next(); + if (thing instanceof String) + { + XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); + List hosts = vhostConfiguration.getList("virtualhost.name"); + for (int j = 0; j < hosts.size(); j++) + { + String name = (String) hosts.get(j); + // Add the keys of the virtual host to the main config then bail out + + Configuration myConf = vhostConfiguration.subset("virtualhost." + name); + Iterator k = myConf.getKeys(); + while (k.hasNext()) + { + String key = (String) k.next(); + conf.setProperty("virtualhosts.virtualhost."+name+"."+key, myConf.getProperty(key)); + } + VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name)); + _virtualHosts.put(vhostConfig.getName(), vhostConfig); + } + } + } + } + + private void substituteEnvironmentVariables() + { + for (Entry var : envVarMap.entrySet()) + { + String val = System.getenv(var.getKey()); + if (val != null) + { + _config.setProperty(var.getValue(), val); + } + } + } + + private final static Configuration parseConfig(File file) throws ConfigurationException + { + ConfigurationFactory factory = new ConfigurationFactory(); + factory.setConfigurationFileName(file.getAbsolutePath()); + Configuration conf = factory.getConfiguration(); + Iterator keys = conf.getKeys(); + if (!keys.hasNext()) + { + keys = null; + conf = flatConfig(file); + } + return conf; + } + + // 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 final static Configuration flatConfig(File file) throws ConfigurationException + { + // We have to override the interpolate methods so that + // interpolation takes place accross the entirety of the + // composite configuration. Without doing this each + // configuration object only interpolates variables defined + // inside itself. + final MyConfiguration conf = new MyConfiguration(); + conf.addConfiguration(new SystemConfiguration() + { + protected String interpolate(String o) + { + return conf.interpolate(o); + } + }); + conf.addConfiguration(new XMLConfiguration(file) + { + protected String interpolate(String o) + { + return conf.interpolate(o); + } + }); + return conf; + } + + @Override + public void handle(Signal arg0) + { + try + { + reparseConfigFile(); + } + catch (ConfigurationException e) + { + _log.error("Could not reload configuration file", e); + } + } + + public void reparseConfigFile() throws ConfigurationException + { + if (_configFile != null) + { + Configuration newConfig = parseConfig(_configFile); + _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); + ApplicationRegistry.getInstance().getAccessManager().configurePlugins(_securityConfiguration); + + VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); + for (String hostname : _virtualHosts.keySet()) + { + VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); + SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security")); + vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); + } + } + } + + public String getQpidWork() + { + return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); + } + + public void setJMXManagementPort(int mport) + { + _jmxPort = mport; + } + + public int getJMXManagementPort() + { + return _jmxPort; + } + + public boolean getPlatformMbeanserver() + { + return _config.getBoolean("management.platform-mbeanserver", true); + } + + public String[] getVirtualHosts() + { + return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); + } + + public String getPluginDirectory() + { + return _config.getString("plugin-directory"); + } + + public VirtualHostConfiguration getVirtualHostConfig(String name) + { + return _virtualHosts.get(name); + } + + public List getPrincipalDatabaseNames() + { + return _config.getList("security.principal-databases.principal-database.name"); + } + + public List getPrincipalDatabaseClass() + { + return _config.getList("security.principal-databases.principal-database.class"); + } + + public List getPrincipalDatabaseAttributeNames(int index) + { + String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name"; + return _config.getList(name); + } + + public List getPrincipalDatabaseAttributeValues(int index) + { + String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value"; + return _config.getList(name); + } + + public List getManagementPrincipalDBs() + { + return _config.getList("security.jmx.principal-database"); + } + + public List getManagementAccessList() + { + return _config.getList("security.jmx.access"); + } + + public int getFrameSize() + { + return _config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + } + + public boolean getProtectIOEnabled() + { + return _config.getBoolean("broker.connector.protectio.enabled", false); + } + + public int getBufferReadLimit() + { + return _config.getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); + } + + public int getBufferWriteLimit() + { + return _config.getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); + } + + public boolean getSynchedClocks() + { + return _config.getBoolean("advanced.synced-clocks", false); + } + + public boolean getMsgAuth() + { + return _config.getBoolean("security.msg-auth", false); + } + + public String getJMXPrincipalDatabase() + { + return _config.getString("security.jmx.principal-database"); + } + + public String getManagementKeyStorePath() + { + return _config.getString("management.ssl.keyStorePath", null); + } + + public boolean getManagementSSLEnabled() + { + return _config.getBoolean("management.ssl.enabled", true); + } + + public String getManagementKeyStorePassword() + { + return _config.getString("management.ssl.keyStorePassword"); + } + + public SecurityConfiguration getSecurityConfiguration() + { + return _securityConfiguration; + } + + public boolean getQueueAutoRegister() + { + return _config.getBoolean("queue.auto_register", true); + } + + public boolean getManagementEnabled() + { + return _config.getBoolean("management.enabled", true); + } + + public void setManagementEnabled(boolean enabled) + { + _config.setProperty("management.enabled", enabled); + } + + public int getHeartBeatDelay() + { + return _config.getInt("heartbeat.delay", 5); + } + + public double getHeartBeatTimeout() + { + return _config.getDouble("heartbeat.timeoutFactor", 2.0); + } + + public int getDeliveryPoolSize() + { + return _config.getInt("delivery.poolsize", 0); + } + + public long getMaximumMessageAge() + { + return _config.getLong("maximumMessageAge", 0); + } + + public long getMaximumMessageCount() + { + return _config.getLong("maximumMessageCount", 0); + } + + public long getMaximumQueueDepth() + { + return _config.getLong("maximumQueueDepth", 0); + } + + public long getMaximumMessageSize() + { + return _config.getLong("maximumMessageSize", 0); + } + + public long getMinimumAlertRepeatGap() + { + return _config.getLong("minimumAlertRepeatGap", 0); + } + + public int getProcessors() + { + return _config.getInt("connector.processors", 4); + } + + public int getPort() + { + return _config.getInt("connector.port", DEFAULT_PORT); + } + + public String getBind() + { + return _config.getString("connector.bind", "wildcard"); + } + + public int getReceiveBufferSize() + { + return _config.getInt("connector.socketReceiveBuffer", 32767); + } + + public int getWriteBufferSize() + { + return _config.getInt("connector.socketWriteBuffer", 32767); + } + + public boolean getTcpNoDelay() + { + return _config.getBoolean("connector.tcpNoDelay", true); + } + + public boolean getEnableExecutorPool() + { + return _config.getBoolean("advanced.filterchain[@enableExecutorPool]", false); + } + + public boolean getEnablePooledAllocator() + { + return _config.getBoolean("advanced.enablePooledAllocator", false); + } + + public boolean getEnableDirectBuffers() + { + return _config.getBoolean("advanced.enableDirectBuffers", false); + } + + public boolean getEnableSSL() + { + return _config.getBoolean("connector.ssl.enabled", false); + } + + public boolean getSSLOnly() + { + return _config.getBoolean("connector.ssl.sslOnly", true); + } + + public int getSSLPort() + { + return _config.getInt("connector.ssl.port", DEFAUL_SSL_PORT); + } + + public String getKeystorePath() + { + return _config.getString("connector.ssl.keystorePath", "none"); + } + + public String getKeystorePassword() + { + return _config.getString("connector.ssl.keystorePassword", "none"); + } + + public String getCertType() + { + return _config.getString("connector.ssl.certType", "SunX509"); + } + + public boolean getQpidNIO() + { + return _config.getBoolean("connector.qpidnio", false); + } + + public boolean getUseBiasedWrites() + { + return _config.getBoolean("advanced.useWriteBiasedPool", false); + } + + public String getDefaultVirtualHost() + { + return _config.getString("virtualhosts.default"); + } + + public void setHousekeepingExpiredMessageCheckPeriod(long value) + { + _config.setProperty("housekeeping.expiredMessageCheckPeriod", value); + } + + public long getHousekeepingCheckPeriod() + { + return _config.getLong("housekeeping.checkPeriod", + _config.getLong("housekeeping.expiredMessageCheckPeriod", + DEFAULT_HOUSEKEEPING_PERIOD)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java new file mode 100644 index 0000000000..0273a13262 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MemoryMessageStore; + +public class VirtualHostConfiguration +{ + private Configuration _config; + private String _name; + private Map _queues = new HashMap(); + private Map _exchanges = new HashMap(); + + public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException + { + _config = config; + _name = name; + Iterator i = _config.getList("queues.queue.name").iterator(); + + while (i.hasNext()) + { + String queueName = (String) i.next(); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); + mungedConf.addConfiguration(_config.subset("queues")); + _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); + } + + i = _config.getList("exchanges.exchange.name").iterator(); + int count = 0; + while (i.hasNext()) + { + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); + mungedConf.addConfiguration(_config.subset("exchanges")); + String exchName = (String) i.next(); + _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); + } + + } + + public String getName() + { + return _name; + } + + public long getHousekeepingExpiredMessageCheckPeriod() + { + return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod()); + } + + public String getAuthenticationDatabase() + { + return _config.getString("security.authentication.name"); + } + + public List getCustomExchanges() + { + return _config.getList("custom-exchanges.class-name"); + } + + public SecurityConfiguration getSecurityConfiguration() + { + return new SecurityConfiguration(_config.subset("security")); + } + + public Configuration getStoreConfiguration() + { + return _config.subset("store"); + } + + public String getMessageStoreClass() + { + return _config.getString("store.class", MemoryMessageStore.class.getName()); + } + + public List getExchanges() + { + return _config.getList("exchanges.exchange.name"); + } + + public String[] getQueueNames() + { + return _queues.keySet().toArray(new String[_queues.size()]); + } + + public ExchangeConfiguration getExchangeConfiguration(String exchangeName) + { + return _exchanges.get(exchangeName); + } + + public QueueConfiguration getQueueConfiguration(String queueName) + { + // We might be asked for the config for a queue we don't know about, + // such as one that's been dynamically created. Those get the defaults by default. + if (_queues.containsKey(queueName)) + { + return _queues.get(queueName); + } + else + { + return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); + } + } + + public long getMemoryUsageMaximum() + { + return _config.getLong("queues.maximumMemoryUsage", 0); + } + + public long getMemoryUsageMinimum() + { + return _config.getLong("queues.minimumMemoryUsage", 0); + } + + public int getMaximumMessageAge() + { + return _config.getInt("queues.maximumMessageAge", 0); + } + + public Long getMaximumQueueDepth() + { + return _config.getLong("queues.maximumQueueDepth", 0); + } + + public Long getMaximumMessageSize() + { + return _config.getLong("queues.maximumMessageSize", 0); + } + + public Long getMaximumMessageCount() + { + return _config.getLong("queues.maximumMessageCount", 0); + } + + public Long getMinimumAlertRepeatGap() + { + return _config.getLong("queues.minimumAlertRepeatGap", 0); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java new file mode 100644 index 0000000000..8e4bf01c6a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.management; + +import javax.management.MBeanOperationInfo; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.management.MBeanOperation; + +public interface ConfigurationManagement +{ + + String TYPE = "ConfigurationManagement"; + int VERSION = 1; + + /** + * Reload the + * @throws ConfigurationException + */ + @MBeanOperation(name="reloadSecurityConfiguration", + description = "Force a reload of the security configuration sections", + impact = MBeanOperationInfo.ACTION) + void reloadSecurityConfiguration() throws ConfigurationException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java new file mode 100644 index 0000000000..ead6053d70 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.management; + +import javax.management.NotCompliantMBeanException; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement +{ + + public ConfigurationManagementMBean() throws NotCompliantMBeanException + { + super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION); + } + + @Override + public String getObjectInstanceName() + { + return ConfigurationManagement.TYPE; + } + + @Override + public void reloadSecurityConfiguration() throws ConfigurationException + { + ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java new file mode 100644 index 0000000000..d287595e2d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.connection; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.protocol.AMQConstant; + +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.List; + +public class ConnectionRegistry implements IConnectionRegistry +{ + private List _registry = new CopyOnWriteArrayList(); + + private VirtualHost _virtualHost; + + public ConnectionRegistry(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public void initialise() + { + + } + + /** Close all of the currently open connections. */ + public void close() throws AMQException + { + while (!_registry.isEmpty()) + { + AMQProtocolSession connection = _registry.get(0); + + connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", + 0, 0, + connection.getProtocolOutputConverter().getProtocolMajorVersion(), + connection.getProtocolOutputConverter().getProtocolMinorVersion(), + (Throwable) null), true); + } + } + + public void registerConnection(AMQProtocolSession connnection) + { + _registry.add(connnection); + } + + public void deregisterConnection(AMQProtocolSession connnection) + { + _registry.remove(connnection); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java new file mode 100644 index 0000000000..d64fde1c20 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.connection; + +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +public interface IConnectionRegistry +{ + + public void initialise(); + + public void close() throws AMQException; + + public void registerConnection(AMQProtocolSession connnection); + + public void deregisterConnection(AMQProtocolSession connnection); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java new file mode 100644 index 0000000000..30af09ce4b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -0,0 +1,211 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.ArrayType; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public abstract class AbstractExchange implements Exchange, Managable +{ + private AMQShortString _name; + + + + protected boolean _durable; + protected String _exchangeType; + protected int _ticket; + + private VirtualHost _virtualHost; + + 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 + { + // open mbean data types for representing exchange bindings + protected String[] _bindingItemNames; + protected String[] _bindingItemIndexNames; + protected OpenType[] _bindingItemTypes; + protected CompositeType _bindingDataType; + protected TabularType _bindinglistDataType; + protected TabularDataSupport _bindingList; + + public ExchangeMBean() throws NotCompliantMBeanException + { + super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); + } + + protected void init() throws OpenDataException + { + _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[2]; + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + + public ManagedObject getParentObject() + { + return _virtualHost.getManagedObject(); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public String getExchangeType() + { + return _exchangeType; + } + + public Integer getTicketNo() + { + return _ticket; + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + // Added exchangetype in the object name lets maangement apps to do any customization required + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + _exchangeType; + return new ObjectName(objNameString); + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + } // End of MBean class + + public AMQShortString 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(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + { + _virtualHost = host; + _name = name; + _durable = durable; + _autoDelete = autoDelete; + _ticket = ticket; + _exchangeMbean = createMBean(); + _exchangeMbean.register(); + } + + 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().getSimpleName() + "[" + getName() +"]"; + } + + public ManagedObject getManagedObject() + { + return _exchangeMbean; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public QueueRegistry getQueueRegistry() + { + return getVirtualHost().getQueueRegistry(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java new file mode 100644 index 0000000000..c04b6c559c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -0,0 +1,114 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class DefaultExchangeFactory implements ExchangeFactory +{ + private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); + + private Map> _exchangeClassMap = new HashMap>(); + private final VirtualHost _host; + + public DefaultExchangeFactory(VirtualHost host) + { + _host = host; + registerExchangeType(DirectExchange.TYPE); + registerExchangeType(TopicExchange.TYPE); + registerExchangeType(HeadersExchange.TYPE); + registerExchangeType(FanoutExchange.TYPE); + } + + public void registerExchangeType(ExchangeType type) + { + _exchangeClassMap.put(type.getName(), type); + } + + public Collection> getRegisteredTypes() + { + return _exchangeClassMap.values(); + } + + public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException + { + ExchangeType exchType = _exchangeClassMap.get(type); + if (exchType == null) + { + + throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); + } + Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); + return e; + } + + @Override + public void initialise(VirtualHostConfiguration hostConfig) + { + + if (hostConfig == null) + { + return; + } + + for(Object className : hostConfig.getCustomExchanges()) + { + try + { + ExchangeType exchangeType = ApplicationRegistry.getInstance().getPluginManager().getExchanges().get(String.valueOf(className)); + if (exchangeType == null) + { + _logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\""); + return; + } + Class exchangeTypeClass = exchangeType.getClass(); + ExchangeType type = exchangeTypeClass.newInstance(); + registerExchangeType(type); + } + catch (ClassCastException classCastEx) + { + _logger.error("No custom exchange class: \""+String.valueOf(className)+"\" cannot be registered as it does not extend class \""+ExchangeType.class+"\""); + } + catch (IllegalAccessException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } + catch (InstantiationException e) + { + _logger.error("Cannot create custom exchange class: \""+String.valueOf(className)+"\"",e); + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java new file mode 100644 index 0000000000..0ab8208d88 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.protocol.ExchangeInitialiser; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; +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(); + + private Exchange _defaultExchange; + private VirtualHost _host; + + public DefaultExchangeRegistry(VirtualHost host) + { + //create 'standard' exchanges: + _host = host; + + } + + public void initialise() throws AMQException + { + new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); + } + + public MessageStore getMessageStore() + { + return _host.getMessageStore(); + } + + public void registerExchange(Exchange exchange) throws AMQException + { + _exchangeMap.put(exchange.getName(), exchange); + if (exchange.isDurable()) + { + getMessageStore().createExchange(exchange); + } + } + + public void setDefaultExchange(Exchange exchange) + { + _defaultExchange = exchange; + } + + public Exchange getDefaultExchange() + { + return _defaultExchange; + } + + public Collection getExchangeNames() + { + return _exchangeMap.keySet(); + } + + public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException + { + // TODO: check inUse argument + Exchange e = _exchangeMap.remove(name); + if (e != null) + { + if (e.isDurable()) + { + getMessageStore().removeExchange(e); + } + e.close(); + } + else + { + throw new AMQException("Unknown exchange " + name); + } + } + + public Exchange getExchange(AMQShortString name) + { + if ((name == null) || name.length() == 0) + { + return getDefaultExchange(); + } + else + { + 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(IncomingMessage payload) throws AMQException + { + final AMQShortString exchange = payload.getExchange(); + final Exchange exch = getExchange(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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java new file mode 100644 index 0000000000..e9af92bad8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -0,0 +1,251 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class DirectExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(DirectExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final Index _index = new Index(); + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return DirectExchange.class; + } + + public DirectExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + DirectExchange exch = new DirectExchange(); + exch.initialise(host,name,durable,ticket,autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.DIRECT_EXCHANGE_NAME; + } + }; + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Direct Exchange") + private final class DirectExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DirectExchangeMBean() throws JMException + { + super(); + _exchangeType = "direct"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + Map> bindings = _index.getBindingsMap(); + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (Map.Entry> entry : bindings.entrySet()) + { + AMQShortString key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = entry.getValue(); + for (AMQQueue q : queues) + { + queueList.add(q.getName().toString()); + } + + Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(DirectExchange.this, new AMQShortString(binding), null); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + }// End of MBean class + + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DirectExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public AMQShortString getType() + { + return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + if (!_index.add(routingKey, queue)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey); + } + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this); + } + } + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + + if (!_index.remove(routingKey, queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that _routing key"); + } + } + + public void route(IncomingMessage payload) throws AMQException + { + + final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); + + final ArrayList queues = (routingKey == null) ? null : _index.get(routingKey); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + queues); + } + + payload.enqueue(queues); + + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey,queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + final List queues = _index.get(routingKey); + return queues != null && queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + final List queues = _index.get(routingKey); + return queues != null && !queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + Map> bindings = _index.getBindingsMap(); + for (List queues : bindings.values()) + { + if (queues.contains(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() + { + return !_index.getBindingsMap().isEmpty(); + } + + public Map> getBindings() + { + return _index.getBindingsMap(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java new file mode 100644 index 0000000000..06209c5458 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; + +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.List; +import java.util.Map; + +public interface Exchange +{ + AMQShortString getName(); + + AMQShortString getType(); + + void initialise(VirtualHost host, AMQShortString 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(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void route(IncomingMessage message) throws AMQException; + + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key and arguments + * @param routingKey + * @param arguments + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue); + + /** + * Determines whether a message would be isBound to a particular queue using a specific routing key + * @param routingKey + * @param queue + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey, AMQQueue queue); + + /** + * Determines whether a message is routing to any queue using a specific _routing key + * @param routingKey + * @return + * @throws AMQException + */ + boolean isBound(AMQShortString routingKey); + + boolean isBound(AMQQueue queue); + + /** + * Returns true if this exchange has at least one binding associated with it. + * @return + * @throws AMQException + */ + boolean hasBindings(); + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java new file mode 100644 index 0000000000..2f76d41228 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.Collection; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; + + +public interface ExchangeFactory +{ + Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException; + + void initialise(VirtualHostConfiguration hostConfig); + + Collection> getRegisteredTypes(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java new file mode 100644 index 0000000000..c77f114428 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; + +/** + * ExchangeInUseRegistry indicates that an exchange cannot be unregistered because it is currently being used. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to unregister exchange that is in use. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo This exception is not used. However, it is part of the ExchangeRegistry interface, and looks like code is + * going to need to be added to throw/deal with this. Alternatively ExchangeResitries may be able to handle the + * issue internally. + */ +public class ExchangeInUseException extends AMQException +{ + public ExchangeInUseException(String exchangeName) + { + super("Exchange " + exchangeName + " is currently in use"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java new file mode 100644 index 0000000000..fe3b19e74e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; + +import java.util.Collection; + + +public interface ExchangeRegistry extends MessageRouter +{ + void registerExchange(Exchange exchange) throws AMQException; + + /** + * 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(AMQShortString name, boolean inUse) throws ExchangeInUseException, AMQException; + + Exchange getExchange(AMQShortString name); + + void setDefaultExchange(Exchange exchange); + + Exchange getDefaultExchange(); + + Collection getExchangeNames(); + + void initialise() throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java new file mode 100644 index 0000000000..0b55caa2f1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeType.java @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; + + +public interface ExchangeType +{ + public AMQShortString getName(); + public Class getExchangeClass(); + public T newInstance(VirtualHost host, AMQShortString name, + boolean durable, int ticket, boolean autoDelete) throws AMQException; + public AMQShortString getDefaultExchangeName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java new file mode 100644 index 0000000000..e9fd4d548b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -0,0 +1,224 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class FanoutExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Fanout Exchange") + private final class FanoutExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") + public FanoutExchangeMBean() throws JMException + { + super(); + _exchangeType = "fanout"; + init(); + } + + public TabularData bindings() throws OpenDataException + { + + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (AMQQueue queue : _queues) + { + String queueName = queue.getName().toString(); + + Object[] bindingItemValues = {queueName, new String[]{queueName}}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(FanoutExchange.this, new AMQShortString(binding), null); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new FanoutExchange.FanoutExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the direct exchange mbean", ex); + throw new AMQException("Exception occured in creating the direct exchange mbean", ex); + } + } + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return FanoutExchange.class; + } + + public FanoutExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + FanoutExchange exch = new FanoutExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.FANOUT_EXCHANGE_NAME; + } + }; + + public Map> getBindings() + { + return null; + } + + public AMQShortString getType() + { + return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (_queues.contains(queue)) + { + _logger.debug("Queue " + queue + " is already registered"); + } + else + { + _queues.add(queue); + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); + } + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + + if (!_queues.remove(queue)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); + } + } + + public void route(IncomingMessage payload) throws AMQException + { + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + _queues); + } + + payload.enqueue(new ArrayList(_queues)); + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return _queues.contains(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + + return (_queues != null) && !_queues.isEmpty(); + } + + public boolean isBound(AMQQueue queue) + { + + return _queues.contains(queue); + } + + public boolean hasBindings() + { + return !_queues.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java new file mode 100644 index 0000000000..2b7df4361a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -0,0 +1,219 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.FieldTable; + +/** + * Defines binding and matching based on a set of headers. + */ +class HeadersBinding +{ + private static final Logger _logger = Logger.getLogger(HeadersBinding.class); + + private final FieldTable _mappings; + private final Set required = new HashSet(); + private final Map matches = new HashMap(); + private boolean matchAny; + + private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor + { + private Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor + { + Boolean _result = Boolean.FALSE; + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if(required.contains(propertyName)) + { + _result = Boolean.TRUE; + return false; + } + return true; + } + + public Object getResult() + { + return _result; + } + } + + + + /** + * 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(FieldTable mappings) + { + _mappings = mappings; + initMappings(); + } + + private void initMappings() + { + + _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + if (isSpecial(propertyName)) + { + processSpecial(propertyName, value.getValue()); + } + else if (value.getValue() == null || value.getValue().equals("")) + { + required.add(propertyName); + } + else + { + matches.put(propertyName,value.getValue()); + } + + return true; + } + + public Object getResult() + { + return null; + } + }); + } + + protected FieldTable 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(FieldTable headers) + { + if(headers == null) + { + return required.isEmpty() && matches.isEmpty(); + } + else + { + return matchAny ? or(headers) : and(headers); + } + } + + private boolean and(FieldTable headers) + { + if(headers.keys().containsAll(required)) + { + for(Map.Entry e : matches.entrySet()) + { + if(!e.getValue().equals(headers.getObject(e.getKey()))) + { + return false; + } + } + return true; + } + else + { + return false; + } + } + + + private boolean or(final FieldTable headers) + { + if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) + { + return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) + || (required.isEmpty() && matches.isEmpty()); + } + else + { + return true; + } + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java new file mode 100644 index 0000000000..1ee1f35de6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -0,0 +1,350 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * An exchange that binds queues based on a set of required headers and header values + * and routes messages to these queues by matching the headers of the message against + * those with which the queues were bound. + *

      + *

      + * The Headers Exchange
      + *
      + *  Routes messages according to the value/presence of fields in the message header table.
      + *  (Basic and JMS content has a content header field called "headers" that is a table of
      + *   message header fields).
      + *
      + *  class = "headers"
      + *  routing key is not used
      + *
      + *  Has the following binding arguments:
      + *
      + *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
      + *  other fields prefixed with "X-" are ignored (and generate a console warning message).
      + *  a field with no value or empty value indicates a match on presence only.
      + *  a field with a value indicates match on field presence and specific value.
      + *
      + *  Standard instances:
      + *
      + *  amq.match - pub/sub on field content/value
      + *  
      + */ +public class HeadersExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(HeadersExchange.class); + + + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return HeadersExchange.class; + } + + public HeadersExchange newInstance(VirtualHost host, AMQShortString name, boolean durable, int ticket, + boolean autoDelete) throws AMQException + { + HeadersExchange exch = new HeadersExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + + return ExchangeDefaults.HEADERS_EXCHANGE_NAME; + } + }; + + + 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 + { + @MBeanConstructor("Creates an MBean for AMQ Headers exchange") + public HeadersExchangeMBean() throws JMException + { + super(); + _exchangeType = "headers"; + init(); + } + + /** + * initialises the OpenType objects. + */ + protected void init() throws OpenDataException + { + _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; + _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; + + _bindingItemTypes = new OpenType[3]; + _bindingItemTypes[0] = SimpleType.INTEGER; + _bindingItemTypes[1] = SimpleType.STRING; + _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", + _bindingItemNames, _bindingItemNames, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + _bindingDataType, _bindingItemIndexNames); + } + + public TabularData bindings() throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + int count = 1; + for (Iterator itr = _bindings.iterator(); itr.hasNext();) + { + Registration registration = itr.next(); + String queueName = registration.queue.getName().toString(); + + HeadersBinding headers = registration.binding; + FieldTable headerMappings = headers.getMappings(); + final List mappingList = new ArrayList(); + + headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + mappingList.add(propertyName + "=" + value.getValue()); + return true; + } + + public Object getResult() + { + return mappingList; + } + }); + + + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + /** + * Creates bindings. Binding pattern is as follows- + * =,=,... + * @param queueName + * @param binding + * @throws javax.management.JMException + */ + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + String[] bindings = binding.split(","); + FieldTable bindingMap = new FieldTable(); + for (int i = 0; i < bindings.length; i++) + { + String[] keyAndValue = bindings[i].split("="); + if (keyAndValue == null || keyAndValue.length < 2) + { + throw new JMException("Format for headers binding should be \"=,=\" "); + } + bindingMap.setString(keyAndValue[0], keyAndValue[1]); + } + + _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); + } + + } // End of MBean class + + public AMQShortString getType() + { + return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + } + + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); + _bindings.add(new Registration(new HeadersBinding(args), queue)); + } + + public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); + if(!_bindings.remove(new Registration(new HeadersBinding(args), queue))) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + + " with headers args " + args); + } + } + + public void route(IncomingMessage payload) throws AMQException + { + FieldTable headers = getHeaders(payload.getContentHeaderBody()); + if (_logger.isDebugEnabled()) + { + _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); + } + boolean routed = false; + ArrayList queues = new ArrayList(); + 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()); + } + queues.add(e.queue); + + routed = true; + } + } + payload.enqueue(queues); + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + //fixme isBound here should take the arguements in to consideration. + return isBound(routingKey, queue); + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return isBound(queue); + } + + public boolean isBound(AMQShortString routingKey) + { + return hasBindings(); + } + + public boolean isBound(AMQQueue queue) + { + for (Registration r : _bindings) + { + if (r.queue.equals(queue)) + { + return true; + } + } + return false; + } + + public boolean hasBindings() + { + return !_bindings.isEmpty(); + } + + protected FieldTable 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 (JMException ex) + { + _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); + throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); + } + } + + public Map> getBindings() + { + return null; + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java new file mode 100644 index 0000000000..ec83161029 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -0,0 +1,99 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * An index of queues against routing key. Allows multiple queues to be stored + * against the same key. Used in the DirectExchange. + */ +class Index +{ + private ConcurrentMap> _index + = new ConcurrentHashMap>(); + + synchronized boolean add(AMQShortString key, AMQQueue queue) + { + ArrayList queues = _index.get(key); + if(queues == null) + { + queues = new ArrayList(); + } + else + { + queues = new ArrayList(queues); + } + //next call is atomic, so there is no race to create the list + _index.put(key, queues); + + if(queues.contains(queue)) + { + return false; + } + else + { + return queues.add(queue); + } + } + + synchronized boolean remove(AMQShortString key, AMQQueue queue) + { + ArrayList queues = _index.get(key); + if (queues != null) + { + queues = new ArrayList(queues); + boolean removed = queues.remove(queue); + if(removed) + { + if (queues.size() == 0) + { + _index.remove(key); + } + else + { + _index.put(key, queues); + } + } + return removed; + } + return false; + } + + ArrayList get(AMQShortString key) + { + return _index.get(key); + } + + Map> getBindingsMap() + { + return new HashMap>(_index); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java new file mode 100644 index 0000000000..317ff385ab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -0,0 +1,99 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.queue.ManagedQueue; + +/** + * The management interface exposed to allow management of an Exchange. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedExchange +{ + static final String TYPE = "Exchange"; + static final int VERSION = 1; + + /** + * Returns the name of the managed exchange. + * @return the name of the exchange. + * @throws IOException + */ + @MBeanAttribute(name="Name", description=TYPE + " Name") + String getName() throws IOException; + + @MBeanAttribute(name="ExchangeType", description="Exchange Type") + String getExchangeType() throws IOException; + + @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") + Integer getTicketNo() throws IOException; + + /** + * Tells if the exchange is durable or not. + * @return true if the exchange is durable. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description="true if Exchange is durable") + boolean isDurable() throws IOException; + + /** + * Tells if the exchange is set for autodelete or not. + * @return true if the exchange is set as autodelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") + boolean isAutoDelete() throws IOException; + + // Operations + + /** + * Returns all the bindings this exchange has with the queues. + * @return the bindings with the exchange. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") + TabularData bindings() throws IOException, JMException; + + /** + * Creates new binding with the given queue and binding. + * @param queueName + * @param binding + * @throws JMException + */ + @MBeanOperation(name="createNewBinding", + description="create a new binding with this exchange", + impact= MBeanOperationInfo.ACTION) + void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, + @MBeanOperationParameter(name="Binding", description="New binding")String binding) + throws JMException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java new file mode 100644 index 0000000000..db9beb6da7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; + +/** + * 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(IncomingMessage message) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java new file mode 100644 index 0000000000..d18ad7ab14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.IncomingMessage; + +/** + * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message + * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report + * this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      + */ +public class NoRouteException extends RequiredDeliveryException +{ + public NoRouteException(String msg, AMQMessage amqMessage) + { + super(msg, amqMessage); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.NO_ROUTE; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java new file mode 100644 index 0000000000..bc303a219d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -0,0 +1,670 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.common.AMQPFilterTypes; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQShortStringTokenizer; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.topic.TopicParser; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; +import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.filter.JMSSelectorFilter; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.lang.ref.WeakReference; + +public class TopicExchange extends AbstractExchange +{ + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public Class getExchangeClass() + { + return TopicExchange.class; + } + + public TopicExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + TopicExchange exch = new TopicExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return ExchangeDefaults.TOPIC_EXCHANGE_NAME; + } + }; + + + private static final Logger _logger = Logger.getLogger(TopicExchange.class); + +/* + private final ConcurrentHashMap> _bindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _simpleBindingKey2queues = + new ConcurrentHashMap>(); + private final ConcurrentHashMap> _wildCardBindingKey2queues = + new ConcurrentHashMap>(); +*/ + // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); + private static final byte TOPIC_SEPARATOR = (byte)'.'; + private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); + private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); + private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); + + private static final byte HASH_BYTE = (byte)'#'; + private static final byte STAR_BYTE = (byte)'*'; + + private final TopicParser _parser = new TopicParser(); + + private final Map _topicExchangeResults = + new ConcurrentHashMap(); + + private final Map _bindings = new HashMap(); + + private final Map>> _selectorCache = new WeakHashMap>>(); + + public static class Binding + { + private final AMQShortString _bindingKey; + private final AMQQueue _queue; + private final FieldTable _args; + + public Binding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) + { + _bindingKey = bindingKey; + _queue = queue; + _args = args; + } + + public AMQShortString getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public int hashCode() + { + return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); + } + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(o instanceof Binding) + { + Binding other = (Binding) o; + return (_queue == other._queue) + && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); + } + return false; + } + } + + + + private final class TopicExchangeResult implements TopicMatcherResult + { + private final Map _unfilteredQueues = new ConcurrentHashMap(); + private final ConcurrentHashMap,Integer>> _filteredQueues = new ConcurrentHashMap, Integer>>(); + + public void addUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == null) + { + _unfilteredQueues.put(queue, 1); + } + else + { + _unfilteredQueues.put(queue, instances + 1); + } + } + + public void removeUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == 1) + { + _unfilteredQueues.remove(queue); + } + else + { + _unfilteredQueues.put(queue,instances - 1); + } + + } + + + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map,Integer> filters = _filteredQueues.get(queue); + if(filters == null) + { + filters = new ConcurrentHashMap,Integer>(); + _filteredQueues.put(queue, filters); + } + Integer instances = filters.get(filter); + if(instances == null) + { + filters.put(filter,1); + } + else + { + filters.put(filter, instances + 1); + } + + } + + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map,Integer> filters = _filteredQueues.get(queue); + if(filters != null) + { + Integer instances = filters.get(filter); + if(instances != null) + { + if(instances == 1) + { + filters.remove(filter); + if(filters.isEmpty()) + { + _filteredQueues.remove(queue); + } + } + else + { + filters.put(filter, instances - 1); + } + } + + } + + } + + public void replaceQueueFilter(AMQQueue queue, + MessageFilter oldFilter, + MessageFilter newFilter) + { + Map,Integer> filters = _filteredQueues.get(queue); + Map,Integer> newFilters = new ConcurrentHashMap,Integer>(filters); + Integer oldFilterInstances = filters.get(oldFilter); + if(oldFilterInstances == 1) + { + newFilters.remove(oldFilter); + } + else + { + newFilters.put(oldFilter, oldFilterInstances-1); + } + Integer newFilterInstances = filters.get(newFilter); + if(newFilterInstances == null) + { + newFilters.put(newFilter, 1); + } + else + { + newFilters.put(newFilter, newFilterInstances+1); + } + _filteredQueues.put(queue,newFilters); + } + + public Collection processMessage(IncomingMessage msg, Collection queues) + { + if(queues == null) + { + if(_filteredQueues.isEmpty()) + { + return new ArrayList(_unfilteredQueues.keySet()); + } + else + { + queues = new HashSet(); + } + } + else if(!(queues instanceof Set)) + { + queues = new HashSet(queues); + } + + queues.addAll(_unfilteredQueues.keySet()); + if(!_filteredQueues.isEmpty()) + { + for(Map.Entry, Integer>> entry : _filteredQueues.entrySet()) + { + if(!queues.contains(entry.getKey())) + { + for(MessageFilter filter : entry.getValue().keySet()) + { + if(filter.matches(msg)) + { + queues.add(entry.getKey()); + } + } + } + } + } + return queues; + } + + } + + + /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ + @MBeanDescription("Management Bean for Topic Exchange") + private final class TopicExchangeMBean extends ExchangeMBean + { + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public TopicExchangeMBean() throws JMException + { + super(); + _exchangeType = "topic"; + init(); + } + + /** returns exchange bindings in tabular form */ + public TabularData bindings() throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + Map> bindingData = new HashMap>(); + for (Binding binding : _bindings.keySet()) + { + String key = binding.getBindingKey().toString(); + List queueNames = bindingData.get(key); + if(queueNames == null) + { + queueNames = new ArrayList(); + bindingData.put(key, queueNames); + } + queueNames.add(binding.getQueue().getName().toString()); + + } + for(Map.Entry> entry : bindingData.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; + CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + _bindingList.put(bindingCompositeData); + } + + return _bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + queue.bind(TopicExchange.this, new AMQShortString(binding), null); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + public AMQShortString getType() + { + return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; + } + + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); + + + AMQShortString routingKey; + + if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) + { + routingKey = normalize(rKey); + } + else + { + routingKey = rKey; + } + + Binding binding = new Binding(rKey, queue, args); + + if(_bindings.containsKey(binding)) + { + FieldTable oldArgs = _bindings.get(binding); + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + + if(argumentsContainSelector(args)) + { + if(argumentsContainSelector(oldArgs)) + { + result.replaceQueueFilter(queue,createSelectorFilter(oldArgs), createSelectorFilter(args)); + } + else + { + result.addFilteredQueue(queue,createSelectorFilter(args)); + result.removeUnfilteredQueue(queue); + } + } + else + { + if(argumentsContainSelector(oldArgs)) + { + result.addUnfilteredQueue(queue); + result.removeFilteredQueue(queue, createSelectorFilter(oldArgs)); + } + else + { + // TODO - fix control flow + return; + } + } + + } + else + { + + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + if(result == null) + { + result = new TopicExchangeResult(); + if(argumentsContainSelector(args)) + { + result.addFilteredQueue(queue, createSelectorFilter(args)); + } + else + { + result.addUnfilteredQueue(queue); + } + _parser.addBinding(routingKey, result); + _topicExchangeResults.put(routingKey,result); + } + else + { + if(argumentsContainSelector(args)) + { + result.addFilteredQueue(queue, createSelectorFilter(args)); + } + else + { + result.addUnfilteredQueue(queue); + } + } + _bindings.put(binding, args); + } + + + } + + private JMSSelectorFilter createSelectorFilter(final FieldTable args) + throws AMQException + { + + final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); + WeakReference> selectorRef = _selectorCache.get(selectorString); + JMSSelectorFilter selector = null; + + if(selectorRef == null || (selector = selectorRef.get())==null) + { + selector = new JMSSelectorFilter(selectorString); + _selectorCache.put(selectorString, new WeakReference>(selector)); + } + return selector; + } + + private static boolean argumentsContainSelector(final FieldTable args) + { + return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0; + } + + private AMQShortString normalize(AMQShortString routingKey) + { + if(routingKey == null) + { + routingKey = AMQShortString.EMPTY_STRING; + } + + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + List subscriptionList = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + subscriptionList.add(routingTokens.nextToken()); + } + + int size = subscriptionList.size(); + + for (int index = 0; index < size; index++) + { + // if there are more levels + if ((index + 1) < size) + { + if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) + { + if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) + { + // we don't need #.# delete this one + subscriptionList.remove(index); + size--; + // redo this normalisation + index--; + } + + if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + subscriptionList.add(index + 1, subscriptionList.remove(index)); + } + } + } // if we have more levels + } + + + + AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); + + return normalizedString; + } + + public void route(IncomingMessage payload) throws AMQException + { + + final AMQShortString routingKey = payload.getRoutingKey(); + + // The copy here is unfortunate, but not too bad relevant to the amount of + // things created and copied in getMatchedQueues + ArrayList queues = new ArrayList(); + queues.addAll(getMatchedQueues(payload, routingKey)); + + if(queues == null || queues.isEmpty()) + { + _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); + } + + payload.enqueue(queues); + + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + Binding binding = new Binding(routingKey, queue, arguments); + if (arguments == null) + { + return _bindings.containsKey(binding); + } + else + { + FieldTable o = _bindings.get(binding); + if (o != null) + { + return o.equals(arguments); + } + else + { + return false; + } + + } + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return isBound(routingKey, null, queue); + } + + public boolean isBound(AMQShortString routingKey) + { + for(Binding b : _bindings.keySet()) + { + if(b.getBindingKey().equals(routingKey)) + { + return true; + } + } + + return false; + } + + public boolean isBound(AMQQueue queue) + { + for(Binding b : _bindings.keySet()) + { + if(b.getQueue().equals(queue)) + { + return true; + } + } + + return false; + } + + public boolean hasBindings() + { + return !_bindings.isEmpty(); + } + + public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert rKey != null; + + Binding binding = new Binding(rKey, queue, args); + + + if (!_bindings.containsKey(binding)) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName() + + " with routing key " + rKey + "."); + } + + FieldTable bindingArgs = _bindings.remove(binding); + AMQShortString bindingKey = normalize(rKey); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + if(argumentsContainSelector(bindingArgs)) + { + result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs)); + } + else + { + result.removeUnfilteredQueue(queue); + } + + } + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new TopicExchangeMBean(); + } + catch (JMException ex) + { + _logger.error("Exception occured in creating the topic exchenge mbean", ex); + throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); + } + } + + private Collection getMatchedQueues(IncomingMessage message, AMQShortString routingKey) + { + + Collection results = _parser.parse(routingKey); + if(results.isEmpty()) + { + return Collections.EMPTY_SET; + } + else + { + Collection queues = results.size() == 1 ? null : new HashSet(); + for(TopicMatcherResult result : results) + { + + queues = ((TopicExchangeResult)result).processMessage(message, queues); + } + return queues; + } + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java new file mode 100644 index 0000000000..8fdb91cbef --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java @@ -0,0 +1,40 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQShortString; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderKey +{ + public static final HeaderKey UNKNOWN = new HeaderKey(new AMQShortString("<< UNKNOWN >>")); + private AMQShortString _key; + + public HeaderKey(final AMQShortString key) + { + _key = key; + } + + public String toString() + { + return _key.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java new file mode 100644 index 0000000000..7be99a88c9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java @@ -0,0 +1,50 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.Map; +import java.util.HashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderKeyDictionary +{ + + private final Map _dictionary = new HashMap(); + + + public HeaderKey get(final AMQShortString key) + { + HeaderKey headerKey = _dictionary.get(key); + return headerKey == null ? HeaderKey.UNKNOWN : headerKey; + } + + public HeaderKey getOrCreate(final AMQShortString key) + { + HeaderKey headerKey = _dictionary.get(key); + if(headerKey == null) + { + headerKey = new HeaderKey(key); + _dictionary.put(key, headerKey); + } + return headerKey; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java new file mode 100644 index 0000000000..518064bb29 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java @@ -0,0 +1,25 @@ +package org.apache.qpid.server.exchange.headers; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeaderMatcherResult +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java new file mode 100644 index 0000000000..9da93d483a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java @@ -0,0 +1,339 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.topic.TopicMatcherDFAState; +import org.apache.qpid.server.exchange.topic.TopicWord; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; + +import java.util.*; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeadersMatcherDFAState +{ + + + private final Collection _results; + private final Map> _nextStateMap; + private final HeaderKeyDictionary _dictionary; + + public HeadersMatcherDFAState(Map> nextStateMap, + Collection results, + HeaderKeyDictionary dictionary) + { + _nextStateMap = nextStateMap; + _results = results; + _dictionary = dictionary; + } + + + public Collection match(final FieldTable table) + { + return match(table.iterator()); + } + + + + public Collection match(Iterator> fieldTableIterator) + { + + if(_nextStateMap.isEmpty()) + { + return _results; + } + + while(fieldTableIterator.hasNext()) + { + + Map.Entry fieldTableEntry = fieldTableIterator.next(); + HeaderKey key = _dictionary.get(fieldTableEntry.getKey()); + if(key != HeaderKey.UNKNOWN) + { + Map valueToStateMap = _nextStateMap.get(key); + + if(valueToStateMap != null) + { + HeadersMatcherDFAState nextState = valueToStateMap.get(fieldTableEntry.getValue()); + + if(nextState == null) + { + nextState = valueToStateMap.get(null); + } + if(nextState != null && nextState != this) + { + return nextState.match(fieldTableIterator); + } + } + + } + } + + return _results; + + } + + + HeadersMatcherDFAState mergeStateMachines(HeadersMatcherDFAState otherStateMachine) + { + + assert(otherStateMachine._dictionary == _dictionary); + + Map, HeadersMatcherDFAState> newStateMap= new HashMap, HeadersMatcherDFAState>(); + + Collection results; + + if(_results.isEmpty()) + { + results = otherStateMachine._results; + } + else if(otherStateMachine._results.isEmpty()) + { + results = _results; + } + else + { + results = new HashSet(_results); + results.addAll(otherStateMachine._results); + } + + + final Map> newNextStateMap = new HashMap>(); + + HeadersMatcherDFAState newState = new HeadersMatcherDFAState(newNextStateMap, results, _dictionary); + + + Set oldStates = new HashSet(); + oldStates.add(this); + oldStates.add(otherStateMachine); + + newStateMap.put(oldStates, newState); + + mergeStateMachines(oldStates, newNextStateMap, newStateMap); + + return newState; + + + } + + private void mergeStateMachines(final Set oldStates, + final Map> newNextStateMap, + final Map, HeadersMatcherDFAState> newStateMap) + { + Map>> nfaMap = new HashMap>>(); + + Set distinctKeys = new HashSet(); + + for(HeadersMatcherDFAState state : oldStates) + { + Map> map = state._nextStateMap; + + for(Map.Entry> entry : map.entrySet()) + { + Map> valueToStatesMap = nfaMap.get(entry.getKey()); + + if(valueToStatesMap == null) + { + valueToStatesMap = new HashMap>(); + nfaMap.put(entry.getKey(), valueToStatesMap); + } + + for(Map.Entry valueToStateEntry : entry.getValue().entrySet()) + { + Set states = valueToStatesMap.get(valueToStateEntry.getKey()); + if(states == null) + { + states = new HashSet(); + valueToStatesMap.put(valueToStateEntry.getKey(),states); + } + states.add(valueToStateEntry.getValue()); + } + + distinctKeys.add(entry.getKey()); + } + } + + Map> anyValueStates = new HashMap>(); + + for(HeaderKey distinctKey : distinctKeys) + { + Map> valueToStateMap = nfaMap.get(distinctKey); + if(valueToStateMap != null) + { + Set statesForKeyDefault = valueToStateMap.get(null); + if(statesForKeyDefault != null) + { + anyValueStates.put(distinctKey, statesForKeyDefault); + } + } + } + + // add the defaults for "null" to all other specified values of a given header key + + for( Map.Entry>> entry : nfaMap.entrySet()) + { + Map> valueToStatesMap = entry.getValue(); + for(Map.Entry> valueToStates : valueToStatesMap.entrySet()) + { + if(valueToStates.getKey() != null) + { + + + Set defaults = anyValueStates.get(entry.getKey()); + if(defaults != null) + { + valueToStates.getValue().addAll(defaults); + } + } + } + } + + // if a given header key is not mentioned in the map of a machine; then that machine would stay at the same state + // for that key. + for(HeaderKey distinctKey : distinctKeys) + { + Map> valueToStatesMap = nfaMap.get(distinctKey); + for(HeadersMatcherDFAState oldState : oldStates) + { + if(!oldState._nextStateMap.containsKey(distinctKey)) + { + for(Set endStates : valueToStatesMap.values()) + { + endStates.add(oldState); + } + } + } + } + + + + + for(Map.Entry>> transitionClass : nfaMap.entrySet()) + { + Map valueToDFAState = newNextStateMap.get(transitionClass.getKey()); + if(valueToDFAState == null) + { + valueToDFAState = new HashMap(); + newNextStateMap.put(transitionClass.getKey(), valueToDFAState); + } + + for(Map.Entry> transition : transitionClass.getValue().entrySet()) + { + Set destinations = transition.getValue(); + + + HeadersMatcherDFAState nextState = newStateMap.get(destinations); + + if(nextState == null) + { + + if(destinations.size() == 1) + { + nextState = destinations.iterator().next(); + newStateMap.put(destinations, nextState); + } + else + { + Collection results; + + Set> resultSets = new HashSet>(); + for(HeadersMatcherDFAState destination : destinations) + { + resultSets.add(destination._results); + } + resultSets.remove(Collections.EMPTY_SET); + if(resultSets.size() == 0) + { + results = Collections.EMPTY_SET; + } + else if(resultSets.size() == 1) + { + results = resultSets.iterator().next(); + } + else + { + results = new HashSet(); + for(Collection oldResult : resultSets) + { + results.addAll(oldResult); + } + } + + final Map> nextStateMap = new HashMap>(); + + nextState = new HeadersMatcherDFAState(nextStateMap, results, _dictionary); + newStateMap.put(destinations, nextState); + + mergeStateMachines( + destinations, + nextStateMap, + newStateMap); + + + } + + + } + valueToDFAState.put(transition.getKey(),nextState); + } + } + + + + final ArrayList removeKeyList = new ArrayList(); + + for(Map.Entry> entry : _nextStateMap.entrySet()) + { + final ArrayList removeValueList = new ArrayList(); + + for(Map.Entry valueToDFAState : entry.getValue().entrySet()) + { + if(valueToDFAState.getValue() == this) + { + HeadersMatcherDFAState defaultState = entry.getValue().get(null); + if(defaultState == null || defaultState == this) + { + removeValueList.add(valueToDFAState.getKey()); + } + } + } + + for(AMQTypedValue removeValue : removeValueList) + { + entry.getValue().remove(removeValue); + } + + if(entry.getValue().isEmpty()) + { + removeKeyList.add(entry.getKey()); + } + + } + + for(HeaderKey removeKey : removeKeyList) + { + _nextStateMap.remove(removeKey); + } + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java new file mode 100644 index 0000000000..85e74122c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java @@ -0,0 +1,439 @@ +package org.apache.qpid.server.exchange.headers; + +import org.apache.qpid.framing.*; + +import java.util.*; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class HeadersParser +{ + + private final HeaderKeyDictionary _dictionary = new HeaderKeyDictionary(); + private static final AMQShortString MATCHING_TYPE_KEY = new AMQShortString("x-match"); + private static final String ANY_MATCHING = "any"; + private static final AMQShortString RESERVED_KEY_PREFIX = new AMQShortString("x-"); + + + HeadersMatcherDFAState createStateMachine(FieldTable bindingArguments, HeaderMatcherResult result) + { + String matchingType = bindingArguments.getString(MATCHING_TYPE_KEY); + boolean matchAny = matchingType.equalsIgnoreCase(ANY_MATCHING); + if(matchAny) + { + return createStateMachineForAnyMatch(bindingArguments, result); + } + else + { + return createStateMachineForAllMatch(bindingArguments, result); + } + + + } + + + private HeadersMatcherDFAState createStateMachineForAnyMatch(final FieldTable bindingArguments, + final HeaderMatcherResult result) + { + + // DFAs for "any" matches have only two states, "not-matched" and "matched"... they start in the former + // and upon meeting any of the criteria they move to the latter + + //noinspection unchecked + final HeadersMatcherDFAState successState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); + + Map> nextStateMap = + new HashMap>(); + + Set seenKeys = new HashSet(); + + Iterator> tableIterator = bindingArguments.iterator(); + + while(tableIterator.hasNext()) + { + final Map.Entry entry = tableIterator.next(); + final AMQShortString key = entry.getKey(); + final AMQTypedValue value = entry.getValue(); + + + if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) + { + final AMQType type = value.getType(); + + final HeaderKey headerKey = _dictionary.getOrCreate(key); + final Map valueMap; + + if(type == AMQType.VOID || + ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) + { + valueMap = Collections.singletonMap(null,successState); + + } + else + { + valueMap = Collections.singletonMap(value,successState); + } + nextStateMap.put(headerKey,valueMap); + + } + + } + + if(seenKeys.size() == 0) + { + return successState; + } + else + { + return new HeadersMatcherDFAState(nextStateMap,Collections.EMPTY_SET,_dictionary); + } + + + } + + + private HeadersMatcherDFAState createStateMachineForAllMatch(final FieldTable bindingArguments, + final HeaderMatcherResult result) + { + // DFAs for "all" matches have a "success" state, a "fail" state, and states for every subset of + // matches which are possible, starting with the empty subset. For example if we have a binding + // { x-match="all" + // a=1 + // b=1 + // c=1 + // d=1 } + // Then we would have the following states + // (1) Seen none of a, b, c, or d + // (2) Seen a=1 ; none of b,c, or d + // (3) Seen b=1 ; none of a,c, or d + // (4) Seen c=1 ; none of a,b, or d + // (5) Seen d=1 ; none of a,b, or c + // (6) Seen a=1,b=1 ; none of c,d + // (7) Seen a=1,c=1 ; none of b,d + // (8) Seen a=1,d=1 ; none of b,c + // (9) Seen b=1,c=1 ; none of a,d + //(10) Seen b=1,d=1 ; none of c,d + //(11) Seen c=1,d=1 ; none of a,b + //(12) Seen a=1,b=1,c=1 ; not d + //(13) Seen a=1,b=1,d=1 ; not c + //(14) Seen a=1,c=1,d=1 ; not b + //(15) Seen b=1,c=1,d=1 ; not a + //(16) success + //(17) fail + // + // All states but (16) can transition to (17); additionally: + // (1) can transition to (2),(3),(4),(5) + // (2) can transition to (6),(7),(8) + // (3) can transition to (6),(9),(10) + // (4) can transition to (7),(9),(11) + // (5) can transition to (8),(10),(11) + // (6) can transition to (12),(13) + // (7) can transition to (12),(14) + // (8) can transition to (13),(14) + // (9) can transition to (12),(15) + //(10) can transition to (13),(15) + //(11) can transition to (14),(15) + //(12)-(15) can transition to (16) + + Set seenKeys = new HashSet(); + List requiredTerms = new ArrayList(bindingArguments.size()); + + Iterator> tableIterator = bindingArguments.iterator(); + + + + while(tableIterator.hasNext()) + { + final Map.Entry entry = tableIterator.next(); + final AMQShortString key = entry.getKey(); + final AMQTypedValue value = entry.getValue(); + + + if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX)) + { + final AMQType type = value.getType(); + + if(type == AMQType.VOID || + ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0)) + { + requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),null)); + } + else + { + requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),value)); + } + } + + } + + final HeadersMatcherDFAState successState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary); + + final HeadersMatcherDFAState failState = + new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.EMPTY_SET,_dictionary); + + Map, HeadersMatcherDFAState> notSeenTermsToStateMap = + new HashMap, HeadersMatcherDFAState>(); + + notSeenTermsToStateMap.put(Collections.EMPTY_SET, successState); + + + final int numberOfTerms = requiredTerms.size(); + + for(int numMissingTerms = 1; numMissingTerms <= numberOfTerms; numMissingTerms++) + { + int[] pos = new int[numMissingTerms]; + for(int i = 0; i < numMissingTerms; i++) + { + pos[i] = i; + } + + final int maxTermValue = (numberOfTerms - (numMissingTerms - 1)); + + while(pos[0] < maxTermValue) + { + + Set stateSet = new HashSet(); + for(int posIndex = 0; posIndex < pos.length; posIndex++) + { + stateSet.add(requiredTerms.get(pos[posIndex])); + } + + final Map> nextStateMap = + new HashMap>(); + + + for(int posIndex = 0; posIndex < pos.length; posIndex++) + { + KeyValuePair nextTerm = requiredTerms.get(pos[posIndex]); + HashSet nextStateSet = + new HashSet(stateSet); + nextStateSet.remove(nextTerm); + + Map valueToStateMap = + new HashMap(); + nextStateMap.put(nextTerm._key, valueToStateMap); + + valueToStateMap.put( nextTerm._value,notSeenTermsToStateMap.get(nextStateSet)); + if(nextTerm._value != null) + { + valueToStateMap.put(null, failState); + } + + + } + + + HeadersMatcherDFAState newState = new HeadersMatcherDFAState(nextStateMap, Collections.EMPTY_SET, _dictionary); + + notSeenTermsToStateMap.put(stateSet, newState); + + int i = numMissingTerms; + while(i-- != 0) + { + if(++pos[i] <= numberOfTerms -(numMissingTerms-i)) + { + int k = pos[i]; + for(int j = i+1; j < numMissingTerms; j++) + { + pos[j] = ++k; + } + break; + } + } + } + + + + + } + + + return notSeenTermsToStateMap.get(new HashSet(requiredTerms)); + + + + } + + public static void main(String[] args) throws AMQFrameDecodingException + { + + FieldTable bindingTable = new FieldTable(); + + bindingTable.setString(new AMQShortString("x-match"),"all"); + bindingTable.setInteger("a",1); + bindingTable.setVoid(new AMQShortString("b")); + bindingTable.setString("c",""); + bindingTable.setInteger("d",4); + bindingTable.setInteger("e",1); + + + + FieldTable bindingTable2 = new FieldTable(); + bindingTable2.setString(new AMQShortString("x-match"),"all"); + bindingTable2.setInteger("a",1); + bindingTable2.setVoid(new AMQShortString("b")); + bindingTable2.setString("c",""); + bindingTable2.setInteger("d",4); + bindingTable2.setInteger("e",1); + bindingTable2.setInteger("f",1); + + + FieldTable table = new FieldTable(); + table.setInteger("a",1); + table.setInteger("b",2); + table.setString("c",""); + table.setInteger("d",4); + table.setInteger("e",1); + table.setInteger("f",1); + table.setInteger("h",1); + table.setInteger("i",1); + table.setInteger("j",1); + table.setInteger("k",1); + table.setInteger("l",1); + + org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.allocate( (int) table.getEncodedSize()); + EncodingUtils.writeFieldTableBytes(buffer, table); + buffer.flip(); + + FieldTable table2 = EncodingUtils.readFieldTable(buffer); + + + + FieldTable bindingTable3 = new FieldTable(); + bindingTable3.setString(new AMQShortString("x-match"),"any"); + bindingTable3.setInteger("a",1); + bindingTable3.setInteger("b",3); + + + FieldTable bindingTable4 = new FieldTable(); + bindingTable4.setString(new AMQShortString("x-match"),"any"); + bindingTable4.setVoid(new AMQShortString("a")); + + + FieldTable bindingTable5 = new FieldTable(); + bindingTable5.setString(new AMQShortString("x-match"),"all"); + bindingTable5.setString(new AMQShortString("h"),"hello"); + + for(int i = 0; i < 100; i++) + { + printMatches(new FieldTable[] {bindingTable5} , table2); + } + + + + } + + + + private static void printMatches(final FieldTable[] bindingKeys, final FieldTable routingKey) + { + HeadersMatcherDFAState sm = null; + Map resultMap = new HashMap(); + + HeadersParser parser = new HeadersParser(); + + for(int i = 0; i < bindingKeys.length; i++) + { + HeaderMatcherResult r = new HeaderMatcherResult(); + resultMap.put(r, bindingKeys[i].toString()); + + + if(i==0) + { + sm = parser.createStateMachine(bindingKeys[i], r); + } + else + { + sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeys[i], r)); + } + } + + Collection results = null; + long beforeTime = System.currentTimeMillis(); + for(int i = 0; i < 1000000; i++) + { + routingKey.size(); + + assert sm != null; + results = sm.match(routingKey); + + } + long elapsed = System.currentTimeMillis() - beforeTime; + System.out.println("1000000 Iterations took: " + elapsed); + Collection resultStrings = new ArrayList(); + + assert results != null; + for(HeaderMatcherResult result : results) + { + resultStrings.add(resultMap.get(result)); + } + + final ArrayList nonMatches = new ArrayList(); + for(FieldTable key : bindingKeys) + { + nonMatches.add(key.toString()); + } + nonMatches.removeAll(resultStrings); + System.out.println("\""+routingKey+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); + + + } + + + public final static class KeyValuePair + { + public final HeaderKey _key; + public final AMQTypedValue _value; + private final int _hashCode; + + public KeyValuePair(final HeaderKey key, final AMQTypedValue value) + { + _key = key; + _value = value; + int hash = (1 + 31 * _key.hashCode()); + if(_value != null) + { + hash+=_value.hashCode(); + } + _hashCode = hash; + } + + public int hashCode() + { + return _hashCode; + } + + public boolean equals(Object o) + { + KeyValuePair other = (KeyValuePair)o; + return (_key == other._key) && (_value == null ? other._value == null : _value.equals(other._value)); + } + + + public String toString() + { + return "{" + _key + " -> " + _value + "}"; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java new file mode 100644 index 0000000000..36076cf75b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java @@ -0,0 +1,295 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicMatcherDFAState +{ + private static final AtomicInteger stateId = new AtomicInteger(); + + private final int _id = stateId.incrementAndGet(); + + private final Collection _results; + private final Map _nextStateMap; + private static final byte TOPIC_DELIMITTER = (byte)'.'; + + + public TopicMatcherDFAState(Map nextStateMap, + Collection results ) + { + _nextStateMap = nextStateMap; + _results = results; + } + + + public TopicMatcherDFAState nextState(TopicWord word) + { + final TopicMatcherDFAState nextState = _nextStateMap.get(word); + return nextState == null ? _nextStateMap.get(TopicWord.ANY_WORD) : nextState; + } + + public Collection terminate() + { + return _results; + } + + + public Collection parse(TopicWordDictionary dictionary, AMQShortString routingKey) + { + return parse(dictionary, routingKey.tokenize(TOPIC_DELIMITTER)); + } + + private Collection parse(final TopicWordDictionary dictionary, + final AMQShortStringTokenizer tokens) + { + if(!tokens.hasMoreTokens()) + { + return _results; + } + TopicWord word = dictionary.getWord(tokens.nextToken()); + TopicMatcherDFAState nextState = _nextStateMap.get(word); + if(nextState == null && word != TopicWord.ANY_WORD) + { + nextState = _nextStateMap.get(TopicWord.ANY_WORD); + } + if(nextState == null) + { + return Collections.EMPTY_SET; + } + // Shortcut if we are at a looping terminal state + if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD)) + { + return _results; + } + + return nextState.parse(dictionary, tokens); + + } + + + public TopicMatcherDFAState mergeStateMachines(TopicMatcherDFAState otherStateMachine) + { + Map, TopicMatcherDFAState> newStateMap= new HashMap, TopicMatcherDFAState>(); + + Collection results; + + if(_results.isEmpty()) + { + results = otherStateMachine._results; + } + else if(otherStateMachine._results.isEmpty()) + { + results = _results; + } + else + { + results = new HashSet(_results); + results.addAll(otherStateMachine._results); + } + + + final Map newNextStateMap = new HashMap(); + + TopicMatcherDFAState newState = new TopicMatcherDFAState(newNextStateMap, results); + + + Set oldStates = new HashSet(); + oldStates.add(this); + oldStates.add(otherStateMachine); + + newStateMap.put(oldStates, newState); + + mergeStateMachines(oldStates, newNextStateMap, newStateMap); + + return newState; + + } + + private static void mergeStateMachines( + final Set oldStates, + final Map newNextStateMap, + final Map, TopicMatcherDFAState> newStateMap) + { + Map> nfaMap = new HashMap>(); + + for(TopicMatcherDFAState state : oldStates) + { + Map map = state._nextStateMap; + for(Map.Entry entry : map.entrySet()) + { + Set states = nfaMap.get(entry.getKey()); + if(states == null) + { + states = new HashSet(); + nfaMap.put(entry.getKey(), states); + } + states.add(entry.getValue()); + } + } + + Set anyWordStates = nfaMap.get(TopicWord.ANY_WORD); + + for(Map.Entry> transition : nfaMap.entrySet()) + { + Set destinations = transition.getValue(); + + if(anyWordStates != null) + { + destinations.addAll(anyWordStates); + } + + TopicMatcherDFAState nextState = newStateMap.get(destinations); + if(nextState == null) + { + + if(destinations.size() == 1) + { + nextState = destinations.iterator().next(); + newStateMap.put(destinations, nextState); + } + else + { + Collection results; + + Set> resultSets = new HashSet>(); + for(TopicMatcherDFAState destination : destinations) + { + resultSets.add(destination._results); + } + resultSets.remove(Collections.EMPTY_SET); + if(resultSets.size() == 0) + { + results = Collections.EMPTY_SET; + } + else if(resultSets.size() == 1) + { + results = resultSets.iterator().next(); + } + else + { + results = new HashSet(); + for(Collection oldResult : resultSets) + { + results.addAll(oldResult); + } + } + + final Map nextStateMap = new HashMap(); + + nextState = new TopicMatcherDFAState(nextStateMap, results); + newStateMap.put(destinations, nextState); + + mergeStateMachines( + destinations, + nextStateMap, + newStateMap); + + + } + + + } + newNextStateMap.put(transition.getKey(),nextState); + } + + // Remove redundant transitions where defined tokenWord has same action as ANY_WORD + TopicMatcherDFAState anyWordState = newNextStateMap.get(TopicWord.ANY_WORD); + if(anyWordState != null) + { + List removeList = new ArrayList(); + for(Map.Entry entry : newNextStateMap.entrySet()) + { + if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) + { + removeList.add(entry.getKey()); + } + } + for(TopicWord removeKey : removeList) + { + newNextStateMap.remove(removeKey); + } + } + + + + } + + + public String toString() + { + StringBuilder transitions = new StringBuilder(); + for(Map.Entry entry : _nextStateMap.entrySet()) + { + transitions.append("[ "); + transitions.append(entry.getKey()); + transitions.append("\t ->\t "); + transitions.append(entry.getValue()._id); + transitions.append(" ]\n"); + } + + + return "[ State " + _id + " ]\n" + transitions + "\n"; + + } + + public String reachableStates() + { + StringBuilder result = new StringBuilder("Start state: " + _id + "\n"); + + SortedSet reachableStates = + new TreeSet(new Comparator() + { + public int compare(final TopicMatcherDFAState o1, final TopicMatcherDFAState o2) + { + return o1._id - o2._id; + } + }); + reachableStates.add(this); + + int count; + + do + { + count = reachableStates.size(); + Collection originalStates = new ArrayList(reachableStates); + for(TopicMatcherDFAState state : originalStates) + { + reachableStates.addAll(state._nextStateMap.values()); + } + } + while(reachableStates.size() != count); + + + + for(TopicMatcherDFAState state : reachableStates) + { + result.append(state.toString()); + } + + return result.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java new file mode 100644 index 0000000000..71d30adfac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java @@ -0,0 +1,25 @@ +package org.apache.qpid.server.exchange.topic; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface TopicMatcherResult +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java new file mode 100644 index 0000000000..3e9facf412 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java @@ -0,0 +1,613 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.io.IOException; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicParser +{ + private static final byte TOPIC_DELIMITER = (byte)'.'; + + private final TopicWordDictionary _dictionary = new TopicWordDictionary(); + private final AtomicReference _stateMachine = new AtomicReference(); + + private static class Position + { + private final TopicWord _word; + private final boolean _selfTransition; + private final int _position; + private final boolean _endState; + private boolean _followedByAnyLoop; + + + public Position(final int position, final TopicWord word, final boolean selfTransition, final boolean endState) + { + _position = position; + _word = word; + _selfTransition = selfTransition; + _endState = endState; + } + + + } + + private static final Position ERROR_POSITION = new Position(Integer.MAX_VALUE,null, true, false); + + private static class SimpleState + { + Set _positions; + Map _nextState; + } + + + public void addBinding(AMQShortString bindingKey, TopicMatcherResult result) + { + + TopicMatcherDFAState startingStateMachine; + TopicMatcherDFAState newStateMachine; + + do + { + startingStateMachine = _stateMachine.get(); + if(startingStateMachine == null) + { + newStateMachine = createStateMachine(bindingKey, result); + } + else + { + newStateMachine = startingStateMachine.mergeStateMachines(createStateMachine(bindingKey, result)); + } + + } + while(!_stateMachine.compareAndSet(startingStateMachine,newStateMachine)); + + } + + public Collection parse(AMQShortString routingKey) + { + TopicMatcherDFAState stateMachine = _stateMachine.get(); + if(stateMachine == null) + { + return Collections.EMPTY_SET; + } + else + { + return stateMachine.parse(_dictionary,routingKey); + } + } + + + TopicMatcherDFAState createStateMachine(AMQShortString bindingKey, TopicMatcherResult result) + { + List wordList = createTopicWordList(bindingKey); + int wildCards = 0; + for(TopicWord word : wordList) + { + if(word == TopicWord.WILDCARD_WORD) + { + wildCards++; + } + } + if(wildCards == 0) + { + TopicMatcherDFAState[] states = new TopicMatcherDFAState[wordList.size()+1]; + states[states.length-1] = new TopicMatcherDFAState(Collections.EMPTY_MAP, Collections.singleton(result)); + for(int i = states.length-2; i >= 0; i--) + { + states[i] = new TopicMatcherDFAState(Collections.singletonMap(wordList.get(i),states[i+1]),Collections.EMPTY_SET); + + } + return states[0]; + } + else if(wildCards == wordList.size()) + { + Map stateMap = new HashMap(); + TopicMatcherDFAState state = new TopicMatcherDFAState(stateMap, Collections.singleton(result)); + stateMap.put(TopicWord.ANY_WORD, state); + return state; + } + + + int positionCount = wordList.size() - wildCards; + + Position[] positions = new Position[positionCount+1]; + + int lastWord; + + if(wordList.get(wordList.size()-1)== TopicWord.WILDCARD_WORD) + { + lastWord = wordList.size()-1; + positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, true, true); + } + else + { + lastWord = wordList.size(); + positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, false, true); + } + + + int pos = 0; + int wordPos = 0; + + + while(wordPos < lastWord) + { + TopicWord word = wordList.get(wordPos++); + + if(word == TopicWord.WILDCARD_WORD) + { + int nextWordPos = wordPos++; + word = wordList.get(nextWordPos); + + positions[pos] = new Position(pos++,word,true,false); + } + else + { + positions[pos] = new Position(pos++,word,false,false); + } + + } + + + for(int p = 0; p,SimpleState> stateMap = new HashMap,SimpleState>(); + + + SimpleState state = new SimpleState(); + state._positions = Collections.singleton( positions[0] ); + stateMap.put(state._positions, state); + + calculateNextStates(state, stateMap, positions); + + SimpleState[] simpleStates = stateMap.values().toArray(new SimpleState[stateMap.size()]); + HashMap[] dfaStateMaps = new HashMap[simpleStates.length]; + Map simple2DFAMap = new HashMap(); + + for(int i = 0; i < simpleStates.length; i++) + { + + Collection results; + boolean endState = false; + + for(Position p : simpleStates[i]._positions) + { + if(p._endState) + { + endState = true; + break; + } + } + + if(endState) + { + results = Collections.singleton(result); + } + else + { + results = Collections.EMPTY_SET; + } + + dfaStateMaps[i] = new HashMap(); + simple2DFAMap.put(simpleStates[i], new TopicMatcherDFAState(dfaStateMaps[i],results)); + + } + for(int i = 0; i < simpleStates.length; i++) + { + SimpleState simpleState = simpleStates[i]; + + Map nextSimpleStateMap = simpleState._nextState; + for(Map.Entry stateMapEntry : nextSimpleStateMap.entrySet()) + { + dfaStateMaps[i].put(stateMapEntry.getKey(), simple2DFAMap.get(stateMapEntry.getValue())); + } + + } + + return simple2DFAMap.get(state); + + } + + + + private void calculateNextStates(final SimpleState state, + final Map, SimpleState> stateMap, + final Position[] positions) + { + Map> transitions = new HashMap>(); + + for(Position pos : state._positions) + { + if(pos._selfTransition) + { + Set dest = transitions.get(TopicWord.ANY_WORD); + if(dest == null) + { + dest = new HashSet(); + transitions.put(TopicWord.ANY_WORD,dest); + } + dest.add(pos); + } + + final int nextPos = pos._position + 1; + Position nextPosition = nextPos == positions.length ? ERROR_POSITION : positions[nextPos]; + + Set dest = transitions.get(pos._word); + if(dest == null) + { + dest = new HashSet(); + transitions.put(pos._word,dest); + } + dest.add(nextPosition); + + } + + Set anyWordTransitions = transitions.get(TopicWord.ANY_WORD); + if(anyWordTransitions != null) + { + for(Set dest : transitions.values()) + { + dest.addAll(anyWordTransitions); + } + } + + state._nextState = new HashMap(); + + for(Map.Entry> dest : transitions.entrySet()) + { + + if(dest.getValue().size()>1) + { + dest.getValue().remove(ERROR_POSITION); + } + Position loopingTerminal = null; + for(Position destPos : dest.getValue()) + { + if(destPos._selfTransition && destPos._endState) + { + loopingTerminal = destPos; + break; + } + } + + if(loopingTerminal!=null) + { + dest.setValue(Collections.singleton(loopingTerminal)); + } + else + { + Position anyLoop = null; + for(Position destPos : dest.getValue()) + { + if(destPos._followedByAnyLoop) + { + if(anyLoop == null || anyLoop._position removals = new ArrayList(); + for(Position destPos : dest.getValue()) + { + if(destPos._position < anyLoop._position) + { + removals.add(destPos); + } + } + dest.getValue().removeAll(removals); + } + } + + SimpleState stateForEntry = stateMap.get(dest.getValue()); + if(stateForEntry == null) + { + stateForEntry = new SimpleState(); + stateForEntry._positions = dest.getValue(); + stateMap.put(dest.getValue(),stateForEntry); + calculateNextStates(stateForEntry, + stateMap, + positions); + } + state._nextState.put(dest.getKey(),stateForEntry); + + + + } + + // remove redundant transitions + SimpleState anyWordState = state._nextState.get(TopicWord.ANY_WORD); + if(anyWordState != null) + { + List removeList = new ArrayList(); + for(Map.Entry entry : state._nextState.entrySet()) + { + if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD) + { + removeList.add(entry.getKey()); + } + } + for(TopicWord removeKey : removeList) + { + state._nextState.remove(removeKey); + } + } + + + } + + private List createTopicWordList(final AMQShortString bindingKey) + { + AMQShortStringTokenizer tokens = bindingKey.tokenize(TOPIC_DELIMITER); + TopicWord previousWord = null; + + List wordList = new ArrayList(); + + while(tokens.hasMoreTokens()) + { + TopicWord nextWord = _dictionary.getOrCreateWord(tokens.nextToken()); + if(previousWord == TopicWord.WILDCARD_WORD) + { + + if(nextWord == TopicWord.WILDCARD_WORD) + { + // consecutive wildcards can be merged + // i.e. subsequent wildcards can be discarded + continue; + } + else if(nextWord == TopicWord.ANY_WORD) + { + // wildcard and anyword can be reordered to always put anyword first + wordList.set(wordList.size()-1,TopicWord.ANY_WORD); + nextWord = TopicWord.WILDCARD_WORD; + } + } + wordList.add(nextWord); + previousWord = nextWord; + + } + return wordList; + } + + + public static void main(String[] args) + { + + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.*.q.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches(new String[]{ + "#.a.#", + "#.b.#", + "#.c.#", + "#.d.#", + "#.e.#", + "#.f.#", + "#.g.#", + "#.h.#", + "#.i.#", + "#.j.#", + "#.k.#", + "#.l.#", + "#.m.#", + "#.n.#", + "#.o.#", + "#.p.#", + "#.q.#" + + }, "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); +/* + printMatches(new String[]{ + "#.a.#", + "#.b.#", + "#.c.#", + "#.d.#", + "#.e.#", + "#.f.#", + "#.g.#", + "#.h.#", + "#.i.#", + "#.j.#", + "#.k.#", + "#.l.#", + "#.m.#", + "#.n.#", + "#.o.#", + "#.p.#", + "#.q.#", + "#.r.#", + "#.s.#", + "#.t.#", + "#.u.#", + "#.v.#", + "#.w.#", + "#.x.#", + "#.y.#", + "#.z.#" + + + },"a.b"); + + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"); + printMatches("a.#.b.#","a.b.b.b.b.b.b.b.c"); + +*/ + + printMatches("",""); + printMatches("a","a"); + printMatches("a",""); + printMatches("","a"); + printMatches("a.b","a.b"); + printMatches("a","a.b"); + printMatches("a.b","a"); + printMatches("*","a"); + printMatches("*.b","a.b"); + printMatches("*.*","a.b"); + printMatches("a.*","a.b"); + printMatches("a.*.#","a.b"); + printMatches("a.#.b","a.b"); + + printMatches("#.b","a"); + printMatches("#.b","a.b"); + printMatches("#.a.b","a.b"); + + + printMatches("#",""); + printMatches("#","a"); + printMatches("#","a.b"); + printMatches("#.#","a.b"); + printMatches("#.*","a.b"); + + printMatches("#.a.b","a.b"); + printMatches("a.b.#","a.b"); + printMatches("a.#","a.b"); + printMatches("#.*.#","a.b"); + printMatches("#.*.b.#","a.b"); + printMatches("#.a.*.#","a.b"); + printMatches("#.a.#.b.#","a.b"); + printMatches("#.*.#.*.#","a.b"); + printMatches("*.#.*.#","a.b"); + printMatches("#.*.#.*","a.b"); + + + printMatches(new String[]{"a.#.b.#","a.*.#.b.#"},"a.b.b.b.b.b.b.b.c"); + + + printMatches(new String[]{"a.b", "a.c"},"a.b"); + printMatches(new String[]{"a.#", "a.c", "#.b"},"a.b"); + printMatches(new String[]{"a.#", "a.c", "#.b", "#", "*.*"},"a.b"); + + printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.e"); + printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.f.g"); + + + + + } + + private static void printMatches(final String[] bindingKeys, final String routingKey) + { + TopicMatcherDFAState sm = null; + Map resultMap = new HashMap(); + + TopicParser parser = new TopicParser(); + + long start = System.currentTimeMillis(); + for(int i = 0; i < bindingKeys.length; i++) + { + System.out.println((System.currentTimeMillis() - start) + ":\t" + bindingKeys[i]); + TopicMatcherResult r = new TopicMatcherResult(){}; + resultMap.put(r, bindingKeys[i]); + AMQShortString bindingKeyShortString = new AMQShortString(bindingKeys[i]); + + System.err.println("====================================================="); + System.err.println("Adding binding key: " + bindingKeyShortString); + System.err.println("-----------------------------------------------------"); + + + if(i==0) + { + sm = parser.createStateMachine(bindingKeyShortString, r); + } + else + { + sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeyShortString, r)); + } + System.err.println(sm.reachableStates()); + System.err.println("====================================================="); + try + { + System.in.read(); + } + catch (IOException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + AMQShortString routingKeyShortString = new AMQShortString(routingKey); + + Collection results = sm.parse(parser._dictionary, routingKeyShortString); + Collection resultStrings = new ArrayList(); + + for(TopicMatcherResult result : results) + { + resultStrings.add(resultMap.get(result)); + } + + final ArrayList nonMatches = new ArrayList(Arrays.asList(bindingKeys)); + nonMatches.removeAll(resultStrings); + System.out.println("\""+routingKeyShortString+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches); + + + } + + private static void printMatches(String bindingKey, String routingKey) + { + printMatches(new String[] { bindingKey }, routingKey); + } + + + private static boolean matches(String bindingKey, String routingKey) + { + AMQShortString bindingKeyShortString = new AMQShortString(bindingKey); + AMQShortString routingKeyShortString = new AMQShortString(routingKey); + TopicParser parser = new TopicParser(); + + final TopicMatcherResult result = new TopicMatcherResult(){}; + + TopicMatcherDFAState sm = parser.createStateMachine(bindingKeyShortString, result); + return !sm.parse(parser._dictionary,routingKeyShortString).isEmpty(); + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java new file mode 100644 index 0000000000..f14d70f8a1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java @@ -0,0 +1,54 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public final class TopicWord +{ + public static final TopicWord ANY_WORD = new TopicWord("*"); + public static final TopicWord WILDCARD_WORD = new TopicWord("#"); + private String _word; + + public TopicWord() + { + + } + + public TopicWord(String s) + { + _word = s; + } + + public TopicWord(final AMQShortString name) + { + _word = name.toString(); + } + + public String toString() + { + return _word; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java new file mode 100644 index 0000000000..65a0cd3107 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java @@ -0,0 +1,63 @@ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; + +import java.util.concurrent.ConcurrentHashMap; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class TopicWordDictionary +{ + private final ConcurrentHashMap _dictionary = + new ConcurrentHashMap(); + + + + public TopicWordDictionary() + { + _dictionary.put(new AMQShortString("*"), TopicWord.ANY_WORD); + _dictionary.put(new AMQShortString("#"), TopicWord.WILDCARD_WORD); + } + + + + + public TopicWord getOrCreateWord(AMQShortString name) + { + TopicWord word = _dictionary.putIfAbsent(name, new TopicWord(name)); + if(word == null) + { + word = _dictionary.get(name); + } + return word; + } + + + public TopicWord getWord(AMQShortString name) + { + TopicWord word = _dictionary.get(name); + if(word == null) + { + word = TopicWord.ANY_WORD; + } + return word; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java new file mode 100644 index 0000000000..a964bce306 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -0,0 +1,275 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.Filterable; + +/** + * An expression which performs an operation on two expression values + */ +public abstract class ArithmeticExpression extends BinaryExpression +{ + + protected static final int INTEGER = 1; + protected static final int LONG = 2; + protected static final int DOUBLE = 3; + + /** + * @param left + * @param right + */ + public ArithmeticExpression(Expression left, Expression right) + { + super(left, right); + } + + public static Expression createPlus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof String) + { + String text = (String) lvalue; + String answer = text + rvalue; + + return answer; + } + else if (lvalue instanceof Number) + { + return plus((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "+"; + } + }; + } + + public static Expression createMinus(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return minus((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "-"; + } + }; + } + + public static Expression createMultiply(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return multiply((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "*"; + } + }; + } + + public static Expression createDivide(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return divide((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "/"; + } + }; + } + + public static Expression createMod(Expression left, Expression right) + { + return new ArithmeticExpression(left, right) + { + + protected Object evaluate(Object lvalue, Object rvalue) + { + if (lvalue instanceof Number) + { + return mod((Number) lvalue, asNumber(rvalue)); + } + + throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); + } + + public String getExpressionSymbol() + { + return "%"; + } + }; + } + + protected Number plus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() + right.intValue()); + + case LONG: + return new Long(left.longValue() + right.longValue()); + + default: + return new Double(left.doubleValue() + right.doubleValue()); + } + } + + protected Number minus(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() - right.intValue()); + + case LONG: + return new Long(left.longValue() - right.longValue()); + + default: + return new Double(left.doubleValue() - right.doubleValue()); + } + } + + protected Number multiply(Number left, Number right) + { + switch (numberType(left, right)) + { + + case INTEGER: + return new Integer(left.intValue() * right.intValue()); + + case LONG: + return new Long(left.longValue() * right.longValue()); + + default: + return new Double(left.doubleValue() * right.doubleValue()); + } + } + + protected Number divide(Number left, Number right) + { + return new Double(left.doubleValue() / right.doubleValue()); + } + + protected Number mod(Number left, Number right) + { + return new Double(left.doubleValue() % right.doubleValue()); + } + + private int numberType(Number left, Number right) + { + if (isDouble(left) || isDouble(right)) + { + return DOUBLE; + } + else if ((left instanceof Long) || (right instanceof Long)) + { + return LONG; + } + else + { + return INTEGER; + } + } + + private boolean isDouble(Number n) + { + return (n instanceof Float) || (n instanceof Double); + } + + protected Number asNumber(Object value) + { + if (value instanceof Number) + { + return (Number) value; + } + else + { + throw new RuntimeException("Cannot convert value: " + value + " into a number"); + } + } + + public Object evaluate(Filterable message) throws E + { + Object lvalue = left.evaluate(message); + if (lvalue == null) + { + return null; + } + + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + return evaluate(lvalue, rvalue); + } + + /** + * @param lvalue + * @param rvalue + * @return + */ + protected abstract Object evaluate(Object lvalue, Object rvalue); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java new file mode 100644 index 0000000000..7308de80d6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -0,0 +1,106 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +/** + * An expression which performs an operation on two expression values. + */ +public abstract class BinaryExpression implements Expression +{ + protected Expression left; + protected Expression right; + + public BinaryExpression(Expression left, Expression right) + { + this.left = left; + this.right = right; + } + + public Expression getLeft() + { + return left; + } + + public Expression getRight() + { + return right; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + public abstract String getExpressionSymbol(); + + /** + * @param expression + */ + public void setRight(Expression expression) + { + right = expression; + } + + /** + * @param expression + */ + public void setLeft(Expression expression) + { + left = expression; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java new file mode 100644 index 0000000000..9beb9798d0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -0,0 +1,41 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +/** + * A BooleanExpression is an expression that always + * produces a Boolean result. + */ +public interface BooleanExpression extends Expression +{ + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws E + */ + public boolean matches(Filterable message) throws E; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java new file mode 100644 index 0000000000..921005c462 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -0,0 +1,601 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.util.HashSet; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +/** + * A filter performing a comparison of two objects + */ +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression +{ + + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) + { + return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); + } + + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) + { + return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); + } + + private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); + + static + { + REGEXP_CONTROL_CHARS.add(new Character('.')); + REGEXP_CONTROL_CHARS.add(new Character('\\')); + REGEXP_CONTROL_CHARS.add(new Character('[')); + REGEXP_CONTROL_CHARS.add(new Character(']')); + REGEXP_CONTROL_CHARS.add(new Character('^')); + REGEXP_CONTROL_CHARS.add(new Character('$')); + REGEXP_CONTROL_CHARS.add(new Character('?')); + REGEXP_CONTROL_CHARS.add(new Character('*')); + REGEXP_CONTROL_CHARS.add(new Character('+')); + REGEXP_CONTROL_CHARS.add(new Character('{')); + REGEXP_CONTROL_CHARS.add(new Character('}')); + REGEXP_CONTROL_CHARS.add(new Character('|')); + REGEXP_CONTROL_CHARS.add(new Character('(')); + REGEXP_CONTROL_CHARS.add(new Character(')')); + REGEXP_CONTROL_CHARS.add(new Character(':')); + REGEXP_CONTROL_CHARS.add(new Character('&')); + REGEXP_CONTROL_CHARS.add(new Character('<')); + REGEXP_CONTROL_CHARS.add(new Character('>')); + REGEXP_CONTROL_CHARS.add(new Character('=')); + REGEXP_CONTROL_CHARS.add(new Character('!')); + } + + static class LikeExpression extends UnaryExpression implements BooleanExpression + { + + Pattern likePattern; + + /** + * @param right + */ + public LikeExpression(Expression right, String like, int escape) + { + super(right); + + StringBuffer regexp = new StringBuffer(like.length() * 2); + regexp.append("\\A"); // The beginning of the input + for (int i = 0; i < like.length(); i++) + { + char c = like.charAt(i); + if (escape == (0xFFFF & c)) + { + i++; + if (i >= like.length()) + { + // nothing left to escape... + break; + } + + char t = like.charAt(i); + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & t)); + } + else if (c == '%') + { + regexp.append(".*?"); // Do a non-greedy match + } + else if (c == '_') + { + regexp.append("."); // match one + } + else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) + { + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & c)); + } + else + { + regexp.append(c); + } + } + + regexp.append("\\z"); // The end of the input + + likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); + } + + /** + * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() + */ + public String getExpressionSymbol() + { + return "LIKE"; + } + + /** + * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) + */ + public Object evaluate(Filterable message) throws E + { + + Object rv = this.getRight().evaluate(message); + + if (rv == null) + { + return null; + } + + if (!(rv instanceof String)) + { + return + Boolean.FALSE; + // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); + } + + return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; + } + + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + + public static BooleanExpression createLike(Expression left, String right, String escape) + { + if ((escape != null) && (escape.length() != 1)) + { + throw new RuntimeException( + "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); + } + + int c = -1; + if (escape != null) + { + c = 0xFFFF & escape.charAt(0); + } + + return new LikeExpression(left, right, c); + } + + public static BooleanExpression createNotLike(Expression left, String right, String escape) + { + return UnaryExpression.createNOT(createLike(left, right, escape)); + } + + public static BooleanExpression createInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); + + } + + public static BooleanExpression createNotInFilter(Expression left, List elements) + { + + if (!(left instanceof PropertyExpression)) + { + throw new RuntimeException("Expected a property for In expression, got: " + left); + } + + return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); + + } + + public static BooleanExpression createIsNull(Expression left) + { + return doCreateEqual(left, ConstantExpression.NULL); + } + + public static BooleanExpression createIsNotNull(Expression left) + { + return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL)); + } + + public static BooleanExpression createNotEqual(Expression left, Expression right) + { + return UnaryExpression.createNOT(createEqual(left, right)); + } + + public static BooleanExpression createEqual(Expression left, Expression right) + { + checkEqualOperand(left); + checkEqualOperand(right); + checkEqualOperandCompatability(left, right); + + return doCreateEqual(left, right); + } + + private static BooleanExpression doCreateEqual(Expression left, Expression right) + { + return new EqualExpression(left, right); + } + + public static BooleanExpression createGreaterThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { + return answer > 0; + } + + public String getExpressionSymbol() + { + return ">"; + } + }; + } + + public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + protected boolean asBoolean(int answer) + { + return answer >= 0; + } + + public String getExpressionSymbol() + { + return ">="; + } + }; + } + + public static BooleanExpression createLessThan(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + + protected boolean asBoolean(int answer) + { + return answer < 0; + } + + public String getExpressionSymbol() + { + return "<"; + } + + }; + } + + public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) + { + checkLessThanOperand(left); + checkLessThanOperand(right); + + return new ComparisonExpression(left, right) + { + + protected boolean asBoolean(int answer) + { + return answer <= 0; + } + + public String getExpressionSymbol() + { + return "<="; + } + }; + } + + /** + * Only Numeric expressions can be used in >, >=, < or <= expressions.s + * + * @param expr + */ + public static void checkLessThanOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value instanceof Number) + { + return; + } + + // Else it's boolean or a String.. + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + + if (expr instanceof BooleanExpression) + { + throw new RuntimeException("Value '" + expr + "' cannot be compared."); + } + } + + /** + * Validates that the expression can be used in == or <> expression. + * Cannot not be NULL TRUE or FALSE litterals. + * + * @param expr + */ + public static void checkEqualOperand(Expression expr) + { + if (expr instanceof ConstantExpression) + { + Object value = ((ConstantExpression) expr).getValue(); + if (value == null) + { + throw new RuntimeException("'" + expr + "' cannot be compared."); + } + } + } + + /** + * + * @param left + * @param right + */ + private static void checkEqualOperandCompatability(Expression left, Expression right) + { + if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) + { + if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) + { + throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); + } + } + } + + /** + * @param left + * @param right + */ + public ComparisonExpression(Expression left, Expression right) + { + super(left, right); + } + + public Object evaluate(Filterable message) throws E + { + Comparable lv = (Comparable) left.evaluate(message); + if (lv == null) + { + return null; + } + + Comparable rv = (Comparable) right.evaluate(message); + if (rv == null) + { + return null; + } + + return compare(lv, rv); + } + + protected Boolean compare(Comparable lv, Comparable rv) + { + Class lc = lv.getClass(); + Class rc = rv.getClass(); + // If the the objects are not of the same type, + // try to convert up to allow the comparison. + if (lc != rc) + { + if (lc == Byte.class) + { + if (rc == Short.class) + { + lv = new Short(((Number) lv).shortValue()); + } + else if (rc == Integer.class) + { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Short.class) + { + if (rc == Integer.class) + { + lv = new Integer(((Number) lv).intValue()); + } + else if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Integer.class) + { + if (rc == Long.class) + { + lv = new Long(((Number) lv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Long.class) + { + if (rc == Integer.class) + { + rv = new Long(((Number) rv).longValue()); + } + else if (rc == Float.class) + { + lv = new Float(((Number) lv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Float.class) + { + if (rc == Integer.class) + { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Long.class) + { + rv = new Float(((Number) rv).floatValue()); + } + else if (rc == Double.class) + { + lv = new Double(((Number) lv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else if (lc == Double.class) + { + if (rc == Integer.class) + { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Long.class) + { + rv = new Double(((Number) rv).doubleValue()); + } + else if (rc == Float.class) + { + rv = new Float(((Number) rv).doubleValue()); + } + else + { + return Boolean.FALSE; + } + } + else + { + return Boolean.FALSE; + } + } + + return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; + } + + protected abstract boolean asBoolean(int answer); + + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + + private static class EqualExpression extends ComparisonExpression + { + public EqualExpression(final Expression left, final Expression right) + { + super(left, right); + } + + public Object evaluate(Filterable message) throws E + { + Object lv = left.evaluate(message); + Object rv = right.evaluate(message); + + // Iff one of the values is null + if ((lv == null) ^ (rv == null)) + { + return Boolean.FALSE; + } + + if ((lv == rv) || lv.equals(rv)) + { + return Boolean.TRUE; + } + + if ((lv instanceof Comparable) && (rv instanceof Comparable)) + { + return compare((Comparable) lv, (Comparable) rv); + } + + return Boolean.FALSE; + } + + protected boolean asBoolean(int answer) + { + return answer == 0; + } + + public String getExpressionSymbol() + { + return "="; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java new file mode 100644 index 0000000000..3ed2286f2e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -0,0 +1,211 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.math.BigDecimal; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +/** + * Represents a constant expression + */ +public class ConstantExpression implements Expression +{ + + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression + { + public BooleanConstantExpression(Object value) + { + super(value); + } + + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + + public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); + public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); + public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); + + private Object value; + + public static ConstantExpression createFromDecimal(String text) + { + + // Strip off the 'l' or 'L' if needed. + if (text.endsWith("l") || text.endsWith("L")) + { + text = text.substring(0, text.length() - 1); + } + + Number value; + try + { + value = new Long(text); + } + catch (NumberFormatException e) + { + // The number may be too big to fit in a long. + value = new BigDecimal(text); + } + + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFromHex(String text) + { + Number value = new Long(Long.parseLong(text.substring(2), 16)); + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFromOctal(String text) + { + Number value = new Long(Long.parseLong(text, 8)); + long l = value.longValue(); + if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) + { + value = new Integer(value.intValue()); + } + + return new ConstantExpression(value); + } + + public static ConstantExpression createFloat(String text) + { + Number value = new Double(text); + + return new ConstantExpression(value); + } + + public ConstantExpression(Object value) + { + this.value = value; + } + + public Object evaluate(Filterable message) throws E + { + return value; + } + + public Object getValue() + { + return value; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + if (value == null) + { + return "NULL"; + } + + if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; + } + + if (value instanceof String) + { + return encodeString((String) value); + } + + return value.toString(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Encodes the value of string so that it looks like it would look like + * when it was provided in a selector. + * + * @param s + * @return + */ + public static String encodeString(String s) + { + StringBuffer b = new StringBuffer(); + b.append('\''); + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + if (c == '\'') + { + b.append(c); + } + + b.append(c); + } + + b.append('\''); + + return b.toString(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java new file mode 100644 index 0000000000..f2ebe41d26 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -0,0 +1,38 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +/** + * Represents an expression + */ +public interface Expression +{ + + /** + * @return the value of this expression + */ + public Object evaluate(Filterable message) throws E; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java new file mode 100644 index 0000000000..dd3c126ee5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; +import org.apache.qpid.AMQException; + +public interface FilterManager +{ + void add(MessageFilter filter); + + void remove(MessageFilter filter); + + boolean allAllow(Filterable msg); + + boolean hasFilters(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java new file mode 100644 index 0000000000..a7f49d0566 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.framing.FieldTable; + + +public class FilterManagerFactory +{ + //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); + private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); + + //fixme move to a common class so it can be refered to from client code. + + public static FilterManager createManager(FieldTable filters) throws AMQException + { + FilterManager manager = null; + + if (filters != null) + { + + + + if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())) + { + String selector = filters.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); + + if (selector != null && !selector.equals("")) + { + manager = new SimpleFilterManager(); + manager.add(new JMSSelectorFilter(selector)); + } + + } + + + } + else + { + _logger.debug("No Filters found."); + } + + + return manager; + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java new file mode 100644 index 0000000000..96c9353872 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.filter.jms.selector.SelectorParser; +import org.apache.qpid.server.queue.Filterable; + + +public class JMSSelectorFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); + + private String _selector; + private BooleanExpression _matcher; + + public JMSSelectorFilter(String selector) throws AMQException + { + _selector = selector; + _matcher = new SelectorParser().parse(selector); + } + + public boolean matches(Filterable message) throws E + { + boolean match = _matcher.matches(message); + if(_logger.isDebugEnabled()) + { + _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector); + } + return match; + } + + public String getSelector() + { + return _selector; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java new file mode 100644 index 0000000000..094363ed9a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -0,0 +1,122 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +/** + * A filter performing a comparison of two objects + */ +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression +{ + + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new OrExpression(lvalue, rvalue); + } + + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) + { + return new AndExpression(lvalue, rvalue); + } + + /** + * @param left + * @param right + */ + public LogicExpression(BooleanExpression left, BooleanExpression right) + { + super(left, right); + } + + public abstract Object evaluate(Filterable message) throws E; + + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + + private static class OrExpression extends LogicExpression + { + public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + { + super(lvalue, rvalue); + } + + public Object evaluate(Filterable message) throws E + { + + Boolean lv = (Boolean) left.evaluate(message); + // Can we do an OR shortcut?? + if ((lv != null) && lv.booleanValue()) + { + return Boolean.TRUE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "OR"; + } + } + + private static class AndExpression extends LogicExpression + { + public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + { + super(lvalue, rvalue); + } + + public Object evaluate(Filterable message) throws E + { + + Boolean lv = (Boolean) left.evaluate(message); + + // Can we do an AND shortcut?? + if (lv == null) + { + return null; + } + + if (!lv.booleanValue()) + { + return Boolean.FALSE; + } + + Boolean rv = (Boolean) right.evaluate(message); + + return (rv == null) ? null : rv; + } + + public String getExpressionSymbol() + { + return "AND"; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java new file mode 100644 index 0000000000..58fc55f8e6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +public interface MessageFilter +{ + boolean matches(Filterable message) throws E; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java new file mode 100644 index 0000000000..f1b3b2511d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.Filterable; + +public class NoConsumerFilter implements MessageFilter +{ + private final static Logger _logger = org.apache.log4j.Logger.getLogger(NoConsumerFilter.class); + + + public NoConsumerFilter() throws AMQException + { + _logger.info("Created NoConsumerFilter"); + } + + public boolean matches(Filterable message) + { + return true; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java new file mode 100644 index 0000000000..b30c70dac3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -0,0 +1,268 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.server.queue.Filterable; + +/** + * Represents a property expression + */ +public class PropertyExpression implements Expression +{ + // Constants - defined the same as JMS + private static final int NON_PERSISTENT = 1; + private static final int PERSISTENT = 2; + private static final int DEFAULT_PRIORITY = 4; + + private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); + + private static final HashMap> JMS_PROPERTY_EXPRESSIONS = new HashMap>(); + + { + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() + { + public Object evaluate(Filterable message) + { + //TODO + return null; + } + }); + JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new ReplyToExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSType", new TypeExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new DeliveryModeExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new CorrelationIdExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); + + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() + { + public Object evaluate(Filterable message) throws E + { + return message.isRedelivered(); + } + }); + } + + private final String name; + private final Expression jmsPropertyExpression; + + public boolean outerTest() + { + return false; + } + + public PropertyExpression(String name) + { + this.name = name; + + + + jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); + } + + public Object evaluate(Filterable message) throws E + { + + if (jmsPropertyExpression != null) + { + return jmsPropertyExpression.evaluate(message); + } + else + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) message.getContentHeaderBody().properties; + + if (_logger.isDebugEnabled()) + { + _logger.debug("Looking up property:" + name); + _logger.debug("Properties are:" + _properties.getHeaders().keySet()); + } + + return _properties.getHeaders().getObject(name); + } + } + + public String getName() + { + return name; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return name; + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return name.equals(((PropertyExpression) o).name); + + } + + private static class ReplyToExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString replyTo = _properties.getReplyTo(); + + return (replyTo == null) ? null : replyTo.toString(); + + } + + } + + private static class TypeExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString type = _properties.getType(); + + return (type == null) ? null : type.toString(); + + } + } + + private static class DeliveryModeExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; + if (_logger.isDebugEnabled()) + { + _logger.debug("JMSDeliveryMode is :" + mode); + } + + return mode; + } + } + + private static class PriorityExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return (int) _properties.getPriority(); + } + } + + private static class MessageIDExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString messageId = _properties.getMessageId(); + + return (messageId == null) ? null : messageId; + + } + } + + private static class TimestampExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getTimestamp(); + } + } + + private static class CorrelationIdExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + AMQShortString correlationId = _properties.getCorrelationId(); + + return (correlationId == null) ? null : correlationId.toString(); + } + } + + private static class ExpirationExpression implements Expression + { + public Object evaluate(Filterable message) throws E + { + + CommonContentHeaderProperties _properties = + (CommonContentHeaderProperties) + message.getContentHeaderBody().properties; + + return _properties.getExpiration(); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java new file mode 100644 index 0000000000..cb738e1489 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.filter; + +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +public class SimpleFilterManager implements FilterManager +{ + private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); + + private final ConcurrentLinkedQueue> _filters; + + public SimpleFilterManager() + { + _logger.debug("Creating SimpleFilterManager"); + _filters = new ConcurrentLinkedQueue>(); + } + + public void add(MessageFilter filter) + { + _filters.add(filter); + } + + public void remove(MessageFilter filter) + { + _filters.remove(filter); + } + + public boolean allAllow(Filterable msg) + { + for (MessageFilter filter : _filters) + { + try + { + if (!filter.matches(msg)) + { + return false; + } + } + catch (AMQException e) + { + //fixme + e.printStackTrace(); + return false; + } + } + return true; + } + + public boolean hasFilters() + { + return !_filters.isEmpty(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java new file mode 100644 index 0000000000..799a38af5a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -0,0 +1,369 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.Filterable; + +/** + * An expression which performs an operation on two expression values + */ +public abstract class UnaryExpression implements Expression +{ + + private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); + protected Expression right; + + public static Expression createNegate(Expression left) + { + return new NegativeExpression(left); + } + + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + { + + // Use a HashSet if there are many elements. + Collection t; + if (elements.size() == 0) + { + t = null; + } + else if (elements.size() < 5) + { + t = elements; + } + else + { + t = new HashSet(elements); + } + + final Collection inList = t; + + return new InExpression(right, inList, not); + } + + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + { + public BooleanUnaryExpression(Expression left) + { + super(left); + } + + public boolean matches(Filterable message) throws E + { + Object object = evaluate(message); + + return (object != null) && (object == Boolean.TRUE); + } + } + ; + + public static BooleanExpression createNOT(BooleanExpression left) + { + return new NotExpression(left); + } + + public static BooleanExpression createXPath(final String xpath) + { + return new XPathExpression(xpath); + } + + public static BooleanExpression createXQuery(final String xpath) + { + return new XQueryExpression(xpath); + } + + public static BooleanExpression createBooleanCast(Expression left) + { + return new BooleanCastExpression(left); + } + + private static Number negate(Number left) + { + Class clazz = left.getClass(); + if (clazz == Integer.class) + { + return new Integer(-left.intValue()); + } + else if (clazz == Long.class) + { + return new Long(-left.longValue()); + } + else if (clazz == Float.class) + { + return new Float(-left.floatValue()); + } + else if (clazz == Double.class) + { + return new Double(-left.doubleValue()); + } + else if (clazz == BigDecimal.class) + { + // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the + // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it + // as a Big decimal. But it gets Negated right away.. to here we try to covert it back + // to a Long. + BigDecimal bd = (BigDecimal) left; + bd = bd.negate(); + + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) + { + return new Long(Long.MIN_VALUE); + } + + return bd; + } + else + { + throw new RuntimeException("Don't know how to negate: " + left); + } + } + + public UnaryExpression(Expression left) + { + this.right = left; + } + + public Expression getRight() + { + return right; + } + + public void setRight(Expression expression) + { + right = expression; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * TODO: more efficient hashCode() + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + + if ((o == null) || !this.getClass().equals(o.getClass())) + { + return false; + } + + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return + */ + public abstract String getExpressionSymbol(); + + private static class NegativeExpression extends UnaryExpression + { + public NegativeExpression(final Expression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue instanceof Number) + { + return negate((Number) rvalue); + } + + return null; + } + + public String getExpressionSymbol() + { + return "-"; + } + } + + private static class InExpression extends BooleanUnaryExpression + { + private final Collection _inList; + private final boolean _not; + + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) + { + super(right); + _inList = inList; + _not = not; + } + + public Object evaluate(Filterable message) throws E + { + + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (rvalue.getClass() != String.class) + { + return null; + } + + if (((_inList != null) && _inList.contains(rvalue)) ^ _not) + { + return Boolean.TRUE; + } + else + { + return Boolean.FALSE; + } + + } + + public String toString() + { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count = 0; + for (Iterator i = _inList.iterator(); i.hasNext();) + { + Object o = (Object) i.next(); + if (count != 0) + { + answer.append(", "); + } + + answer.append(o); + count++; + } + + answer.append(" )"); + + return answer.toString(); + } + + public String getExpressionSymbol() + { + if (_not) + { + return "NOT IN"; + } + else + { + return "IN"; + } + } + } + + private static class NotExpression extends BooleanUnaryExpression + { + public NotExpression(final BooleanExpression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Boolean lvalue = (Boolean) right.evaluate(message); + if (lvalue == null) + { + return null; + } + + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + public String getExpressionSymbol() + { + return "NOT"; + } + } + + private static class BooleanCastExpression extends BooleanUnaryExpression + { + public BooleanCastExpression(final Expression left) + { + super(left); + } + + public Object evaluate(Filterable message) throws E + { + Object rvalue = right.evaluate(message); + if (rvalue == null) + { + return null; + } + + if (!rvalue.getClass().equals(Boolean.class)) + { + return Boolean.FALSE; + } + + return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + public String toString() + { + return right.toString(); + } + + public String getExpressionSymbol() + { + return ""; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java new file mode 100644 index 0000000000..1311178fb1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -0,0 +1,127 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Used to evaluate an XPath Expression in a JMS selector. + */ +public final class XPathExpression implements BooleanExpression { + + private static final Logger log = Logger.getLogger(XPathExpression.class); + private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.qpid.server.filter.XPathEvaluatorClassName"; + private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName(); + + private static final Constructor EVALUATOR_CONSTRUCTOR; + + static { + String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); + Constructor m = null; + try { + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e) { + log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e); + cn = DEFAULT_EVALUATOR_CLASS_NAME; + try { + m = getXPathEvaluatorConstructor(cn); + } catch (Throwable e2) { + log.error("Default XPath evaluator could not be loaded",e); + } + } + } finally { + EVALUATOR_CONSTRUCTOR = m; + } + } + + private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { + Class c = XPathExpression.class.getClassLoader().loadClass(cn); + if( !XPathEvaluator.class.isAssignableFrom(c) ) { + throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class); + } + return c.getConstructor(new Class[]{String.class}); + } + + private final String xpath; + private final XPathEvaluator evaluator; + + static public interface XPathEvaluator { + public boolean evaluate(Filterable message) throws AMQException; + } + + XPathExpression(String xpath) { + this.xpath = xpath; + this.evaluator = createEvaluator(xpath); + } + + private XPathEvaluator createEvaluator(String xpath2) { + try { + return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath}); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if( cause instanceof RuntimeException ) { + throw (RuntimeException)cause; + } + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } catch (Throwable e) { + throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e); + } + } + + public Object evaluate(Filterable message) throws AMQException { +// try { +//FIXME this is flow to disk work +// if( message.isDropped() ) +// return null; + return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE; +// } catch (IOException e) { +// +// JMSException exception = new JMSException(e.getMessage()); +// exception.initCause(e); +// throw exception; +// +// } + + } + + public String toString() { + return "XPATH "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws AMQException + */ + public boolean matches(Filterable message) throws AMQException + { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java new file mode 100644 index 0000000000..c13f81cd08 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -0,0 +1,58 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.filter; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; + +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +/** + * Used to evaluate an XQuery Expression in a JMS selector. + */ +public final class XQueryExpression implements BooleanExpression { + private final String xpath; + + XQueryExpression(String xpath) { + super(); + this.xpath = xpath; + } + + public Object evaluate(Filterable message) throws AMQException { + return Boolean.FALSE; + } + + public String toString() { + return "XQUERY "+ConstantExpression.encodeString(xpath); + } + + /** + * @param message + * @return true if the expression evaluates to Boolean.TRUE. + * @throws AMQException + */ + public boolean matches(Filterable message) throws AMQException + { + Object object = evaluate(message); + return object!=null && object==Boolean.TRUE; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java new file mode 100644 index 0000000000..cc67776682 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -0,0 +1,103 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.qpid.server.filter; +// +// Based on like named file from r450141 of the Apache ActiveMQ project +// + +import java.io.ByteArrayInputStream; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.Filterable; +import org.apache.xpath.CachedXPathAPI; +import org.w3c.dom.Document; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; + +public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { + + private final String xpath; + + public XalanXPathEvaluator(String xpath) { + this.xpath = xpath; + } + + public boolean evaluate(Filterable m) throws AMQException + { + // TODO - we would have to check the content type and then evaluate the content + // here... is this really a feature we wish to implement? - RobG + /* + + if( m instanceof TextMessage ) { + String text = ((TextMessage)m).getText(); + return evaluate(text); + } else if ( m instanceof BytesMessage ) { + BytesMessage bm = (BytesMessage) m; + byte data[] = new byte[(int) bm.getBodyLength()]; + bm.readBytes(data); + return evaluate(data); + } + */ + return false; + + } + + private boolean evaluate(byte[] data) { + try { + + InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + + } catch (Throwable e) { + return false; + } + } + + private boolean evaluate(String text) { + try { + InputSource inputSource = new InputSource(new StringReader(text)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder dbuilder = factory.newDocumentBuilder(); + Document doc = dbuilder.parse(inputSource); + + // We should associated the cachedXPathAPI object with the message being evaluated + // since that should speedup subsequent xpath expressions. + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); + NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); + return iterator.nextNode()!=null; + } catch (Throwable e) { + return false; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java new file mode 100644 index 0000000000..895db7b15b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java @@ -0,0 +1,62 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.flow; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; +import java.util.HashSet; + +public abstract class AbstractFlowCreditManager implements FlowCreditManager +{ + protected final AtomicBoolean _suspended = new AtomicBoolean(false); + private final Set _listeners = new HashSet(); + + public final void addStateListener(FlowCreditManagerListener listener) + { + _listeners.add(listener); + } + + public final boolean removeListener(FlowCreditManagerListener listener) + { + return _listeners.remove(listener); + } + + private void notifyListeners(final boolean suspended) + { + for(FlowCreditManagerListener listener : _listeners) + { + listener.creditStateChanged(!suspended); + } + } + + protected final void setSuspended(final boolean suspended) + { + if(_suspended.compareAndSet(!suspended, suspended)) + { + notifyListeners(suspended); + } + } + + protected final void notifyIncreaseBytesCredit() + { + notifyListeners(false); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java new file mode 100644 index 0000000000..96a1071135 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -0,0 +1,77 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; +import java.util.HashSet; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class BytesOnlyCreditManager extends AbstractFlowCreditManager +{ + private final AtomicLong _bytesCredit; + + public BytesOnlyCreditManager(long initialCredit) + { + _bytesCredit = new AtomicLong(initialCredit); + } + + public void addCredit(long messageCredit, long bytesCredit) + { + _bytesCredit.addAndGet(bytesCredit); + setSuspended(false); + } + + public void removeAllCredit() + { + _bytesCredit.set(0L); + } + + public boolean hasCredit() + { + return _bytesCredit.get() > 0L; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + final long msgSize = msg.getSize(); + if(hasCredit()) + { + if(_bytesCredit.addAndGet(-msgSize) >= 0) + { + return true; + } + else + { + _bytesCredit.addAndGet(msgSize); + setSuspended(true); + return false; + } + } + else + { + return false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java new file mode 100644 index 0000000000..a249a6e63a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java @@ -0,0 +1,44 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface FlowCreditManager +{ + + public static interface FlowCreditManagerListener + { + void creditStateChanged(boolean hasCredit); + } + + void addStateListener(FlowCreditManagerListener listener); + + boolean removeListener(FlowCreditManagerListener listener); + + public void addCredit(long messageCredit, long bytesCredit); + + public void removeAllCredit(); + + public boolean hasCredit(); + + public boolean useCreditForMessage(AMQMessage msg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java new file mode 100644 index 0000000000..d63431c3eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java @@ -0,0 +1,44 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + public void addCredit(long messageCredit, long bytesCredit) + { + } + + public void removeAllCredit() + { + } + + public boolean hasCredit() + { + return true; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java new file mode 100644 index 0000000000..9c377481de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -0,0 +1,79 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class MessageAndBytesCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + private long _messageCredit; + private long _bytesCredit; + + MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) + { + _messageCredit = messageCredit; + _bytesCredit = bytesCredit; + } + + public synchronized void addCredit(long messageCredit, long bytesCredit) + { + _messageCredit += messageCredit; + _bytesCredit += bytesCredit; + setSuspended(hasCredit()); + } + + public synchronized void removeAllCredit() + { + _messageCredit = 0L; + _bytesCredit = 0L; + setSuspended(true); + } + + public synchronized boolean hasCredit() + { + return (_messageCredit > 0L) && ( _bytesCredit > 0L ); + } + + public synchronized boolean useCreditForMessage(AMQMessage msg) + { + if(_messageCredit == 0L) + { + setSuspended(true); + return false; + } + else + { + final long msgSize = msg.getSize(); + if(msgSize > _bytesCredit) + { + setSuspended(true); + return false; + } + _messageCredit--; + _bytesCredit -= msgSize; + setSuspended(false); + return true; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java new file mode 100644 index 0000000000..c1b3a09006 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java @@ -0,0 +1,76 @@ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.concurrent.atomic.AtomicLong; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class MessageOnlyCreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + private final AtomicLong _messageCredit; + + public MessageOnlyCreditManager(final long initialCredit) + { + _messageCredit = new AtomicLong(initialCredit); + } + + public void addCredit(long messageCredit, long bytesCredit) + { + setSuspended(false); + _messageCredit.addAndGet(messageCredit); + } + + public void removeAllCredit() + { + setSuspended(true); + _messageCredit.set(0L); + } + + public boolean hasCredit() + { + return _messageCredit.get() > 0L; + } + + public boolean useCreditForMessage(AMQMessage msg) + { + if(hasCredit()) + { + if(_messageCredit.addAndGet(-1L) >= 0) + { + setSuspended(false); + return true; + } + else + { + _messageCredit.addAndGet(1L); + setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java new file mode 100644 index 0000000000..be0300f2c1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java @@ -0,0 +1,185 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.queue.AMQMessage; + +public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager +{ + + private volatile long _bytesCreditLimit; + private volatile long _messageCreditLimit; + + private volatile long _bytesCredit; + private volatile long _messageCredit; + + public Pre0_10CreditManager(long bytesCreditLimit, long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + _bytesCredit = bytesCreditLimit; + _messageCredit = messageCreditLimit; + } + + + public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit) + { + long bytesCreditChange = bytesCreditLimit - _bytesCreditLimit; + long messageCreditChange = messageCreditLimit - _messageCreditLimit; + + + + if(bytesCreditChange != 0L) + { + if(bytesCreditLimit == 0L) + { + _bytesCredit = 0; + } + else + { + _bytesCredit += bytesCreditChange; + } + } + + + if(messageCreditChange != 0L) + { + if(messageCreditLimit == 0L) + { + _messageCredit = 0; + } + else + { + _messageCredit += messageCreditChange; + } + } + + + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + + setSuspended(!hasCredit()); + + } + + + public synchronized void addCredit(final long messageCredit, final long bytesCredit) + { + final long messageCreditLimit = _messageCreditLimit; + boolean notifyIncrease = true; + if(messageCreditLimit != 0L) + { + notifyIncrease = (_messageCredit != 0); + long newCredit = _messageCredit + messageCredit; + _messageCredit = newCredit > messageCreditLimit ? messageCreditLimit : newCredit; + } + + + final long bytesCreditLimit = _bytesCreditLimit; + if(bytesCreditLimit != 0L) + { + long newCredit = _bytesCredit + bytesCredit; + _bytesCredit = newCredit > bytesCreditLimit ? bytesCreditLimit : newCredit; + if(notifyIncrease && bytesCredit>0) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + public synchronized void removeAllCredit() + { + _bytesCredit = 0L; + _messageCredit = 0L; + setSuspended(!hasCredit()); + } + + public synchronized boolean hasCredit() + { + return (_bytesCreditLimit == 0L || _bytesCredit > 0) + && (_messageCreditLimit == 0L || _messageCredit > 0); + } + + public synchronized boolean useCreditForMessage(final AMQMessage msg) + { + if(_messageCreditLimit != 0L) + { + if(_messageCredit != 0L) + { + if(_bytesCreditLimit == 0L) + { + _messageCredit--; + + return true; + } + else + { + if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + { + _messageCredit--; + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + } + else + { + setSuspended(true); + return false; + } + } + else + { + if(_bytesCreditLimit == 0L) + { + + return true; + } + else + { + if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit)) + { + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java new file mode 100644 index 0000000000..e64eaeae76 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -0,0 +1,61 @@ +package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +/** + * @author Apache Software Foundation + * + * + */ +public class AccessRequestHandler implements StateAwareMethodListener +{ + private static final AccessRequestHandler _instance = new AccessRequestHandler(); + + + public static AccessRequestHandler getInstance() + { + return _instance; + } + + private AccessRequestHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + // We don't implement access control class, but to keep clients happy that expect it + // always use the "0" ticket. + AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java new file mode 100644 index 0000000000..f90e7c3dff --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicAckBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class BasicAckMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicAckMethodHandler.class); + + private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); + + public static BasicAckMethodHandler getInstance() + { + return _instance; + } + + private BasicAckMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicAckBody body, int channelId) throws AMQException + { + AMQProtocolSession protocolSession = stateManager.getProtocolSession(); + + + if (_log.isDebugEnabled()) + { + _log.debug("Ack(Tag:" + body.getDeliveryTag() + ":Mult:" + body.getMultiple() + ") received on channel " + channelId); + } + + final AMQChannel channel = protocolSession.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + // this method throws an AMQException if the delivery tag is not known + channel.acknowledgeMessage(body.getDeliveryTag(), body.getMultiple()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java new file mode 100644 index 0000000000..29054f55c1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -0,0 +1,74 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicCancelBody; +import org.apache.qpid.framing.BasicCancelOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicCancelMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicCancelMethodHandler.class); + + private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); + + public static BasicCancelMethodHandler getInstance() + { + return _instance; + } + + private BasicCancelMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicCancelBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + final AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + if (_log.isDebugEnabled()) + { + _log.debug("BasicCancel: for:" + body.getConsumerTag() + + " nowait:" + body.getNowait()); + } + + channel.unsubscribeConsumer(body.getConsumerTag()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + BasicCancelOkBody cancelOkBody = methodRegistry.createBasicCancelOkBody(body.getConsumerTag()); + session.writeFrame(cancelOkBody.generateFrame(channelId)); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java new file mode 100644 index 0000000000..08610f24cd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -0,0 +1,173 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ConsumerTagNotUniqueException; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicConsumeMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicConsumeMethodHandler.class); + + private static final BasicConsumeMethodHandler _instance = new BasicConsumeMethodHandler(); + + public static BasicConsumeMethodHandler getInstance() + { + return _instance; + } + + private BasicConsumeMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicConsumeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + + + AMQChannel channel = session.getChannel(channelId); + + VirtualHost vHost = session.getVirtualHost(); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("BasicConsume: from '" + body.getQueue() + + "' for:" + body.getConsumerTag() + + " nowait:" + body.getNowait() + + " args:" + body.getArguments()); + } + + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue().intern()); + + if (queue == null) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("No queue for '" + body.getQueue() + "'"); + } + if (body.getQueue() != null) + { + String msg = "No such queue, '" + body.getQueue() + "'"; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg); + } + else + { + String msg = "No queue name provided, no default queue defined."; + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg); + } + } + else + { + + final AMQShortString consumerTagName; + + // Check authz + if (!vHost.getAccessManager().authoriseConsume(session, + body.getExclusive(), body.getNoAck(), + body.getNoLocal(), body.getNowait(), queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + if (body.getConsumerTag() != null) + { + consumerTagName = body.getConsumerTag().intern(); + } + else + { + consumerTagName = null; + } + + try + { + AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(), + body.getArguments(), body.getNoLocal(), body.getExclusive()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + + + } + catch (org.apache.qpid.AMQInvalidArgumentException ise) + { + _logger.debug("Closing connection due to invalid selector"); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelCloseBody(AMQConstant.INVALID_ARGUMENT.getCode(), + new AMQShortString(ise.getMessage()), + body.getClazz(), + body.getMethod()); + session.writeFrame(responseBody.generateFrame(channelId)); + + + } + catch (ConsumerTagNotUniqueException e) + { + AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + msg, // replytext + body.getClazz(), + body.getMethod()); + session.writeFrame(responseBody.generateFrame(0)); + } + catch (AMQQueue.ExistingExclusiveSubscription e) + { + throw body.getChannelException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " as it already has an existing exclusive consumer"); + } + catch (AMQQueue.ExistingSubscriptionPreventsExclusive e) + { + throw body.getChannelException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " exclusively as it already has a consumer"); + } + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java new file mode 100644 index 0000000000..001b7858ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.MessageOnlyCreditManager; +import org.apache.qpid.server.subscription.SubscriptionImpl; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.SimpleAMQQueue; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + VirtualHost vHost = session.getVirtualHost(); + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); + if (queue == null) + { + _log.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue()+ "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined."); + } + } + else + { + + //Perform ACLs + if (!vHost.getAccessManager().authoriseConsume(session, body.getNoAck(), queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + if (!performGet(queue,session, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + // TODO - set clusterId + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } + } + + public static boolean performGet(final AMQQueue queue, + final AMQProtocolSession session, + final AMQChannel channel, + final boolean acks) + throws AMQException + { + + final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); + + final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod() + { + + int _msg; + + public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) + throws AMQException + { + singleMessageCredit.useCreditForMessage(entry.getMessage()); + session.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(), + deliveryTag, queue.getMessageCount()); + + } + }; + final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, null); + } + }; + + Subscription sub; + if(acks) + { + sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod); + } + else + { + sub = new GetNoAckSubscription(channel, + session, + null, + null, + false, + singleMessageCredit, + getDeliveryMethod, + getRecordMethod); + } + + queue.registerSubscription(sub,false); + queue.flushSubscription(sub); + queue.unregisterSubscription(sub); + return(!singleMessageCredit.hasCredit()); + + + } + + public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription + { + public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + public boolean wouldSuspend(QueueEntry msg) + { + return !getCreditManager().useCreditForMessage(msg.getMessage()); + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java new file mode 100644 index 0000000000..a7d3ad6217 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -0,0 +1,106 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicPublishMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicPublishMethodHandler.class); + + private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); + + + public static BasicPublishMethodHandler getInstance() + { + return _instance; + } + + private BasicPublishMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicPublishBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Publish received on channel " + channelId); + } + + AMQShortString exchange = body.getExchange(); + // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? + if (exchange == null) + { + exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; + + } + + VirtualHost vHost = session.getVirtualHost(); + Exchange e = vHost.getExchangeRegistry().getExchange(exchange); + // if the exchange does not exist we raise a channel exception + if (e == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name"); + } + 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 = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //Access Control + if (!vHost.getAccessManager().authorisePublish(session, + body.getImmediate(), body.getMandatory(), + body.getRoutingKey(), e)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body); + info.setExchange(exchange); + channel.setPublishFrame(info, e); + } + } + +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java new file mode 100644 index 0000000000..dd3281c65f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicQosBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class BasicQosHandler implements StateAwareMethodListener +{ + private static final BasicQosHandler _instance = new BasicQosHandler(); + + public static BasicQosHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicQosBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount()); + + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java new file mode 100644 index 0000000000..c7842cd643 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.BasicRecoverOkBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, BasicRecoverBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v8_0)) + { + MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java new file mode 100644 index 0000000000..2c264c3d45 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java @@ -0,0 +1,75 @@ +package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.BasicRecoverSyncBody; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class); + + private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler(); + + public static BasicRecoverSyncMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.debug("Recover received on protocol session " + session + " and channel " + channelId); + AMQChannel channel = session.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.resend(body.getRequeue()); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(session.getProtocolVersion().equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + session.writeFrame(recoverOk.generateFrame(channelId)); + + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java new file mode 100644 index 0000000000..f3cab10ed7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -0,0 +1,125 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicRejectBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicRejectMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRejectMethodHandler.class); + + private static BasicRejectMethodHandler _instance = new BasicRejectMethodHandler(); + + public static BasicRejectMethodHandler getInstance() + { + return _instance; + } + + private BasicRejectMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicRejectBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting:" + body.getDeliveryTag() + + ": Requeue:" + body.getRequeue() + + //": Resend:" + evt.getMethod().resend + + " on channel:" + channel.debugIdentity()); + } + + long deliveryTag = body.getDeliveryTag(); + + QueueEntry message = channel.getUnacknowledgedMessageMap().get(deliveryTag); + + if (message == null) + { + _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag); +// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known"); + } + else + { + if (message.isQueueDeleted()) + { + _logger.warn("Message's Queue as already been purged, unable to Reject. " + + "Dropping message should use Dead Letter Queue"); + message = channel.getUnacknowledgedMessageMap().remove(deliveryTag); + if(message != null) + { + message.discard(channel.getStoreContext()); + } + //sendtoDeadLetterQueue(msg) + return; + } + + if (!message.getMessage().isReferenced()) + { + _logger.warn("Message as already been purged, unable to Reject."); + return; + } + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage().debugIdentity() + + ": Requeue:" + body.getRequeue() + + //": Resend:" + evt.getMethod().resend + + " on channel:" + channel.debugIdentity()); + } + + // If we haven't requested message to be resent to this consumer then reject it from ever getting it. + //if (!evt.getMethod().resend) + { + message.reject(); + } + + if (body.getRequeue()) + { + channel.requeue(deliveryTag); + } + else + { + _logger.warn("Dropping message as requeue not required and there is no dead letter queue"); + message = channel.getUnacknowledgedMessageMap().remove(deliveryTag); + //sendtoDeadLetterQueue(AMQMessage message) +// message.queue = channel.getDefaultDeadLetterQueue(); +// channel.requeue(deliveryTag); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java new file mode 100644 index 0000000000..9133cce6b7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +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, ChannelCloseBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isInfoEnabled()) + { + _logger.info("Received channel close for id " + channelId + " citing class " + body.getClassId() + + " and method " + body.getMethodId()); + } + + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel"); + } + + session.closeChannel(channelId); + // Client requested closure so we don't wait for ok we send it + stateManager.getProtocolSession().closeChannelOk(channelId); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + ChannelCloseOkBody responseBody = methodRegistry.createChannelCloseOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java new file mode 100644 index 0000000000..a857490e7e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ChannelCloseOkBody body, int channelId) throws AMQException + { + + _logger.info("Received channel-close-ok for channel-id " + channelId); + + // Let the Protocol Session know the channel is now closed. + stateManager.getProtocolSession().closeChannelOk(channelId); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java new file mode 100644 index 0000000000..696ca8a63b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ChannelFlowBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setSuspended(!body.getActive()); + _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive()); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelFlowOkBody(body.getActive()); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java new file mode 100644 index 0000000000..054674aed4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -0,0 +1,103 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.UUID; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ChannelOpenHandler implements StateAwareMethodListener +{ + private static ChannelOpenHandler _instance = new ChannelOpenHandler(); + + public static ChannelOpenHandler getInstance() + { + return _instance; + } + + private ChannelOpenHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ChannelOpenBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + + final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getMessageStore() + ); + session.addChannel(channel); + + ChannelOpenOkBody response; + + ProtocolVersion pv = session.getProtocolVersion(); + + if(pv.equals(ProtocolVersion.v8_0)) + { + MethodRegistry_8_0 methodRegistry = (MethodRegistry_8_0) MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + response = methodRegistry.createChannelOpenOkBody(); + + } + else if(pv.equals(ProtocolVersion.v0_9)) + { + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + UUID uuid = UUID.randomUUID(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + try + { + dataOut.writeLong(uuid.getMostSignificantBits()); + dataOut.writeLong(uuid.getLeastSignificantBits()); + dataOut.flush(); + dataOut.close(); + } + catch (IOException e) + { + // This *really* shouldn't happen as we're not doing any I/O + throw new RuntimeException("I/O exception when writing to byte array", e); + } + + // should really associate this channelId to the session + byte[] channelName = output.toByteArray(); + + response = methodRegistry.createChannelOpenOkBody(channelName); + } + else + { + throw new AMQException(AMQConstant.INTERNAL_ERROR, "Got channel open for protocol version not catered for: " + pv, null); + } + + + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java new file mode 100644 index 0000000000..dade5d5f54 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -0,0 +1,72 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionCloseBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isInfoEnabled()) + { + _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" + + body.getReplyText() + " for " + session); + } + try + { + session.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + ConnectionCloseOkBody responseBody = methodRegistry.createConnectionCloseOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java new file mode 100644 index 0000000000..bc6e5ab403 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionCloseOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + //todo should this not do more than just log the method? + _logger.info("Received Connection-close-ok"); + + try + { + stateManager.changeState(AMQState.CONNECTION_CLOSED); + session.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java new file mode 100644 index 0000000000..824f084f57 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -0,0 +1,102 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; + +public class ConnectionOpenMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); + + private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); + + public static ConnectionOpenMethodHandler getInstance() + { + return _instance; + } + + private ConnectionOpenMethodHandler() + { + } + + private static AMQShortString generateClientID() + { + return new AMQShortString(Long.toString(System.currentTimeMillis())); + } + + public void methodReceived(AMQStateManager stateManager, ConnectionOpenBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + + //ignore leading '/' + String virtualHostName; + if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/') + { + virtualHostName = new StringBuilder(body.getVirtualHost().subSequence(1, body.getVirtualHost().length())).toString(); + } + else + { + virtualHostName = body.getVirtualHost() == null ? null : String.valueOf(body.getVirtualHost()); + } + + VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); + + if (virtualHost == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'"); + } + else + { + session.setVirtualHost(virtualHost); + + //Perform ACL + if (!virtualHost.getAccessManager().authoriseConnect(session, virtualHost)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts + if (session.getContextKey() == null) + { + session.setContextKey(generateClientID()); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost()); + + stateManager.changeState(AMQState.CONNECTION_OPEN); + + session.writeFrame(responseBody.generateFrame(channelId)); + + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java new file mode 100644 index 0000000000..a2a6faf21b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -0,0 +1,126 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionSecureOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +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, ConnectionSecureOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + + SaslServer ss = session.getSaslServer(); + if (ss == null) + { + throw new AMQException("No SASL context set up in session"); + } + MethodRegistry methodRegistry = session.getMethodRegistry(); + AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); + switch (authResult.status) + { + case ERROR: + Exception cause = authResult.getCause(); + + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + // This should be abstracted + stateManager.changeState(AMQState.CONNECTION_CLOSING); + + ConnectionCloseBody connectionCloseBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + session.writeFrame(connectionCloseBody.generateFrame(0)); + disposeSaslServer(session); + break; + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + + ConnectionTuneBody tuneBody = + methodRegistry.createConnectionTuneBody(0xFFFF, + ConnectionStartOkMethodHandler.getConfiguredFrameSize(), + ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); + session.writeFrame(tuneBody.generateFrame(0)); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + disposeSaslServer(session); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + session.writeFrame(secureBody.generateFrame(0)); + } + } + + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java new file mode 100644 index 0000000000..6698ae888a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -0,0 +1,163 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionStartOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + + +public class ConnectionStartOkMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionStartOkMethodHandler.class); + + private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler(); + + public static ConnectionStartOkMethodHandler getInstance() + { + return _instance; + } + + private ConnectionStartOkMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ConnectionStartOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + _logger.info("SASL Mechanism selected: " + body.getMechanism()); + _logger.info("Locale selected: " + body.getLocale()); + + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); + + SaslServer ss = null; + try + { + ss = authMgr.createSaslServer(String.valueOf(body.getMechanism()), session.getLocalFQDN()); + + if (ss == null) + { + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism() + ); + } + + session.setSaslServer(ss); + + AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); + + //save clientProperties + if (session.getClientProperties() == null) + { + session.setClientProperties(body.getClientProperties()); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + + switch (authResult.status) + { + case ERROR: + Exception cause = authResult.getCause(); + + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + stateManager.changeState(AMQState.CONNECTION_CLOSING); + + ConnectionCloseBody closeBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + session.writeFrame(closeBody.generateFrame(0)); + disposeSaslServer(session); + break; + + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + + ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, + getConfiguredFrameSize(), + ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); + session.writeFrame(tuneBody.generateFrame(0)); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + session.writeFrame(secureBody.generateFrame(0)); + } + } + catch (SaslException e) + { + disposeSaslServer(session); + 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 ServerConfiguration config = ApplicationRegistry.getInstance().getConfiguration(); + final int framesize = config.getFrameSize(); + _logger.info("Framesize set to " + framesize); + return framesize; + } +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java new file mode 100644 index 0000000000..0fe8c5dc92 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionTuneOkBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +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, ConnectionTuneOkBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + if (_logger.isDebugEnabled()) + { + _logger.debug(body); + } + stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); + session.initHeartbeats(body.getHeartbeat()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java new file mode 100644 index 0000000000..ccd42204d9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -0,0 +1,178 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.exchange.Exchange; +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.qpid.server.virtualhost.VirtualHost; + +/** + * @author Apache Software Foundation + * + * + */ +public class ExchangeBoundHandler implements StateAwareMethodListener +{ + private static final ExchangeBoundHandler _instance = new ExchangeBoundHandler(); + + public static final int OK = 0; + + public static final int EXCHANGE_NOT_FOUND = 1; + + public static final int QUEUE_NOT_FOUND = 2; + + public static final int NO_BINDINGS = 3; + + public static final int QUEUE_NOT_BOUND = 4; + + public static final int NO_QUEUE_BOUND_WITH_RK = 5; + + public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; + + public static ExchangeBoundHandler getInstance() + { + return _instance; + } + + private ExchangeBoundHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ExchangeBoundBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MethodRegistry methodRegistry = session.getMethodRegistry(); + + + + + AMQShortString exchangeName = body.getExchange(); + AMQShortString queueName = body.getQueue(); + AMQShortString routingKey = body.getRoutingKey(); + if (exchangeName == null) + { + throw new AMQException("Exchange exchange must not be null"); + } + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + ExchangeBoundOkBody response; + if (exchange == null) + { + + + response = methodRegistry.createExchangeBoundOkBody(EXCHANGE_NOT_FOUND, + new AMQShortString("Exchange " + exchangeName + " not found")); + } + else if (routingKey == null) + { + if (queueName == null) + { + if (exchange.hasBindings()) + { + response = methodRegistry.createExchangeBoundOkBody(OK, null); + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_BINDINGS, // replyCode + null); // replyText + } + } + else + { + + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + new AMQShortString("Queue " + queueName + " not found")); // replyText + } + else + { + if (exchange.isBound(queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_BOUND, // replyCode + new AMQShortString("Queue " + queueName + " not bound to exchange " + exchangeName)); // replyText + } + } + } + } + else if (queueName != null) + { + AMQQueue queue = queueRegistry.getQueue(queueName); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + new AMQShortString("Queue " + queueName + " not found")); // replyText + } + else + { + if (exchange.isBound(body.getRoutingKey(), queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode + new AMQShortString("Queue " + queueName + " not bound with routing key " + + body.getRoutingKey() + " to exchange " + exchangeName)); // replyText + } + } + } + else + { + if (exchange.isBound(body.getRoutingKey())) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_QUEUE_BOUND_WITH_RK, // replyCode + new AMQShortString("No queue bound with routing key " + body.getRoutingKey() + + " to exchange " + exchangeName)); // replyText + } + } + session.writeFrame(response.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java new file mode 100644 index 0000000000..ba60808492 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -0,0 +1,122 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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 ExchangeDeclareHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, ExchangeDeclareBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + if (!body.getPassive()) + { + // Perform ACL if request is not passive + if (!virtualHost.getAccessManager().authoriseCreateExchange(session, body.getAutoDelete(), + body.getDurable(), body.getExchange(), body.getInternal(), body.getNowait(), body.getPassive(), + body.getType())) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + body.getExchange()); + } + synchronized(exchangeRegistry) + { + Exchange exchange = exchangeRegistry.getExchange(body.getExchange()); + + + + if (exchange == null) + { + if(body.getPassive() && ((body.getType() == null) || body.getType().length() ==0)) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + body.getExchange()); + } + else + { + try + { + + exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), + body.getType() == null ? null : body.getType().intern(), + body.getDurable(), + body.getPassive(), body.getTicket()); + exchangeRegistry.registerExchange(exchange); + } + catch(AMQUnknownExchangeType e) + { + throw body.getConnectionException(AMQConstant.COMMAND_INVALID, "Unknown exchange: " + body.getExchange(),e); + } + } + } + else if (!exchange.getType().equals(body.getType())) + { + + throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null); + } + + } + if(!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java new file mode 100644 index 0000000000..bd4b610933 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ExchangeDeleteBody; +import org.apache.qpid.framing.ExchangeDeleteOkBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.exchange.ExchangeInUseException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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, ExchangeDeleteBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete(session, + exchangeRegistry.getExchange(body.getExchange()))) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + try + { + exchangeRegistry.unregisterExchange(body.getExchange(), body.getIfUnused()); + + ExchangeDeleteOkBody responseBody = session.getMethodRegistry().createExchangeDeleteOkBody(); + + session.writeFrame(responseBody.generateFrame(channelId)); + } + catch (ExchangeInUseException e) + { + // TODO: sort out consistent channel close mechanism that does all clean up etc. + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java new file mode 100644 index 0000000000..ac516b6133 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.concurrent.Executor; + +/** + * An executor that executes the task on the current thread. + */ +public class OnCurrentThreadExecutor implements Executor +{ + public void execute(Runnable command) + { + command.run(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java new file mode 100644 index 0000000000..84491c1d2e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -0,0 +1,143 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidRoutingKeyException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +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, QueueBindBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + + final AMQQueue queue; + final AMQShortString routingKey; + + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); + } + + if (body.getRoutingKey() == null) + { + routingKey = queue.getName(); + } + else + { + routingKey = body.getRoutingKey().intern(); + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + routingKey = body.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : body.getRoutingKey().intern(); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); + } + + + try + { + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseBind(session, exch, + queue, routingKey)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + if (!exch.isBound(routingKey, body.getArguments(), queue)) + { + queue.bind(exch, routingKey, body.getArguments()); + } + } + catch (AMQInvalidRoutingKeyException rke) + { + throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); + } + catch (AMQException e) + { + throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); + } + + if (_log.isInfoEnabled()) + { + _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java new file mode 100644 index 0000000000..b705ea7dba --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -0,0 +1,203 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.QueueDeclareOkBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class QueueDeclareHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(QueueDeclareHandler.class); + + private static final QueueDeclareHandler _instance = new QueueDeclareHandler(); + + public static QueueDeclareHandler getInstance() + { + return _instance; + } + + public boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister(); + + private final AtomicInteger _counter = new AtomicInteger(); + + public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + + + if (!body.getPassive()) + { + // Perform ACL if request is not passive + if (!virtualHost.getAccessManager().authoriseCreateQueue(session, body.getAutoDelete(), body.getDurable(), + body.getExclusive(), body.getNowait(), body.getPassive(), body.getQueue())) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + } + + final AMQShortString queueName; + + // if we aren't given a queue name, we create one which we return to the client + + if ((body.getQueue() == null) || (body.getQueue().length() == 0)) + { + queueName = createName(); + } + else + { + queueName = body.getQueue().intern(); + } + + AMQQueue queue; + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + synchronized (queueRegistry) + { + + + + if (((queue = queueRegistry.getQueue(queueName)) == null)) + { + + if (body.getPassive()) + { + String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg); + } + else + { + queue = createQueue(queueName, body, virtualHost, session); + if (queue.isDurable() && !queue.isAutoDelete()) + { + store.createQueue(queue, body.getArguments()); + } + queueRegistry.registerQueue(queue); + if (autoRegister) + { + Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); + + queue.bind(defaultExchange, queueName, null); + _logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getName() + ")"); + } + } + } + else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) + { + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + queueName + "')," + + " as exclusive queue with same name " + + "declared on another client ID('" + + queue.getOwner() + "')"); + } + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //set this as the default queue on the channel: + channel.setDefaultQueue(queue); + } + + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + QueueDeclareOkBody responseBody = + methodRegistry.createQueueDeclareOkBody(queueName, + queue.getMessageCount(), + queue.getConsumerCount()); + session.writeFrame(responseBody.generateFrame(channelId)); + + _logger.info("Queue " + queueName + " declared successfully"); + } + } + + protected AMQShortString createName() + { + return new AMQShortString("tmp_" + UUID.randomUUID()); + } + + protected AMQQueue createQueue(final AMQShortString queueName, + QueueDeclareBody body, + VirtualHost virtualHost, + final AMQProtocolSession session) + throws AMQException + { + final QueueRegistry registry = virtualHost.getQueueRegistry(); + AMQShortString owner = body.getExclusive() ? session.getContextKey() : null; + + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost, + body.getArguments()); + + + if (body.getExclusive() && !body.getDurable()) + { + final AMQProtocolSession.Task deleteQueueTask = + new AMQProtocolSession.Task() + { + public void doTask(AMQProtocolSession session) throws AMQException + { + if (registry.getQueue(queueName) == queue) + { + queue.delete(); + } + } + }; + + session.addSessionCloseTask(deleteQueueTask); + + queue.addQueueDeleteTask(new AMQQueue.Task() + { + public void doTask(AMQQueue queue) + { + session.removeSessionCloseTask(deleteQueueTask); + } + }); + }// if exclusive and not durable + + return queue; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java new file mode 100644 index 0000000000..b397db9246 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -0,0 +1,127 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueueDeleteBody; +import org.apache.qpid.framing.QueueDeleteOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +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.qpid.server.store.MessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueueDeleteHandler implements StateAwareMethodListener +{ + private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); + + public static QueueDeleteHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueueDeleteHandler() + { + this(true); + } + + public QueueDeleteHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + + } + + public void methodReceived(AMQStateManager stateManager, QueueDeleteBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + MessageStore store = virtualHost.getMessageStore(); + + AMQQueue queue; + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if (queue == null) + { + if (_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + if (body.getIfEmpty() && !queue.isEmpty()) + { + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is not empty."); + } + else if (body.getIfUnused() && !queue.isUnused()) + { + // TODO - Error code + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used."); + + } + else + { + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete(session, queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + int purged = queue.delete(); + + + if (queue.isDurable()) + { + store.removeQueue(queue); + } + + MethodRegistry methodRegistry = session.getMethodRegistry(); + QueueDeleteOkBody responseBody = methodRegistry.createQueueDeleteOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java new file mode 100644 index 0000000000..2768518f53 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.QueuePurgeBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +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.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + AMQChannel channel = session.getChannel(channelId); + + + AMQQueue queue; + if(body.getQueue() == null) + { + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); + } + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + + //Perform ACLs + if (!virtualHost.getAccessManager().authorisePurge(session, queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + long purged = queue.clearQueue(channel.getStoreContext()); + + + if(!body.getNowait()) + { + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java new file mode 100644 index 0000000000..d4272239d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -0,0 +1,137 @@ +package org.apache.qpid.server.handler; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidRoutingKeyException; +import org.apache.qpid.protocol.AMQConstant; + +public class QueueUnbindHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(QueueUnbindHandler.class); + + private static final QueueUnbindHandler _instance = new QueueUnbindHandler(); + + public static QueueUnbindHandler getInstance() + { + return _instance; + } + + private QueueUnbindHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueUnbindBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + VirtualHost virtualHost = session.getVirtualHost(); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + + final AMQQueue queue; + final AMQShortString routingKey; + + if (body.getQueue() == null) + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null"); + } + + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); + + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(); + } + + if (queue == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + final Exchange exch = exchangeRegistry.getExchange(body.getExchange()); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); + } + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseUnbind(session, exch, routingKey, queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + + try + { + queue.unBind(exch, routingKey, body.getArguments()); + } + catch (AMQInvalidRoutingKeyException rke) + { + throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); + } + catch (AMQException e) + { + if(e.getErrorCode() == AMQConstant.NOT_FOUND) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND,e.getMessage(),e); + } + throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); + } + + if (_log.isInfoEnabled()) + { + _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + + MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueueUnbindOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java new file mode 100644 index 0000000000..9475b83c8f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java @@ -0,0 +1,566 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.Map; +import java.util.HashMap; + +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.framing.*; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl implements MethodDispatcher +{ + private final AMQStateManager _stateManager; + + private static interface DispatcherFactory + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager); + } + + private static final Map _dispatcherFactories = + new HashMap(); + + + static + { + _dispatcherFactories.put(ProtocolVersion.v8_0, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_8_0(stateManager); + } + }); + + _dispatcherFactories.put(ProtocolVersion.v0_9, + new DispatcherFactory() + { + public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager) + { + return new ServerMethodDispatcherImpl_0_9(stateManager); + } + }); + + } + + + private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance(); + private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance(); + private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance(); + private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance(); + private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance(); + private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance(); + private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance(); + private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance(); + private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance(); + private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance(); + private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance(); + private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance(); + private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance(); + private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance(); + private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance(); + private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance(); + private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance(); + private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance(); + private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance(); + private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance(); + private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance(); + private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance(); + private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance(); + private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance(); + private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance(); + private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance(); + private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance(); + private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance(); + private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance(); + + + + public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion) + { + return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager); + } + + + public ServerMethodDispatcherImpl(AMQStateManager stateManager) + { + _stateManager = stateManager; + } + + + protected AMQStateManager getStateManager() + { + return _stateManager; + } + + + + public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException + { + _accessRequestHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException + { + _basicAckMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException + { + _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException + { + _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException + { + _basicGetMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException + { + _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException + { + _basicQosHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException + { + _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException + { + _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException + { + _channelOpenHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException + { + _channelCloseHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException + { + _channelCloseOkHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException + { + _channelFlowHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException + { + _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException + { + _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException + { + _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException + { + _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException + { + _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException + { + _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException + { + _exchangeBoundHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException + { + _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException + { + _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException + { + _queueBindHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException + { + _queueDeclareHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException + { + _queueDeleteHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException + { + _queuePurgeHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException + { + _txCommitHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException + { + _txRollbackHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException + { + _txSelectHandler.methodReceived(_stateManager, body, channelId); + return true; + } + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java new file mode 100644 index 0000000000..8b1dca77ba --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp_0_9.MethodDispatcher_0_9; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + + + +public class ServerMethodDispatcherImpl_0_9 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_0_9 + +{ + + private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler = + BasicRecoverSyncMethodHandler.getInstance(); + private static final QueueUnbindHandler _queueUnbindHandler = + QueueUnbindHandler.getInstance(); + + + public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException + { + _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId); + return true; + } + + public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException + { + _queueUnbindHandler.methodReceived(getStateManager(),body,channelId); + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java new file mode 100644 index 0000000000..d599ca3d4e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.AMQException; + +public class ServerMethodDispatcherImpl_8_0 + extends ServerMethodDispatcherImpl + implements MethodDispatcher_8_0 +{ + public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager) + { + super(stateManager); + } + + public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException + { + return false; + } + + public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException + { + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java new file mode 100644 index 0000000000..9b23d88838 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxCommitBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxCommitHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(TxCommitHandler.class); + + private static TxCommitHandler _instance = new TxCommitHandler(); + + public static TxCommitHandler getInstance() + { + return _instance; + } + + private TxCommitHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxCommitBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + try + { + if (_log.isDebugEnabled()) + { + _log.debug("Commit received on channel " + channelId); + } + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.commit(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + channel.processReturns(); + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java new file mode 100644 index 0000000000..5f402f3fda --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxRollbackBody; +import org.apache.qpid.framing.TxRollbackOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxRollbackHandler implements StateAwareMethodListener +{ + private static TxRollbackHandler _instance = new TxRollbackHandler(); + + public static TxRollbackHandler getInstance() + { + return _instance; + } + + private TxRollbackHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + try + { + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.rollback(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + + + //Now resend all the unacknowledged messages back to the original subscribers. + //(Must be done after the TxnRollback-ok response). + // Why, are we not allowed to send messages back to client before the ok method? + channel.resend(false); + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java new file mode 100644 index 0000000000..308f5b73cf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxSelectBody; +import org.apache.qpid.framing.TxSelectOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class TxSelectHandler implements StateAwareMethodListener +{ + private static TxSelectHandler _instance = new TxSelectHandler(); + + public static TxSelectHandler getInstance() + { + return _instance; + } + + private TxSelectHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, TxSelectBody body, int channelId) throws AMQException + { + AMQProtocolSession session = stateManager.getProtocolSession(); + + AMQChannel channel = session.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + channel.setLocalTransactional(); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + TxSelectOkBody responseBody = methodRegistry.createTxSelectOkBody(); + session.writeFrame(responseBody.generateFrame(channelId)); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java new file mode 100644 index 0000000000..fb18519fe1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + + +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.AMQException; + +public class UnexpectedMethodException extends AMQException +{ + public UnexpectedMethodException(AMQMethodBody body) + { + super("Unexpected method recevied: " + body.getClass().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java new file mode 100644 index 0000000000..f723ab206c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +public interface LoggingManagement +{ + String TYPE = "LoggingManagement"; + int VERSION = 1; + + //TabularType and contained CompositeType key/description information + String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; + String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; + String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; + + /** + * Attribute to represent the log4j xml configuration file's LogWatch interval. + * @return The logwatch interval in seconds. + */ + @MBeanAttribute(name="Log4jLogWatchInterval", + description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") + Integer getLog4jLogWatchInterval(); + + /** + * Attribute to represent the available log4j logger output levels. + * @return The logging level names. + */ + @MBeanAttribute(name="AvailableLoggerLevels", description = "The values to which log output level can be set.") + String[] getAvailableLoggerLevels(); + + + //****** log4j runtime operations ****** // + + /** + * Sets the level of an active Log4J logger + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Retrieves a TabularData set of the active log4j loggers and their levels + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + */ + @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + + "for active log4j logger's.", impact = MBeanOperationInfo.INFO) + TabularData viewEffectiveRuntimeLoggerLevels(); + + /** + * Sets the level of the active Log4J RootLogger + * @param level The level to set the RootLogger to + * @return True if successful, false if unsuccessful (eg if an invalid level is specified) + */ + @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", + impact = MBeanOperationInfo.ACTION) + boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); + + /** + * Attribute to represent the level of the active Log4J RootLogger + * @return The level of the RootLogger. + */ + @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") + String getRuntimeRootLoggerLevel(); + + + //****** log4j XML configuration file operations ****** // + + /** + * Updates the level of an existing Log4J logger within the xml configuration file + * @param logger The name of the logger + * @param level The level to set the logger to + * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + + "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, + @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file + * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) + TabularData viewConfigFileLoggerLevels() throws IOException; + + /** + * Updates the level of the Log4J RootLogger within the xml configuration file if it is present + * @param level The level to set the logger to + * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) + * @throws IOException if there is an error parsing the configuration file. + */ + @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + + "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) + boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; + + /** + * Attribute to represent the level of the Log4J RootLogger within the xml configuration file + * @return The level of the RootLogger, or null if it is not present + */ + @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + + "in the log4j xml configuration file.") + String getConfigFileRootLoggerLevel() throws IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java new file mode 100644 index 0000000000..cd3f85f8ca --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -0,0 +1,674 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.management; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.Log4jEntityResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + + +/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */ +@MBeanDescription("Logging Management Interface") +public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement +{ + + private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); + private String _log4jConfigFileName; + private int _log4jLogWatchInterval; + private static final String[] LEVELS = new String[]{Level.ALL.toString(), Level.TRACE.toString(), + Level.DEBUG.toString(), Level.INFO.toString(), + Level.WARN.toString(), Level.ERROR.toString(), + Level.FATAL.toString(),Level.OFF.toString()}; + static TabularType _loggerLevelTabularType; + static CompositeType _loggerLevelCompositeType; + + static + { + try + { + OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; + + _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); + + _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", + _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing logger levels was incorrect."); + _loggerLevelTabularType = null; + } + } + + public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException + { + super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); + _log4jConfigFileName = log4jConfigFileName; + _log4jLogWatchInterval = log4jLogWatchInterval; + } + + public String getObjectInstanceName() + { + return LoggingManagement.TYPE; + } + + public Integer getLog4jLogWatchInterval() + { + return _log4jLogWatchInterval; + } + + public String[] getAvailableLoggerLevels() + { + return LEVELS; + } + @SuppressWarnings("unchecked") + public synchronized boolean setRuntimeLoggerLevel(String logger, String level) + { + //check specified level is valid + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + //check specified logger exists + Enumeration loggers = LogManager.getCurrentLoggers(); + Boolean loggerExists = false; + + while(loggers.hasMoreElements()) + { + Logger log = (Logger) loggers.nextElement(); + if (log.getName().equals(logger)) + { + loggerExists = true; + break; + } + } + + if(!loggerExists) + { + return false; + } + + //set the logger to the new level + _logger.info("Setting level to " + level + " for logger: " + logger); + + Logger log = Logger.getLogger(logger); + log.setLevel(newLevel); + + return true; + } + + @SuppressWarnings("unchecked") + public synchronized TabularData viewEffectiveRuntimeLoggerLevels() + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting levels for currently active log4j loggers"); + + Enumeration loggers = LogManager.getCurrentLoggers(); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Logger logger; + String loggerName; + String level; + + try + { + while(loggers.hasMoreElements()){ + logger = (Logger) loggers.nextElement(); + + loggerName = logger.getName(); + level = logger.getEffectiveLevel().toString(); + + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + + return loggerLevelList; + + } + + public synchronized String getRuntimeRootLoggerLevel() + { + Logger rootLogger = Logger.getRootLogger(); + + return rootLogger.getLevel().toString(); + } + + public synchronized boolean setRuntimeRootLoggerLevel(String level) + { + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + _logger.info("Setting RootLogger level to " + level); + + Logger log = Logger.getRootLogger(); + log.setLevel(newLevel); + + return true; + } + + //method to convert from a string to a log4j Level, throws exception if the given value is invalid + private Level getLevel(String level) throws Exception + { + Level newLevel = Level.toLevel(level); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new Exception("Invalid level name"); + } + + return newLevel; + } + + //handler to catch errors signalled by the JAXP parser and throw an appropriate exception + private class SaxErrorHandler implements ErrorHandler + { + + public void error(SAXParseException e) throws SAXException + { + throw new SAXException("Error parsing XML file: " + e.getMessage()); + } + + public void fatalError(SAXParseException e) throws SAXException + { + throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + } + + public void warning(SAXParseException e) throws SAXException + { + throw new SAXException("Warning parsing XML file: " + e.getMessage()); + } + } + + //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. + private synchronized Document parseConfigFile(String fileName) throws IOException + { + //check file was specified, exists, and is readable + if(fileName == null) + { + _logger.warn("No log4j XML configuration file has been set"); + throw new IOException("No log4j XML configuration file has been set"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); + throw new IOException("Specified log4j XML configuration file does not exist"); + } + else if (!configFile.canRead()) + { + _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); + throw new IOException("Specified log4j XML configuration file is not readable"); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document doc; + + ErrorHandler errHandler = new SaxErrorHandler(); + try + { + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + doc = docBuilder.parse(fileName); + } + catch (ParserConfigurationException e) + { + _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); + //recommended that MBeans should use java.* and javax.* exceptions only + throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); + } + catch (SAXException e) + { + _logger.warn("The specified log4j XML file is invalid: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); + } + catch (IOException e) + { + _logger.warn("Unable to parse the specified log4j XML file" + e); + throw new IOException("Unable to parse the specified log4j XML file", e); + } + + return doc; + } + + + private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + { + File log4jConfigFile = new File(log4jConfigFileName); + + if (!log4jConfigFile.canWrite()) + { + _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); + throw new IOException("Specified log4j XML configuration file is not writable"); + } + + Transformer transformer = null; + try + { + transformer = TransformerFactory.newInstance().newTransformer(); + } + catch (Exception e) + { + _logger.warn("Could not create an XML transformer: " +e); + return false; + } + + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); + DOMSource source = new DOMSource(doc); + + File tmp; + try + { + tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); + tmp.deleteOnExit(); + StreamResult result = new StreamResult(tmp); + transformer.transform(source, result); + } + catch (TransformerException e) + { + _logger.warn("Could not transform the XML into new file: " +e); + return false; + } + catch (IOException e) + { + _logger.warn("Could not create the new file: " +e); + return false; + } + + // Swap temp file in to replace existing configuration file. + File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + log4jConfigFile.renameTo(old); + return tmp.renameTo(log4jConfigFile); + } + + + /* The log4j XML configuration file DTD defines three possible element + * combinations for specifying optional logger+level settings. + * Must account for the following: + * + * OR + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + //retrieve the 'category' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + + String categoryName; + String priority = null; + + for (int i = 0; i < categoryElements.getLength(); i++) + { + Element categoryElement = (Element) categoryElements.item(i); + categoryName = categoryElement.getAttribute("name"); + + //retrieve the category's mandatory 'priority' or 'level' element's value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = categoryElement.getElementsByTagName("priority"); + NodeList levelElements = categoryElement.getElementsByTagName("level"); + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value").toUpperCase(); + } + else if (levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value").toUpperCase(); + } + else + { + //there is no exiting priority or level to view, move onto next category/logger + continue; + } + + try + { + Object[] itemData = {categoryName, priority}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + //retrieve the 'logger' element nodes + NodeList loggerElements = doc.getElementsByTagName("logger"); + + String loggerName; + String level; + + for (int i = 0; i < loggerElements.getLength(); i++) + { + Element loggerElement = (Element) loggerElements.item(i); + loggerName = loggerElement.getAttribute("name"); + + //retrieve the logger's mandatory 'level' element's value + //It may not be the only child node, so request by tag name. + NodeList levelElements = loggerElement.getElementsByTagName("level"); + + Element levelElement = (Element) levelElements.item(0); + level = levelElement.getAttribute("value").toUpperCase(); + + try + { + Object[] itemData = {loggerName, level}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } + } + + return loggerLevelList; + } + + public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for logger '" + logger + + "' in log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the 'category' and 'logger' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + NodeList loggerElements = doc.getElementsByTagName("logger"); + + //collect them into a single elements list + List logElements = new ArrayList(); + + for (int i = 0; i < categoryElements.getLength(); i++) + { + logElements.add((Element) categoryElements.item(i)); + } + for (int i = 0; i < loggerElements.getLength(); i++) + { + logElements.add((Element) loggerElements.item(i)); + } + + //try to locate the specified logger/category in the elements retrieved + Element logElement = null; + for (Element e : logElements) + { + if (e.getAttribute("name").equals(logger)) + { + logElement = e; + break; + } + } + + if (logElement == null) + { + //no loggers/categories with given name found, does not exist to update + _logger.warn("Specified logger does not exist in the configuration file: " +logger); + return false; + } + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = logElement.getElementsByTagName("priority"); + NodeList levelElements = logElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority or level element to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } + + + /* The log4j XML configuration file DTD defines 2 possible element + * combinations for specifying the optional root logger level settings + * Must account for the following: + * + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + _logger.info("Getting root logger level from log4j configuration file"); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + //there is not root logger definition + return null; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + String priority = null; + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value"); + } + else if(levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value"); + } + + if(priority != null) + { + return priority.toUpperCase(); + } + else + { + return null; + } + } + + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException + { + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } + + _logger.info("Setting level to " + level + " for the Root logger in " + + "log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + return false; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority/level to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java new file mode 100644 index 0000000000..c6e07f6f48 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -0,0 +1,97 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * This class provides additinal feature of Notification Broadcaster to the + * DefaultManagedObject. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public abstract class AMQManagedObject extends DefaultManagedObject + implements NotificationBroadcaster +{ + /** + * broadcaster support class + */ + protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); + + /** + * sequence number for notifications + */ + protected long _notificationSequenceNumber = 0; + + protected MBeanInfo _mbeanInfo; + + protected AMQManagedObject(Class managementInterface, String typeName, int version) + throws NotCompliantMBeanException + { + super(managementInterface, typeName, version); + 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java new file mode 100644 index 0000000000..67aee90ba4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -0,0 +1,200 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; + +/** + * 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; + private int _version; + + protected DefaultManagedObject(Class managementInterface, String typeName, int version) + throws NotCompliantMBeanException + { + super(managementInterface); + _managementInterface = managementInterface; + _typeName = typeName; + _version = version; + } + + public String getType() + { + return _typeName; + } + + public Class getManagementInterface() + { + return _managementInterface; + } + + public ManagedObject getParentObject() + { + return null; + } + + public void register() throws AMQException + { + try + { + getManagedObjectRegistry().registerObject(this); + } + catch (JMException e) + { + throw new AMQException("Error registering managed object " + this + ": " + e, e); + } + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + + public void unregister() throws AMQException + { + try + { + 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); + + objectName.append(","); + objectName.append("version=").append(_version); + + + return new ObjectName(objectName.toString()); + } + + protected ObjectName getObjectNameForSingleInstanceMBean() throws MalformedObjectNameException + { + StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); + + objectName.append(":type="); + objectName.append(getHierarchicalType(this)); + + String hierarchyName = getHierarchicalName(this); + if (hierarchyName != null) + { + objectName.append(","); + objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); + } + + objectName.append(","); + objectName.append("version=").append(_version); + + return new ObjectName(objectName.toString()); + } + + protected String getHierarchicalType(ManagedObject obj) + { + if (obj.getParentObject() != null) + { + String parentType = getHierarchicalType(obj.getParentObject()).toString(); + return parentType + "." + obj.getType(); + } + else + return obj.getType(); + } + + protected String getHierarchicalName(ManagedObject obj) + { + if (obj.getParentObject() != null) + { + String 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; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java new file mode 100644 index 0000000000..5a113de5be --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -0,0 +1,371 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; + +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.management.remote.rmi.RMIJRMPServerImpl; +import javax.management.remote.rmi.RMIServerImpl; +import javax.rmi.ssl.SslRMIClientSocketFactory; +import javax.rmi.ssl.SslRMIServerSocketFactory; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.rmi.AlreadyBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.UnicastRemoteObject; +import java.util.HashMap; +import java.util.Map; + +/** + * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no + * security features implemented like user authentication and authorisation. + */ +public class JMXManagedObjectRegistry implements ManagedObjectRegistry +{ + private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); + private static final Logger _startupLog = Logger.getLogger("Qpid.Broker"); + + public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; + public static final int MANAGEMENT_PORT_DEFAULT = 8999; + public static final int PORT_EXPORT_OFFSET = 100; + + private final MBeanServer _mbeanServer; + private Registry _rmiRegistry; + + + public JMXManagedObjectRegistry() throws AMQException + { + _log.info("Initialising managed object registry using platform MBean server"); + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + + // Retrieve the config parameters + boolean platformServer = appRegistry.getConfiguration().getPlatformMbeanserver(); + + _mbeanServer = + platformServer ? ManagementFactory.getPlatformMBeanServer() + : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + } + + + public void start() throws IOException, ConfigurationException + { + //check if system properties are set to use the JVM's out-of-the-box JMXAgent + if (areOutOfTheBoxJMXOptionsSet()) + { + _log.warn("JMX: Using the out of the box JMX Agent"); + _startupLog.warn("JMX: Using the out of the box JMX Agent"); + return; + } + + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + int port = appRegistry.getConfiguration().getJMXManagementPort(); + + //retrieve the Principal Database assigned to JMX authentication duties + String jmxDatabaseName = appRegistry.getConfiguration().getJMXPrincipalDatabase(); + Map map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = map.get(jmxDatabaseName); + + final JMXConnectorServer cs; + HashMap env = new HashMap(); + + //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration + RMIClientSocketFactory csf; + RMIServerSocketFactory ssf; + + //check ssl enabled option in config, default to true if option is not set + boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); + + if (sslEnabled) + { + //set the SSL related system properties used by the SSL RMI socket factories to the values + //given in the configuration file, unless command line settings have already been specified + String keyStorePath; + + if(System.getProperty("javax.net.ssl.keyStore") != null) + { + keyStorePath = System.getProperty("javax.net.ssl.keyStore"); + } + else + { + keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); + } + + //check the keystore path value is valid + if (keyStorePath == null) + { + throw new ConfigurationException("JMX management SSL keystore path not defined, " + + "unable to start SSL protected JMX ConnectorServer"); + } + else + { + //ensure the system property is set + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + + //check the file is usable + File ksf = new File(keyStorePath); + + if (!ksf.exists()) + { + throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf + "\n" + + "Check broker configuration, or see create-example-ssl-stores script" + + "in the bin/ directory if you need to generate an example store."); + } + if (!ksf.canRead()) + { + throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " + + ksf + ". Check permissions."); + } + + _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + } + + //check the key store password is set + if (System.getProperty("javax.net.ssl.keyStorePassword") == null) + { + + if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) + { + throw new ConfigurationException("JMX management SSL keystore password not defined, " + + "unable to start requested SSL protected JMX server"); + } + else + { + System.setProperty("javax.net.ssl.keyStorePassword", + appRegistry.getConfiguration().getManagementKeyStorePassword()); + } + } + + //create the SSL RMI socket factories + csf = new SslRMIClientSocketFactory(); + ssf = new SslRMIServerSocketFactory(); + + _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + } + else + { + //Do not specify any specific RMI socket factories, resulting in use of the defaults. + csf = null; + ssf = null; + + _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + } + + //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server + RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); + rmipa.setPrincipalDatabase(db); + env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); + + /* + * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. + * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. + * As a result, only binds made using the object reference will succeed, thus securing it from external change. + */ + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); + + /* + * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls + * to bind the ConnectorServer to the registry, which will now fail as for security we have + * locked it from any RMI based modifications, including our own. Instead, we will manually bind + * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. + * + * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer + * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. + */ + final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); + final String hostname = InetAddress.getLocalHost().getHostName(); + final JMXServiceURL externalUrl = new JMXServiceURL( + "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); + + final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); + cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + { + @Override + public synchronized void start() throws IOException + { + try + { + //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent + _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); + } + catch (AlreadyBoundException abe) + { + //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means. + + //IOExceptions are the only checked type throwable by the method, wrap and rethrow + IOException ioe = new IOException(abe.getMessage()); + ioe.initCause(abe); + throw ioe; + } + + //now do the normal tasks + super.start(); + } + + @Override + public JMXServiceURL getAddress() + { + //must return our pre-crafted url that includes the full details, inc JNDI details + return externalUrl; + } + + }; + + + //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + } + + /* + * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry. + * Supplied to the registry at creation, this will prevent RMI-based operations on the + * registry such as attempting to bind a new object, thereby securing it from tampering. + * This is accomplished by always returning null when attempting to determine the address + * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc + * made using the object reference will not be affected and continue to operate normally. + */ + + private class CustomRMIServerSocketFactory implements RMIServerSocketFactory + { + + public ServerSocket createServerSocket(int port) throws IOException + { + return new NoLocalAddressServerSocket(port); + } + + private class NoLocalAddressServerSocket extends ServerSocket + { + NoLocalAddressServerSocket(int port) throws IOException + { + super(port); + } + + @Override + public Socket accept() throws IOException + { + Socket s = new NoLocalAddressSocket(); + super.implAccept(s); + return s; + } + } + + private class NoLocalAddressSocket extends Socket + { + @Override + public InetAddress getInetAddress() + { + return null; + } + } + } + + + public void registerObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.unregisterMBean(managedObject.getObjectName()); + } + + // checks if the system properties are set which enable the JVM's out-of-the-box JMXAgent. + private boolean areOutOfTheBoxJMXOptionsSet() + { + if (System.getProperty("com.sun.management.jmxremote") != null) + { + return true; + } + + if (System.getProperty("com.sun.management.jmxremote.port") != null) + { + return true; + } + + return false; + } + + // stops the RMIRegistry and unregisters the MBeans from the MBeanServer + public void close() throws RemoteException + { + if (_rmiRegistry != null) + { + // Stopping the RMI registry + UnicastRemoteObject.unexportObject(_rmiRegistry, true); + } + + //ObjectName query to gather all Qpid related MBeans + ObjectName mbeanNameQuery = null; + try + { + mbeanNameQuery = new ObjectName(ManagedObject.DOMAIN + ":*"); + } + catch (Exception e1) + { + _log.warn("Unable to generate MBean ObjectName query for close operation"); + } + + for (ObjectName name : _mbeanServer.queryNames(mbeanNameQuery, null)) + { + try + { + _mbeanServer.unregisterMBean(name); + } + catch (JMException e) + { + _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage()); + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java new file mode 100644 index 0000000000..7d42297699 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean attributes. This should be used with getter or setter + * methods of attributes. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanAttribute +{ + String name(); + String description(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java new file mode 100644 index 0000000000..9138e03085 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean constructors. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.CONSTRUCTOR) +@Inherited +public @interface MBeanConstructor +{ + String value(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java new file mode 100644 index 0000000000..448fed3280 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean class. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface MBeanDescription { + String value(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java new file mode 100644 index 0000000000..0c2ec2aebd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -0,0 +1,388 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; + +/** + * 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()) + { + 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; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java new file mode 100644 index 0000000000..e9b4d85e66 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -0,0 +1,257 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.server.configuration.management.ConfigurationManagement; +import org.apache.qpid.server.logging.management.LoggingManagement; +import org.apache.qpid.server.security.access.management.UserManagement; +import org.apache.log4j.Logger; + +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.JMXPrincipal; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.JMException; +import javax.security.auth.Subject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Principal; +import java.security.AccessControlContext; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.Properties; + +/** + * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements + * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite + * and admin users. + */ +public class MBeanInvocationHandlerImpl implements InvocationHandler +{ + private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); + + public final static String ADMIN = "admin"; + public final static String READWRITE = "readwrite"; + public final static String READONLY = "readonly"; + private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; + private MBeanServer _mbs; + private static Properties _userRoles = new Properties(); + + private static HashSet _adminOnlyMethods = new HashSet(); + { + _adminOnlyMethods.add(UserManagement.TYPE); + _adminOnlyMethods.add(LoggingManagement.TYPE); + _adminOnlyMethods.add(ConfigurationManagement.TYPE); + } + + public static MBeanServerForwarder newProxyInstance() + { + final InvocationHandler handler = new MBeanInvocationHandlerImpl(); + final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + + Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); + return MBeanServerForwarder.class.cast(proxy); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + final String methodName = method.getName(); + + if (methodName.equals("getMBeanServer")) + { + return _mbs; + } + + if (methodName.equals("setMBeanServer")) + { + if (args[0] == null) + { + throw new IllegalArgumentException("Null MBeanServer"); + } + if (_mbs != null) + { + throw new IllegalArgumentException("MBeanServer object already initialized"); + } + _mbs = (MBeanServer) args[0]; + return null; + } + + // Retrieve Subject from current AccessControlContext + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(_mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) + { + return method.invoke(_mbs, args); + } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + _logger.debug("User trying to create or unregister an MBean"); + throw new SecurityException("Access denied"); + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied"); + } + + Principal principal = principals.iterator().next(); + String identity = principal.getName(); + + if (isAdminMethod(args)) + { + if (isAdmin(identity)) + { + return method.invoke(_mbs, args); + } + else + { + throw new SecurityException("Access denied"); + } + } + + // Following users can perform any operation other than "createMBean" and "unregisterMBean" + if (isAllowedToModify(identity)) + { + return method.invoke(_mbs, args); + } + + // These users can only call "getAttribute" on the MBeanServerDelegate MBean + // Here we can add other fine grained permissions like specific method for a particular mbean + if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + { + return method.invoke(_mbs, args); + } + + throw new SecurityException("Access denied"); + } + + private boolean isAdminMethod(Object[] args) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + + return _adminOnlyMethods.contains(object.getKeyProperty("type")); + } + return false; + } + + // Initialises the user roles + public static void setAccessRights(Properties accessRights) + { + _userRoles = accessRights; + } + + private boolean isAdmin(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isAllowedToModify(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName)) + || READWRITE.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyUser(String userName) + { + if (READONLY.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyMethod(Method method, Object[] args) + { + String methodName = method.getName(); + + //handle standard get/set/query and select 'is' methods from MBeanServer + if (methodName.startsWith("query") || methodName.startsWith("get") + ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) + { + return true; + } + else if (methodName.startsWith("set")) + { + return false; + } + + //handle invocation of other methods on mbeans + if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) + { + + //get invoked method name + String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + return false; + } + + try + { + //check if the given method is tagged with an INFO impact attribute + MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); + if (mbeanInfo != null) + { + MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); + for (MBeanOperationInfo opInfo : opInfos) + { + if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + { + return true; + } + } + } + } + catch (JMException ex) + { + ex.printStackTrace(); + } + } + + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java new file mode 100644 index 0000000000..a2dca3e51d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.management.MBeanOperationInfo; + +/** + * Annotation for MBean operations. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanOperation +{ + String name(); + String description(); + int impact() default MBeanOperationInfo.INFO; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java new file mode 100644 index 0000000000..aba5ec70d8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for MBean operation parameters. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface MBeanOperationParameter { + String name(); + String description(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java new file mode 100644 index 0000000000..166a2a376d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +/** + * Any object that can return a related MBean should implement this interface. + * + * This enables other classes to get the managed object, which in turn is useful when + * constructing relationships between managed objects without having to maintain + * separate data structures containing MBeans. + * + */ +public interface Managable +{ + ManagedObject getManagedObject(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java new file mode 100644 index 0000000000..c18417fc43 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.management; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; + +import org.apache.qpid.server.exchange.ManagedExchange; +import org.apache.qpid.server.queue.ManagedQueue; + +/** + * The ManagedBroker is the management interface to expose management + * features of the Broker. + * + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedBroker +{ + static final String TYPE = "VirtualHostManager"; + + static final int VERSION = 1 ; + + /** + * Creates a new Exchange. + * @param name + * @param type + * @param durable + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) + void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, + @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, + @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) + throws IOException, JMException; + + /** + * unregisters all the channels, queuebindings etc and unregisters + * this exchange from managed objects. + * @param exchange + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="unregisterExchange", + description="Unregisters all the related channels and queuebindings of this exchange", + impact= MBeanOperationInfo.ACTION) + void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) + throws IOException, JMException; + + /** + * Create a new Queue on the Broker server + * @param queueName + * @param durable + * @param owner + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) + void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, + @MBeanOperationParameter(name="owner", description="Owner name")String owner, + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) + throws IOException, JMException; + + /** + * Unregisters the Queue bindings, removes the subscriptions and unregisters + * from the managed objects. + * @param queueName + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteQueue", + description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", + impact= MBeanOperationInfo.ACTION) + void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) + throws IOException, JMException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java new file mode 100644 index 0000000000..42ea8921a4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.AMQException; + +/** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java new file mode 100644 index 0000000000..b58b17ba86 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; + +import org.apache.commons.configuration.ConfigurationException; + +import java.rmi.RemoteException; +import java.io.IOException; + +/** + * 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 start() throws IOException, ConfigurationException; + + void registerObject(ManagedObject managedObject) throws JMException; + + void unregisterObject(ManagedObject managedObject) throws JMException; + + void close() throws RemoteException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java new file mode 100644 index 0000000000..b4fbed6948 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import javax.management.JMException; + +import org.apache.log4j.Logger; + +import java.rmi.RemoteException; + +/** + * 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 start() + { + //no-op + } + + public void registerObject(ManagedObject managedObject) throws JMException + { + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + } + + public void close() throws RemoteException + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java new file mode 100644 index 0000000000..e01c5aabbf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.AMQException; + +public interface ProtocolOutputConverter +{ + void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag); + + interface Factory + { + ProtocolOutputConverter newInstance(AMQProtocolSession session); + } + + void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException; + + void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + + byte getProtocolMinorVersion(); + + byte getProtocolMajorVersion(); + + void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException; + + void writeFrame(AMQDataBlock block); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java new file mode 100644 index 0000000000..36e7e88fd6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.output.ProtocolOutputConverter.Factory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.framing.ProtocolVersion; + +import java.util.Map; +import java.util.HashMap; + +public class ProtocolOutputConverterRegistry +{ + + private static final Map _registry = + new HashMap(); + + + static + { + register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); + register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); + + } + + private static void register(ProtocolVersion version, Factory converter) + { + + _registry.put(version,converter); + } + + + public static ProtocolOutputConverter getConverter(AMQProtocolSession session) + { + return _registry.get(session.getProtocolVersion()).newInstance(session); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java new file mode 100644 index 0000000000..2b55d294b5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -0,0 +1,284 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + + final int bodyCount = messageHandle.getBodyCount(storeContext); + + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + } + + + } + + + } + + + private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicDeliverBody deliverBody = + methodRegistry.createBasicDeliverBody(consumerTag, + deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey()); + AMQFrame deliverFrame = deliverBody.generateFrame(channelId); + + + return deliverFrame; + } + + private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicGetOkBody getOkBody = + methodRegistry.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicReturnBody basicReturnBody = + methodRegistry.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java new file mode 100644 index 0000000000..65184fe744 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -0,0 +1,391 @@ +package org.apache.qpid.server.output.amqp0_9; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +import org.apache.mina.common.ByteBuffer; + +import java.util.Iterator; + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.*; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); + final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); + + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + + final int bodyCount = messageHandle.getBodyCount(storeContext); + + if(bodyCount == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); + + CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + { + + final AMQMessageHandle messageHandle = message.getMessageHandle(); + final StoreContext storeContext = message.getStoreContext(); + + AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + final int bodyCount = messageHandle.getBodyCount(storeContext); + if(bodyCount == 0) + { + SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, + contentHeader); + writeFrame(compositeBlock); + } + else + { + + + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + + AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); + AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + + // + // Now start writing out the other content bodies + // + for(int i = 1; i < bodyCount; i++) + { + cb = messageHandle.getContentChunk(storeContext, i); + writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); + } + + + } + + + } + + + private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + final boolean isRedelivered = messageHandle.isRedelivered(); + final AMQShortString exchangeName = pb.getExchange(); + final AMQShortString routingKey = pb.getRoutingKey(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + throws AMQException + { + final MessagePublishInfo pb = message.getMessagePublishInfo(); + final AMQMessageHandle messageHandle = message.getMessageHandle(); + + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + messageHandle.isRedelivered(), + pb.getExchange(), + pb.getRoutingKey(), + queueSize); + AMQFrame getOkFrame = getOkBody.generateFrame(channelId); + + return getOkFrame; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + message.getMessagePublishInfo().getExchange(), + message.getMessagePublishInfo().getRoutingKey()); + AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + + return returnFrame; + } + + public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); + + AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + + Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); + writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + + writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + writeFrame(bodyFrameIterator.next()); + } + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java new file mode 100644 index 0000000000..b0ebf197f9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.plugins; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator +{ + + BundleContext _context = null; + + public void start(BundleContext ctx) throws Exception + { + _context = ctx; + } + + public void stop(BundleContext ctx) throws Exception + { + start(null); + } + + public BundleContext getContext() + { + return _context; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java new file mode 100644 index 0000000000..dbfcefb6ab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.plugins; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.felix.framework.Felix; +import org.apache.felix.framework.cache.BundleCache; +import org.apache.felix.framework.util.FelixConstants; +import org.apache.felix.framework.util.StringMap; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.access.plugins.DenyAll; +import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; +import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleException; +import org.osgi.util.tracker.ServiceTracker; + +/** + * + * @author aidan + * + * Provides access to pluggable elements, such as exchanges + */ + +public class PluginManager +{ + + private Felix _felix = null; + private ServiceTracker _exchangeTracker = null; + private ServiceTracker _securityTracker = null; + private Activator _activator = null; + private boolean _empty; + private Map _securityPlugins; + + public PluginManager(String plugindir) throws Exception + { + StringMap configMap = new StringMap(false); + + // Tell felix it's being embedded + configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); + // Add the bundle provided service interface package and the core OSGi + // packages to be exported from the class path via the system bundle. + configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, "org.osgi.framework; version=1.3.0," + + "org.osgi.service.packageadmin; version=1.2.0," + + "org.osgi.service.startlevel; version=1.0.0," + + "org.osgi.service.url; version=1.0.0," + + "org.apache.qpid.framing; version=0.2.1," + + "org.apache.qpid.server.exchange; version=0.2.1," + + "org.apache.qpid.server.management; version=0.2.1,"+ + "org.apache.qpid.protocol; version=0.2.1,"+ + "org.apache.qpid.server.virtualhost; version=0.2.1," + + "org.apache.qpid; version=0.2.1," + + "org.apache.qpid.server.queue; version=0.2.1," + + "javax.management.openmbean; version=1.0.0,"+ + "javax.management; version=1.0.0,"+ + "org.apache.qpid.junit.extensions.util; version=0.6.1," + ); + + if (plugindir == null) + { + _empty = true; + return; + } + + // Set the list of bundles to load + File dir = new File(plugindir); + if (!dir.exists()) + { + _empty = true; + return; + } + StringBuffer pluginJars = new StringBuffer(); + + if (dir.isDirectory()) + { + for (String child : dir.list()) + { + if (child.endsWith("jar")) + { + pluginJars.append(String.format(" file:%s%s%s", plugindir,File.separator,child)); + } + } + } + if (pluginJars.length() == 0) + { + _empty = true; + return; + } + + configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); + configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); + + List activators = new ArrayList(); + _activator = new Activator(); + activators.add(_activator); + + _felix = new Felix(configMap, activators); + try + { + _felix.start(); + + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); + _exchangeTracker.open(); + + _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); + _exchangeTracker.open(); + + } + catch (BundleException e) + { + throw new Exception("Could not create bundle"); + } + } + + private Map getServices(ServiceTracker tracker) + { + Mapexchanges = new HashMap(); + + if (tracker != null) + { + for (Object service : tracker.getServices()) + { + exchanges.put(service.getClass().getName(), (type) service); + } + } + + return exchanges; + } + + public Map> getExchanges() + { + return getServices(_exchangeTracker); + } + + public Map getSecurityPlugins() + { + if (_securityPlugins == null) + { + _securityPlugins = getServices(_securityTracker); + // A little gross that we have to add them here, but not all the plugins are OSGIfied + _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); + _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); + _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); + _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); + _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); + } + return _securityPlugins; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java new file mode 100644 index 0000000000..205ca73f13 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -0,0 +1,859 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.log4j.Logger; + +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoServiceConfig; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.CloseFuture; +import org.apache.mina.transport.vmpipe.VmPipeAddress; + +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.codec.AMQDecoder; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.*; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.transport.Sender; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +public class AMQMinaProtocolSession implements AMQProtocolSession, Managable +{ + private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + // to save boxing the channelId and looking up in a map... cache in an array the low numbered + // channels. This value must be of the form 2^x - 1. + private static final int CHANNEL_CACHE_SIZE = 0xff; + + private final IoSession _minaProtocolSession; + + private AMQShortString _contextKey; + + private AMQShortString _clientVersion = null; + + private VirtualHost _virtualHost; + + private final Map _channelMap = new HashMap(); + + private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; + + private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); + + private final AMQStateManager _stateManager; + + private AMQCodecFactory _codecFactory; + + private AMQProtocolSessionMBean _managedObject; + + private SaslServer _saslServer; + + private Object _lastReceived; + + private Object _lastSent; + + protected boolean _closed; + // maximum number of channels this session should have + private long _maxNoOfChannels = 1000; + + /* AMQP Version for this session */ + private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); + + private FieldTable _clientProperties; + private final List _taskList = new CopyOnWriteArrayList(); + + private List _closingChannelsList = new CopyOnWriteArrayList(); + private ProtocolOutputConverter _protocolOutputConverter; + private Principal _authorizedID; + private MethodDispatcher _dispatcher; + private ProtocolSessionIdentifier _sessionIdentifier; + + private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L; + private org.apache.mina.common.WriteFuture _lastWriteFuture; + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) + throws AMQException + { + _stateManager = new AMQStateManager(virtualHostRegistry, this); + _minaProtocolSession = session; + session.setAttachment(this); + + _codecFactory = codecFactory; + + try + { + IoServiceConfig config = session.getServiceConfig(); + ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); + threadModel.getAsynchronousReadFilter().createNewJobForSession(session); + threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); + } + catch (RuntimeException e) + { + e.printStackTrace(); + throw e; + + } + } + + public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, + AMQStateManager stateManager) throws AMQException + { + _stateManager = stateManager; + _minaProtocolSession = session; + session.setAttachment(this); + + _codecFactory = codecFactory; + + } + + private AMQProtocolSessionMBean createMBean() throws AMQException + { + try + { + return new AMQProtocolSessionMBean(this); + } + catch (JMException ex) + { + _logger.error("AMQProtocolSession MBean creation has failed ", ex); + throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); + } + } + + public IoSession getIOSession() + { + return _minaProtocolSession; + } + + public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) + { + return (AMQProtocolSession) minaProtocolSession.getAttachment(); + } + + public void dataBlockReceived(AMQDataBlock message) throws Exception + { + _lastReceived = message; + if (message instanceof ProtocolInitiation) + { + protocolInitiationReceived((ProtocolInitiation) message); + + } + else if (message instanceof AMQFrame) + { + AMQFrame frame = (AMQFrame) message; + frameReceived(frame); + + } + else + { + throw new UnknnownMessageTypeException(message); + } + } + + private void frameReceived(AMQFrame frame) throws AMQException + { + int channelId = frame.getChannel(); + AMQBody body = frame.getBodyFrame(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Frame Received: " + frame); + } + + // Check that this channel is not closing + if (channelAwaitingClosure(channelId)) + { + if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); + } + } + else + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); + } + + closeProtocolSession(); + return; + } + } + + try + { + body.handle(channelId, this); + } + catch (AMQException e) + { + closeChannel(channelId); + throw e; + } + + } + + private void protocolInitiationReceived(ProtocolInitiation pi) + { + // this ensures the codec never checks for a PI message again + ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); + try + { + ProtocolVersion pv = pi.checkVersion(); // Fails if not correct + + // This sets the protocol version (and hence framing classes) for this session. + setProtocolVersion(pv); + + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + + String locales = "en_US"; + + AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), + (short) getProtocolMinorVersion(), + null, + mechanisms.getBytes(), + locales.getBytes()); + _minaProtocolSession.write(responseBody.generateFrame(0)); + + } + catch (AMQException e) + { + _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion()); + + _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + + // TODO: Close connection (but how to wait until message is sent?) + // ritchiem 2006-12-04 will this not do? + // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); + // future.join(); + // close connection + + } + } + + public void methodFrameReceived(int channelId, AMQMethodBody methodBody) + { + + final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); + + try + { + try + { + + boolean wasAnyoneInterested = _stateManager.methodReceived(evt); + + if (!_frameListeners.isEmpty()) + { + for (AMQMethodListener listener : _frameListeners) + { + wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; + } + } + + if (!wasAnyoneInterested) + { + throw new AMQNoMethodHandlerException(evt); + } + } + catch (AMQChannelException e) + { + if (getChannel(channelId) != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing channel due to: " + e.getMessage()); + } + + writeFrame(e.getCloseFrame(channelId)); + closeChannel(channelId); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + AMQConnectionException ce = + evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); + + closeConnection(channelId, ce, false); + } + } + catch (AMQConnectionException e) + { + closeConnection(channelId, e, false); + } + } + catch (Exception e) + { + + for (AMQMethodListener listener : _frameListeners) + { + listener.error(e); + } + + _logger.error("Unexpected exception while processing frame. Closing connection.", e); + + closeProtocolSession(); + } + } + + public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException + { + + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentHeader(body); + + } + + public void contentBodyReceived(int channelId, ContentBody body) throws AMQException + { + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentBody(body); + } + + public void heartbeatBodyReceived(int channelId, HeartbeatBody body) + { + // NO - OP + } + + /** + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). + * + * @param frame the frame to write + */ + public void writeFrame(AMQDataBlock frame) + { + _lastSent = frame; + + _lastWriteFuture = _minaProtocolSession.write(frame); + } + + public AMQShortString getContextKey() + { + return _contextKey; + } + + public void setContextKey(AMQShortString contextKey) + { + _contextKey = contextKey; + } + + public List getChannels() + { + return new ArrayList(_channelMap.values()); + } + + public AMQChannel getAndAssertChannel(int channelId) throws AMQException + { + AMQChannel channel = getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); + } + + return channel; + } + + public AMQChannel getChannel(int channelId) throws AMQException + { + final AMQChannel channel = + ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); + if ((channel == null) || channel.isClosing()) + { + return null; + } + else + { + return channel; + } + } + + public boolean channelAwaitingClosure(int channelId) + { + return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId); + } + + public void addChannel(AMQChannel channel) throws AMQException + { + if (_closed) + { + throw new AMQException("Session is closed"); + } + + final int channelId = channel.getChannelId(); + + if (_closingChannelsList.contains(channelId)) + { + throw new AMQException("Session is marked awaiting channel close"); + } + + if (_channelMap.size() == _maxNoOfChannels) + { + String errorMessage = + toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels + + "); can't create channel"; + _logger.error(errorMessage); + throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); + } + else + { + _channelMap.put(channel.getChannelId(), channel); + } + + if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) + { + _cachedChannels[channelId] = channel; + } + + checkForNotification(); + } + + private void checkForNotification() + { + int channelsCount = _channelMap.size(); + if (channelsCount >= _maxNoOfChannels) + { + _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); + } + } + + public Long getMaximumNumberOfChannels() + { + return _maxNoOfChannels; + } + + public void setMaximumNumberOfChannels(Long value) + { + _maxNoOfChannels = value; + } + + public void commitTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.commit(); + } + } + + public void rollbackTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.rollback(); + } + } + + /** + * Close a specific channel. This will remove any resources used by the channel, including:

      • 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 = getChannel(channelId); + if (channel == null) + { + throw new IllegalArgumentException("Unknown channel id"); + } + else + { + try + { + channel.close(); + markChannelAwaitingCloseOk(channelId); + } + finally + { + removeChannel(channelId); + } + } + } + + public void closeChannelOk(int channelId) + { + // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler. + // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory. + // We do it from the Close Handler as we are sending the OK back to the client. + // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException + // will send a close-ok.. Where we should call removeChannel. + // However, due to the poor exception handling on the client. The client-user will be notified of the + // InvalidArgument and if they then decide to close the session/connection then the there will be time + // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. + //removeChannel(channelId); + _closingChannelsList.remove(new Integer(channelId)); + } + + private void markChannelAwaitingCloseOk(int channelId) + { + _closingChannelsList.add(channelId); + } + + /** + * In our current implementation this is used by the clustering code. + * + * @param channelId The channel to remove + */ + public void removeChannel(int channelId) + { + _channelMap.remove(channelId); + if ((channelId & CHANNEL_CACHE_SIZE) == channelId) + { + _cachedChannels[channelId] = null; + } + } + + /** + * Initialise heartbeats on the session. + * + * @param delay delay in seconds (not ms) + */ + public void initHeartbeats(int delay) + { + if (delay > 0) + { + _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); + _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, (int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay)); + } + } + + /** + * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. + * + * @throws AMQException if an error occurs while closing any channel + */ + private void closeAllChannels() throws AMQException + { + for (AMQChannel channel : _channelMap.values()) + { + channel.close(); + } + + _channelMap.clear(); + for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) + { + _cachedChannels[i] = null; + } + } + + /** This must be called when the session is _closed in order to free up any resources managed by the session. */ + public void closeSession() throws AMQException + { + if (!_closed) + { + _closed = true; + + if (_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + } + + for (Task task : _taskList) + { + task.doTask(this); + } + } + } + + public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + markChannelAwaitingCloseOk(channelId); + closeSession(); + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(e.getCloseFrame(channelId)); + + if (closeProtocolSession) + { + closeProtocolSession(); + } + } + + public void closeProtocolSession() + { + closeProtocolSession(true); + } + + public void closeProtocolSession(boolean waitLast) + { + if (waitLast && (_lastWriteFuture != null)) + { + _logger.debug("Waiting for last write to join."); + _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); + } + + _logger.debug("REALLY Closing protocol session:" + _minaProtocolSession); + final CloseFuture future = _minaProtocolSession.close(); + future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); + + try + { + _stateManager.changeState(AMQState.CONNECTION_CLOSED); + } + catch (AMQException e) + { + _logger.info(e.getMessage()); + } + } + + public String toString() + { + return _minaProtocolSession.getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")"); + } + + public String dump() + { + return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; + } + + /** @return an object that can be used to identity */ + public Object getKey() + { + return _minaProtocolSession.getRemoteAddress(); + } + + /** + * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may + * be bound to multiple addresses this could vary depending on the acceptor this session was created from. + * + * @return a String FQDN + */ + public String getLocalFQDN() + { + SocketAddress address = _minaProtocolSession.getLocalAddress(); + // we use the vmpipe address in some tests hence the need for this rather ugly test. The host + // information is used by SASL primary. + if (address instanceof InetSocketAddress) + { + return ((InetSocketAddress) address).getHostName(); + } + else if (address instanceof VmPipeAddress) + { + return "vmpipe:" + ((VmPipeAddress) address).getPort(); + } + else + { + throw new IllegalArgumentException("Unsupported socket address class: " + address); + } + } + + public SaslServer getSaslServer() + { + return _saslServer; + } + + public void setSaslServer(SaslServer saslServer) + { + _saslServer = saslServer; + } + + public FieldTable getClientProperties() + { + return _clientProperties; + } + + public void setClientProperties(FieldTable clientProperties) + { + _clientProperties = clientProperties; + if (_clientProperties != null) + { + if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) + { + setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); + } + + if (_clientProperties.getString(ClientProperties.version.toString()) != null) + { + _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); + } + } + _sessionIdentifier = new ProtocolSessionIdentifier(this); + } + + private void setProtocolVersion(ProtocolVersion pv) + { + _protocolVersion = pv; + + _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); + _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion); + } + + public byte getProtocolMajorVersion() + { + return _protocolVersion.getMajorVersion(); + } + + public ProtocolVersion getProtocolVersion() + { + return _protocolVersion; + } + + public byte getProtocolMinorVersion() + { + return _protocolVersion.getMinorVersion(); + } + + public boolean isProtocolVersion(byte major, byte minor) + { + return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); + } + + public MethodRegistry getRegistry() + { + return getMethodRegistry(); + } + + public Object getClientIdentifier() + { + return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) throws AMQException + { + _virtualHost = virtualHost; + + _virtualHost.getConnectionRegistry().registerConnection(this); + + _managedObject = createMBean(); + _managedObject.register(); + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + public ProtocolOutputConverter getProtocolOutputConverter() + { + return _protocolOutputConverter; + } + + public void setAuthorizedID(Principal authorizedID) + { + _authorizedID = authorizedID; + } + + public Principal getAuthorizedID() + { + return _authorizedID; + } + + public MethodRegistry getMethodRegistry() + { + return MethodRegistry.getMethodRegistry(getProtocolVersion()); + } + + public MethodDispatcher getMethodDispatcher() + { + return _dispatcher; + } + + public ProtocolSessionIdentifier getSessionIdentifier() + { + return _sessionIdentifier; + } + + public String getClientVersion() + { + return (_clientVersion == null) ? null : _clientVersion.toString(); + } + + public void setSender(Sender sender) + { + // No-op, interface munging between this and AMQProtocolSession + } + + public void init() + { + // No-op, interface munging between this and AMQProtocolSession + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java new file mode 100644 index 0000000000..a7599a3e0d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to handle an AMQP method. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a + * Runtime. + */ +public class AMQNoMethodHandlerException extends AMQException +{ + public AMQNoMethodHandlerException(AMQMethodEvent evt) + { + super("AMQMethodEvent " + evt + " was not processed by any listener on Broker."); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java new file mode 100644 index 0000000000..0dbefd8798 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -0,0 +1,284 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.ReadThrottleFilterBuilder; +import org.apache.mina.filter.SSLFilter; +import org.apache.mina.filter.WriteBufferLimitFilterBuilder; +import org.apache.mina.filter.codec.QpidProtocolCodecFilter; +import org.apache.mina.filter.executor.ExecutorFilter; +import org.apache.mina.util.SessionUtil; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.ssl.SSLContextFactory; + +/** + * The protocol handler handles "protocol events" for all connections. The state + * associated with an individual connection is accessed through the protocol session. + * + * We delegate all frame (message) processing to the AMQProtocolSession which wraps + * the state for the connection. + */ +public class AMQPFastProtocolHandler extends IoHandlerAdapter +{ + private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); + + private final IApplicationRegistry _applicationRegistry; + + private final int BUFFER_READ_LIMIT_SIZE; + private final int BUFFER_WRITE_LIMIT_SIZE; + + public AMQPFastProtocolHandler(Integer applicationRegistryInstance) + { + this(ApplicationRegistry.getInstance(applicationRegistryInstance)); + } + + public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) + { + _applicationRegistry = applicationRegistry; + + // Read the configuration from the application registry + BUFFER_READ_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferReadLimit(); + BUFFER_WRITE_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferWriteLimit(); + + _logger.debug("AMQPFastProtocolHandler created"); + } + + protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) + { + this(handler._applicationRegistry); + } + + public void sessionCreated(IoSession protocolSession) throws Exception + { + SessionUtil.initialize(protocolSession); + final AMQCodecFactory codecFactory = new AMQCodecFactory(true); + + createSession(protocolSession, _applicationRegistry, codecFactory); + _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); + + final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory); + final ServerConfiguration config = _applicationRegistry.getConfiguration(); + + String keystorePath = config.getKeystorePath(); + String keystorePassword = config.getKeystorePassword(); + String certType = config.getCertType(); + SSLContextFactory sslContextFactory = null; + boolean isSsl = false; + if (config.getEnableSSL() && isSSLClient(config, protocolSession)) + { + sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + isSsl = true; + } + if (config.getEnableExecutorPool()) + { + if (isSsl) + { + protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", + new SSLFilter(sslContextFactory.buildServerContext())); + } + protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); + } + else + { + protocolSession.getFilterChain().addLast("protocolFilter", pcf); + if (isSsl) + { + protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", + new SSLFilter(sslContextFactory.buildServerContext())); + } + } + + if (ApplicationRegistry.getInstance().getConfiguration().getProtectIOEnabled()) + { + try + { +// //Add IO Protection Filters + IoFilterChain chain = protocolSession.getFilterChain(); + + + protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter()); + + ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); + readfilter.setMaximumConnectionBufferSize(BUFFER_READ_LIMIT_SIZE); + readfilter.attach(chain); + + WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); + writefilter.setMaximumConnectionBufferSize(BUFFER_WRITE_LIMIT_SIZE); + writefilter.attach(chain); + + protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder"); + _logger.info("Using IO Read/Write Filter Protection"); + } + catch (Exception e) + { + _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage()); + } + } + } + + /** Separated into its own, protected, method to allow easier reuse */ + protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException + { + new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); + } + + public void sessionOpened(IoSession protocolSession) throws Exception + { + _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); + } + + public void sessionClosed(IoSession protocolSession) throws Exception + { + _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + //fixme -- this can be null + if (amqProtocolSession != null) + { + try + { + amqProtocolSession.closeSession(); + } + catch (AMQException e) + { + _logger.error("Caught AMQException whilst closingSession:" + e); + } + } + } + + public void sessionIdle(IoSession session, IdleStatus status) throws Exception + { + _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); + if (IdleStatus.WRITER_IDLE.equals(status)) + { + //write heartbeat frame: + session.write(HeartbeatBody.FRAME); + } + else if (IdleStatus.READER_IDLE.equals(status)) + { + //failover: + throw new IOException("Timed out while waiting for heartbeat from peer."); + } + + } + + public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception + { + AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + if (throwable instanceof AMQProtocolHeaderException) + { + + protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + + protocolSession.close(); + + _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); + } + else if (throwable instanceof IOException) + { + _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable); + } + else + { + _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); + + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(session.getProtocolVersion()); + ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); + + protocolSession.write(closeBody.generateFrame(0)); + + protocolSession.close(); + } + } + + /** + * Invoked when a message is received on a particular protocol session. Note that a + * protocol session is directly tied to a particular physical connection. + * + * @param protocolSession the protocol session that received the message + * @param message the message itself (i.e. a decoded frame) + * + * @throws Exception if the message cannot be processed + */ + public void messageReceived(IoSession protocolSession, Object message) throws Exception + { + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + + if (message instanceof AMQDataBlock) + { + amqProtocolSession.dataBlockReceived((AMQDataBlock) message); + + } + else if (message instanceof ByteBuffer) + { + throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); + } + else + { + throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); + } + } + + /** + * Called after a message has been sent out on a particular protocol session + * + * @param protocolSession the protocol session (i.e. connection) on which this + * message was sent + * @param object the message (frame) that was encoded and sent + * + * @throws Exception if we want to indicate an error + */ + public void messageSent(IoSession protocolSession, Object object) throws Exception + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Message sent: " + object); + } + } + + protected boolean isSSLClient(ServerConfiguration connectionConfig, + IoSession protocolSession) + { + InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); + return addr.getPort() == connectionConfig.getSSLPort(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java new file mode 100644 index 0000000000..07c153bfe8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; + +/** + * The protocol provide's role is to encapsulate the initialisation of the protocol handler. + * + * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events + * such as connection closing or a frame being received. It can either do this directly + * or pass off to the protocol session in the cases where state information is required to + * deal with the event. + * + */ +public class AMQPProtocolProvider +{ + /** + * Handler for protocol events + */ + private AMQPFastProtocolHandler _handler; + + public AMQPProtocolProvider() + { + IApplicationRegistry registry = ApplicationRegistry.getInstance(); + _handler = new AMQPFastProtocolHandler(registry); + } + + public AMQPFastProtocolHandler getHandler() + { + return _handler; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java new file mode 100644 index 0000000000..1bac601225 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -0,0 +1,207 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 javax.security.sasl.SaslServer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.*; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.security.Principal; + + +public interface AMQProtocolSession extends AMQVersionAwareProtocolSession +{ + + public static final class ProtocolSessionIdentifier + { + private final Object _sessionIdentifier; + private final Object _sessionInstance; + + ProtocolSessionIdentifier(AMQProtocolSession session) + { + _sessionIdentifier = session.getClientIdentifier(); + _sessionInstance = session.getClientProperties() == null ? null : session.getClientProperties().getObject(ClientProperties.instance.toAMQShortString()); + } + + public Object getSessionIdentifier() + { + return _sessionIdentifier; + } + + public Object getSessionInstance() + { + return _sessionInstance; + } + } + + public static interface Task + { + public void doTask(AMQProtocolSession session) throws AMQException; + } + + /** + * 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; + + /** + * Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC + * 6). + * + * @return the context key + */ + AMQShortString 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(AMQShortString 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) throws AMQException; + + /** + * 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; + + /** + * Markes the specific channel as closed. This will release the lock for that channel id so a new channel can be + * created on that id. + * + * @param channelId id of the channel to close + */ + void closeChannelOk(int channelId); + + /** + * Check to see if this chanel is closing + * + * @param channelId id to check + * @return boolean with state of channel awaiting closure + */ + boolean channelAwaitingClosure(int channelId); + + /** + * 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; + + /** This must be called to close the session in order to free up any resources managed by the session. */ + void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) 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); + + + FieldTable getClientProperties(); + + void setClientProperties(FieldTable clientProperties); + + Object getClientIdentifier(); + + VirtualHost getVirtualHost(); + + void setVirtualHost(VirtualHost virtualHost) throws AMQException; + + void addSessionCloseTask(Task task); + + void removeSessionCloseTask(Task task); + + public ProtocolOutputConverter getProtocolOutputConverter(); + + void setAuthorizedID(Principal authorizedID); + + /** @return a Principal that was used to authorized this session */ + Principal getAuthorizedID(); + + public MethodRegistry getMethodRegistry(); + + public MethodDispatcher getMethodDispatcher(); + + public ProtocolSessionIdentifier getSessionIdentifier(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java new file mode 100644 index 0000000000..5dd3cc075a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -0,0 +1,304 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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; +import java.util.List; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; + +/** + * This MBean class implements the management interface. 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") +public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection +{ + private AMQMinaProtocolSession _session = null; + private String _name = null; + + // openmbean data types for representing the channel attributes + private static final String[] _channelAtttibuteNames = + { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; + private static final String[] _indexNames = { _channelAtttibuteNames[0] }; + private static final OpenType[] _channelAttributeTypes = + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; + private static CompositeType _channelType = null; // represents the data type for channel data + private static TabularType _channelsType = null; // Data type for list of channels type + private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = + new AMQShortString("Broker Management Console has closed the connection."); + + @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") + public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException + { + super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); + _session = session; + String remote = getRemoteAddress(); + remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; + _name = jmxEncode(new StringBuffer(remote), 0).toString(); + init(); + } + + static + { + try + { + init(); + } + catch (JMException ex) + { + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); + } + } + + /** + * initialises the openmbean data types + */ + private static void init() throws OpenDataException + { + _channelType = + new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, + _channelAttributeTypes); + _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); + } + + public String getClientId() + { + return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); + } + + public String getAuthorizedId() + { + return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; + } + + public String getVersion() + { + return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); + } + + public Date getLastIoTime() + { + return new Date(_session.getIOSession().getLastIoTime()); + } + + public String getRemoteAddress() + { + return _session.getIOSession().getRemoteAddress().toString(); + } + + public ManagedObject getParentObject() + { + return _session.getVirtualHost().getManagedObject(); + } + + public Long getWrittenBytes() + { + return _session.getIOSession().getWrittenBytes(); + } + + public Long getReadBytes() + { + return _session.getIOSession().getReadBytes(); + } + + public Long getMaximumNumberOfChannels() + { + return _session.getMaximumNumberOfChannels(); + } + + public void setMaximumNumberOfChannels(Long value) + { + _session.setMaximumNumberOfChannels(value); + } + + public String getObjectInstanceName() + { + return _name; + } + + /** + * commits transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if commit fails + */ + public void commitTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + + _session.commitTransactions(channel); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * rollsback the transactions for a transactional channel + * + * @param channelId + * @throws JMException if channel with given id doesn't exist or if rollback fails + */ + public void rollbackTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _session.getChannel(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + + _session.rollbackTransactions(channel); + } + 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 channels() throws OpenDataException + { + TabularDataSupport channelsList = new TabularDataSupport(_channelsType); + List list = _session.getChannels(); + + for (AMQChannel channel : list) + { + Object[] itemValues = + { + channel.getChannelId(), channel.isTransactional(), + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, + channel.getUnacknowledgedMessageMap().size() + }; + + CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); + channelsList.put(channelData); + } + + return channelsList; + } + + /** + * closes the connection. The administrator can use this management operation to close connection to free up + * resources. + * @throws JMException + */ + public void closeConnection() throws JMException + { + + MethodRegistry methodRegistry = _session.getMethodRegistry(); + ConnectionCloseBody responseBody = + methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), + // replyCode + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION, + // replyText, + 0, + 0); + + _session.writeFrame(responseBody.generateFrame(0)); + + try + { + _session.closeSession(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; + String name = MonitorNotification.class.getName(); + String description = "Channel count has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[] { info1 }; + } + + public void notifyClients(String notificationMsg) + { + Notification n = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); + _broadcaster.sendNotification(n); + } + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java new file mode 100644 index 0000000000..2abcecb6de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeType; + +public class ExchangeInitialiser +{ + public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ + for (ExchangeType type : factory.getRegisteredTypes()) + { + define (registry, factory, type.getDefaultExchangeName(), type.getName()); + } + + define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); + } + + private void define(ExchangeRegistry r, ExchangeFactory f, + AMQShortString name, AMQShortString type) throws AMQException + { + if(r.getExchange(name)== null) + { + r.registerExchange(f.createExchange(name, type, true, false, 0)); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java new file mode 100644 index 0000000000..e75b09a0cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -0,0 +1,136 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.protocol; + +import java.io.IOException; +import java.util.Date; +import java.security.Principal; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +/** + * The management interface exposed to allow management of Connections. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedConnection +{ + static final String TYPE = "Connection"; + static final int VERSION = 1; + + @MBeanAttribute(name = "ClientId", description = "Client Id") + String getClientId(); + + @MBeanAttribute(name = "AuthorizedId", description = "User Name") + String getAuthorizedId(); + + @MBeanAttribute(name = "Version", description = "Client Version") + String getVersion(); + + /** + * Tells the remote address of this connection. + * @return remote address + */ + @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") + String getRemoteAddress(); + + /** + * Tells the last time, the IO operation was done. + * @return last IO time. + */ + @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done") + Date getLastIoTime(); + + /** + * Tells the total number of bytes written till now. + * @return number of bytes written. + * + @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") + Long getWrittenBytes(); + */ + /** + * Tells the total number of bytes read till now. + * @return number of bytes read. + * + @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") + Long getReadBytes(); + */ + + /** + * Threshold high value for no of channels. This is useful in setting notifications or + * taking required action is there are more channels being created. + * @return threshold limit for no of channels + */ + Long getMaximumNumberOfChannels(); + + /** + * Sets the threshold high value for number of channels for a connection + * @param value + */ + @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") + void setMaximumNumberOfChannels(Long value); + + //********** Operations *****************// + + /** + * channel details of all the channels opened for this connection. + * @return general channel details + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="channels", description="Channel details for this connection") + TabularData channels() throws IOException, JMException; + + /** + * Commits the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="commitTransaction", + description="Commits the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Rollsback the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="rollbackTransactions", + description="Rollsback the transactions for given channel Id, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Closes all the related channels and unregisters this connection from managed objects. + */ + @MBeanOperation(name="closeConnection", + description="Closes this connection and all related channels", + impact= MBeanOperationInfo.ACTION) + void closeConnection() throws Exception; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java new file mode 100644 index 0000000000..6e72aa062f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; + +/** + * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represents failure to cast a frame to its expected type. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would + * be better just to leave that as a ClassCastException. However, check the framing layer catches this error + * first. + */ +public class UnknnownMessageTypeException extends AMQException +{ + public UnknnownMessageTypeException(AMQDataBlock message) + { + super("Unknown message type: " + message.getClass().getName() + ": " + message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java new file mode 100644 index 0000000000..a485649410 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -0,0 +1,482 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.TransactionalContext; + + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A deliverable message. + */ +public class AMQMessage implements Filterable +{ + /** Used for debugging purposes. */ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + private final AtomicInteger _referenceCount = new AtomicInteger(1); + + private final AMQMessageHandle _messageHandle; + + /** Holds the transactional context in which this message is being processed. */ + private StoreContext _storeContext; + + /** Flag to indicate that this message requires 'immediate' delivery. */ + + private static final byte IMMEDIATE = 0x01; + + /** + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. + */ + + private static final byte DELIVERED_TO_CONSUMER = 0x02; + + private byte _flags = 0; + + private long _expiration; + + private final long _size; + + private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; + private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); + + + + /** + * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory + * therefore is memory-efficient. + */ + private class BodyFrameIterator implements Iterator + { + private int _channel; + + private int _index = -1; + private AMQProtocolSession _protocolSession; + + private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + _channel = channel; + _protocolSession = protocolSession; + } + + public boolean hasNext() + { + try + { + return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); + } + catch (AMQException e) + { + _log.error("Unable to get body count: " + e, e); + + return false; + } + } + + public AMQDataBlock next() + { + try + { + + AMQBody cb = + getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), + ++_index)); + + return new AMQFrame(_channel, cb); + } + catch (AMQException e) + { + // have no choice but to throw a runtime exception + throw new RuntimeException("Error getting content body: " + e, e); + } + + } + + private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() + { + return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public void clearStoreContext() + { + _storeContext = new StoreContext(); + } + + public StoreContext getStoreContext() + { + return _storeContext; + } + + private class BodyContentIterator implements Iterator + { + + private int _index = -1; + + public boolean hasNext() + { + try + { + return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); + } + catch (AMQException e) + { + _log.error("Error getting body count: " + e, e); + + return false; + } + } + + public ContentChunk next() + { + try + { + return _messageHandle.getContentChunk(getStoreContext(), ++_index); + } + catch (AMQException e) + { + throw new RuntimeException("Error getting content body: " + e, e); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + + + /** + * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal + * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to + * queues. + * + * @param messageId + * @param store + * @param factory + * + * @throws AMQException + */ + public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) + throws AMQException + { + _messageHandle = factory.createMessageHandle(messageId, store, true); + _storeContext = txnConext.getStoreContext(); + _size = _messageHandle.getBodySize(txnConext.getStoreContext()); + } + + /** + * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal + * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to + * queues. + * + * @param messageHandle + * + * @throws AMQException + */ + public AMQMessage( + AMQMessageHandle messageHandle, + StoreContext storeConext, + MessagePublishInfo info) + throws AMQException + { + _messageHandle = messageHandle; + _storeContext = storeConext; + + if(info.isImmediate()) + { + _flags |= IMMEDIATE; + } + _size = messageHandle.getBodySize(storeConext); + + } + + + protected AMQMessage(AMQMessage msg) throws AMQException + { + _messageHandle = msg._messageHandle; + _storeContext = msg._storeContext; + _flags = msg._flags; + _size = msg._size; + + } + + + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; + } + + public void setExpiration(final long expiration) + { + + _expiration = expiration; + + } + + public boolean isReferenced() + { + return _referenceCount.get() > 0; + } + + public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) + { + return new BodyFrameIterator(protocolSession, channel); + } + + public Iterator getContentBodyIterator() + { + return new BodyContentIterator(); + } + + public ContentHeaderBody getContentHeaderBody() throws AMQException + { + return _messageHandle.getContentHeaderBody(getStoreContext()); + } + + + + public Long getMessageId() + { + return _messageHandle.getMessageId(); + } + + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. + */ + public AMQMessage takeReference() + { + incrementReference(); // _referenceCount.incrementAndGet(); + + return this; + } + + public boolean incrementReference() + { + return incrementReference(1); + } + + /* Threadsafe. Increment the reference count on the message. */ + public boolean incrementReference(int count) + { + if(_referenceCount.addAndGet(count) <= 1) + { + _referenceCount.addAndGet(-count); + return false; + } + else + { + return true; + } + + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * @param storeContext + * + * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + public void decrementReference(StoreContext storeContext) throws MessageCleanupException + { + + int count = _referenceCount.decrementAndGet(); + + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (count == 0) + { + // set the reference count way below 0 so that we can detect that the message has been deleted + // this is to guard against the message being spontaneously recreated (from the mgmt console) + // by copying from other queues at the same time as it is being removed. + _referenceCount.set(Integer.MIN_VALUE/2); + + try + { + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + if (_messageHandle != null) + { + _messageHandle.removeMessage(storeContext); + } + } + catch (AMQException e) + { + // to maintain consistency, we revert the count + incrementReference(); + throw new MessageCleanupException(getMessageId(), e); + } + } + else + { + if (count < 0) + { + throw new MessageCleanupException("Reference count for message id " + debugIdentity() + + " has gone below 0."); + } + } + } + + + /** + * Called selectors to determin if the message has already been sent + * + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return (_flags & DELIVERED_TO_CONSUMER) != 0; + } + + public boolean isPersistent() throws AMQException + { + return _messageHandle.isPersistent(); + } + + /** + * Called to enforce the 'immediate' flag. + * + * @returns true if the message is marked for immediate delivery but has not been marked as delivered + * to a consumer + */ + public boolean immediateAndNotDelivered() + { + + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; + + } + + public MessagePublishInfo getMessagePublishInfo() throws AMQException + { + return _messageHandle.getMessagePublishInfo(getStoreContext()); + } + + public boolean isRedelivered() + { + return _messageHandle.isRedelivered(); + } + + public void setRedelivered(boolean redelivered) + { + _messageHandle.setRedelivered(redelivered); + } + + public long getArrivalTime() + { + return _messageHandle.getArrivalTime(); + } + + /** + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @param queue The queue to check the expiration against. (Currently not used) + * + * @return true if the message has expire + * + * @throws AMQException + */ + public boolean expired(AMQQueue queue) throws AMQException + { + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > _expiration); + } + + return false; + } + + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + */ + public void setDeliveredToConsumer() + { + _flags |= DELIVERED_TO_CONSUMER; + } + + + + public AMQMessageHandle getMessageHandle() + { + return _messageHandle; + } + + public long getSize() + { + return _size; + + } + + public Object getPublisherClientInstance() + { + return _sessionIdentifier.getSessionInstance(); + } + + public Object getPublisherIdentifier() + { + return _sessionIdentifier.getSessionIdentifier(); + } + + public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) + { + _sessionIdentifier = sessionIdentifier; + } + + + public String toString() + { + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; + + return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java new file mode 100644 index 0000000000..0ddd4e4d92 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +/** + * A pluggable way of getting message data. Implementations can provide intelligent caching for example or + * even no caching at all to minimise the broker memory footprint. + */ +public interface AMQMessageHandle +{ + ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException; + + /** + * + * @return the messageId for the message associated with this handle + */ + Long getMessageId(); + + + /** + * @return the number of body frames associated with this message + */ + int getBodyCount(StoreContext context) throws AMQException; + + /** + * @return the size of the body + */ + long getBodySize(StoreContext context) throws AMQException; + + /** + * Get a particular content body + * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 + * @return a content body + * @throws IllegalArgumentException if the index is invalid + */ + ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException; + + void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; + + MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; + + boolean isRedelivered(); + + void setRedelivered(boolean redelivered); + + boolean isPersistent(); + + void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException; + + void removeMessage(StoreContext storeContext) throws AMQException; + + long getArrivalTime(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java new file mode 100644 index 0000000000..bb6ce65d42 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -0,0 +1,70 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.AMQException; + +public class AMQPriorityQueue extends SimpleAMQQueue +{ + protected AMQPriorityQueue(final AMQShortString name, + final boolean durable, + final AMQShortString owner, + final boolean autoDelete, + final VirtualHost virtualHost, + int priorities) + throws AMQException + { + super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); + } + + public int getPriorities() + { + return ((PriorityQueueList) _entries).getPriorities(); + } + + @Override + protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) + { + // check that all subscriptions are not in advance of the entry + SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator(); + while(subIter.advance() && !entry.isAcquired()) + { + final Subscription subscription = subIter.getNode().getSubscription(); + QueueEntry subnode = subscription.getLastSeenEntry(); + while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()) + { + if(subscription.setLastSeenEntry(subnode,entry)) + { + break; + } + else + { + subnode = subscription.getLastSeenEntry(); + } + } + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java new file mode 100644 index 0000000000..014b348822 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -0,0 +1,220 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.Set; + +public interface AMQQueue extends Managable, Comparable +{ + + AMQShortString getName(); + + boolean isDurable(); + + boolean isAutoDelete(); + + AMQShortString getOwner(); + + VirtualHost getVirtualHost(); + + + void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; + + void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; + + List getExchangeBindings(); + + + void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; + + void unregisterSubscription(final Subscription subscription) throws AMQException; + + + int getConsumerCount(); + + int getActiveConsumerCount(); + + boolean isUnused(); + + boolean isEmpty(); + + int getMessageCount(); + + int getUndeliveredMessageCount(); + + + long getQueueDepth(); + + long getReceivedMessageCount(); + + long getOldestMessageArrivalTime(); + + boolean isDeleted(); + + + int delete() throws AMQException; + + + QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; + + void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; + + void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; + + + + boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; + + + + void addQueueDeleteTask(final Task task); + + + List getMessagesOnTheQueue(); + + List getMessagesOnTheQueue(long fromMessageId, long toMessageId); + + List getMessagesOnTheQueue(int num); + + List getMessagesOnTheQueue(int num, int offest); + + QueueEntry getMessageOnTheQueue(long messageId); + + + void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, + StoreContext storeContext); + + void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext); + + void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); + + + + long getMaximumMessageSize(); + + void setMaximumMessageSize(long value); + + + long getMaximumMessageCount(); + + void setMaximumMessageCount(long value); + + + long getMaximumQueueDepth(); + + void setMaximumQueueDepth(long value); + + + long getMaximumMessageAge(); + + void setMaximumMessageAge(final long maximumMessageAge); + + + long getMinimumAlertRepeatGap(); + + void setMinimumAlertRepeatGap(long value); + + + void deleteMessageFromTop(StoreContext storeContext) throws AMQException; + + long clearQueue(StoreContext storeContext) throws AMQException; + + /** + * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. + * @throws AMQException + */ + void checkMessageStatus() throws AMQException; + + Set getNotificationChecks(); + + void flushSubscription(final Subscription sub) throws AMQException; + + void deliverAsync(final Subscription sub); + + void deliverAsync(); + + void stop(); + + /** + * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create a subscription, because an exclusive subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + static final class ExistingExclusiveSubscription extends AMQException + { + + public ExistingExclusiveSubscription() + { + super(""); + } + } + + /** + * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription + * already exists. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to create an exclusize subscription, as a subscription already exists. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Move to top level, used outside this class. + */ + static final class ExistingSubscriptionPreventsExclusive extends AMQException + { + public ExistingSubscriptionPreventsExclusive() + { + super(""); + } + } + + static interface Task + { + public void doTask(AMQQueue queue) throws AMQException; + } + + void configure(QueueConfiguration config); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java new file mode 100644 index 0000000000..84b59456cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.virtualhost.VirtualHost; + + +public class AMQQueueFactory +{ + public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + + public static AMQQueue createAMQQueueImpl(AMQShortString name, + boolean durable, + AMQShortString owner, + boolean autoDelete, + VirtualHost virtualHost, final FieldTable arguments) + throws AMQException + { + + final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + + AMQQueue q = null; + if(priorities > 1) + { + q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); + } + else + { + q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + } + + //Register the new queue + virtualHost.getQueueRegistry().registerQueue(q); + return q; + } + + public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException + { + AMQShortString queueName = new AMQShortString(config.getName()); + + boolean durable = config.getDurable(); + boolean autodelete = config.getAutoDelete(); + AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null; + FieldTable arguments = null; + boolean priority = config.getPriority(); + int priorities = config.getPriorities(); + if(priority || priorities > 0) + { + if(arguments == null) + { + arguments = new FieldTable(); + } + if (priorities < 0) + { + priorities = 10; + } + arguments.put(new AMQShortString("x-qpid-priorities"), priorities); + } + + AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); + q.configure(config); + return q; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java new file mode 100644 index 0000000000..c8ead67b1f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -0,0 +1,478 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.store.StoreContext; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.OperationsException; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * AMQQueueMBean is the management bean for an {@link AMQQueue}. + * + *

      CRC Caption + * Responsibilities Collaborations + * + */ +@MBeanDescription("Management Interface for AMQQueue") +public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener +{ + /** Used for debugging purposes. */ + private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class); + + private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); + + /** + * Since the MBean is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + private StoreContext _storeContext = new StoreContext(); + + private AMQQueue _queue = null; + private String _queueName = null; + // OpenMBean data types for viewMessages method + private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; + private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; + private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + + // OpenMBean data types for viewMessageContent method + private static CompositeType _msgContentType = null; + private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; + private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; + private Notification _lastNotification = null; + + + + + @MBeanConstructor("Creates an MBean exposing an AMQQueue") + public AMQQueueMBean(AMQQueue queue) throws JMException + { + super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); + _queue = queue; + _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); + } + + public ManagedObject getParentObject() + { + return _queue.getVirtualHost().getManagedObject(); + } + + static + { + try + { + init(); + } + catch (JMException ex) + { + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); + } + } + + /** + * initialises the openmbean data types + */ + private static void init() throws OpenDataException + { + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = + new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, + _msgContentAttributeTypes); + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = + new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); + } + + public String getObjectInstanceName() + { + return _queueName; + } + + public String getName() + { + return _queueName; + } + + public boolean isDurable() + { + return _queue.isDurable(); + } + + public String getOwner() + { + return String.valueOf(_queue.getOwner()); + } + + public boolean isAutoDelete() + { + return _queue.isAutoDelete(); + } + + public Integer getMessageCount() + { + return _queue.getMessageCount(); + } + + public Long getMaximumMessageSize() + { + return _queue.getMaximumMessageSize(); + } + + public Long getMaximumMessageAge() + { + return _queue.getMaximumMessageAge(); + } + + public void setMaximumMessageAge(Long maximumMessageAge) + { + _queue.setMaximumMessageAge(maximumMessageAge); + } + + public void setMaximumMessageSize(Long value) + { + _queue.setMaximumMessageSize(value); + } + + public Integer getConsumerCount() + { + return _queue.getConsumerCount(); + } + + public Integer getActiveConsumerCount() + { + return _queue.getActiveConsumerCount(); + } + + public Long getReceivedMessageCount() + { + return _queue.getReceivedMessageCount(); + } + + public Long getMaximumMessageCount() + { + return _queue.getMaximumMessageCount(); + } + + public void setMaximumMessageCount(Long value) + { + _queue.setMaximumMessageCount(value); + } + + /** + * returns the maximum total size of messages(bytes) in the queue. + */ + public Long getMaximumQueueDepth() + { + return _queue.getMaximumQueueDepth(); + } + + public void setMaximumQueueDepth(Long value) + { + _queue.setMaximumQueueDepth(value); + } + + /** + * returns the total size of messages(bytes) in the queue. + */ + public Long getQueueDepth() throws JMException + { + return _queue.getQueueDepth(); + } + + /** + * Checks if there is any notification to be send to the listeners + */ + public void checkForNotification(AMQMessage msg) throws AMQException + { + + final Set notificationChecks = _queue.getNotificationChecks(); + + if(!notificationChecks.isEmpty()) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); + + for (NotificationCheck check : notificationChecks) + { + if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) + { + if (check.notifyIfNecessary(msg, _queue, this)) + { + _lastNotificationTimes[check.ordinal()] = currentTime; + } + } + } + } + + } + + /** + * Sends the notification to the listeners + */ + public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) + { + // important : add log to the log file - monitoring tools may be looking for this + _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); + notificationMsg = notification.name() + " " + notificationMsg; + + _lastNotification = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); + + _broadcaster.sendNotification(_lastNotification); + } + + public Notification getLastNotification() + { + return _lastNotification; + } + + /** + * @see AMQQueue#deleteMessageFromTop + */ + public void deleteMessageFromTop() throws JMException + { + try + { + _queue.deleteMessageFromTop(_storeContext); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * @see AMQQueue#clearQueue + */ + public void clearQueue() throws JMException + { + try + { + _queue.clearQueue(_storeContext); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * returns message content as byte array and related attributes for the given message id. + */ + public CompositeData viewMessageContent(long msgId) throws JMException + { + QueueEntry entry = _queue.getMessageOnTheQueue(msgId); + + if (entry == null) + { + throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); + } + + AMQMessage msg = entry.getMessage(); + // get message content + Iterator cBodies = msg.getContentBodyIterator(); + List msgContent = new ArrayList(); + while (cBodies.hasNext()) + { + ContentChunk body = cBodies.next(); + if (body.getSize() != 0) + { + if (body.getSize() != 0) + { + ByteBuffer slice = body.getData().slice(); + for (int j = 0; j < slice.limit(); j++) + { + msgContent.add(slice.get()); + } + } + } + } + + try + { + // Create header attributes list + CommonContentHeaderProperties headerProperties = + (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; + String mimeType = null, encoding = null; + if (headerProperties != null) + { + AMQShortString mimeTypeShortSting = headerProperties.getContentType(); + mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); + encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); + } + + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + } + catch (AMQException e) + { + JMException jme = new JMException("Error creating header attributes list: " + e); + jme.initCause(e); + throw jme; + } + } + + /** + * Returns the header contents of the messages stored in this queue in tabular form. + */ + public TabularData viewMessages(int beginIndex, int endIndex) throws JMException + { + if ((beginIndex > endIndex) || (beginIndex < 1)) + { + throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + } + + List list = _queue.getMessagesOnTheQueue(); + TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); + + try + { + // Create the tabular list of message header contents + for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) + { + AMQMessage msg = list.get(i - 1).getMessage(); + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + String[] headerAttributes = getMessageHeaderProperties(headerBody); + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; + CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + _messageList.put(messageData); + } + } + catch (AMQException e) + { + JMException jme = new JMException("Error creating message contents: " + e); + jme.initCause(e); + throw jme; + } + + return _messageList; + } + + private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) + { + List list = new ArrayList(); + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + list.add("reply-to = " + headerProperties.getReplyToAsString()); + list.add("propertyFlags = " + headerProperties.getPropertyFlags()); + list.add("ApplicationID = " + headerProperties.getAppIdAsString()); + list.add("ClusterID = " + headerProperties.getClusterIdAsString()); + list.add("UserId = " + headerProperties.getUserIdAsString()); + list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); + list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); + + int delMode = headerProperties.getDeliveryMode(); + list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); + + list.add("JMSPriority = " + headerProperties.getPriority()); + list.add("JMSType = " + headerProperties.getType()); + + long longDate = headerProperties.getExpiration(); + String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSExpiration = " + strDate); + + longDate = headerProperties.getTimestamp(); + strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSTimestamp = " + strDate); + + return list.toArray(new String[list.size()]); + } + + /** + * @see ManagedQueue#moveMessages + * @param fromMessageId + * @param toMessageId + * @param toQueueName + * @throws JMException + */ + public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + } + + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + } + + /** + * returns Notifications sent by this MBean. + */ + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; + String name = MonitorNotification.class.getName(); + String description = "Either Message count or Queue depth or Message size has reached threshold high value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[] { info1 }; + } + +} // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java new file mode 100644 index 0000000000..cbe9246f09 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class DefaultQueueRegistry implements QueueRegistry +{ + private ConcurrentMap _queueMap = new ConcurrentHashMap(); + + private final VirtualHost _virtualHost; + + public DefaultQueueRegistry(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void registerQueue(AMQQueue queue) throws AMQException + { + _queueMap.put(queue.getName(), queue); + } + + public void unregisterQueue(AMQShortString name) throws AMQException + { + _queueMap.remove(name); + } + + public AMQQueue getQueue(AMQShortString name) + { + return _queueMap.get(name); + } + + public Collection getQueueNames() + { + return _queueMap.keySet(); + } + + public Collection getQueues() + { + return _queueMap.values(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java new file mode 100644 index 0000000000..a2fcab9e73 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +public class ExchangeBinding +{ + private final Exchange _exchange; + private final AMQShortString _routingKey; + private final FieldTable _arguments; + + private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + + ExchangeBinding(AMQShortString routingKey, Exchange exchange) + { + this(routingKey, exchange, EMPTY_ARGUMENTS); + } + + ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) + { + _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; + _exchange = exchange; + _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; + } + + void unbind(AMQQueue queue) throws AMQException + { + _exchange.deregisterQueue(_routingKey, queue, _arguments); + } + + public Exchange getExchange() + { + return _exchange; + } + + public AMQShortString getRoutingKey() + { + return _routingKey; + } + + public FieldTable getArguments() + { + return _arguments; + } + + public int hashCode() + { + return (_exchange == null ? 0 : _exchange.hashCode()) + + (_routingKey == null ? 0 : _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); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java new file mode 100644 index 0000000000..fb839c1783 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -0,0 +1,82 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; + +/** + * 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 +{ + 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(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + { + _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); + } + + + public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) + { + return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); + } + + + /** + * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java new file mode 100644 index 0000000000..6466e81dd2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * Signals that the dequeue of a message from a queue failed. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Indicates the a message could not be dequeued from a queue. + *
      + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo Happens as a consequence of a message store failure, or reference counting error. Both of which migh become + * runtime exceptions, as unrecoverable conditions? In which case this one might be dropped too. + */ +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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java new file mode 100644 index 0000000000..d38932bb61 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.AMQException; + +public interface Filterable +{ + ContentHeaderBody getContentHeaderBody() throws E; + + boolean isPersistent() throws E; + + boolean isRedelivered(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java new file mode 100644 index 0000000000..35ad5be4e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -0,0 +1,157 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.LinkedList; +import java.util.List; +import java.util.Collections; +import java.util.ArrayList; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.store.StoreContext; + +/** + */ +public class InMemoryMessageHandle implements AMQMessageHandle +{ + + private ContentHeaderBody _contentHeaderBody; + + private MessagePublishInfo _messagePublishInfo; + + private List _contentBodies; + + private boolean _redelivered; + + private long _arrivalTime; + + private final Long _messageId; + + public InMemoryMessageHandle(final Long messageId) + { + _messageId = messageId; + } + + public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException + { + return _contentHeaderBody; + } + + public Long getMessageId() + { + return _messageId; + } + + public int getBodyCount(StoreContext context) + { + return _contentBodies.size(); + } + + public long getBodySize(StoreContext context) throws AMQException + { + return getContentHeaderBody(context).bodySize; + } + + public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException + { + if (index > _contentBodies.size() - 1) + { + throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + + (_contentBodies.size() - 1)); + } + return _contentBodies.get(index); + } + + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) + throws AMQException + { + if(_contentBodies == null) + { + if(isLastContentBody) + { + _contentBodies = Collections.singletonList(contentBody); + } + else + { + _contentBodies = new ArrayList(); + _contentBodies.add(contentBody); + } + } + else + { + _contentBodies.add(contentBody); + } + } + + public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException + { + return _messagePublishInfo; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public boolean isPersistent() + { + return false; + } + + /** + * This is called when all the content has been received. + * @param messagePublishInfo + * @param contentHeaderBody + * @throws AMQException + */ + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + _messagePublishInfo = messagePublishInfo; + _contentHeaderBody = contentHeaderBody; + if(contentHeaderBody.bodySize == 0) + { + _contentBodies = Collections.EMPTY_LIST; + } + _arrivalTime = System.currentTimeMillis(); + } + + public void removeMessage(StoreContext storeContext) throws AMQException + { + // NO OP + } + + public long getArrivalTime() + { + return _arrivalTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java new file mode 100644 index 0000000000..091baf2751 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -0,0 +1,319 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.exchange.NoRouteException; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; + +public class IncomingMessage implements Filterable +{ + + /** Used for debugging purposes. */ + private static final Logger _logger = Logger.getLogger(IncomingMessage.class); + + private static final boolean SYNCHED_CLOCKS = + ApplicationRegistry.getInstance().getConfiguration().getSynchedClocks(); + + private final MessagePublishInfo _messagePublishInfo; + private ContentHeaderBody _contentHeaderBody; + private AMQMessageHandle _messageHandle; + private final Long _messageId; + private final TransactionalContext _txnContext; + + private static final boolean MSG_AUTH = + ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); + + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + /** + * This is stored during routing, to know the queues to which this message should immediately be + * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done + * by the message handle. + */ + private ArrayList _destinationQueues; + + private AMQProtocolSession _publisher; + private MessageStore _messageStore; + private long _expiration; + + private Exchange _exchange; + + + public IncomingMessage(final Long messageId, + final MessagePublishInfo info, + final TransactionalContext txnContext, + final AMQProtocolSession publisher) + { + _messageId = messageId; + _messagePublishInfo = info; + _txnContext = txnContext; + _publisher = publisher; + + } + + public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException + { + _contentHeaderBody = contentHeaderBody; + } + + public void setExpiration() + { + long expiration = + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getExpiration(); + long timestamp = + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getTimestamp(); + + if (SYNCHED_CLOCKS) + { + _expiration = expiration; + } + else + { + // Update TTL to be in broker time. + if (expiration != 0L) + { + if (timestamp != 0L) + { + // todo perhaps use arrival time + long diff = (System.currentTimeMillis() - timestamp); + + if ((diff > 1000L) || (diff < 1000L)) + { + _expiration = expiration + diff; + } + } + } + } + + } + + public void routingComplete(final MessageStore store, + final 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 + + if(_destinationQueues != null) + { + for (int i = 0; i < _destinationQueues.size(); i++) + { + store.enqueueMessage(_txnContext.getStoreContext(), + _destinationQueues.get(i), _messageId); + } + } + } + } + + public AMQMessage deliverToQueues() + throws AMQException + { + + // we get a reference to the destination queues now so that we can clear the + // transient message data as quickly as possible + if (_logger.isDebugEnabled()) + { + _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); + } + + AMQMessage message = null; + + try + { + // first we allow the handle to know that the message has been fully received. This is useful if it is + // maintaining any calculated values based on content chunks + _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), + _messagePublishInfo, getContentHeaderBody()); + + + + message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); + + message.setExpiration(_expiration); + message.setClientIdentifier(_publisher.getSessionIdentifier()); + + // 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()); + + AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; + + if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) + { + throw new UnauthorizedAccessException("Acccess Refused",message); + } + + if ((_destinationQueues == null) || _destinationQueues.size() == 0) + { + + if (isMandatory() || isImmediate()) + { + throw new NoRouteException("No Route for message", message); + + } + else + { + _logger.warn("MESSAGE DISCARDED: No routes for message - " + message); + } + } + else + { + int offset; + final int queueCount = _destinationQueues.size(); + message.incrementReference(queueCount); + if(queueCount == 1) + { + offset = 0; + } + else + { + offset = ((int)(message.getMessageId().longValue())) % queueCount; + if(offset < 0) + { + offset = -offset; + } + } + for (int i = offset; i < queueCount; i++) + { + // normal deliver so add this message at the end. + _txnContext.deliver(_destinationQueues.get(i), message); + } + for (int i = 0; i < offset; i++) + { + // normal deliver so add this message at the end. + _txnContext.deliver(_destinationQueues.get(i), message); + } + } + + message.clearStoreContext(); + return message; + } + finally + { + // Remove refence for routing process . Reference count should now == delivered queue count + if(message != null) message.decrementReference(_txnContext.getStoreContext()); + } + + } + + public void addContentBodyFrame(final ContentChunk contentChunk) + throws AMQException + { + + _bodyLengthReceived += contentChunk.getSize(); + + _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); + + } + + public boolean allContentReceived() + { + return (_bodyLengthReceived == getContentHeaderBody().bodySize); + } + + public AMQShortString getExchange() throws AMQException + { + return _messagePublishInfo.getExchange(); + } + + public AMQShortString getRoutingKey() throws AMQException + { + return _messagePublishInfo.getRoutingKey(); + } + + public boolean isMandatory() throws AMQException + { + return _messagePublishInfo.isMandatory(); + } + + + public boolean isImmediate() throws AMQException + { + return _messagePublishInfo.isImmediate(); + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + + public boolean isPersistent() + { + //todo remove literal values to a constant file such as AMQConstants in common + return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2; + } + + public boolean isRedelivered() + { + return false; + } + + public void setMessageStore(final MessageStore messageStore) + { + _messageStore = messageStore; + } + + public Long getMessageId() + { + return _messageId; + } + + public void setExchange(final Exchange e) + { + _exchange = e; + } + + public void route() throws AMQException + { + _exchange.route(this); + } + + public void enqueue(final ArrayList queues) + { + _destinationQueues = queues; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java new file mode 100644 index 0000000000..579656893b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -0,0 +1,245 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +/** + * The management interface exposed to allow management of a queue. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedQueue +{ + static final String TYPE = "Queue"; + static final int VERSION = 2; + + /** + * Returns the Name of the ManagedQueue. + * @return the name of the managedQueue. + * @throws IOException + */ + @MBeanAttribute(name="Name", description = TYPE + " Name") + String getName() throws IOException; + + /** + * Total number of messages on the queue, which are yet to be delivered to the consumer(s). + * @return number of undelivered message in the Queue. + * @throws IOException + */ + @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") + Integer getMessageCount() throws IOException; + + /** + * Tells the total number of messages receieved by the queue since startup. + * @return total number of messages received. + * @throws IOException + */ + @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") + Long getReceivedMessageCount() throws IOException; + + /** + * Size of messages in the queue + * @return + * @throws IOException + */ + @MBeanAttribute(name="QueueDepth", description="The total size(Bytes) of messages in the queue") + Long getQueueDepth() throws IOException, JMException; + + /** + * Returns the total number of active subscribers to the queue. + * @return the number of active subscribers + * @throws IOException + */ + @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") + Integer getActiveConsumerCount() throws IOException; + + /** + * Returns the total number of subscribers to the queue. + * @return the number of subscribers. + * @throws IOException + */ + @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") + Integer getConsumerCount() throws IOException; + + /** + * Tells the Owner of the ManagedQueue. + * @return the owner's name. + * @throws IOException + */ + @MBeanAttribute(name="Owner", description = "Owner") + String getOwner() throws IOException; + + /** + * Tells whether this ManagedQueue is durable or not. + * @return true if this ManagedQueue is a durable queue. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") + boolean isDurable() throws IOException; + + /** + * Tells if the ManagedQueue is set to AutoDelete. + * @return true if the ManagedQueue is set to AutoDelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") + boolean isAutoDelete() throws IOException; + + /** + * Returns the maximum age of a message (expiration time) in milliseconds + * @return the maximum age + * @throws IOException + */ + Long getMaximumMessageAge() throws IOException; + + /** + * Sets the maximum age of a message in milliseconds + * @param age maximum age of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value(milliseconds) for message age") + void setMaximumMessageAge(Long age) throws IOException; + + /** + * Returns the maximum size of a message (in Bytes) allowed to be accepted by the + * ManagedQueue. This is useful in setting notifications or taking + * appropriate action, if the size of the message received is more than + * the allowed size. + * @return the maximum size of a message allowed to be aceepted by the + * ManagedQueue. + * @throws IOException + */ + Long getMaximumMessageSize() throws IOException; + + /** + * Sets the maximum size of the message (in Bytes) that is allowed to be + * accepted by the Queue. + * @param size maximum size of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(Bytes) for a message size") + void setMaximumMessageSize(Long size) throws IOException; + + /** + * Tells the maximum number of messages that can be stored in the queue. + * This is useful in setting the notifications or taking required + * action is the number of message increase this limit. + * @return maximum muber of message allowed to be stored in the queue. + * @throws IOException + */ + Long getMaximumMessageCount() throws IOException; + + /** + * Sets the maximum number of messages allowed to be stored in the queue. + * @param value the maximum number of messages allowed to be stored in the queue. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") + void setMaximumMessageCount(Long value) throws IOException; + + /** + * This is useful for setting notifications or taking required action if the size of messages + * stored in the queue increases over this limit. + * @return threshold high value for Queue Depth + * @throws IOException + */ + Long getMaximumQueueDepth() throws IOException; + + /** + * Sets the maximum size of all the messages together, that can be stored + * in the queue. + * @param value + * @throws IOException + */ + @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth") + void setMaximumQueueDepth(Long value) throws IOException; + + + //********** Operations *****************// + + + /** + * Returns a subset of all the messages stored in the queue. The messages + * are returned based on the given index numbers. + * @param fromIndex + * @param toIndex + * @return + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="viewMessages", + description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") + TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, + @MBeanOperationParameter(name="to index", description="to index")int toIndex) + throws IOException, JMException, AMQException; + + @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") + CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) + throws IOException, JMException; + + /** + * Deletes the first message from top. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", + impact= MBeanOperationInfo.ACTION) + void deleteMessageFromTop() throws IOException, JMException; + + /** + * Clears the queue by deleting all the undelivered messages from the queue. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="clearQueue", + description="Clears the queue by deleting all the undelivered messages from the queue", + impact= MBeanOperationInfo.ACTION) + void clearQueue() throws IOException, JMException; + + /** + * Moves the messages in given range of message Ids to given Queue. QPID-170 + * @param fromMessageId first in the range of message ids + * @param toMessageId last in the range of message ids + * @param toQueue where the messages are to be moved + * @throws IOException + * @throws JMException + * @throws AMQException + */ + @MBeanOperation(name="moveMessages", + description="You can move messages to another queue from this queue ", + impact= MBeanOperationInfo.ACTION) + void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, + @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, + @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) + throws IOException, JMException, AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java new file mode 100644 index 0000000000..090096d3c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * MessageCleanupException represents the failure to perform reference counting on messages correctly. This should not + * happen, but there may be programming errors giving race conditions that cause the reference counting to go wrong. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Signals that the reference count of a message has gone below zero. + *
      Indicates that a message store has lost a message which is still referenced. + *
      + * + * @todo Not an AMQP exception as no status code. + * + * @todo The race conditions leading to this error should be cleaned up, and a runtime exception used instead. If the + * message store loses messages, then something is seriously wrong and it would be sensible to terminate the + * broker. This may be disguising out of memory errors. + */ +public class MessageCleanupException extends AMQException +{ + public MessageCleanupException(long messageId, AMQException e) + { + super("Failed to cleanup message with id " + messageId, e); + } + + public MessageCleanupException(String message) + { + super(message); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java new file mode 100644 index 0000000000..0b214ca336 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.store.MessageStore; + +/** + * Constructs a message handle based on the publish body, the content header and the queue to which the message + * has been routed. + * + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class MessageHandleFactory +{ + + public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) + { + // just hardcoded for now + if (persistent) + { + return new WeakReferenceMessageHandle(messageId, store); + } + else + { + return new InMemoryMessageHandle(messageId); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java new file mode 100644 index 0000000000..6118a4c11f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +/** + * Encapsulates a publish body and a content header. In the context of the message store these are treated as a + * single unit. + */ +public class MessageMetaData +{ + private MessagePublishInfo _messagePublishInfo; + + private ContentHeaderBody _contentHeaderBody; + + private int _contentChunkCount; + + private long _arrivalTime; + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); + } + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) + { + _contentHeaderBody = contentHeaderBody; + _messagePublishInfo = publishBody; + _contentChunkCount = contentChunkCount; + _arrivalTime = arrivalTime; + } + + public int getContentChunkCount() + { + return _contentChunkCount; + } + + public void setContentChunkCount(int contentChunkCount) + { + _contentChunkCount = contentChunkCount; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void setArrivalTime(long arrivalTime) + { + _arrivalTime = arrivalTime; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java new file mode 100644 index 0000000000..d6fd1eec89 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; + +/** + * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate + * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is + * always used to report this condition. + * + *

      + *
      CRC Card
      Responsibilities Collaborations + *
      Represent failure to deliver a message that must be delivered. + *
      + */ +public class NoConsumersException extends RequiredDeliveryException +{ + public NoConsumersException(AMQMessage message) + { + super("Immediate delivery is not possible.", message); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.NO_CONSUMERS; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java new file mode 100644 index 0000000000..6f9efd3200 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +public enum NotificationCheck +{ + + MESSAGE_COUNT_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + int msgCount; + final long maximumMessageCount = queue.getMaximumMessageCount(); + if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount) + { + listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached."); + return true; + } + return false; + } + }, + MESSAGE_SIZE_ALERT(true) + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + final long maximumMessageSize = queue.getMaximumMessageSize(); + if(maximumMessageSize != 0) + { + // Check for threshold message size + long messageSize; + try + { + messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; + } + catch (AMQException e) + { + messageSize = 0; + } + + + if (messageSize >= maximumMessageSize) + { + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + return true; + } + } + return false; + } + + }, + QUEUE_DEPTH_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + // Check for threshold queue depth in bytes + final long maximumQueueDepth = queue.getMaximumQueueDepth(); + + if(maximumQueueDepth != 0) + { + final long queueDepth = queue.getQueueDepth(); + + if (queueDepth >= maximumQueueDepth) + { + listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached."); + return true; + } + } + return false; + } + + }, + MESSAGE_AGE_ALERT + { + boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + { + + final long maxMessageAge = queue.getMaximumMessageAge(); + if(maxMessageAge != 0) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - maxMessageAge; + final long firstArrivalTime = queue.getOldestMessageArrivalTime(); + + if(firstArrivalTime < thresholdTime) + { + long oldestAge = currentTime - firstArrivalTime; + listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached."); + + return true; + } + } + return false; + + } + + } + ; + + private final boolean _messageSpecific; + + NotificationCheck() + { + this(false); + } + + NotificationCheck(boolean messageSpecific) + { + _messageSpecific = messageSpecific; + } + + public boolean isMessageSpecific() + { + return _messageSpecific; + } + + abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java new file mode 100644 index 0000000000..fd46a8a5ff --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -0,0 +1,169 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.AMQException; + +public class PriorityQueueList implements QueueEntryList +{ + private final AMQQueue _queue; + private final QueueEntryList[] _priorityLists; + private final int _priorities; + private final int _priorityOffset; + + public PriorityQueueList(AMQQueue queue, int priorities) + { + _queue = queue; + _priorityLists = new QueueEntryList[priorities]; + _priorities = priorities; + _priorityOffset = 5-((priorities + 1)/2); + for(int i = 0; i < priorities; i++) + { + _priorityLists[i] = new SimpleQueueEntryList(queue); + } + } + + public int getPriorities() + { + return _priorities; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public QueueEntry add(AMQMessage message) + { + try + { + int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; + if(index >= _priorities) + { + index = _priorities-1; + } + else if(index < 0) + { + index = 0; + } + return _priorityLists[index].add(message); + } + catch (AMQException e) + { + // TODO - fix AMQ Exception + throw new RuntimeException(e); + } + + } + + public QueueEntry next(QueueEntry node) + { + QueueEntryImpl nodeImpl = (QueueEntryImpl)node; + QueueEntry next = nodeImpl.getNext(); + + if(next == null) + { + QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList(); + int index; + for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--); + + while(next == null && index != 0) + { + index--; + next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext(); + } + + } + return next; + } + + private final class PriorityQueueEntryListIterator implements QueueEntryIterator + { + private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; + private QueueEntry _lastNode; + + PriorityQueueEntryListIterator() + { + for(int i = 0; i < _priorityLists.length; i++) + { + _iterators[i] = _priorityLists[i].iterator(); + } + _lastNode = _iterators[_iterators.length - 1].getNode(); + } + + + public boolean atTail() + { + for(int i = 0; i < _iterators.length; i++) + { + if(!_iterators[i].atTail()) + { + return false; + } + } + return true; + } + + public QueueEntry getNode() + { + return _lastNode; + } + + public boolean advance() + { + for(int i = _iterators.length-1; i >= 0; i--) + { + if(_iterators[i].advance()) + { + _lastNode = _iterators[i].getNode(); + return true; + } + } + return false; + } + } + + public QueueEntryIterator iterator() + { + return new PriorityQueueEntryListIterator(); + } + + public QueueEntry getHead() + { + return _priorityLists[_priorities-1].getHead(); + } + + static class Factory implements QueueEntryListFactory + { + private final int _priorities; + + Factory(int priorities) + { + _priorities = priorities; + } + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new PriorityQueueList(queue, _priorities); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java new file mode 100644 index 0000000000..2657c459a9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -0,0 +1,184 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public interface QueueEntry extends Comparable +{ + + + + public static enum State + { + AVAILABLE, + ACQUIRED, + EXPIRED, + DEQUEUED, + DELETED + } + + public static interface StateChangeListener + { + public void stateChanged(QueueEntry entry, State oldSate, State newState); + } + + public abstract class EntryState + { + private EntryState() + { + } + + public abstract State getState(); + } + + + public final class AvailableState extends EntryState + { + + public State getState() + { + return State.AVAILABLE; + } + } + + + public final class DequeuedState extends EntryState + { + + public State getState() + { + return State.DEQUEUED; + } + } + + + public final class DeletedState extends EntryState + { + + public State getState() + { + return State.DELETED; + } + } + + public final class ExpiredState extends EntryState + { + + public State getState() + { + return State.EXPIRED; + } + } + + + public final class NonSubscriptionAcquiredState extends EntryState + { + public State getState() + { + return State.ACQUIRED; + } + } + + public final class SubscriptionAcquiredState extends EntryState + { + private final Subscription _subscription; + + public SubscriptionAcquiredState(Subscription subscription) + { + _subscription = subscription; + } + + + public State getState() + { + return State.ACQUIRED; + } + + public Subscription getSubscription() + { + return _subscription; + } + } + + + final static EntryState AVAILABLE_STATE = new AvailableState(); + final static EntryState DELETED_STATE = new DeletedState(); + final static EntryState DEQUEUED_STATE = new DequeuedState(); + final static EntryState EXPIRED_STATE = new ExpiredState(); + final static EntryState NON_SUBSCRIPTION_ACQUIRED_STATE = new NonSubscriptionAcquiredState(); + + + + + AMQQueue getQueue(); + + AMQMessage getMessage(); + + long getSize(); + + boolean getDeliveredToConsumer(); + + boolean expired() throws AMQException; + + boolean isAcquired(); + + boolean acquire(); + boolean acquire(Subscription sub); + + boolean delete(); + boolean isDeleted(); + + boolean acquiredBySubscription(); + + void setDeliveredToSubscription(); + + void release(); + + String debugIdentity(); + + boolean immediateAndNotDelivered(); + + void setRedelivered(boolean b); + + Subscription getDeliveredSubscription(); + + void reject(); + + void reject(Subscription subscription); + + boolean isRejectedBy(Subscription subscription); + + void requeue(StoreContext storeContext) throws AMQException; + + void dequeue(final StoreContext storeContext) throws FailedDequeueException; + + void dispose(final StoreContext storeContext) throws MessageCleanupException; + + void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException; + + boolean isQueueDeleted(); + + void addStateChangeListener(StateChangeListener listener); + boolean removeStateChangeListener(StateChangeListener listener); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java new file mode 100644 index 0000000000..dbad5438dc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -0,0 +1,388 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.log4j.Logger; + +import java.util.Set; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.CopyOnWriteArraySet; + + +public class QueueEntryImpl implements QueueEntry +{ + + /** + * Used for debugging purposes. + */ + private static final Logger _log = Logger.getLogger(QueueEntryImpl.class); + + private final SimpleQueueEntryList _queueEntryList; + + private AMQMessage _message; + + + private Set _rejectedBy = null; + + private volatile EntryState _state = AVAILABLE_STATE; + + private static final + AtomicReferenceFieldUpdater + _stateUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, EntryState.class, "_state"); + + + private volatile Set _stateChangeListeners; + + private static final + AtomicReferenceFieldUpdater + _listenersUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, Set.class, "_stateChangeListeners"); + + + private static final + AtomicLongFieldUpdater + _entryIdUpdater = + AtomicLongFieldUpdater.newUpdater + (QueueEntryImpl.class, "_entryId"); + + + private volatile long _entryId; + + volatile QueueEntryImpl _next; + + + QueueEntryImpl(SimpleQueueEntryList queueEntryList) + { + this(queueEntryList,null,Long.MIN_VALUE); + _state = DELETED_STATE; + } + + + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) + { + _queueEntryList = queueEntryList; + _message = message; + + _entryIdUpdater.set(this, entryId); + } + + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) + { + _queueEntryList = queueEntryList; + _message = message; + } + + protected void setEntryId(long entryId) + { + _entryIdUpdater.set(this, entryId); + } + + protected long getEntryId() + { + return _entryId; + } + + public AMQQueue getQueue() + { + return _queueEntryList.getQueue(); + } + + public AMQMessage getMessage() + { + return _message; + } + + public long getSize() + { + return getMessage().getSize(); + } + + public boolean getDeliveredToConsumer() + { + return getMessage().getDeliveredToConsumer(); + } + + public boolean expired() throws AMQException + { + return getMessage().expired(getQueue()); + } + + public boolean isAcquired() + { + return _state.getState() == State.ACQUIRED; + } + + public boolean acquire() + { + return acquire(NON_SUBSCRIPTION_ACQUIRED_STATE); + } + + private boolean acquire(final EntryState state) + { + boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state); + if(acquired && _stateChangeListeners != null) + { + notifyStateChange(State.AVAILABLE, State.ACQUIRED); + } + + return acquired; + } + + public boolean acquire(Subscription sub) + { + return acquire(sub.getOwningState()); + } + + public boolean acquiredBySubscription() + { + + return (_state instanceof SubscriptionAcquiredState); + } + + public void setDeliveredToSubscription() + { + getMessage().setDeliveredToConsumer(); + } + + public void release() + { + _stateUpdater.set(this,AVAILABLE_STATE); + } + + public String debugIdentity() + { + return getMessage().debugIdentity(); + } + + + public boolean immediateAndNotDelivered() + { + return _message.immediateAndNotDelivered(); + } + + public void setRedelivered(boolean b) + { + getMessage().setRedelivered(b); + } + + public Subscription getDeliveredSubscription() + { + EntryState state = _state; + if (state instanceof SubscriptionAcquiredState) + { + return ((SubscriptionAcquiredState) state).getSubscription(); + } + else + { + return null; + } + + } + + public void reject() + { + reject(getDeliveredSubscription()); + } + + public void reject(Subscription subscription) + { + if (subscription != null) + { + if (_rejectedBy == null) + { + _rejectedBy = new HashSet(); + } + + _rejectedBy.add(subscription); + } + else + { + _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + } + } + + public boolean isRejectedBy(Subscription subscription) + { + + if (_rejectedBy != null) // We have subscriptions that rejected this message + { + return _rejectedBy.contains(subscription); + } + else // This messasge hasn't been rejected yet. + { + return false; + } + } + + + public void requeue(final StoreContext storeContext) throws AMQException + { + getQueue().requeue(storeContext, this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } + } + + public void dequeue(final StoreContext storeContext) throws FailedDequeueException + { + EntryState state = _state; + + if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) + { + if (state instanceof SubscriptionAcquiredState) + { + Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); + s.restoreCredit(this); + } + + getQueue().dequeue(storeContext, this); + if(_stateChangeListeners != null) + { + notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); + } + + } + + } + + private void notifyStateChange(final State oldState, final State newState) + { + for(StateChangeListener l : _stateChangeListeners) + { + l.stateChanged(this, oldState, newState); + } + } + + public void dispose(final StoreContext storeContext) throws MessageCleanupException + { + if(delete()) + { + getMessage().decrementReference(storeContext); + } + } + + public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + { + //if the queue is null then the message is waiting to be acked, but has been removed. + if (getQueue() != null) + { + dequeue(storeContext); + } + + dispose(storeContext); + } + + public boolean isQueueDeleted() + { + return getQueue().isDeleted(); + } + + public void addStateChangeListener(StateChangeListener listener) + { + Set listeners = _stateChangeListeners; + if(listeners == null) + { + _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet()); + listeners = _stateChangeListeners; + } + + listeners.add(listener); + } + + public boolean removeStateChangeListener(StateChangeListener listener) + { + Set listeners = _stateChangeListeners; + if(listeners != null) + { + return listeners.remove(listener); + } + + return false; + } + + + public int compareTo(final QueueEntry o) + { + QueueEntryImpl other = (QueueEntryImpl)o; + return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0; + } + + public QueueEntryImpl getNext() + { + + QueueEntryImpl next = nextNode(); + while(next != null && next.isDeleted()) + { + + final QueueEntryImpl newNext = next.nextNode(); + if(newNext != null) + { + SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext); + next = nextNode(); + } + else + { + next = null; + } + + } + return next; + } + + QueueEntryImpl nextNode() + { + return _next; + } + + public boolean isDeleted() + { + return _state == DELETED_STATE; + } + + public boolean delete() + { + EntryState state = _state; + + if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) + { + _queueEntryList.advanceHead(); + return true; + } + else + { + return false; + } + } + + public QueueEntryList getQueueEntryList() + { + return _queueEntryList; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java new file mode 100644 index 0000000000..c5c115a2d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java @@ -0,0 +1,30 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +public interface QueueEntryIterator +{ + boolean atTail(); + + QueueEntry getNode(); + + boolean advance(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java new file mode 100644 index 0000000000..313e076f61 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -0,0 +1,34 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +public interface QueueEntryList +{ + AMQQueue getQueue(); + + QueueEntry add(AMQMessage message); + + QueueEntry next(QueueEntry node); + + QueueEntryIterator iterator(); + + QueueEntry getHead(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java new file mode 100644 index 0000000000..4dbce45f67 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java @@ -0,0 +1,26 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +interface QueueEntryListFactory +{ + public QueueEntryList createQueueEntryList(AMQQueue queue); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java new file mode 100644 index 0000000000..959ca03c80 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java @@ -0,0 +1,27 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + + +public interface QueueNotificationListener +{ + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java new file mode 100644 index 0000000000..1210f0e97c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collection; + +public interface QueueRegistry +{ + VirtualHost getVirtualHost(); + + void registerQueue(AMQQueue queue) throws AMQException; + + void unregisterQueue(AMQShortString name) throws AMQException; + + AMQQueue getQueue(AMQShortString name); + + Collection getQueueNames(); + + Collection getQueues(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java new file mode 100644 index 0000000000..09258682bd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -0,0 +1,1600 @@ +package org.apache.qpid.server.queue; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import javax.management.JMException; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener +{ + private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + private final AMQShortString _name; + + /** null means shared */ + private final AMQShortString _owner; + + private final boolean _durable; + + /** If true, this queue is deleted when the last subscriber is removed */ + private final boolean _autoDelete; + + private final VirtualHost _virtualHost; + + /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ + private final ExchangeBindings _bindings = new ExchangeBindings(this); + + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + private final List _deleteTaskList = new CopyOnWriteArrayList(); + + private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); + + private final AtomicLong _atomicQueueSize = new AtomicLong(0L); + + private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); + + protected final SubscriptionList _subscriptionList = new SubscriptionList(this); + private final AtomicReference _lastSubscriptionNode = new AtomicReference(_subscriptionList.getHead()); + + private volatile Subscription _exclusiveSubscriber; + + protected final QueueEntryList _entries; + + private final AMQQueueMBean _managedObject; + private final Executor _asyncDelivery; + private final AtomicLong _totalMessagesReceived = new AtomicLong(); + + /** max allowed size(KB) of a single message */ + public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); + + /** max allowed number of messages on a queue. */ + public long _maximumMessageCount = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageCount(); + + /** max queue depth for the queue */ + public long _maximumQueueDepth = ApplicationRegistry.getInstance().getConfiguration().getMaximumQueueDepth(); + + /** maximum message age before alerts occur */ + public long _maximumMessageAge = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageAge(); + + /** the minimum interval between sending out consecutive alerts of the same type */ + public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); + + private static final int MAX_ASYNC_DELIVERIES = 10; + + private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); + + private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); + private AtomicReference _asynchronousRunner = new AtomicReference(null); + private AtomicInteger _deliveredMessages = new AtomicInteger(); + private AtomicBoolean _stopped = new AtomicBoolean(false); + + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException + { + this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); + } + + protected SimpleAMQQueue(AMQShortString name, + boolean durable, + AMQShortString owner, + boolean autoDelete, + VirtualHost virtualHost, + QueueEntryListFactory entryListFactory) + throws AMQException + { + + if (name == null) + { + throw new IllegalArgumentException("Queue name must not be null"); + } + + if (virtualHost == null) + { + throw new IllegalArgumentException("Virtual Host must not be null"); + } + + _name = name; + _durable = durable; + _owner = owner; + _autoDelete = autoDelete; + _virtualHost = virtualHost; + _entries = entryListFactory.createQueueEntryList(this); + + _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); + + try + { + _managedObject = new AMQQueueMBean(this); + _managedObject.register(); + } + catch (JMException e) + { + throw new AMQException("AMQQueue MBean creation has failed ", e); + } + + resetNotifications(); + + } + + public void resetNotifications() + { + // This ensure that the notification checks for the configured alerts are created. + setMaximumMessageAge(_maximumMessageAge); + setMaximumMessageCount(_maximumMessageCount); + setMaximumMessageSize(_maximumMessageSize); + setMaximumQueueDepth(_maximumQueueDepth); + } + + // ------ Getters and Setters + + public AMQShortString getName() + { + return _name; + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public AMQShortString getOwner() + { + return _owner; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + // ------ bind and unbind + + public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + { + exchange.registerQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + } + + _bindings.addBinding(routingKey, arguments, exchange); + } + + public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + { + exchange.deregisterQueue(routingKey, this, arguments); + if (isDurable() && exchange.isDurable()) + { + _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + } + + boolean removed = _bindings.remove(routingKey, arguments, exchange); + if (!removed) + { + _logger.error("Mismatch between queue bindings and exchange record of bindings"); + } + } + + public List getExchangeBindings() + { + return new ArrayList(_bindings.getExchangeBindings()); + } + + // ------ Manage Subscriptions + + public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException + { + + if (isExclusiveSubscriber()) + { + throw new ExistingExclusiveSubscription(); + } + + if (exclusive) + { + if (getConsumerCount() != 0) + { + throw new ExistingSubscriptionPreventsExclusive(); + } + else + { + _exclusiveSubscriber = subscription; + + } + } + + _activeSubscriberCount.incrementAndGet(); + subscription.setStateListener(this); + subscription.setLastSeenEntry(null, _entries.getHead()); + + if (!isDeleted()) + { + subscription.setQueue(this); + _subscriptionList.add(subscription); + if (isDeleted()) + { + subscription.queueDeleted(this); + } + } + else + { + // TODO + } + + deliverAsync(subscription); + + } + + public synchronized void unregisterSubscription(final Subscription subscription) throws AMQException + { + if (subscription == null) + { + throw new NullPointerException("subscription argument is null"); + } + + boolean removed = _subscriptionList.remove(subscription); + + if (removed) + { + subscription.close(); + // No longer can the queue have an exclusive consumer + setExclusiveSubscriber(null); + + QueueEntry lastSeen; + + while ((lastSeen = subscription.getLastSeenEntry()) != null) + { + subscription.setLastSeenEntry(lastSeen, null); + } + + // auto-delete queues must be deleted if there are no remaining subscribers + + if (_autoDelete && getConsumerCount() == 0) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Auto-deleteing queue:" + this); + } + + delete(); + + // 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 + subscription.queueDeleted(this); + } + } + + } + + // ------ Enqueue / Dequeue + + public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException + { + + incrementQueueCount(); + incrementQueueSize(message); + + _totalMessagesReceived.incrementAndGet(); + + QueueEntry entry; + Subscription exclusiveSub = _exclusiveSubscriber; + + if (exclusiveSub != null) + { + exclusiveSub.getSendLock(); + + try + { + entry = _entries.add(message); + + deliverToSubscription(exclusiveSub, entry); + + // where there is more than one producer there's a reasonable chance that even though there is + // no "queueing" we do not deliver because we get an interleving of _entries.add and + // deliverToSubscription between threads. Therefore have one more try. + if (!(entry.isAcquired() || entry.isDeleted())) + { + deliverToSubscription(exclusiveSub, entry); + } + } + finally + { + exclusiveSub.releaseSendLock(); + } + } + else + { + entry = _entries.add(message); + /* + + iterate over subscriptions and if any is at the end of the queue and can deliver this message, then deliver the message + + */ + SubscriptionList.SubscriptionNode node = _lastSubscriptionNode.get(); + SubscriptionList.SubscriptionNode nextNode = node.getNext(); + if (nextNode == null) + { + nextNode = _subscriptionList.getHead().getNext(); + } + while (nextNode != null) + { + if (_lastSubscriptionNode.compareAndSet(node, nextNode)) + { + break; + } + else + { + node = _lastSubscriptionNode.get(); + nextNode = node.getNext(); + if (nextNode == null) + { + nextNode = _subscriptionList.getHead().getNext(); + } + } + } + + // always do one extra loop after we believe we've finished + // this catches the case where we *just* miss an update + int loops = 2; + + while (!(entry.isAcquired() || entry.isDeleted()) && loops != 0) + { + if (nextNode == null) + { + loops--; + nextNode = _subscriptionList.getHead(); + } + else + { + // if subscription at end, and active, offer + Subscription sub = nextNode.getSubscription(); + deliverToSubscription(sub, entry); + } + nextNode = nextNode.getNext(); + + } + } + + if (entry.immediateAndNotDelivered()) + { + dequeue(storeContext, entry); + entry.dispose(storeContext); + } + else if (!(entry.isAcquired() || entry.isDeleted())) + { + checkSubscriptionsNotAheadOfDelivery(entry); + + deliverAsync(); + } + + _managedObject.checkForNotification(entry.getMessage()); + + return entry; + } + + private void deliverToSubscription(final Subscription sub, final QueueEntry entry) + throws AMQException + { + + sub.getSendLock(); + try + { + if (subscriptionReadyAndHasInterest(sub, entry) + && !sub.isSuspended()) + { + if (!sub.wouldSuspend(entry)) + { + if (!sub.isBrowser() && !entry.acquire(sub)) + { + // restore credit here that would have been taken away by wouldSuspend since we didn't manage + // to acquire the entry for this subscription + sub.restoreCredit(entry); + } + else + { + + deliverMessage(sub, entry); + + } + } + } + } + finally + { + sub.releaseSendLock(); + } + } + + protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) + { + // This method is only required for queues which mess with ordering + // Simple Queues don't :-) + } + + private void incrementQueueSize(final AMQMessage message) + { + getAtomicQueueSize().addAndGet(message.getSize()); + } + + private void incrementQueueCount() + { + getAtomicQueueCount().incrementAndGet(); + } + + private void deliverMessage(final Subscription sub, final QueueEntry entry) + throws AMQException + { + _deliveredMessages.incrementAndGet(); + sub.send(entry); + + } + + private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) + { + + // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no + // interest in. + QueueEntry node = sub.getLastSeenEntry(); + while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node))) + { + + QueueEntry newNode = _entries.next(node); + if (newNode != null) + { + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + else + { + node = null; + break; + } + + } + + if (node == entry) + { + // If the first entry that subscription can process is the one we are trying to deliver to it, then we are + // good + return true; + } + else + { + // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing + // no-one else has updated it to something furhter on in the list + //TODO - check + //updateLastSeenEntry(sub, entry); + return false; + } + + } + + private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry) + { + QueueEntry node = sub.getLastSeenEntry(); + + if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) + { + do + { + if (sub.setLastSeenEntry(node, entry)) + { + return; + } + else + { + node = sub.getLastSeenEntry(); + } + } + while (node != null && entry.compareTo(node) < 0); + } + + } + + public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException + { + + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards + while (subscriberIter.advance()) + { + Subscription sub = subscriberIter.getNode().getSubscription(); + + // we don't make browsers send the same stuff twice + if (!sub.isBrowser()) + { + updateLastSeenEntry(sub, entry); + } + } + + deliverAsync(); + + } + + public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + { + decrementQueueCount(); + decrementQueueSize(entry); + if (entry.acquiredBySubscription()) + { + _deliveredMessages.decrementAndGet(); + } + + try + { + AMQMessage msg = entry.getMessage(); + if (msg.isPersistent()) + { + _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); + } + //entry.dispose(storeContext); + + } + catch (MessageCleanupException e) + { + // Message was dequeued, but could not then be deleted + // though it is no longer referenced. This should be very + // rare and can be detected and cleaned up on recovery or + // done through some form of manual intervention. + _logger.error(e, e); + } + catch (AMQException e) + { + throw new FailedDequeueException(_name.toString(), e); + } + + } + + private void decrementQueueSize(final QueueEntry entry) + { + getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); + } + + void decrementQueueCount() + { + getAtomicQueueCount().decrementAndGet(); + } + + public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException + { + /* TODO : This is wrong as the subscription may be suspended, we should instead change the state of the message + entry to resend and move back the subscription pointer. */ + + subscription.getSendLock(); + try + { + if (!subscription.isClosed()) + { + deliverMessage(subscription, entry); + return true; + } + else + { + return false; + } + } + finally + { + subscription.releaseSendLock(); + } + } + + public int getConsumerCount() + { + return _subscriptionList.size(); + } + + public int getActiveConsumerCount() + { + return _activeSubscriberCount.get(); + } + + public boolean isUnused() + { + return getConsumerCount() == 0; + } + + public boolean isEmpty() + { + return getMessageCount() == 0; + } + + public int getMessageCount() + { + return getAtomicQueueCount().get(); + } + + public long getQueueDepth() + { + return getAtomicQueueSize().get(); + } + + public int getUndeliveredMessageCount() + { + int count = getMessageCount() - _deliveredMessages.get(); + if (count < 0) + { + return 0; + } + else + { + return count; + } + } + + public long getReceivedMessageCount() + { + return _totalMessagesReceived.get(); + } + + public long getOldestMessageArrivalTime() + { + QueueEntry entry = getOldestQueueEntry(); + return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); + } + + protected QueueEntry getOldestQueueEntry() + { + return _entries.next(_entries.getHead()); + } + + public boolean isDeleted() + { + return _deleted.get(); + } + + public List getMessagesOnTheQueue() + { + ArrayList entryList = new ArrayList(); + QueueEntryIterator queueListIterator = _entries.iterator(); + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (node != null && !node.isDeleted()) + { + entryList.add(node); + } + } + return entryList; + + } + + public void stateChange(Subscription sub, Subscription.State oldState, Subscription.State newState) + { + if (oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE) + { + _activeSubscriberCount.decrementAndGet(); + + } + else if (newState == Subscription.State.ACTIVE) + { + if (oldState != Subscription.State.ACTIVE) + { + _activeSubscriberCount.incrementAndGet(); + + } + deliverAsync(sub); + } + } + + public int compareTo(final AMQQueue o) + { + return _name.compareTo(o.getName()); + } + + public AtomicInteger getAtomicQueueCount() + { + return _atomicQueueCount; + } + + public AtomicLong getAtomicQueueSize() + { + return _atomicQueueSize; + } + + private boolean isExclusiveSubscriber() + { + return _exclusiveSubscriber != null; + } + + private void setExclusiveSubscriber(Subscription exclusiveSubscriber) + { + _exclusiveSubscriber = exclusiveSubscriber; + } + + public static interface QueueEntryFilter + { + public boolean accept(QueueEntry entry); + + public boolean filterComplete(); + } + + public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) + { + return getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return messageId >= fromMessageId && messageId <= toMessageId; + } + + public boolean filterComplete() + { + return false; + } + }); + } + + public QueueEntry getMessageOnTheQueue(final long messageId) + { + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + private boolean _complete; + + public boolean accept(QueueEntry entry) + { + _complete = entry.getMessage().getMessageId() == messageId; + return _complete; + } + + public boolean filterComplete() + { + return _complete; + } + }); + return entries.isEmpty() ? null : entries.get(0); + } + + public List getMessagesOnTheQueue(QueueEntryFilter filter) + { + ArrayList entryList = new ArrayList(); + QueueEntryIterator queueListIterator = _entries.iterator(); + while (queueListIterator.advance() && !filter.filterComplete()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && filter.accept(node)) + { + entryList.add(node); + } + } + return entryList; + + } + + public void moveMessagesToAnotherQueue(final long fromMessageId, + final long toMessageId, + String queueName, + StoreContext storeContext) + { + + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + MessageStore store = getVirtualHost().getMessageStore(); + + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + return (messageId >= fromMessageId) + && (messageId <= toMessageId) + && entry.acquire(); + } + + public boolean filterComplete() + { + return false; + } + }); + + try + { + store.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : entries) + { + AMQMessage message = entry.getMessage(); + + if (message.isPersistent() && toQueue.isDurable()) + { + store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + } + // dequeue does not decrement the refence count + entry.dequeue(storeContext); + } + + // Commit and flush the move transcations. + try + { + store.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + } + catch (AMQException e) + { + try + { + store.abortTran(storeContext); + } + catch (AMQException rollbackEx) + { + _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); + } + throw new RuntimeException(e); + } + + try + { + for (QueueEntry entry : entries) + { + toQueue.enqueue(storeContext, entry.getMessage()); + + } + } + catch (MessageCleanupException e) + { + throw new RuntimeException(e); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void copyMessagesToAnotherQueue(final long fromMessageId, + final long toMessageId, + String queueName, + final StoreContext storeContext) + { + AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + MessageStore store = getVirtualHost().getMessageStore(); + + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + final long messageId = entry.getMessage().getMessageId(); + if ((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + if (!entry.isDeleted()) + { + return entry.getMessage().incrementReference(); + } + } + + return false; + } + + public boolean filterComplete() + { + return false; + } + }); + + try + { + store.beginTran(storeContext); + + // Move the messages in on the message store. + for (QueueEntry entry : entries) + { + AMQMessage message = entry.getMessage(); + + if (message.isReferenced() && message.isPersistent() && toQueue.isDurable()) + { + store.enqueueMessage(storeContext, toQueue, message.getMessageId()); + } + } + + // Commit and flush the move transcations. + try + { + store.commitTran(storeContext); + } + catch (AMQException e) + { + throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); + } + } + catch (AMQException e) + { + try + { + store.abortTran(storeContext); + } + catch (AMQException rollbackEx) + { + _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); + } + throw new RuntimeException(e); + } + + try + { + for (QueueEntry entry : entries) + { + if (entry.getMessage().isReferenced()) + { + toQueue.enqueue(storeContext, entry.getMessage()); + } + } + } + catch (MessageCleanupException e) + { + throw new RuntimeException(e); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + { + + try + { + QueueEntryIterator queueListIterator = _entries.iterator(); + + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + + final long messageId = node.getMessage().getMessageId(); + + if ((messageId >= fromMessageId) + && (messageId <= toMessageId) + && !node.isDeleted() + && node.acquire()) + { + node.discard(storeContext); + } + + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + // ------ Management functions + + public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + { + QueueEntryIterator queueListIterator = _entries.iterator(); + boolean noDeletes = true; + + while (noDeletes && queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && node.acquire()) + { + node.discard(storeContext); + noDeletes = false; + } + + } + } + + public long clearQueue(StoreContext storeContext) throws AMQException + { + + QueueEntryIterator queueListIterator = _entries.iterator(); + long count = 0; + + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && node.acquire()) + { + node.discard(storeContext); + count++; + } + + } + return count; + + } + + public void addQueueDeleteTask(final Task task) + { + _deleteTaskList.add(task); + } + + public int delete() throws AMQException + { + if (!_deleted.getAndSet(true)) + { + + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); + + while (subscriptionIter.advance()) + { + Subscription s = subscriptionIter.getNode().getSubscription(); + if (s != null) + { + s.queueDeleted(this); + } + } + + _bindings.deregister(); + _virtualHost.getQueueRegistry().unregisterQueue(_name); + + _managedObject.unregister(); + for (Task task : _deleteTaskList) + { + task.doTask(this); + } + + _deleteTaskList.clear(); + stop(); + } + return getMessageCount(); + + } + + public void stop() + { + if (!_stopped.getAndSet(true)) + { + ReferenceCountingExecutorService.getInstance().releaseExecutorService(); + } + } + + public void deliverAsync() + { + _stateChangeCount.incrementAndGet(); + + Runner runner = new Runner(); + + if (_asynchronousRunner.compareAndSet(null, runner)) + { + _asyncDelivery.execute(runner); + } + } + + public void deliverAsync(Subscription sub) + { + _asyncDelivery.execute(new SubFlushRunner(sub)); + } + + private class Runner implements ReadWriteRunnable + { + public void run() + { + try + { + processQueue(this); + } + catch (AMQException e) + { + _logger.error(e); + } + + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } + } + + private class SubFlushRunner implements ReadWriteRunnable + { + private final Subscription _sub; + + public SubFlushRunner(Subscription sub) + { + _sub = sub; + } + + public void run() + { + boolean complete = false; + try + { + complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); + + } + catch (AMQException e) + { + _logger.error(e); + } + if (!complete && !_sub.isSuspended()) + { + _asyncDelivery.execute(this); + } + + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } + } + + public void flushSubscription(Subscription sub) throws AMQException + { + flushSubscription(sub, Long.MAX_VALUE); + } + + public boolean flushSubscription(Subscription sub, Long iterations) throws AMQException + { + boolean atTail = false; + + while (!sub.isSuspended() && !atTail && iterations != 0) + { + try + { + sub.getSendLock(); + atTail = attemptDelivery(sub); + if (atTail && sub.isAutoClose()) + { + unregisterSubscription(sub); + + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + } + else if (!atTail) + { + iterations--; + } + } + finally + { + sub.releaseSendLock(); + } + } + + // if there's (potentially) more than one subscription the others will potentially not have been advanced to the + // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc + // which would give us memory "leak". + + if (!isExclusiveSubscriber()) + { + advanceAllSubscriptions(); + } + return atTail; + } + + private boolean attemptDelivery(Subscription sub) throws AMQException + { + boolean atTail = false; + boolean advanced = false; + boolean subActive = sub.isActive(); + if (subActive) + { + QueueEntry node = moveSubscriptionToNextNode(sub); + if (!(node.isAcquired() || node.isDeleted())) + { + if (!sub.isSuspended()) + { + if (sub.hasInterest(node)) + { + if (!sub.wouldSuspend(node)) + { + if (!sub.isBrowser() && !node.acquire(sub)) + { + sub.restoreCredit(node); + } + else + { + deliverMessage(sub, node); + + if (sub.isBrowser()) + { + QueueEntry newNode = _entries.next(node); + + if (newNode != null) + { + advanced = true; + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + } + } + + } + else // Not enough Credit for message and wouldSuspend + { + //QPID-1187 - Treat the subscription as suspended for this message + // and wait for the message to be removed to continue delivery. + subActive = false; + node.addStateChangeListener(new QueueEntryListener(sub, node)); + } + } + else + { + // this subscription is not interested in this node so we can skip over it + QueueEntry newNode = _entries.next(node); + if (newNode != null) + { + sub.setLastSeenEntry(node, newNode); + } + } + } + + } + atTail = (_entries.next(node) == null) && !advanced; + } + return atTail || !subActive; + } + + protected void advanceAllSubscriptions() throws AMQException + { + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + while (subscriberIter.advance()) + { + SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); + Subscription sub = subNode.getSubscription(); + moveSubscriptionToNextNode(sub); + } + } + + private QueueEntry moveSubscriptionToNextNode(final Subscription sub) + throws AMQException + { + QueueEntry node = sub.getLastSeenEntry(); + + while (node != null && (node.isAcquired() || node.isDeleted() || node.expired())) + { + if (!node.isAcquired() && !node.isDeleted() && node.expired()) + { + if (node.acquire()) + { + final StoreContext reapingStoreContext = new StoreContext(); + node.discard(reapingStoreContext); + } + } + QueueEntry newNode = _entries.next(node); + if (newNode != null) + { + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); + } + else + { + break; + } + + } + return node; + } + + private void processQueue(Runnable runner) throws AMQException + { + long stateChangeCount; + long previousStateChangeCount = Long.MIN_VALUE; + boolean deliveryIncomplete = true; + + int extraLoops = 1; + Long iterations = new Long(MAX_ASYNC_DELIVERIES); + + _asynchronousRunner.compareAndSet(runner, null); + + while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) + { + // we want to have one extra loop after every subscription has reached the point where it cannot move + // further, just in case the advance of one subscription in the last loop allows a different subscription to + // move forward in the next iteration + + if (previousStateChangeCount != stateChangeCount) + { + extraLoops = 1; + } + + previousStateChangeCount = stateChangeCount; + deliveryIncomplete = _subscriptionList.size() != 0; + boolean done = true; + + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); + //iterate over the subscribers and try to advance their pointer + while (subscriptionIter.advance()) + { + boolean closeConsumer = false; + Subscription sub = subscriptionIter.getNode().getSubscription(); + sub.getSendLock(); + try + { + if (sub != null) + { + + QueueEntry node = moveSubscriptionToNextNode(sub); + if (node != null) + { + done = attemptDelivery(sub); + } + } + if (done) + { + if (extraLoops == 0) + { + deliveryIncomplete = false; + if (sub.isAutoClose()) + { + unregisterSubscription(sub); + + ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + } + } + else + { + extraLoops--; + } + } + else + { + iterations--; + extraLoops = 1; + } + } + finally + { + sub.releaseSendLock(); + } + } + _asynchronousRunner.set(null); + } + + // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit + // therefore we should schedule this runner again (unless someone beats us to it :-) ). + if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner)) + { + _asyncDelivery.execute(runner); + } + } + + @Override + public void checkMessageStatus() throws AMQException + { + + final StoreContext storeContext = new StoreContext(); + + QueueEntryIterator queueListIterator = _entries.iterator(); + + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && node.expired() && node.acquire()) + { + node.discard(storeContext); + } + else + { + _managedObject.checkForNotification(node.getMessage()); + } + } + + } + + public long getMinimumAlertRepeatGap() + { + return _minimumAlertRepeatGap; + } + + public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap) + { + _minimumAlertRepeatGap = minimumAlertRepeatGap; + } + + public long getMaximumMessageAge() + { + return _maximumMessageAge; + } + + public void setMaximumMessageAge(long maximumMessageAge) + { + _maximumMessageAge = maximumMessageAge; + if (maximumMessageAge == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT); + } + } + + public long getMaximumMessageCount() + { + return _maximumMessageCount; + } + + public void setMaximumMessageCount(final long maximumMessageCount) + { + _maximumMessageCount = maximumMessageCount; + if (maximumMessageCount == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT); + } + + } + + public long getMaximumQueueDepth() + { + return _maximumQueueDepth; + } + + // Sets the queue depth, the max queue size + public void setMaximumQueueDepth(final long maximumQueueDepth) + { + _maximumQueueDepth = maximumQueueDepth; + if (maximumQueueDepth == 0L) + { + _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT); + } + + } + + public long getMaximumMessageSize() + { + return _maximumMessageSize; + } + + public void setMaximumMessageSize(final long maximumMessageSize) + { + _maximumMessageSize = maximumMessageSize; + if (maximumMessageSize == 0L) + { + _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT); + } + else + { + _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT); + } + } + + public Set getNotificationChecks() + { + return _notificationChecks; + } + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + private final class QueueEntryListener implements QueueEntry.StateChangeListener + { + private final QueueEntry _entry; + private final Subscription _sub; + + public QueueEntryListener(final Subscription sub, final QueueEntry entry) + { + _entry = entry; + _sub = sub; + } + + public boolean equals(Object o) + { + return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub; + } + + public int hashCode() + { + return System.identityHashCode(_entry) ^ System.identityHashCode(_sub); + } + + public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState) + { + entry.removeStateChangeListener(this); + deliverAsync(_sub); + } + } + + public List getMessagesOnTheQueue(int num) + { + return getMessagesOnTheQueue(num, 0); + } + + public List getMessagesOnTheQueue(int num, int offset) + { + ArrayList ids = new ArrayList(num); + QueueEntryIterator it = _entries.iterator(); + for (int i = 0; i < offset; i++) + { + it.advance(); + } + + for (int i = 0; i < num && !it.atTail(); i++) + { + it.advance(); + ids.add(it.getNode().getMessage().getMessageId()); + } + return ids; + } + + public void configure(QueueConfiguration config) + { + if (config != null) + { + setMaximumMessageAge(config.getMaximumMessageAge()); + setMaximumQueueDepth(config.getMaximumQueueDepth()); + setMaximumMessageSize(config.getMaximumMessageSize()); + setMaximumMessageCount(config.getMaximumMessageCount()); + setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java new file mode 100644 index 0000000000..a46c5ae2e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -0,0 +1,178 @@ +package org.apache.qpid.server.queue; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +public class SimpleQueueEntryList implements QueueEntryList +{ + private final QueueEntryImpl _head; + + private volatile QueueEntryImpl _tail; + + static final AtomicReferenceFieldUpdater + _tailUpdater = + AtomicReferenceFieldUpdater.newUpdater + (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail"); + + + private final AMQQueue _queue; + + static final AtomicReferenceFieldUpdater + _nextUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); + + + + + + public SimpleQueueEntryList(AMQQueue queue) + { + _queue = queue; + _head = new QueueEntryImpl(this); + _tail = _head; + } + + void advanceHead() + { + QueueEntryImpl head = _head.nextNode(); + while(head._next != null && head.isDeleted()) + { + + final QueueEntryImpl newhead = head.nextNode(); + if(newhead != null) + { + _nextUpdater.compareAndSet(_head,head, newhead); + } + head = _head.nextNode(); + } + } + + + public AMQQueue getQueue() + { + return _queue; + } + + + public QueueEntry add(AMQMessage message) + { + QueueEntryImpl node = new QueueEntryImpl(this, message); + for (;;) + { + QueueEntryImpl tail = _tail; + QueueEntryImpl next = tail.nextNode(); + if (tail == _tail) + { + if (next == null) + { + node.setEntryId(tail.getEntryId()+1); + if (_nextUpdater.compareAndSet(tail, null, node)) + { + _tailUpdater.compareAndSet(this, tail, node); + + return node; + } + } + else + { + _tailUpdater.compareAndSet(this,tail, next); + } + } + } + } + + public QueueEntry next(QueueEntry node) + { + return ((QueueEntryImpl)node).getNext(); + } + + + public class QueueEntryIteratorImpl implements QueueEntryIterator + { + + private QueueEntryImpl _lastNode; + + QueueEntryIteratorImpl(QueueEntryImpl startNode) + { + _lastNode = startNode; + } + + + public boolean atTail() + { + return _lastNode.nextNode() == null; + } + + public QueueEntry getNode() + { + + return _lastNode; + + } + + public boolean advance() + { + + if(!atTail()) + { + QueueEntryImpl nextNode = _lastNode.nextNode(); + while(nextNode.isDeleted() && nextNode.nextNode() != null) + { + nextNode = nextNode.nextNode(); + } + _lastNode = nextNode; + return true; + + } + else + { + return false; + } + + } + + } + + + public QueueEntryIterator iterator() + { + return new QueueEntryIteratorImpl(_head); + } + + + public QueueEntry getHead() + { + return _head; + } + + static class Factory implements QueueEntryListFactory + { + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new SimpleQueueEntryList(queue); + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java new file mode 100644 index 0000000000..9b91c71a1d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -0,0 +1,127 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; + +/** + * Contains data that is only used in AMQMessage transiently, e.g. while the content + * body fragments are arriving. + * + * Having this data stored in a separate class means that the AMQMessage class avoids + * the small overhead of numerous guaranteed-null references. + * + * @author Apache Software Foundation + */ +public class TransientMessageData +{ + /** + * Stored temporarily until the header has been received at which point it is used when + * constructing the handle + */ + private MessagePublishInfo _messagePublishInfo; + + /** + * Also stored temporarily. + */ + private ContentHeaderBody _contentHeaderBody; + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + /** + * This is stored during routing, to know the queues to which this message should immediately be + * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done + * by the message handle. + */ + private List _destinationQueues; + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public List getDestinationQueues() + { + return _destinationQueues == null ? (List) Collections.EMPTY_LIST : _destinationQueues; + } + + public void setDestinationQueues(List destinationQueues) + { + _destinationQueues = destinationQueues; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public long getBodyLengthReceived() + { + return _bodyLengthReceived; + } + + public void addBodyLength(int value) + { + _bodyLengthReceived += value; + } + + public boolean isAllContentReceived() throws AMQException + { + return _bodyLengthReceived == _contentHeaderBody.bodySize; + } + + public void addDestinationQueue(AMQQueue queue) + { + if(_destinationQueues == null) + { + _destinationQueues = new ArrayList(); + } + _destinationQueues.add(queue); + } + + public boolean isPersistent() + { + //todo remove literal values to a constant file such as AMQConstants in common + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java new file mode 100644 index 0000000000..295cb266b9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; + +/** + * UnauthorizedAccessException is a {@link RequiredDeliveryException} that represents the failure case where a message + * is published with a user id different from the one used when creating the connection . + * The AMQP status code, 403, is always used to report this condition. + * + */ + +public class UnauthorizedAccessException extends RequiredDeliveryException +{ + public UnauthorizedAccessException(String msg, AMQMessage amqMessage) + { + super(msg, amqMessage); + } + + public AMQConstant getReplyCode() + { + return AMQConstant.ACCESS_REFUSED; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java new file mode 100644 index 0000000000..3ed8b0e55c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -0,0 +1,219 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class WeakReferenceMessageHandle implements AMQMessageHandle +{ + private WeakReference _contentHeaderBody; + + private WeakReference _messagePublishInfo; + + private List> _contentBodies; + + private boolean _redelivered; + + private final MessageStore _messageStore; + + private final Long _messageId; + private long _arrivalTime; + + public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore) + { + _messageId = messageId; + _messageStore = messageStore; + } + + public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException + { + ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); + if (chb == null) + { + MessageMetaData mmd = loadMessageMetaData(context); + chb = mmd.getContentHeaderBody(); + } + return chb; + } + + public Long getMessageId() + { + return _messageId; + } + + private MessageMetaData loadMessageMetaData(StoreContext context) + throws AMQException + { + MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); + populateFromMessageMetaData(mmd); + return mmd; + } + + private void populateFromMessageMetaData(MessageMetaData mmd) + { + _arrivalTime = mmd.getArrivalTime(); + _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); + _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); + } + + public int getBodyCount(StoreContext context) throws AMQException + { + if (_contentBodies == null) + { + MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); + int chunkCount = mmd.getContentChunkCount(); + _contentBodies = new ArrayList>(chunkCount); + for (int i = 0; i < chunkCount; i++) + { + _contentBodies.add(new WeakReference(null)); + } + } + return _contentBodies.size(); + } + + public long getBodySize(StoreContext context) throws AMQException + { + return getContentHeaderBody(context).bodySize; + } + + public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException + { + if (index > _contentBodies.size() - 1) + { + throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + + (_contentBodies.size() - 1)); + } + WeakReference wr = _contentBodies.get(index); + ContentChunk cb = wr.get(); + if (cb == null) + { + cb = _messageStore.getContentBodyChunk(context, _messageId, index); + _contentBodies.set(index, new WeakReference(cb)); + } + return cb; + } + + /** + * Content bodies are set before the publish and header frames + * + * @param storeContext + * @param contentChunk + * @param isLastContentBody + * @throws AMQException + */ + public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException + { + if (_contentBodies == null && isLastContentBody) + { + _contentBodies = new ArrayList>(1); + } + else + { + if (_contentBodies == null) + { + _contentBodies = new LinkedList>(); + } + } + _contentBodies.add(new WeakReference(contentChunk)); + _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, + contentChunk, isLastContentBody); + } + + public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException + { + MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); + if (bpb == null) + { + MessageMetaData mmd = loadMessageMetaData(context); + + bpb = mmd.getMessagePublishInfo(); + } + return bpb; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public boolean isPersistent() + { + return true; + } + + /** + * This is called when all the content has been received. + * + * @param publishBody + * @param contentHeaderBody + * @throws AMQException + */ + public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + // if there are no content bodies the list will be null so we must + // create en empty list here + if (contentHeaderBody.bodySize == 0) + { + _contentBodies = new LinkedList>(); + } + + final long arrivalTime = System.currentTimeMillis(); + + + MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); + + _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); + + + populateFromMessageMetaData(mmd); + } + + public void removeMessage(StoreContext storeContext) throws AMQException + { + _messageStore.removeMessage(storeContext, _messageId); + } + + public long getArrivalTime() + { + return _arrivalTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java new file mode 100644 index 0000000000..22b4623ae1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -0,0 +1,290 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.mina.common.IoAcceptor; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +/** + * 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 +{ + protected static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); + + private static Map _instanceMap = new HashMap(); + + private final Map, Object> _configuredObjects = new HashMap, Object>(); + + protected final ServerConfiguration _configuration; + + public static final int DEFAULT_INSTANCE = 1; + public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; + public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; + + protected final Map _acceptors = new HashMap(); + + protected ManagedObjectRegistry _managedObjectRegistry; + + protected AuthenticationManager _authenticationManager; + + protected VirtualHostRegistry _virtualHostRegistry; + + protected ACLManager _accessManager; + + protected PrincipalDatabaseManager _databaseManager; + + protected PluginManager _pluginManager; + + static + { + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); + } + + private static class ShutdownService implements Runnable + { + public void run() + { + removeAll(); + } + } + + 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); + } + } + + /** + * Method to cleanly shutdown specified registry running in this JVM + * + * @param instanceID the instance to shutdown + */ + + public static void remove(int instanceID) + { + try + { + IApplicationRegistry instance = _instanceMap.get(instanceID); + if (instance != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); + } + instance.close(); + } + } + catch (Exception e) + { + _logger.error("Error shutting down Application Registry(" + instanceID + "): " + e, e); + } + finally + { + _instanceMap.remove(instanceID); + } + } + + /** Method to cleanly shutdown all registries currently running in this JVM */ + public static void removeAll() + { + Object[] keys = _instanceMap.keySet().toArray(); + for (Object k : keys) + { + remove((Integer) k); + } + } + + protected ApplicationRegistry(ServerConfiguration configuration) + { + _configuration = configuration; + } + + public static IApplicationRegistry getInstance() + { + return getInstance(DEFAULT_INSTANCE); + } + + public static IApplicationRegistry getInstance(int instanceID) + { + synchronized (IApplicationRegistry.class) + { + IApplicationRegistry instance = _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", e); + } + } + else + { + return instance; + } + } + } + + public void close() throws Exception + { + if (_logger.isInfoEnabled()) + { + _logger.info("Shutting down ApplicationRegistry:"+this); + } + + //Stop incomming connections + unbind(); + + //Shutdown virtualhosts + for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) + { + virtualHost.close(); + } + + // Replace above with this +// _virtualHostRegistry.close(); + +// _accessManager.close(); + +// _databaseManager.close(); + + _authenticationManager.close(); + +// _databaseManager.close(); + + // close the rmi registry(if any) started for management + if (_managedObjectRegistry != null) + { + _managedObjectRegistry.close(); + } + +// _pluginManager.close(); + } + + private void unbind() + { + synchronized (_acceptors) + { + for (InetSocketAddress bindAddress : _acceptors.keySet()) + { + IoAcceptor acceptor = _acceptors.get(bindAddress); + acceptor.unbind(bindAddress); + } + } + } + + public ServerConfiguration getConfiguration() + { + return _configuration; + } + + public void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor) + { + synchronized (_acceptors) + { + _acceptors.put(bindAddress, acceptor); + } + } + + public static void setDefaultApplicationRegistry(String clazz) + { + _APPLICATION_REGISTRY = clazz; + } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public ACLManager getAccessManager() throws ConfigurationException + { + return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public PluginManager getPluginManager() + { + return _pluginManager; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java new file mode 100644 index 0000000000..39164883f9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -0,0 +1,87 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import java.io.File; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +public class ConfigurationFileApplicationRegistry extends ApplicationRegistry +{ + + public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException + { + super(new ServerConfiguration(configurationURL)); + } + + public void initialise() throws Exception + { + initialiseManagedObjectRegistry(); + + _virtualHostRegistry = new VirtualHostRegistry(); + + _pluginManager = new PluginManager(_configuration.getPluginDirectory()); + + _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); + + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + + _databaseManager.initialiseManagement(_configuration); + + _managedObjectRegistry.start(); + + initialiseVirtualHosts(); + + } + + private void initialiseVirtualHosts() throws Exception + { + for (String name : _configuration.getVirtualHosts()) + { + _virtualHostRegistry.registerVirtualHost(new VirtualHost(_configuration.getVirtualHostConfig(name))); + } + getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); + } + + private void initialiseManagedObjectRegistry() throws AMQException + { + if (_configuration.getManagementEnabled()) + { + _managedObjectRegistry = new JMXManagedObjectRegistry(); + } + else + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java new file mode 100644 index 0000000000..bbfda3addc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import java.util.Collection; +import java.net.InetSocketAddress; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.mina.common.IoAcceptor; + +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; + + /** + * Shutdown this Registry + * @throws Exception - //fixme needs to be made more specific + */ + void close() throws Exception; + + /** + * 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 + */ + ServerConfiguration getConfiguration(); + + ManagedObjectRegistry getManagedObjectRegistry(); + + PrincipalDatabaseManager getDatabaseManager(); + + AuthenticationManager getAuthenticationManager(); + + VirtualHostRegistry getVirtualHostRegistry(); + + ACLManager getAccessManager() throws ConfigurationException; + + PluginManager getPluginManager(); + + /** + * Register any acceptors for this registry + * @param bindAddress The address that the acceptor has been bound with + * @param acceptor The acceptor in use + */ + void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java new file mode 100644 index 0000000000..6f7f66fad2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.SecurityConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ACLManager +{ + private static final Logger _logger = Logger.getLogger(ACLManager.class); + private PluginManager _pluginManager; + private Map _allSecurityPlugins = new HashMap(); + private Map _globalPlugins = new HashMap(); + private Map _hostPlugins = new HashMap(); + + public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException + { + this(configuration, manager, null); + } + + public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException + { + _pluginManager = manager; + + if (manager == null) // No plugin manager, no plugins + { + return; + } + + _allSecurityPlugins = _pluginManager.getSecurityPlugins(); + if (securityPlugin != null) + { + _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); + } + + _globalPlugins = configurePlugins(configuration); + } + + + public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException + { + _hostPlugins = configurePlugins(hostConfig); + } + + public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException + { + Configuration securityConfig = hostConfig.getConfiguration(); + Map plugins = new HashMap(); + Iterator keys = securityConfig.getKeys(); + Collection handledTags = new HashSet(); + while (keys.hasNext()) + { + // Splitting the string is necessary here because of the way that getKeys() returns only + // bottom level children + String tag = ((String) keys.next()).split("\\.", 2)[0]; + if (!handledTags.contains(tag)) + { + for (ACLPluginFactory plugin : _allSecurityPlugins.values()) + { + if (plugin.supportsTag(tag)) + { + _logger.warn("Plugin handling security section "+tag+" is "+plugin.getClass().getSimpleName()); + handledTags.add(tag); + plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); + } + } + } + if (!handledTags.contains(tag)) + { + _logger.warn("No plugin handled security section "+tag); + } + } + return plugins; + } + + public static Logger getLogger() + { + return _logger; + } + + private abstract class AccessCheck + { + abstract AuthzResult allowed(ACLPlugin plugin); + } + + private boolean checkAllPlugins(AccessCheck checker) + { + AuthzResult result = AuthzResult.ABSTAIN; + HashMap remainingPlugins = new HashMap(); + remainingPlugins.putAll(_globalPlugins); + for (Entry plugin : _hostPlugins.entrySet()) + { + result = checker.allowed(plugin.getValue()); + if (result == AuthzResult.DENIED) + { + // Something vetoed the access, we're done + return false; + } + else if (result == AuthzResult.ALLOWED) + { + // Remove plugin from global check list since + // host allow overrides global allow + remainingPlugins.remove(plugin.getKey()); + } + } + + for (ACLPlugin plugin : remainingPlugins.values()) + { + result = checker.allowed(plugin); + if (result == AuthzResult.DENIED) + { + return false; + } + } + return true; + } + + public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue, + final AMQShortString routingKey) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseBind(session, exch, queue, routingKey); + } + + }); + } + + public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseConnect(session, virtualHost); + } + + }); + } + + public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseConsume(session, noAck, queue); + } + + }); + } + + public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck, + final boolean noLocal, final boolean nowait, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue); + } + + }); + } + + public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete, + final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, + final boolean passive, final AMQShortString exchangeType) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait, + passive, exchangeType); + } + + }); + } + + public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete, + final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, + final AMQShortString queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue); + } + + }); + } + + public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseDelete(session, queue); + } + + }); + } + + public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseDelete(session, exchange); + } + + }); + } + + public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory, + final AMQShortString routingKey, final Exchange e) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authorisePublish(session, immediate, mandatory, routingKey, e); + } + + }); + } + + public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authorisePurge(session, queue); + } + + }); + } + + public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch, + final AMQShortString routingKey, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + + @Override + AuthzResult allowed(ACLPlugin plugin) + { + return plugin.authoriseUnbind(session, exch, routingKey, queue); + } + + }); + } + + public void addHostPlugin(ACLPlugin aclPlugin) + { + _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java new file mode 100644 index 0000000000..032184ec39 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public interface ACLPlugin +{ + public enum AuthzResult + { + ALLOWED, + DENIED, + ABSTAIN + } + + void setConfiguration(Configuration config) throws ConfigurationException; + + // These return true if the plugin thinks the action should be allowed, and false if not. + + AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + + AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); + + AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + boolean nowait, boolean passive, AMQShortString queue); + + AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); + + AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); + + AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + boolean nowait, AMQQueue queue); + + AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue); + + AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange); + + AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AMQShortString routingKey, Exchange e); + + AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue); + + AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java new file mode 100644 index 0000000000..256f093477 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +public interface ACLPluginFactory +{ + + public boolean supportsTag(String name); + + public ACLPlugin newInstance(Configuration config) throws ConfigurationException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java new file mode 100644 index 0000000000..d722da4ae0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessResult +{ + public enum AccessStatus + { + GRANTED, REFUSED + } + + private String _authorizer; + private AccessStatus _status; + + public AccessResult(ACLPlugin authorizer, AccessStatus status) + { + _status = status; + _authorizer = authorizer.getClass().getSimpleName(); + } + + public void setAuthorizer(ACLPlugin authorizer) + { + _authorizer += authorizer.getClass().getSimpleName(); + } + + public String getAuthorizer() + { + return _authorizer; + } + + public void setStatus(AccessStatus status) + { + _status = status; + } + + public AccessStatus getStatus() + { + return _status; + } + + public void addAuthorizer(ACLPlugin accessManager) + { + _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java new file mode 100644 index 0000000000..1b79a5a0e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class AccessRights +{ + public enum Rights + { + ANY, + READ, + WRITE, + READWRITE + } + + Rights _right; + + public AccessRights(Rights right) + { + _right = right; + } + + public boolean allows(Rights rights) + { + switch (_right) + { + case ANY: + return (rights.equals(Rights.WRITE) + || rights.equals(Rights.READ) + || rights.equals(Rights.READWRITE) + || rights.equals(Rights.ANY)); + case READ: + return rights.equals(Rights.READ) || rights.equals(Rights.ANY); + case WRITE: + return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); + case READWRITE: + return true; + } + return false; + } + + public Rights getRights() + { + return _right; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java new file mode 100644 index 0000000000..f51cf24caa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public interface Accessable +{ + void setAccessableName(String name); + String getAccessableName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java new file mode 100644 index 0000000000..9527120f30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java @@ -0,0 +1,6 @@ +package org.apache.qpid.server.security.access; + +public class AuthorizationManager +{ + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java new file mode 100644 index 0000000000..b65b0cdc6c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +public enum Permission +{ + CONSUME, + PUBLISH, + CREATEQUEUE, + CREATEEXCHANGE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java new file mode 100755 index 0000000000..f852514444 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -0,0 +1,612 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.QueueBindBody; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.exchange.Exchange; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class PrincipalPermissions +{ + + private static final Object CONSUME_QUEUES_KEY = new Object(); + private static final Object CONSUME_TEMPORARY_KEY = new Object(); + private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object(); + + private static final Object CREATE_QUEUES_KEY = new Object(); + private static final Object CREATE_EXCHANGES_KEY = new Object(); + + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); + private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); + private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); + + private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object(); + private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); + + private static final int PUBLISH_EXCHANGES_KEY = 0; + + private Map _permissions; + + private String _user; + + + public PrincipalPermissions(String user) + { + _user = user; + _permissions = new ConcurrentHashMap(); + } + + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: none + * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly + * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey + * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ + public void grant(Permission permission, Object... parameters) + { + switch (permission) + { + case ACCESS: + break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS + case BIND: + break; // All the details are currently included in the create setup. + case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly + Map consumeRights = (Map) _permissions.get(permission); + + if (consumeRights == null) + { + consumeRights = new ConcurrentHashMap(); + _permissions.put(permission, consumeRights); + } + + //if we have parametsre + if (parameters.length > 0) + { + AMQShortString queueName = (AMQShortString) parameters[0]; + Boolean temporary = (Boolean) parameters[1]; + Boolean ownQueueOnly = (Boolean) parameters[2]; + + if (temporary) + { + consumeRights.put(CONSUME_TEMPORARY_KEY, true); + } + else + { + consumeRights.put(CONSUME_TEMPORARY_KEY, false); + } + + if (ownQueueOnly) + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); + } + else + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); + } + + + LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); + if (queues == null) + { + queues = new LinkedList(); + consumeRights.put(CONSUME_QUEUES_KEY, queues); + } + + if (queueName != null) + { + queues.add(queueName); + } + } + + + break; + case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName + // , AMQShortString exchangeName , AMQShortString routingKey + + Map createRights = (Map) _permissions.get(permission); + + if (createRights == null) + { + createRights = new ConcurrentHashMap(); + _permissions.put(permission, createRights); + + } + + //The existence of the empty map mean permission to all. + if (parameters.length == 0) + { + return; + } + + Boolean temporary = (Boolean) parameters[0]; + + AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; + + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } + + //Allow all temp queues to be created + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } + + // We are granting CREATE rights to all temporary queues only + if (parameters.length == 1) + { + return; + } + + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) + { + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); + } + + if (exchangeName != null) + { + queue.put(exchangeName, routingKey); + } + + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } + + // Store the exchange that we are being granted rights to. This will be used as part of binding + + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } + + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + + if (exchanges == null) + { + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); + } + + //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY + exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) + { + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); + + if (rKeys == null) + { + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); + } + + rKeys.put(queueName, routingKey); + } + } + break; + case CREATEEXCHANGE: + // Parameters AMQShortString exchangeName , AMQShortString Class + Map rights = (Map) _permissions.get(permission); + if (rights == null) + { + rights = new ConcurrentHashMap(); + _permissions.put(permission, rights); + } + + Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); + if (create_exchanges == null) + { + create_exchanges = new ConcurrentHashMap(); + rights.put(CREATE_EXCHANGES_KEY, create_exchanges); + } + + //Should perhaps error if parameters[0] is null; + AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; + AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); + + //Store the exchangeName / class mapping if the mapping is null + rights.put(name, className); + break; + case DELETE: + break; + + case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + publishRights = new ConcurrentHashMap(); + _permissions.put(permission, publishRights); + } + + if (parameters == null || parameters.length == 0) + { + //If we have no parameters then allow publish to all destinations + // this is signified by having a null value for publish_exchanges + } + else + { + Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + if (publish_exchanges == null) + { + publish_exchanges = new ConcurrentHashMap(); + publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); + } + + + HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); + + // Check to see if we have a routing key + if (parameters.length == 2) + { + if (routingKeys == null) + { + routingKeys = new HashSet(); + } + //Add routing key to permitted publish destinations + routingKeys.add(parameters[1]); + } + + // Add the updated routingkey list or null if all values allowed + publish_exchanges.put(parameters[0], routingKeys); + } + break; + case PURGE: + break; + case UNBIND: + break; + } + + } + + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey + * CONSUME: AMQQueue queue + * CREATEQUEUE: Boolean autodelete, AMQShortString name + * CREATEEXCHANGE: AMQShortString exchangeName + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ + public AuthzResult authorise(Permission permission, Object... parameters) + { + + switch (permission) + { + case ACCESS: + return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it. + // The existence of this user specific PP can be validated in the map SimpleXML maintains. + case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey + + Exchange exchange = (Exchange) parameters[1]; + + AMQQueue bind_queueName = (AMQQueue) parameters[2]; + AMQShortString routingKey = (AMQShortString) parameters[3]; + + //Get all Create Rights for this user + Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); + + //Look up the Queue Creation Rights + Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues + Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); + + // Check and see if we have a queue white list to check + if (bind_create_queues_queues != null) + { + //There a white list for queues + Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); + + if (exchangeDetails == null) //Then all queue can be bound to all exchanges. + { + return AuthzResult.ALLOWED; + } + + // Check to see if we have a white list of routingkeys to check + Map rkeys = (Map) exchangeDetails.get(exchange.getName()); + + // if keys is null then any rkey is allowed on this exchange + if (rkeys == null) + { + // There is no routingkey white list + return AuthzResult.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = rkeys.keySet().iterator(); + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + if (rkey.endsWith("*")) + { + matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); + } + else + { + matched = routingKey.equals(rkey); + } + } + + + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + + + } + else + { + //There a is no white list for queues + + // So can allow all queues to be bound + // but we should first check and see if we have a temp queue and validate that we are allowed + // to bind temp queues. + + //Check to see if we have a temporary queue + if (bind_queueName.isAutoDelete()) + { + // Check and see if we have an exchange white list. + Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + // If the exchange exists then we must check to see if temporary queues are allowed here + if (bind_exchanges != null) + { + // Check to see if the requested exchange is allowed. + Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); + + return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + + //no white list so all allowed, drop through to return true below. + } + + // not a temporary queue and no white list so all allowed. + return AuthzResult.ALLOWED; + } + + case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name + + Map createRights = (Map) _permissions.get(permission); + + // If there are no create rights then deny request + if (createRights == null) + { + return AuthzResult.DENIED; + } + + //Look up the Queue Creation Rights + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues allowed to be created + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + + AMQShortString queueName = (AMQShortString) parameters[1]; + Boolean autoDelete = (Boolean) parameters[0]; + + if (autoDelete)// we have a temporary queue + { + return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + // If there is a white list then check + if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } + + } + case CREATEEXCHANGE: + Map rights = (Map) _permissions.get(permission); + + AMQShortString exchangeName = (AMQShortString) parameters[0]; + + // If the exchange list is doesn't exist then all is allowed else + // check the valid exchanges + if (rights == null || rights.containsKey(exchangeName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } + case CONSUME: // Parameters : AMQQueue + + if (parameters.length == 1 && parameters[0] instanceof AMQQueue) + { + AMQQueue queue = ((AMQQueue) parameters[0]); + Map queuePermissions = (Map) _permissions.get(permission); + + List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); + + Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); + Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); + + // If user is allowed to publish to temporary queues and this is a temp queue then allow it. + if (temporayQueues) + { + if (queue.isAutoDelete()) + // This will allow consumption from any temporary queue including ones not owned by this user. + // Of course the exclusivity will not be broken. + { + // if not limited to ownQueuesOnly then ok else check queue Owner. + return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + return AuthzResult.DENIED; + } + } + + // if queues are white listed then ensure it is ok + if (queues != null) + { + // if no queues are listed then ALL are ok othereise it must be specified. + if (ownQueuesOnly) + { + if (queue.getOwner().equals(_user)) + { + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + return AuthzResult.DENIED; + } + } + + // If we are + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + + // Can't authenticate without the right parameters + return AuthzResult.DENIED; + case DELETE: + break; + + case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + return AuthzResult.DENIED; + } + + Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + // Having no exchanges listed gives full publish rights to all exchanges + if (exchanges == null) + { + return AuthzResult.ALLOWED; + } + // Otherwise exchange must be listed in the white list + + // If the map doesn't have the exchange then it isn't allowed + if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) + { + return AuthzResult.DENIED; + } + else + { + + // Get valid routing keys + HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); + + // Having no routingKeys in the map then all are allowed. + if (routingKeys == null) + { + return AuthzResult.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = routingKeys.iterator(); + + + AMQShortString publishRKey = (AMQShortString)parameters[1]; + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + + if (rkey.endsWith("*")) + { + matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); + } + else + { + matched = publishRKey.equals(rkey); + } + } + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + case PURGE: + break; + case UNBIND: + break; + + } + + return AuthzResult.DENIED; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java new file mode 100644 index 0000000000..13151a66b8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access; + +public class VirtualHostAccess +{ + private String _vhost; + private AccessRights _rights; + + public VirtualHostAccess(String vhostaccess) + { + //format () + int hostend = vhostaccess.indexOf('('); + + if (hostend == -1) + { + throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); + } + + _vhost = vhostaccess.substring(0, hostend); + + String rights = vhostaccess.substring(hostend); + + if (rights.indexOf('r') != -1) + { + if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.READWRITE); + } + else + { + _rights = new AccessRights(AccessRights.Rights.READ); + } + } + else if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.WRITE); + } + } + + public AccessRights getAccessRights() + { + return _rights; + } + + public String getVirtualHost() + { + return _vhost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java new file mode 100644 index 0000000000..121f571abe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -0,0 +1,501 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.management; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.access.management.UserManagement; +import org.apache.log4j.Logger; +import org.apache.commons.configuration.ConfigurationException; + +import javax.management.JMException; +import javax.management.remote.JMXPrincipal; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.auth.Subject; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.List; +import java.util.Enumeration; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; +import java.security.AccessControlContext; +import java.security.AccessController; + +/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ +@MBeanDescription("User Management Interface") +public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement +{ + + private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + + private PrincipalDatabase _principalDatabase; + private Properties _accessRights; + private File _accessFile; + + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); + + // Setup for the TabularType + static TabularType _userlistDataType; // Datatype for representing User Lists + + static CompositeType _userDataType; // Composite type for representing User + static String[] _userItemNames = {"Username", "read", "write", "admin"}; + + static + { + String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", + "Management Console Write Permission", "Management Console Admin Permission"}; + + OpenType[] userItemTypes = new OpenType[4]; // User item types. + userItemTypes[0] = SimpleType.STRING; // For Username + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + String[] userDataIndex = {_userItemNames[0]}; + + try + { + _userDataType = + new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); + + _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing users incorrect."); + _userlistDataType = null; + } + } + + + public AMQUserManagementMBean() throws JMException + { + super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); + } + + public String getObjectInstanceName() + { + return UserManagement.TYPE; + } + + public boolean setPassword(String username, char[] password) + { + try + { + //delegate password changes to the Principal Database + return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + return false; + } + } + + public boolean setRights(String username, boolean read, boolean write, boolean admin) + { + + Object oldRights = null; + if ((oldRights =_accessRights.get(username)) == null) + { + // If the user doesn't exist in the access rights file check that they at least have an account. + if (_principalDatabase.getUser(username) == null) + { + return false; + } + } + + try + { + _accessRightsUpdate.lock(); + + // Update the access rights + if (admin) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); + } + else + { + if (read | write) + { + if (read) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); + } + if (write) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); + } + } + else + { + _accessRights.remove(username); + } + } + + //save the rights file + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); + + //the rights file was not successfully saved, restore user rights to previous value + _logger.warn("Reverting attempted rights update for user'" + username + "'"); + if (oldRights != null) + { + _accessRights.put(username, oldRights); + } + else + { + _accessRights.remove(username); + } + + return false; + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + return true; + } + + public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) + { + if (!setRights(username, read, write, admin)) + { + //unable to set rights for user, remove account + try + { + _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); + } + catch (AccountNotFoundException e) + { + //ignore + } + return false; + } + else + { + return true; + } + } + + return false; + } + + public boolean deleteUser(String username) + { + try + { + if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) + { + try + { + _accessRightsUpdate.lock(); + + _accessRights.remove(username); + + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); + return false; + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + return false; + } + + return true; + } + + public boolean reloadData() + { + try + { + loadAccessFile(); + _principalDatabase.reload(); + } + catch (ConfigurationException e) + { + _logger.warn("Reload failed due to:" + e); + return false; + } + catch (IOException e) + { + _logger.warn("Reload failed due to:" + e); + return false; + } + // Reload successful + return true; + } + + + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + public TabularData viewUsers() + { + // Table of users + // Username(string), Access rights Read,Write,Admin(bool,bool,bool) + + if (_userlistDataType == null) + { + _logger.warn("TabluarData not setup correctly"); + return null; + } + + List users = _principalDatabase.getUsers(); + + TabularDataSupport userList = new TabularDataSupport(_userlistDataType); + + try + { + // Create the tabular list of message header contents + for (Principal user : users) + { + // Create header attributes list + + String rights = (String) _accessRights.get(user.getName()); + + Boolean read = false; + Boolean write = false; + Boolean admin = false; + + if (rights != null) + { + read = rights.equals(MBeanInvocationHandlerImpl.READONLY) + || rights.equals(MBeanInvocationHandlerImpl.READWRITE); + write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); + admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); + } + + Object[] itemData = {user.getName(), read, write, admin}; + CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); + userList.put(messageData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create user list due to :" + e); + return null; + } + + return userList; + } + + /*** Broker Methods **/ + + /** + * setPrincipalDatabase + * + * @param database set The Database to use for user lookup + */ + public void setPrincipalDatabase(PrincipalDatabase database) + { + _principalDatabase = database; + } + + /** + * setAccessFile + * + * @param accessFile the file to use for updating. + * + * @throws java.io.IOException If the file cannot be accessed + * @throws org.apache.commons.configuration.ConfigurationException + * if checks on the file fail. + */ + public void setAccessFile(String accessFile) throws IOException, ConfigurationException + { + if (accessFile != null) + { + _accessFile = new File(accessFile); + if (!_accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFile + "' does not exist"); + } + + if (!_accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFile + "'."); + } + + if (!_accessFile.canWrite()) + { + _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); + } + + loadAccessFile(); + } + else + { + _logger.warn("Access rights file specified is null. Access rights not changed."); + } + } + + private void loadAccessFile() throws IOException, ConfigurationException + { + if(_accessFile == null) + { + _logger.error("No jmx access rights file has been specified."); + return; + } + + if(_accessFile.exists()) + { + try + { + _accessRightsUpdate.lock(); + + Properties accessRights = new Properties(); + accessRights.load(new FileInputStream(_accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + else + { + _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); + } + } + + private void checkAccessRights(Properties accessRights) + { + Enumeration values = accessRights.propertyNames(); + + while (values.hasMoreElements()) + { + String user = (String) values.nextElement(); + + if (_principalDatabase.getUser(user) == null) + { + _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); + } + } + } + + private void saveAccessFile() throws IOException + { + try + { + _accessRightsUpdate.lock(); + + // Create temporary file + File tmp = File.createTempFile(_accessFile.getName(), ".tmp"); + + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); + output.close(); + + // Rename new file to main file + tmp.renameTo(_accessFile); + + // delete tmp + tmp.delete(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + } + + private String getCurrentJMXUser() + { + AccessControlContext acc = AccessController.getContext(); + + Subject subject = Subject.getSubject(acc); + if (subject == null) + { + return "Unknown user, authentication Subject was null"; + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + return "Unknown user principals were null"; + } + + Principal principal = principals.iterator().next(); + return principal.getName(); + } + + /** + * user=read user=write user=readwrite user=admin + * + * @param accessRights The properties list of access rights to process + */ + private void setAccessRights(Properties accessRights) + { + _logger.debug("Setting Access Rights:" + accessRights); + _accessRights = accessRights; + MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java new file mode 100644 index 0000000000..9fcdd4cd17 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.management; + +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.AMQException; + +import javax.management.openmbean.TabularData; +import javax.management.openmbean.CompositeData; +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import java.io.IOException; + +public interface UserManagement +{ + + String TYPE = "UserManagement"; + int VERSION = 2; + + //********** Operations *****************// + /** + * set password for user + * + * @param username The username to create + * @param password The password for the user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setPassword", description = "Set password for user.", + impact = MBeanOperationInfo.ACTION) + boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")char[] password); + + /** + * set rights for users with given details + * + * @param username The username to create + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setRights", description = "Set access rights for user.", + impact = MBeanOperationInfo.ACTION) + boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * Create users with given details + * + * @param username The username to create + * @param password The password for the user + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "createUser", description = "Create new user from system.", + impact = MBeanOperationInfo.ACTION) + boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")char[] password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * View users returns all the users that are currently available to the system. + * + * @param username The user to delete + * + * @return The result of the operation + */ + @MBeanOperation(name = "deleteUser", description = "Delete user from system.", + impact = MBeanOperationInfo.ACTION) + boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); + + + /** + * Reload the date from disk + * + * @return The result of the operation + */ + @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", + impact = MBeanOperationInfo.ACTION) + boolean reloadData(); + + /** + * View users returns all the users that are currently available to the system. + * + * @return a table of users data (Username, read, write, admin) + */ + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", + impact = MBeanOperationInfo.INFO) + TabularData viewUsers(); + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java new file mode 100644 index 0000000000..682135bc25 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java @@ -0,0 +1,99 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. + */ +public abstract class AbstractACLPlugin implements ACLPlugin +{ + + private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; + + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, + AMQShortString routingKey) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + boolean nowait, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) + { + // TODO Auto-generated method stub + return null; + } + + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, + boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AMQShortString routingKey, Exchange e) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + return DEFAULT_ANSWER; + } + + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, + AMQQueue queue) + { + return DEFAULT_ANSWER; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java new file mode 100644 index 0000000000..4af178574b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; + +public class AllowAll extends BasicACLPlugin +{ + + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return false; + } + + public ACLPlugin newInstance(Configuration config) + { + return new AllowAll(); + } + }; + + public String getPluginName() + { + return this.getClass().getSimpleName(); + } + + @Override + protected AuthzResult getResult() + { + // Always allow + return AuthzResult.ALLOWED; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java new file mode 100644 index 0000000000..f7e537b02b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public abstract class BasicACLPlugin implements ACLPlugin +{ + + // Returns true or false if the plugin should authorise or deny the request + protected abstract AuthzResult getResult(); + + @Override + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, + AMQQueue queue, AMQShortString routingKey) + { + return getResult(); + } + + @Override + public AuthzResult authoriseConnect(AMQProtocolSession session, + VirtualHost virtualHost) + { + return getResult(); + } + + @Override + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, + AMQQueue queue) + { + return getResult(); + } + + @Override + public AuthzResult authoriseConsume(AMQProtocolSession session, + boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, + AMQQueue queue) + { + return getResult(); + } + + @Override + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, + boolean autoDelete, boolean durable, AMQShortString exchangeName, + boolean internal, boolean nowait, boolean passive, + AMQShortString exchangeType) + { + return getResult(); + } + + @Override + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, + boolean autoDelete, boolean durable, boolean exclusive, + boolean nowait, boolean passive, AMQShortString queue) + { + return getResult(); + } + + @Override + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + return getResult(); + } + + @Override + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + return getResult(); + } + + @Override + public AuthzResult authorisePublish(AMQProtocolSession session, + boolean immediate, boolean mandatory, AMQShortString routingKey, + Exchange e) + { + return getResult(); + } + + @Override + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + return getResult(); + } + + @Override + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, + AMQShortString routingKey, AMQQueue queue) + { + return getResult(); + } + + @Override + public void setConfiguration(Configuration config) + { + // no-op + } + + public boolean supportsTag(String name) + { + // This plugin doesn't support any tags + return false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java new file mode 100644 index 0000000000..26a76c9af1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Permission; + +public class DenyAll extends BasicACLPlugin +{ + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return false; + } + + public ACLPlugin newInstance(Configuration config) + { + return new DenyAll(); + } + }; + + public AccessResult authorise(AMQProtocolSession session, + Permission permission, AMQMethodBody body, Object... parameters) + throws AMQConnectionException + { + + if (ACLManager.getLogger().isInfoEnabled()) + { + ACLManager.getLogger().info( + "Denying user:" + session.getAuthorizedID()); + } + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "DenyAll Plugin"); + } + + public String getPluginName() + { + return getClass().getSimpleName(); + } + + @Override + protected AuthzResult getResult() + { + // Always deny + return AuthzResult.DENIED; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java new file mode 100644 index 0000000000..fc1bc048d4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.access.plugins; + +import java.util.Collection; +import java.util.HashSet; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; + +/** + * + * Used to suppress warnings in legacy config files that have things in which aren't handled by a plugin directly. + * + */ +public class LegacyAccessPlugin extends BasicACLPlugin +{ + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + private Collection maskedTags = new HashSet(); + { + maskedTags.add("principal-databases"); + maskedTags.add("access"); + maskedTags.add("msg-auth"); + maskedTags.add("false"); + maskedTags.add("jmx"); + } + + public boolean supportsTag(String name) + { + return maskedTags .contains(name); + } + + public ACLPlugin newInstance(Configuration config) + { + return new LegacyAccessPlugin(); + } + }; + + public String getPluginName() + { + return getClass().getSimpleName(); + } + + @Override + protected AuthzResult getResult() + { + // Always abstain + return AuthzResult.ABSTAIN; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java new file mode 100644 index 0000000000..2cc0c530de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -0,0 +1,432 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicConsumeBody; +import org.apache.qpid.framing.BasicPublishBody; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Permission; +import org.apache.qpid.server.security.access.PrincipalPermissions; +import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This uses the default + */ +public class SimpleXML implements ACLPlugin +{ + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return name.startsWith("access_control_list"); + } + + public ACLPlugin newInstance(Configuration config) + { + SimpleXML plugin = new SimpleXML(); + plugin.setConfiguration(config); + return plugin; + } + }; + + private Map _users; + private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); + + public SimpleXML() + { + _users = new ConcurrentHashMap(); + } + + public void setConfiguration(Configuration config) + { + processConfig(config); + } + + private void processConfig(Configuration config) + { + processPublish(config); + + processConsume(config); + + processCreate(config); + } + + /** + * Publish format takes Exchange + Routing Key Pairs + * + * @param config + * XML Configuration + */ + private void processPublish(Configuration config) + { + Configuration publishConfig = config.subset("access_control_list.publish"); + + // Process users that have full publish permission + String[] users = publishConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user); + } + + // Process exchange limited users + int exchangeCount = 0; + Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + // Get Exchange Name + AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); + + // Get Routing Keys + int keyCount = 0; + Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + + while (!routingkeyConfig.isEmpty()) + { + // Get RoutingKey Value + AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); + + // Apply Exchange + RoutingKey permissions to Users + users = routingkeyConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); + } + + // Apply permissions to Groups + + // Check for more configs + keyCount++; + routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + } + + // Apply Exchange wide permissions to Users + users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName); + } + + // Apply permissions to Groups + exchangeCount++; + exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + } + + private void grant(Permission permission, String user, Object... parameters) + { + PrincipalPermissions permissions = _users.get(user); + + if (permissions == null) + { + permissions = new PrincipalPermissions(user); + } + + _users.put(user, permissions); + permissions.grant(permission, parameters); + } + + private void processConsume(Configuration config) + { + Configuration consumeConfig = config.subset("access_control_list.consume"); + + // Process queue limited users + int queueCount = 0; + Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + // Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + // if there is no name then there may be a temporary element + boolean temporary = queueConfig.containsKey("temporary"); + boolean ownQueues = queueConfig.containsKey("own_queues"); + + // Process permissions for this queue + String[] users = queueConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CONSUME, user, queueName, temporary, ownQueues); + } + + // See if we have another config + queueCount++; + queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process users that have full consume permission + String[] users = consumeConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CONSUME, user); + } + } + + private void processCreate(Configuration config) + { + Configuration createConfig = config.subset("access_control_list.create"); + + // Process create permissions for queue creation + int queueCount = 0; + Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + // Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + + // if there is no name then there may be a temporary element + boolean temporary = queueConfig.containsKey("temporary"); + + int exchangeCount = 0; + Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); + + // Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CREATEEXCHANGE, user, exchange); + grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange + .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); + } + + // See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that are not bound to an exchange + String[] users = queueConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATEQUEUE, user, temporary, queueName); + } + + // See if we have another config + queueCount++; + queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process create permissions for exchange creation + int exchangeCount = 0; + Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); + + // Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CREATEEXCHANGE, user, exchange, clazz); + } + + // See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that have full create permission + String[] users = createConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATEEXCHANGE, user); + grant(Permission.CREATEQUEUE, user); + } + + } + + public String getPluginName() + { + return "Simple"; + } + + public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.BIND, null, exch, queue, routingKey); + } + } + + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.ACCESS); + } + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.CONSUME, queue); + } + } + + public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + boolean nowait, AMQQueue queue) + { + return authoriseConsume(session, noAck, queue); + } + + public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.CREATEEXCHANGE, exchangeName); + } + } + + public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + boolean nowait, boolean passive, AMQShortString queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.CREATEQUEUE, autoDelete, queue); + } + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.DELETE); + } + } + + public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.DELETE); + } + } + + public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AMQShortString routingKey, Exchange e) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.PUBLISH, e, routingKey); + } + } + + public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.PURGE); + } + } + + public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) + { + PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + if (principalPermissions == null) + { + return AuthzResult.DENIED; + } + else + { + return principalPermissions.authorise(Permission.UNBIND); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java new file mode 100644 index 0000000000..a1a399e5bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins.network; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; + +public class FirewallFactory implements ACLPluginFactory +{ + + @Override + public ACLPlugin newInstance(Configuration config) throws ConfigurationException + { + FirewallPlugin plugin = new FirewallPlugin(); + plugin.setConfiguration(config); + return plugin; + } + + @Override + public boolean supportsTag(String name) + { + return name.equals("firewall"); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java new file mode 100644 index 0000000000..85026121ab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -0,0 +1,264 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins.network; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.util.NetMatcher; + +public class FirewallPlugin extends AbstractACLPlugin +{ + + public class FirewallPluginException extends Exception {} + + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + { + public boolean supportsTag(String name) + { + return name.startsWith("firewall"); + } + + public ACLPlugin newInstance(Configuration config) throws ConfigurationException + { + FirewallPlugin plugin = new FirewallPlugin(); + plugin.setConfiguration(config); + return plugin; + } + }; + + public class FirewallRule + { + + private static final long DNS_TIMEOUT = 30000; + private AuthzResult _access; + private NetMatcher _network; + private Pattern[] _hostnamePatterns; + + public FirewallRule(String access, List networks, List hostnames) + { + _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + + if (networks != null && networks.size() > 0) + { + String[] networkStrings = objListToStringArray(networks); + _network = new NetMatcher(networkStrings); + } + + if (hostnames != null && hostnames.size() > 0) + { + int i = 0; + _hostnamePatterns = new Pattern[hostnames.size()]; + for (String hostname : objListToStringArray(hostnames)) + { + _hostnamePatterns[i++] = Pattern.compile(hostname); + } + } + + } + + private String[] objListToStringArray(List objList) + { + String[] networkStrings = new String[objList.size()]; + int i = 0; + for (Object network : objList) + { + networkStrings[i++] = (String) network; + } + return networkStrings; + } + + public boolean match(InetAddress remote) throws FirewallPluginException + { + if (_hostnamePatterns != null) + { + String hostname = getHostname(remote); + if (hostname == null) + { + throw new FirewallPluginException(); + } + for (Pattern pattern : _hostnamePatterns) + { + if (pattern.matcher(hostname).matches()) + { + return true; + } + } + return false; + } + else + { + return _network.matchInetNetwork(remote); + } + } + + /** + * @param remote the InetAddress to look up + * @return the hostname, null if not found or takes longer than 30s to find + */ + private String getHostname(final InetAddress remote) + { + final String[] hostname = new String[]{null}; + final AtomicBoolean done = new AtomicBoolean(false); + // Spawn thread + Thread thread = new Thread(new Runnable() + { + public void run() + { + hostname[0] = remote.getCanonicalHostName(); + done.getAndSet(true); + synchronized (done) + { + done.notifyAll(); + } + } + }); + + thread.run(); + long endTime = System.currentTimeMillis() + DNS_TIMEOUT; + + while (System.currentTimeMillis() < endTime && !done.get()) + { + try + { + synchronized (done) + { + done.wait(endTime - System.currentTimeMillis()); + } + } + catch (InterruptedException e) + { + // Check the time and if necessary sleep for a bit longer + } + } + return hostname[0]; + } + + public AuthzResult getAccess() + { + return _access; + } + + } + + private AuthzResult _default = AuthzResult.ABSTAIN; + private FirewallRule[] _rules; + + @Override + public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + { + if (!(session instanceof AMQMinaProtocolSession)) + { + return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which + // mean MINA right now + } + + InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session); + + if (addr == null) + { + return AuthzResult.ABSTAIN; // Not an Inet socket on the other end + } + + boolean match = false; + for (FirewallRule rule : _rules) + { + try + { + match = rule.match(addr); + } + catch (FirewallPluginException e) + { + return AuthzResult.DENIED; + } + if (match) + { + return rule.getAccess(); + } + } + return _default; + + } + + private InetAddress getInetAdressFromMinaSession(AMQMinaProtocolSession session) + { + SocketAddress remote = session.getIOSession().getRemoteAddress(); + if (remote instanceof InetSocketAddress) + { + return ((InetSocketAddress) remote).getAddress(); + } + else + { + return null; + } + } + + @Override + public void setConfiguration(Configuration config) throws ConfigurationException + { + // Get default action + String defaultAction = config.getString("[@default-action]"); + if (defaultAction == null) + { + _default = AuthzResult.ABSTAIN; + } + else if (defaultAction.toLowerCase().equals("allow")) + { + _default = AuthzResult.ALLOWED; + } + else + { + _default = AuthzResult.DENIED; + } + CompositeConfiguration finalConfig = new CompositeConfiguration(config); + + List subFiles = config.getList("firewall.xml[@fileName]"); + for (Object subFile : subFiles) + { + finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); + } + + // all rules must have an access attribute + int numRules = finalConfig.getList("rule[@access]").size(); + _rules = new FirewallRule[numRules]; + for (int i = 0; i < numRules; i++) + { + FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), finalConfig.getList("rule(" + + i + ")[@network]"), finalConfig.getList("rule(" + i + ")[@hostname]")); + _rules[i] = rule; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java new file mode 100644 index 0000000000..3f846b9dd0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import javax.security.sasl.SaslException; + +public class AuthenticationResult +{ + public enum AuthenticationStatus + { + SUCCESS, CONTINUE, ERROR + } + + public AuthenticationStatus status; + public byte[] challenge; + + private Exception cause; + + public AuthenticationResult(AuthenticationStatus status) + { + this(null, status, null); + } + + public AuthenticationResult(byte[] challenge, AuthenticationStatus status) + { + this(challenge, status, null); + } + + public AuthenticationResult(AuthenticationStatus error, Exception cause) + { + this(null, error, cause); + } + + public AuthenticationResult(byte[] challenge, AuthenticationStatus status, Exception cause) + { + this.status = status; + this.challenge = challenge; + this.cause = cause; + } + + public Exception getCause() + { + return cause; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..3c211746e3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -0,0 +1,541 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.security.Principal; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; +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 Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + AMQUserManagementMBean _mbean; + public static final String DEFAULT_ENCODING = "utf-8"; + private Map _users = new HashMap(); + private ReentrantLock _userUpdate = new ReentrantLock(); + + public Base64MD5PasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); + cram.initialise(this); + _saslServers.put(cram.getMechanismName(), cram); + + //fixme The PDs should setup a PD Mangement MBean +// try +// { +// _mbean = new AMQUserManagementMBean(); +// _mbean.setPrincipalDatabase(this); +// } +// catch (JMException e) +// { +// _logger.warn("User management disabled as unable to create MBean:" + e); +// } + } + + public void setPasswordFile(String passwordFile) throws IOException + { + 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."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * If you want to change the password for a user, use updatePassword instead. + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannont be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws 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); + } + } + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + char[] pwd = lookupPassword(principal); + + if (pwd == null) + { + throw new AccountNotFoundException("Unable to lookup the specfied users password"); + } + + byte[] byteArray = new byte[password.length]; + int index = 0; + for (char c : password) + { + byteArray[index++] = (byte) c; + } + + byte[] MD5byteArray; + try + { + MD5byteArray = HashedUser.getMD5(byteArray); + } + catch (Exception e1) + { + _logger.warn("Unable to hash password for user '" + principal + "' for comparison"); + return false; + } + + char[] hashedPassword = new char[MD5byteArray.length]; + + index = 0; + for (byte c : MD5byteArray) + { + hashedPassword[index++] = (char) c; + } + + return compareCharArray(pwd, hashedPassword); + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + /** + * Changes the password for the specified user + * + * @param principal to change the password for + * @param password plaintext password to set the password too + */ + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + HashedUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + try + { + _userUpdate.lock(); + char[] orig = user.getPassword(); + user.setPassword(password,false); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user'" + + principal + "' will revert at restart"); + //revert the password change + user.setPassword(orig,true); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (Exception e) + { + return false; + } + } + + public boolean createPrincipal(Principal principal, char[] password) + { + if (_users.get(principal.getName()) != null) + { + return false; + } + + HashedUser user; + try + { + user = new HashedUser(principal.getName(), password); + } + catch (Exception e1) + { + _logger.warn("Unable to create new user '" + principal.getName() + "'"); + return false; + } + + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + //remove the use on failure. + _users.remove(user.getName()); + return false; + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + HashedUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; + } + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(_users.values()); + } + + public Principal getUser(String username) + { + if (_users.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + /** + * 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 The principal name to lookup + * + * @return a char[] for use in SASL. + */ + private char[] lookupPassword(String name) + { + HashedUser user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + 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 || result[0].startsWith("#")) + { + continue; + } + + HashedUser user = new HashedUser(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + continue; + } + + HashedUser user = _users.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + try + { + byte[] encodedPassword = user.getEncodedPassword(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to encode new password reverting to old password."); + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + } + } + } + + for (HashedUser user : _users.values()) + { + if (user.isModified()) + { + byte[] encodedPassword; + try + { + encodedPassword = user.getEncodedPassword(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); + } + } + } + } + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public void reload() throws IOException + { + loadPasswordFile(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java new file mode 100644 index 0000000000..e0d4c49af1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -0,0 +1,232 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.AMQException; + +import javax.management.JMException; + +public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager +{ + private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); + + Map _databases; + + public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception + { + _logger.info("Initialising PrincipleDatabase authentication manager"); + _databases = initialisePrincipalDatabases(_configuration); + } + + private Map initialisePrincipalDatabases(ServerConfiguration _configuration) throws Exception + { + List databaseNames = _configuration.getPrincipalDatabaseNames(); + List databaseClasses = _configuration.getPrincipalDatabaseClass(); + Map databases = new HashMap(); + + if (databaseNames.size() == 0) + { + _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); + } + + 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, _configuration, 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 not permitted"); + } + + _logger.info("Initialised principal database '" + name + "' successfully"); + databases.put(name, (PrincipalDatabase) o); + } + + return databases; + } + + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, ServerConfiguration _configuration, int index) + throws FileNotFoundException, ConfigurationException + { + List argumentNames = _configuration.getPrincipalDatabaseAttributeNames(index); + List argumentValues = _configuration.getPrincipalDatabaseAttributeValues(index); + for (int i = 0; i < argumentNames.size(); i++) + { + String argName = argumentNames.get(i); + if ((argName == null) || (argName.length() == 0)) + { + throw new ConfigurationException("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 = null; + try + { + method = principalDatabase.getClass().getMethod(methodName, String.class); + } + catch (Exception e) + { + // do nothing.. as on error method will be null + } + + if (method == null) + { + throw new ConfigurationException("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"); + } + + try + { + method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception ite) + { + if (ite instanceof ConfigurationException) + { + throw(ConfigurationException) ite; + } + else + { + throw new ConfigurationException(ite.getMessage(), ite); + } + } + } + } + + public Map getDatabases() + { + return _databases; + } + + public void initialiseManagement(ServerConfiguration config) throws ConfigurationException + { + try + { + AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); + + List principalDBs = config.getManagementPrincipalDBs(); + + if (principalDBs.size() == 0) + { + throw new ConfigurationException("No principal-database specified for jmx security"); + } + + String databaseName = principalDBs.get(0); + + PrincipalDatabase database = getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); + } + + _mbean.setPrincipalDatabase(database); + + List jmxaccesslist = config.getManagementAccessList(); + + if (jmxaccesslist.size() == 0) + { + throw new ConfigurationException("No access control files specified for jmx security"); + } + + String jmxaccesssFile = null; + + try + { + jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); + } + catch (PropertyException e) + { + throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); + } + + try + { + _mbean.setAccessFile(jmxaccesssFile); + } + catch (IOException e) + { + _logger.warn("Unable to load access file:" + jmxaccesssFile); + } + + try + { + _mbean.register(); + } + catch (AMQException e) + { + _logger.warn("Unable to register user management MBean"); + } + } + catch (JMException e) + { + _logger.warn("User management disabled as unable to create MBean:" + e); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java new file mode 100644 index 0000000000..3690e7f92a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -0,0 +1,169 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; + +public class HashedUser implements Principal +{ + private static final Logger _logger = Logger.getLogger(HashedUser.class); + + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + HashedUser(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public HashedUser(String name, char[] password) throws UnsupportedEncodingException, NoSuchAlgorithmException + { + _name = name; + setPassword(password,false); + } + + public static byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + return md.digest(); + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password, boolean alreadyHashed) throws UnsupportedEncodingException, NoSuchAlgorithmException + { + if(alreadyHashed){ + _password = password; + } + else + { + byte[] byteArray = new byte[password.length]; + int index = 0; + for (char c : password) + { + byteArray[index++] = (byte) c; + } + + byte[] MD5byteArray = getMD5(byteArray); + + _password = new char[MD5byteArray.length]; + + index = 0; + for (byte c : MD5byteArray) + { + _password[index++] = (char) c; + } + } + + _modified = true; + _encodedPassword = null; + } + + byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + _encodedPassword = (new Base64()).encode(byteArray); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..5e4678a63b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -0,0 +1,491 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.security.Principal; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; +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 PlainPasswordFilePrincipalDatabase implements PrincipalDatabase +{ + public static final String DEFAULT_ENCODING = "utf-8"; + + private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map _saslServers; + + private Map _users = new HashMap(); + private ReentrantLock _userUpdate = new ReentrantLock(); + + public PlainPasswordFilePrincipalDatabase() + { + _saslServers = new HashMap(); + + /** + * Create Authenticators for Plain Password file. + */ + + // Accept AMQPlain incomming and compare it to the file. + AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); + amqplain.initialise(this); + + // Accept Plain incomming and compare it to the file. + PlainInitialiser plain = new PlainInitialiser(); + plain.initialise(this); + + // Accept MD5 incomming and Hash file value for comparison + CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); + cram.initialise(this); + + _saslServers.put(amqplain.getMechanismName(), amqplain); + _saslServers.put(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws IOException + { + File f = new File(passwordFile); + _logger.info("PlainPasswordFile 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."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * If you want to change the password for a user, use updatePassword instead. + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannot be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException + { + if (_passwordFile == null) + { + 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); + } + } + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The plaintext password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + + char[] pwd = lookupPassword(principal); + + if (pwd == null) + { + throw new AccountNotFoundException("Unable to lookup the specfied users password"); + } + + return compareCharArray(pwd, password); + + } + + /** + * Changes the password for the specified user + * + * @param principal to change the password for + * @param password plaintext password to set the password too + */ + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + PlainUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + try + { + _userUpdate.lock(); + char[] orig = user.getPassword(); + user.setPassword(password); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user '" + principal + "' discarded"); + //revert the password change + user.setPassword(orig); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (Exception e) + { + return false; + } + } + + public boolean createPrincipal(Principal principal, char[] password) + { + if (_users.get(principal.getName()) != null) + { + return false; + } + + PlainUser user = new PlainUser(principal.getName(), password); + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + //remove the use on failure. + _users.remove(user.getName()); + _logger.warn("Unable to create user '" + user.getName()); + return false; + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + PlainUser user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; + } + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(_users.values()); + } + + public Principal getUser(String username) + { + if (_users.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + + /** + * 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 The principal name to lookup + * + * @return a char[] for use in SASL. + */ + private char[] lookupPassword(String name) + { + PlainUser user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + 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 || result[0].startsWith("#")) + { + continue; + } + + PlainUser user = new PlainUser(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + continue; + } + + PlainUser user = _users.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + byte[] password = user.getPasswordBytes(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(password); + writer.println(); + + user.saved(); + } + } + } + + for (PlainUser user : _users.values()) + { + if (user.isModified()) + { + byte[] password; + password = user.getPasswordBytes(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(password); + writer.println(); + user.saved(); + } + } + } + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public void reload() throws IOException + { + loadPasswordFile(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java new file mode 100644 index 0000000000..46a78a55aa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java @@ -0,0 +1,106 @@ +/* +* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; + +import java.security.Principal; + +public class PlainUser implements Principal +{ + private String _name; + private char[] _password; + private boolean _modified = false; + private boolean _deleted = false; + + PlainUser(String[] data) + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be length 2, username, password"); + } + + _name = data[0]; + + _password = data[1].toCharArray(); + + } + + public PlainUser(String name, char[] password) + { + _name = name; + _password = password; + _modified = true; + } + + public String getName() + { + return _name; + } + + public String toString() + { + return _name; + } + + char[] getPassword() + { + return _password; + } + + byte[] getPasswordBytes() + { + byte[] byteArray = new byte[_password.length]; + int index = 0; + for (char c : _password) + { + byteArray[index++] = (byte) c; + } + return byteArray; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java new file mode 100644 index 0000000000..ef37e043a6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Map; +import java.util.List; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; + +/** 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; + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * @param principal The principal to authenticate + * @param password The password to check + * @return true if password is correct + * @throws AccountNotFoundException if the principal cannot be found + */ + boolean verifyPassword(String principal, char[] password) + throws AccountNotFoundException; + + /** + * Update(Change) the password for the given principal + * @param principal Who's password is to be changed + * @param password The new password to use + * @return True if change was successful + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean updatePassword(Principal principal, char[] password) + throws AccountNotFoundException; + + /** + * Create a new principal in the database + * @param principal The principal to create + * @param password The password to set for the principal + * @return True on a successful creation + */ + boolean createPrincipal(Principal principal, char[] password); + + /** + * Delete a principal + * @param principal The principal to delete + * @return True on a successful creation + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean deletePrincipal(Principal principal) + throws AccountNotFoundException; + + /** + * Get the principal from the database with the given username + * @param username of the principal to lookup + * @return The Principal object for the given username or null if not found. + */ + Principal getUser(String username); + + /** + * Reload the database to its ensure contents are up to date + * @throws IOException If there was an error reloading the database + */ + void reload() throws IOException; + + public Map getMechanisms(); + + + List getUsers(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java new file mode 100644 index 0000000000..f9882f8810 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +import java.util.Map; + +public interface PrincipalDatabaseManager +{ + public Map getDatabases(); + + public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java new file mode 100644 index 0000000000..ff8851306f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.util.Properties; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.security.Principal; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class PropertiesPrincipalDatabase implements PrincipalDatabase +{ + private Properties _users; + + private Map _saslServers; + + public PropertiesPrincipalDatabase(Properties users) + { + _users = users; + + _saslServers = new HashMap(); + + /** + * Create Authenticators for Properties Principal Database. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException + { + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + + + + final String pwd = _users.getProperty(principal.getName()); + + if (pwd != null) + { + callback.setPassword(pwd.toCharArray()); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + //fixme this is not correct as toCharArray is not safe based on the type of string. + char[] pwd = _users.getProperty(principal).toCharArray(); + + return compareCharArray(pwd, password); + } + + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, char[] password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + + public Map getMechanisms() + { + return _saslServers; + } + + public List getUsers() + { + return new LinkedList(); //todo + } + + public Principal getUser(String username) + { + if (_users.getProperty(username) != null) + { + return new UsernamePrincipal(username); + } + else + { + return null; + } + } + + public void reload() throws IOException + { + //No file to update from, so do nothing. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java new file mode 100644 index 0000000000..4efe381a8b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ServerConfiguration; + +import java.util.Map; +import java.util.Properties; +import java.util.HashMap; + +public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager +{ + + Map _databases = new HashMap(); + + public PropertiesPrincipalDatabaseManager(String name, Properties users) + { + _databases.put(name, new PropertiesPrincipalDatabase(users)); + } + + public Map getDatabases() + { + return _databases; + } + + @Override + public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException + { + //todo + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java new file mode 100644 index 0000000000..d1803124a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +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); + + void close(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java new file mode 100644 index 0000000000..98c060599a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -0,0 +1,237 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.JCAProvider; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; +import java.security.Security; + +public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.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>(); + + private AuthenticationManager _default = null; + /** The name for the required SASL Server mechanisms */ + public static final String PROVIDER_NAME= "AMQSASLProvider-Server"; + + public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception + { + _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") + + " PrincipleDatabase authentication manager."); + + // Fixme This should be done per Vhost but allowing global hack isn't right but ... + // required as authentication is done before Vhost selection + + Map> providerMap = new TreeMap>(); + + + if (name == null || hostConfig == null) + { + initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); + } + else + { + String databaseName = hostConfig.getAuthenticationDatabase(); + + if (databaseName == null) + { + + _default = ApplicationRegistry.getInstance().getAuthenticationManager(); + return; + } + else + { + PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Requested database:" + databaseName + " was not found"); + } + + initialiseAuthenticationMechanisms(providerMap, database); + } + } + + if (providerMap.size() > 0) + { + // Ensure we are used before the defaults + if (Security.insertProviderAt(new JCAProvider(PROVIDER_NAME, providerMap), 1) == -1) + { + _logger.error("Unable to load custom SASL providers. Qpid custom SASL authenticators unavailable."); + } + else + { + _logger.info("Additional SASL providers successfully registered."); + } + + } + else + { + _logger.warn("No additional SASL providers registered."); + } + + } + + + private void initialiseAuthenticationMechanisms(Map> providerMap, Map databases) throws Exception + { + if (databases.size() > 1) + { + _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); + } + + for (Map.Entry entry : databases.entrySet()) + { + // fixme As the database now provide the mechanisms they support, they will ... + // overwrite each other in the map. There should only be one database per vhost. + // But currently we must have authentication before vhost definition. + initialiseAuthenticationMechanisms(providerMap, entry.getValue()); + } + } + + private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception + { + if (database == null || database.getMechanisms().size() == 0) + { + _logger.warn("No Database or no mechanisms to initialise authentication"); + return; + } + + for (Map.Entry mechanism : database.getMechanisms().entrySet()) + { + initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); + } + } + + private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, + Map> providerMap) + throws Exception + { + 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); + } + _logger.info("Initialised " + mechanism + " SASL provider successfully"); + } + + public String getMechanisms() + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.getMechanisms(); + } + else + { + return _mechanisms; + } + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.createSaslServer(mechanism, localFQDN); + } + else + { + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); + } + + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + // Use the default AuthenticationManager if present + if (_default != null) + { + return _default.authenticate(server, 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, e); + } + } + + public void close() + { + Security.removeProvider(PROVIDER_NAME); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java new file mode 100644 index 0000000000..77040e896c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -0,0 +1,119 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.rmi; + +import java.util.Collections; + +import javax.management.remote.JMXAuthenticator; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; +import javax.security.auth.login.AccountNotFoundException; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +public class RMIPasswordAuthenticator implements JMXAuthenticator +{ + static final String UNABLE_TO_LOOKUP = "The broker was unable to lookup the user details"; + static final String SHOULD_BE_STRING_ARRAY = "User details should be String[]"; + static final String SHOULD_HAVE_2_ELEMENTS = "User details should have 2 elements, username, password"; + static final String SHOULD_BE_NON_NULL = "Supplied username and password should be non-null"; + static final String INVALID_CREDENTIALS = "Invalid user details supplied"; + static final String CREDENTIALS_REQUIRED = "User details are required. " + + "Please ensure you are using an up to date management console to connect."; + + private PrincipalDatabase _db = null; + + public RMIPasswordAuthenticator() + { + } + + public void setPrincipalDatabase(PrincipalDatabase pd) + { + this._db = pd; + } + + public Subject authenticate(Object credentials) throws SecurityException + { + // Verify that credential's are of type String[]. + if (!(credentials instanceof String[])) + { + if (credentials == null) + { + throw new SecurityException(CREDENTIALS_REQUIRED); + } + else + { + throw new SecurityException(SHOULD_BE_STRING_ARRAY); + } + } + + // Verify that required number of credential's. + final String[] userCredentials = (String[]) credentials; + if (userCredentials.length != 2) + { + throw new SecurityException(SHOULD_HAVE_2_ELEMENTS); + } + + String username = (String) userCredentials[0]; + String password = (String) userCredentials[1]; + + // Verify that all required credential's are actually present. + if (username == null || password == null) + { + throw new SecurityException(SHOULD_BE_NON_NULL); + } + + // Verify that a PD has been set. + if (_db == null) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + + boolean authenticated = false; + + // Perform authentication + try + { + if (_db.verifyPassword(username, password.toCharArray())) + { + authenticated = true; + } + } + catch (AccountNotFoundException e) + { + throw new SecurityException(INVALID_CREDENTIALS); + } + + if (authenticated) + { + //credential's check out, return the appropriate JAAS Subject + return new Subject(true, + Collections.singleton(new JMXPrincipal(username)), + Collections.EMPTY_SET, + Collections.EMPTY_SET); + } + else + { + throw new SecurityException(INVALID_CREDENTIALS); + } + } + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java new file mode 100644 index 0000000000..89e545d6f5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +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 + * @throws Exception needs refined Exception is too broad. + */ + void initialise(String baseConfigPath, Configuration configuration, + Map principalDatabases) throws Exception; + + /** + * Initialise the authentication provider. + * @param db The principal database to initialise with + */ + void initialise(PrincipalDatabase db); + + + /** + * @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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java new file mode 100644 index 0000000000..d6a09d8217 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.security.Provider; +import java.security.Security; +import java.util.Map; + +import javax.security.sasl.SaslServerFactory; + +public final class JCAProvider extends Provider +{ + public JCAProvider(String name, Map> providerMap) + { + super(name, 1.0, "A JCA provider that registers all " + + "AMQ SASL providers that want to be registered"); + register(providerMap); + } + + private void register(Map> providerMap) + { + for (Map.Entry> me : + providerMap.entrySet()) + { + put("SaslServerFactory." + me.getKey(), me.getValue().getName()); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java new file mode 100644 index 0000000000..dd0bd096c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -0,0 +1,123 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; + +import org.apache.commons.configuration.Configuration; + +import org.apache.log4j.Logger; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser +{ + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + + 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 + IOException ioe = new IOException("Error looking up user " + e); + ioe.initCause(e); + throw ioe; + } + } + 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); + + initialise(db); + } + + public void initialise(PrincipalDatabase db) + { + if (db == null) + { + throw new NullPointerException("Cannot initialise with a null Principal database."); + } + + _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java new file mode 100644 index 0000000000..d7c8383690 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +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; + } + + public String toString() + { + return _name; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java new file mode 100644 index 0000000000..7acc6322d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class AmqPlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "AMQPLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return AmqPlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java new file mode 100644 index 0000000000..9f56b8521a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java @@ -0,0 +1,132 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +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 = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); + String username = (String) ft.getString("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.getString("PASSWORD"); + AuthorizeCallback authzCb = new AuthorizeCallback(username, username); + Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; + _cbh.handle(callbacks); + String storedPwd = new String(passwordCb.getPassword()); + if (storedPwd.equals(pwd)) + { + _complete = true; + } + if (authzCb.isAuthorized() && _complete) + { + _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java new file mode 100644 index 0000000000..67d20136bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.amqplain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java new file mode 100644 index 0000000000..97f9a4e91a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return CRAMMD5HashedSaslServer.MECHANISM; + } + + public Class getServerFactoryClassForJCARegistration() + { + return CRAMMD5HashedServerFactory.class; + } + + public void initialise(PrincipalDatabase passwordFile) + { + super.initialise(passwordFile); + } + + public Map getProperties() + { + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java new file mode 100644 index 0000000000..f6cab084ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.CallbackHandler; +import java.util.Enumeration; +import java.util.Map; + +public class CRAMMD5HashedSaslServer implements SaslServer +{ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + private SaslServer _realServer; + + public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + Enumeration factories = Sasl.getSaslServerFactories(); + + while (factories.hasMoreElements()) + { + SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); + + if (factory instanceof CRAMMD5HashedServerFactory) + { + continue; + } + + String[] mechs = factory.getMechanismNames(props); + + for (String mech : mechs) + { + if (mech.equals("CRAM-MD5")) + { + _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); + return; + } + } + } + + throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return _realServer.evaluateResponse(response); + } + + public boolean isComplete() + { + return _realServer.isComplete(); + } + + public String getAuthorizationID() + { + return _realServer.getAuthorizationID(); + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return _realServer.unwrap(incoming, offset, len); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return _realServer.wrap(outgoing, offset, len); + } + + public Object getNegotiatedProperty(String propName) + { + return _realServer.getNegotiatedProperty(propName); + } + + public void dispose() throws SaslException + { + _realServer.dispose(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java new file mode 100644 index 0000000000..5298b5cc63 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5HashedServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) + { + return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java new file mode 100644 index 0000000000..264832888d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5Initialiser extends UsernamePasswordInitialiser +{ + private HashDirection _hashDirection; + + public enum HashDirection + { + INCOMMING, PASSWORD_FILE + } + + + 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. + if (_hashDirection == HashDirection.PASSWORD_FILE) + { + return null; + } + else + { + //fixme we need a server that will correctly has the incomming plain text for comparison to file. + _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); + return null; + } + } + + public void initialise(PrincipalDatabase passwordFile) + { + initialise(passwordFile, HashDirection.PASSWORD_FILE); + } + + public void initialise(PrincipalDatabase passwordFile, HashDirection direction) + { + super.initialise(passwordFile); + + _hashDirection = direction; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java new file mode 100644 index 0000000000..1d16cd8755 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; + +public class PlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "PLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return PlainSaslServerFactory.class; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java new file mode 100644 index 0000000000..45fb9a4e42 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -0,0 +1,151 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +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); + 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"); + AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); + Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; + _cbh.handle(callbacks); + String storedPwd = new String(passwordCb.getPassword()); + if (storedPwd.equals(pwd)) + { + _complete = true; + } + if (authzCb.isAuthorized() && _complete) + { + _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/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java new file mode 100644 index 0000000000..f0dd9eeb6d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class 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/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java new file mode 100644 index 0000000000..f427cc7206 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +/** + * States used in the AMQ protocol. Used by the finite state machine to determine + * valid responses. + */ +public enum AMQState +{ + CONNECTION_NOT_STARTED, + CONNECTION_NOT_AUTH, + CONNECTION_NOT_TUNED, + CONNECTION_NOT_OPENED, + CONNECTION_OPEN, + CONNECTION_CLOSING, + CONNECTION_CLOSED +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java new file mode 100644 index 0000000000..c5b3099f58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -0,0 +1,263 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.handler.BasicAckMethodHandler; +import org.apache.qpid.server.handler.BasicCancelMethodHandler; +import org.apache.qpid.server.handler.BasicConsumeMethodHandler; +import org.apache.qpid.server.handler.BasicGetMethodHandler; +import org.apache.qpid.server.handler.BasicPublishMethodHandler; +import org.apache.qpid.server.handler.BasicQosHandler; +import org.apache.qpid.server.handler.BasicRecoverMethodHandler; +import org.apache.qpid.server.handler.BasicRejectMethodHandler; +import org.apache.qpid.server.handler.ChannelCloseHandler; +import org.apache.qpid.server.handler.ChannelCloseOkHandler; +import org.apache.qpid.server.handler.ChannelFlowHandler; +import org.apache.qpid.server.handler.ChannelOpenHandler; +import org.apache.qpid.server.handler.ConnectionCloseMethodHandler; +import org.apache.qpid.server.handler.ConnectionCloseOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionOpenMethodHandler; +import org.apache.qpid.server.handler.ConnectionSecureOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionStartOkMethodHandler; +import org.apache.qpid.server.handler.ConnectionTuneOkMethodHandler; +import org.apache.qpid.server.handler.ExchangeBoundHandler; +import org.apache.qpid.server.handler.ExchangeDeclareHandler; +import org.apache.qpid.server.handler.ExchangeDeleteHandler; +import org.apache.qpid.server.handler.QueueBindHandler; +import org.apache.qpid.server.handler.QueueDeclareHandler; +import org.apache.qpid.server.handler.QueueDeleteHandler; +import org.apache.qpid.server.handler.QueuePurgeHandler; +import org.apache.qpid.server.handler.TxCommitHandler; +import org.apache.qpid.server.handler.TxRollbackHandler; +import org.apache.qpid.server.handler.TxSelectHandler; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +/** + * 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); + + private final VirtualHostRegistry _virtualHostRegistry; + private final AMQProtocolSession _protocolSession; + /** The current state */ + private AMQState _currentState; + + /** + * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of + * AMQFrame. + */ +/* private final EnumMap, StateAwareMethodListener>> _state2HandlersMap = + new EnumMap, StateAwareMethodListener>>( + AMQState.class); + */ + + + private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); + + public AMQStateManager(VirtualHostRegistry virtualHostRegistry, AMQProtocolSession protocolSession) + { + + _virtualHostRegistry = virtualHostRegistry; + _protocolSession = protocolSession; + _currentState = AMQState.CONNECTION_NOT_STARTED; + + } + + /* + protected void registerListeners() + { + Map, StateAwareMethodListener> frame2handlerMap; + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_AUTH, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + _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>(); + ChannelOpenHandler.getInstance(); + ChannelCloseHandler.getInstance(); + ChannelCloseOkHandler.getInstance(); + ConnectionCloseMethodHandler.getInstance(); + ConnectionCloseOkMethodHandler.getInstance(); + ConnectionTuneOkMethodHandler.getInstance(); + ConnectionSecureOkMethodHandler.getInstance(); + ConnectionStartOkMethodHandler.getInstance(); + ExchangeDeclareHandler.getInstance(); + ExchangeDeleteHandler.getInstance(); + ExchangeBoundHandler.getInstance(); + BasicAckMethodHandler.getInstance(); + BasicRecoverMethodHandler.getInstance(); + BasicConsumeMethodHandler.getInstance(); + BasicGetMethodHandler.getInstance(); + BasicCancelMethodHandler.getInstance(); + BasicPublishMethodHandler.getInstance(); + BasicQosHandler.getInstance(); + QueueBindHandler.getInstance(); + QueueDeclareHandler.getInstance(); + QueueDeleteHandler.getInstance(); + QueuePurgeHandler.getInstance(); + ChannelFlowHandler.getInstance(); + TxSelectHandler.getInstance(); + TxCommitHandler.getInstance(); + TxRollbackHandler.getInstance(); + BasicRejectMethodHandler.getInstance(); + + _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + + _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(Exception e) + { + _logger.error("State manager received error notification[Current State:" + _currentState + "]: " + e, e); + for (StateListener l : _stateListeners) + { + l.error(e); + } + } + + public boolean methodReceived(AMQMethodEvent evt) throws AMQException + { + MethodDispatcher dispatcher = _protocolSession.getMethodDispatcher(); + + final int channelId = evt.getChannelId(); + B body = evt.getMethod(); + + if(channelId != 0 && _protocolSession.getChannel(channelId)== null) + { + + if(! ((body instanceof ChannelOpenBody) + || (body instanceof ChannelCloseOkBody) + || (body instanceof ChannelCloseBody))) + { + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "channel is closed"); + } + + } + + return body.execute(dispatcher, channelId); + + } + + private void checkChannel(AMQMethodEvent evt, AMQProtocolSession protocolSession) + throws AMQException + { + if ((evt.getChannelId() != 0) && !(evt.getMethod() instanceof ChannelOpenBody) + && (protocolSession.getChannel(evt.getChannelId()) == null) + && !protocolSession.channelAwaitingClosure(evt.getChannelId())) + { + throw evt.getMethod().getChannelNotFoundException(evt.getChannelId()); + } + } + +/* + protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, + B frame) + // throws IllegalStateTransitionException + { + final Map, StateAwareMethodListener> classToHandlerMap = + _state2HandlersMap.get(currentState); + + final StateAwareMethodListener handler = + (classToHandlerMap == null) ? null : (StateAwareMethodListener) classToHandlerMap.get(frame.getClass()); + + if (handler == null) + { + _logger.debug("No state transition handler defined for receiving frame " + frame); + + return null; + } + else + { + return handler; + } + } +*/ + + public void addStateListener(StateListener listener) + { + _logger.debug("Adding state listener"); + _stateListeners.add(listener); + } + + public void removeStateListener(StateListener listener) + { + _stateListeners.remove(listener); + } + + public VirtualHostRegistry getVirtualHostRegistry() + { + return _virtualHostRegistry; + } + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java new file mode 100644 index 0000000000..cec67a8a6d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; + +/** + * @todo Not an AMQP exception as no status code. + * + * @todo Not used! Delete. + */ +public class IllegalStateTransitionException extends AMQException +{ + private AMQState _originalState; + + private Class _frame; + + public IllegalStateTransitionException(AMQState originalState, Class frame) + { + super("No valid state transition defined for receiving frame " + frame + " from state " + originalState); + _originalState = originalState; + _frame = frame; + } + + public AMQState getOriginalState() + { + return _originalState; + } + + public Class getFrameClass() + { + return _frame; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java new file mode 100644 index 0000000000..3c11bb8a9c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQMethodEvent; + +/** + * 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, B evt, int channelId) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java new file mode 100644 index 0000000000..00fc09867b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; + +public interface StateListener +{ + void stateChanged(AMQState oldState, AMQState newState) throws AMQException; + + void error(Throwable t); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java new file mode 100644 index 0000000000..e7f9c777c9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -0,0 +1,1464 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.QueueRegistry; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.MessageHandleFactory; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +import java.io.File; +import java.io.ByteArrayInputStream; +import java.sql.DriverManager; +import java.sql.Driver; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Blob; +import java.sql.Types; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; + + +public class DerbyMessageStore implements MessageStore +{ + + private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); + + private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; + + + private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; + + private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION"; + + private static final String EXCHANGE_TABLE_NAME = "QPID_EXCHANGE"; + private static final String QUEUE_TABLE_NAME = "QPID_QUEUE"; + private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS"; + private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY"; + private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA"; + private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; + + private static final int DB_VERSION = 1; + + + + private VirtualHost _virtualHost; + private static Class DRIVER_CLASS; + + private final AtomicLong _messageId = new AtomicLong(1); + private AtomicBoolean _closed = new AtomicBoolean(false); + + private String _connectionURL; + + + + private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; + private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; + private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; + private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; + private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; + private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; + private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; + private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; + private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; + private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; + private static final String SELECT_FROM_BINDINGS = + "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; + private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; + private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; + private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; + private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; + private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; + private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; + private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; + private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; + private static final String SELECT_FROM_MESSAGE_META_DATA = + "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_FROM_MESSAGE_CONTENT = + "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; + private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; + private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; + + + private enum State + { + INITIAL, + CONFIGURING, + RECOVERING, + STARTED, + CLOSING, + CLOSED + } + + private State _state = State.INITIAL; + + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + stateTransition(State.INITIAL, State.CONFIGURING); + + initialiseDriver(); + + _virtualHost = virtualHost; + + _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + final String databasePath = config.getStoreConfiguration().getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + + File environmentPath = new File(databasePath); + if (!environmentPath.exists()) + { + if (!environmentPath.mkdirs()) + { + throw new IllegalArgumentException("Environment path " + environmentPath + " could not be read or created. " + + "Ensure the path is correct and that the permissions are correct."); + } + } + + createOrOpenDatabase(databasePath); + + // this recovers durable queues and persistent messages + + recover(); + + stateTransition(State.RECOVERING, State.STARTED); + + } + + private static synchronized void initialiseDriver() throws ClassNotFoundException + { + if(DRIVER_CLASS == null) + { + DRIVER_CLASS = (Class) Class.forName(SQL_DRIVER_NAME); + } + } + + private void createOrOpenDatabase(final String environmentPath) throws SQLException + { + _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; + + Connection conn = newConnection(); + + createVersionTable(conn); + createExchangeTable(conn); + createQueueTable(conn); + createBindingsTable(conn); + createQueueEntryTable(conn); + createMessageMetaDataTable(conn); + createMessageContentTable(conn); + + conn.close(); + } + + + + private void createVersionTable(final Connection conn) throws SQLException + { + if(!tableExists(DB_VERSION_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + + stmt.execute(CREATE_DB_VERSION_TABLE); + stmt.close(); + + PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); + pstmt.setInt(1, DB_VERSION); + pstmt.execute(); + pstmt.close(); + } + + } + + + private void createExchangeTable(final Connection conn) throws SQLException + { + if(!tableExists(EXCHANGE_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + + stmt.execute(CREATE_EXCHANGE_TABLE); + stmt.close(); + } + } + + private void createQueueTable(final Connection conn) throws SQLException + { + if(!tableExists(QUEUE_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_QUEUE_TABLE); + stmt.close(); + } + } + + private void createBindingsTable(final Connection conn) throws SQLException + { + if(!tableExists(BINDINGS_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_BINDINGS_TABLE); + + stmt.close(); + } + + } + + private void createQueueEntryTable(final Connection conn) throws SQLException + { + if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_QUEUE_ENTRY_TABLE); + + stmt.close(); + } + + } + + private void createMessageMetaDataTable(final Connection conn) throws SQLException + { + if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); + + stmt.close(); + } + + } + + + private void createMessageContentTable(final Connection conn) throws SQLException + { + if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); + + stmt.close(); + } + + } + + + + private boolean tableExists(final String tableName, final Connection conn) throws SQLException + { + PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); + stmt.setString(1, tableName); + ResultSet rs = stmt.executeQuery(); + boolean exists = rs.next(); + rs.close(); + stmt.close(); + return exists; + } + + public void recover() throws AMQException + { + stateTransition(State.CONFIGURING, State.RECOVERING); + + _logger.info("Recovering persistent state..."); + StoreContext context = new StoreContext(); + + try + { + Map queues = loadQueues(); + + recoverExchanges(); + + try + { + + beginTran(context); + + deliverMessages(context, queues); + _logger.info("Persistent state recovered successfully"); + commitTran(context); + + } + finally + { + if(inTran(context)) + { + abortTran(context); + } + } + } + catch (SQLException e) + { + + throw new AMQException("Error recovering persistent state: " + e, e); + } + + } + + private Map loadQueues() throws SQLException, AMQException + { + Connection conn = newConnection(); + + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); + Map queueMap = new HashMap(); + while(rs.next()) + { + String queueName = rs.getString(1); + String owner = rs.getString(2); + AMQShortString queueNameShortString = new AMQShortString(queueName); + AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + null); + _virtualHost.getQueueRegistry().registerQueue(q); + queueMap.put(queueNameShortString,q); + + } + return queueMap; + } + + private void recoverExchanges() throws AMQException, SQLException + { + for (Exchange exchange : loadExchanges()) + { + recoverExchange(exchange); + } + } + + + private List loadExchanges() throws AMQException, SQLException + { + + List exchanges = new ArrayList(); + Connection conn = null; + try + { + conn = newConnection(); + + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); + + Exchange exchange; + while(rs.next()) + { + String exchangeName = rs.getString(1); + String type = rs.getString(2); + boolean autoDelete = rs.getShort(3) != 0; + + exchange = _virtualHost.getExchangeFactory().createExchange(new AMQShortString(exchangeName), new AMQShortString(type), true, autoDelete, 0); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + exchanges.add(exchange); + + } + return exchanges; + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + + } + + private void recoverExchange(Exchange exchange) throws AMQException, SQLException + { + _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "..."); + + QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + + Connection conn = null; + try + { + conn = newConnection(); + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); + stmt.setString(1, exchange.getName().toString()); + + ResultSet rs = stmt.executeQuery(); + + + while(rs.next()) + { + String queueName = rs.getString(1); + String bindingKey = rs.getString(2); + Blob arguments = rs.getBlob(3); + + + AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " + + exchange.getName()); + } + else + { + _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + arguments + + ")"); + + FieldTable argumentsFT = null; + if(arguments != null) + { + byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length()); + ByteBuffer buf = ByteBuffer.wrap(argumentBytes); + argumentsFT = new FieldTable(buf,arguments.length()); + } + + queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + + } + } + } + finally + { + if(conn != null) + { + conn.close(); + } + } + } + + public void close() throws Exception + { + _closed.getAndSet(true); + } + + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + { + + boolean localTx = getOrCreateTransaction(storeContext); + + Connection conn = getConnection(storeContext); + ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload(); + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Message Id: " + messageId + " Removing"); + } + + // first we need to look up the header to get the chunk count + MessageMetaData mmd = getMessageMetaData(storeContext, messageId); + try + { + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + wrapper.setRequiresCommit(); + int results = stmt.executeUpdate(); + + if (results == 0) + { + if (localTx) + { + abortTran(storeContext); + } + + throw new AMQException("Message metadata not found for message id " + messageId); + } + stmt.close(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Deleted metadata for message " + messageId); + } + + stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + results = stmt.executeUpdate(); + + if(results != mmd.getContentChunkCount()) + { + if (localTx) + { + abortTran(storeContext); + } + throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results); + + } + + if (localTx) + { + commitTran(storeContext); + } + } + catch (SQLException e) + { + if ((conn != null) && localTx) + { + abortTran(storeContext); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (_state != State.RECOVERING) + { + try + { + Connection conn = null; + + try + { + conn = newConnection(); + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + stmt.setString(1, exchange.getName().toString()); + stmt.setString(2, exchange.getType().toString()); + stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); + stmt.execute(); + stmt.close(); + conn.commit(); + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + } + catch (SQLException e) + { + throw new AMQException("Error writing Exchange with name " + exchange.getName() + " to database: " + e, e); + } + } + + } + + public void removeExchange(Exchange exchange) throws AMQException + { + Connection conn = null; + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); + stmt.setString(1, exchange.getName().toString()); + int results = stmt.executeUpdate(); + if(results == 0) + { + throw new AMQException("Exchange " + exchange.getName() + " not found"); + } + else + { + conn.commit(); + stmt.close(); + } + } + catch (SQLException e) + { + throw new AMQException("Error writing deleting with name " + exchange.getName() + " from database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + throws AMQException + { + if (_state != State.RECOVERING) + { + Connection conn = null; + + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + stmt.setString(1, exchange.getName().toString() ); + stmt.setString(2, queue.getName().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + if(args != null) + { + /* This would be the Java 6 way of setting a Blob + Blob blobArgs = conn.createBlob(); + blobArgs.setBytes(0, args.getDataAsBytes()); + stmt.setBlob(4, blobArgs); + */ + byte[] bytes = args.getDataAsBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + stmt.setBinaryStream(4, bis, bytes.length); + } + else + { + stmt.setNull(4, Types.BLOB); + } + + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing binding for AMQQueue with name " + queue.getName() + " to exchange " + + exchange.getName() + " to database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + } + + + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + throws AMQException + { + Connection conn = null; + + + try + { + conn = newConnection(); + // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); + stmt.setString(1, exchange.getName().toString() ); + stmt.setString(2, queue.getName().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + + + if(stmt.executeUpdate() != 1) + { + throw new AMQException("Queue binding for queue with name " + queue.getName() + " to exchange " + + exchange.getName() + " not found"); + } + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error removing binding for AMQQueue with name " + queue.getName() + " to exchange " + + exchange.getName() + " in database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + + } + + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); + + if (_state != State.RECOVERING) + { + try + { + Connection conn = newConnection(); + + PreparedStatement stmt = + conn.prepareStatement(INSERT_INTO_QUEUE); + + stmt.setString(1, queue.getName().toString()); + stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); + + stmt.execute(); + + stmt.close(); + + conn.commit(); + + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing AMQQueue with name " + queue.getName() + " to database: " + e, e); + } + } + } + + private Connection newConnection() throws SQLException + { + final Connection connection = DriverManager.getConnection(_connectionURL); + return connection; + } + + public void removeQueue(final AMQQueue queue) throws AMQException + { + AMQShortString name = queue.getName(); + _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); + Connection conn = null; + + + try + { + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); + stmt.setString(1, name.toString()); + int results = stmt.executeUpdate(); + + + if (results == 0) + { + throw new AMQException("Queue " + name + " not found"); + } + + conn.commit(); + stmt.close(); + } + catch (SQLException e) + { + throw new AMQException("Error writing deleting with name " + name + " from database: " + e, e); + } + finally + { + if(conn != null) + { + try + { + conn.close(); + } + catch (SQLException e) + { + _logger.error(e); + } + } + + } + + + } + + public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + { + AMQShortString name = queue.getName(); + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); + stmt.setString(1,name.toString()); + stmt.setLong(2,messageId); + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + _logger.error("Failed to enqueue: " + e, e); + throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name + + " to database", e); + } + + } + + public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + { + AMQShortString name = queue.getName(); + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); + stmt.setString(1,name.toString()); + stmt.setLong(2,messageId); + int results = stmt.executeUpdate(); + + connWrapper.requiresCommit(); + + if(results != 1) + { + throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); + } + + if(localTx) + { + commitTran(context); + } + + + + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + _logger.error("Failed to dequeue: " + e, e); + throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name + + " from database", e); + } + + } + + private static final class ConnectionWrapper + { + private final Connection _connection; + private boolean _requiresCommit; + + public ConnectionWrapper(Connection conn) + { + _connection = conn; + } + + public void setRequiresCommit() + { + _requiresCommit = true; + } + + public boolean requiresCommit() + { + return _requiresCommit; + } + + public Connection getConnection() + { + return _connection; + } + } + + public void beginTran(StoreContext context) throws AMQException + { + if (context.getPayload() != null) + { + throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: " + + context.getPayload()); + } + else + { + try + { + Connection conn = newConnection(); + + + context.setPayload(new ConnectionWrapper(conn)); + } + catch (SQLException e) + { + throw new AMQException("Error starting transaction: " + e, e); + } + } + } + + public void commitTran(StoreContext context) throws AMQException + { + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + if (connWrapper == null) + { + throw new AMQException("Fatal internal error: transactional context is empty at commitTran"); + } + + try + { + Connection conn = connWrapper.getConnection(); + if(connWrapper.requiresCommit()) + { + conn.commit(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("commit tran completed"); + } + + } + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error commit tx: " + e, e); + } + finally + { + context.setPayload(null); + } + } + + public void abortTran(StoreContext context) throws AMQException + { + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + if (connWrapper == null) + { + throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("abort tran called: " + connWrapper.getConnection()); + } + + try + { + Connection conn = connWrapper.getConnection(); + if(connWrapper.requiresCommit()) + { + conn.rollback(); + } + + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error aborting transaction: " + e, e); + } + finally + { + context.setPayload(null); + } + } + + public boolean inTran(StoreContext context) + { + return context.getPayload() != null; + } + + public Long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public void storeContentBodyChunk(StoreContext context, + Long messageId, + int index, + ContentChunk contentBody, + boolean lastContentBody) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, index); + byte[] chunkData = new byte[contentBody.getSize()]; + contentBody.getData().duplicate().get(chunkData); + /* this would be the Java 6 way of doing things + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, chunkData); + stmt.setBlob(3, dataAsBlob); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); + stmt.setBinaryStream(3, bis, chunkData.length); + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd) + throws AMQException + { + + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + + try + { + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); + stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); + stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0); + stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0); + + ContentHeaderBody headerBody = mmd.getContentHeaderBody(); + final int bodySize = headerBody.getSize(); + byte[] underlying = new byte[bodySize]; + ByteBuffer buf = ByteBuffer.wrap(underlying); + headerBody.writePayload(buf); +/* + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, underlying); + stmt.setBlob(6, dataAsBlob); +*/ + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(6,bis,underlying.length); + + stmt.setInt(7, mmd.getContentChunkCount()); + + stmt.executeUpdate(); + connWrapper.requiresCommit(); + + if(localTx) + { + commitTran(context); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + } + + + } + + public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + + + try + { + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); + stmt.setLong(1,messageId); + ResultSet rs = stmt.executeQuery(); + + if(rs.next()) + { + final AMQShortString exchange = new AMQShortString(rs.getString(1)); + final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); + final boolean mandatory = (rs.getShort(3) != (short)0); + final boolean immediate = (rs.getShort(4) != (short)0); + MessagePublishInfo info = new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public void setExchange(AMQShortString exchange) + { + + } + + public boolean isImmediate() + { + return immediate; + } + + public boolean isMandatory() + { + return mandatory; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + } ; + + Blob dataAsBlob = rs.getBlob(5); + + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length); + + if(localTx) + { + commitTran(context); + } + + return new MessageMetaData(info, chb, rs.getInt(6)); + + } + else + { + if(localTx) + { + abortTran(context); + } + throw new AMQException("Metadata not found for message with id " + messageId); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } + + + } + + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + { + boolean localTx = getOrCreateTransaction(context); + Connection conn = getConnection(context); + + + try + { + + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, index); + ResultSet rs = stmt.executeQuery(); + + if(rs.next()) + { + Blob dataAsBlob = rs.getBlob(1); + + final int size = (int) dataAsBlob.length(); + byte[] dataAsBytes = dataAsBlob.getBytes(1, size); + final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + + ContentChunk cb = new ContentChunk() + { + + public int getSize() + { + return size; + } + + public ByteBuffer getData() + { + return buf; + } + + public void reduceToFit() + { + + } + }; + + if(localTx) + { + commitTran(context); + } + + return cb; + + } + else + { + if(localTx) + { + abortTran(context); + } + throw new AMQException("Message not found for message with id " + messageId); + } + } + catch (SQLException e) + { + if(localTx) + { + abortTran(context); + } + + throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } + + + + } + + public boolean isPersistent() + { + return true; + } + + private void checkNotClosed() throws MessageStoreClosedException + { + if (_closed.get()) + { + throw new MessageStoreClosedException(); + } + } + + + private static final class ProcessAction + { + private final AMQQueue _queue; + private final StoreContext _context; + private final AMQMessage _message; + + public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message) + { + _queue = queue; + _context = context; + _message = message; + } + + public void process() throws AMQException + { + _queue.enqueue(_context, _message); + + } + + } + + + private void deliverMessages(final StoreContext context, Map queues) + throws SQLException, AMQException + { + Map msgMap = new HashMap(); + List actions = new ArrayList(); + + Map queueRecoveries = new TreeMap(); + + final boolean inLocaltran = inTran(context); + Connection conn = null; + try + { + + if(inLocaltran) + { + conn = getConnection(context); + } + else + { + conn = newConnection(); + } + + + MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); + long maxId = 1; + + TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + + + while (rs.next()) + { + + + + AMQShortString queueName = new AMQShortString(rs.getString(1)); + + + AMQQueue queue = queues.get(queueName); + if (queue == null) + { + queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); + + _virtualHost.getQueueRegistry().registerQueue(queue); + queues.put(queueName, queue); + } + + long messageId = rs.getLong(2); + maxId = Math.max(maxId, messageId); + AMQMessage message = msgMap.get(messageId); + + if(message != null) + { + message.incrementReference(); + } + else + { + message = new AMQMessage(messageId, this, messageHandleFactory, txnContext); + msgMap.put(messageId,message); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); + } + + if (_logger.isInfoEnabled()) + { + Integer count = queueRecoveries.get(queueName); + if (count == null) + { + count = 0; + } + + queueRecoveries.put(queueName, ++count); + + } + + actions.add(new ProcessAction(queue, context, message)); + + } + + for(ProcessAction action : actions) + { + action.process(); + } + + _messageId.set(maxId + 1); + } + catch (SQLException e) + { + _logger.error("Error: " + e, e); + throw e; + } + finally + { + if (inLocaltran && conn != null) + { + conn.close(); + } + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Recovered message counts: " + queueRecoveries); + } + } + + private Connection getConnection(final StoreContext context) + { + return ((ConnectionWrapper)context.getPayload()).getConnection(); + } + + private boolean getOrCreateTransaction(StoreContext context) throws AMQException + { + + ConnectionWrapper tx = (ConnectionWrapper) context.getPayload(); + if (tx == null) + { + beginTran(context); + return true; + } + + return false; + } + + private synchronized void stateTransition(State requiredState, State newState) throws AMQException + { + if (_state != requiredState) + { + throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + + "; currently in state: " + _state); + } + + _state = newState; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java new file mode 100644 index 0000000000..4691f02952 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -0,0 +1,235 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; +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); + private AtomicBoolean _closed = new AtomicBoolean(false); + + 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, VirtualHostConfiguration config) + { + int hashtableCapacity = config.getStoreConfiguration().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(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + configure(base, config); + } + + public void close() throws Exception + { + _closed.getAndSet(true); + if (_metaDataMap != null) + { + _metaDataMap.clear(); + _metaDataMap = null; + } + if (_contentBodyMap != null) + { + _contentBodyMap.clear(); + _contentBodyMap = null; + } + } + + public void removeMessage(StoreContext context, Long messageId) throws AMQException + { + checkNotClosed(); + if (_log.isDebugEnabled()) + { + _log.debug("Removing message with id " + messageId); + } + _metaDataMap.remove(messageId); + _contentBodyMap.remove(messageId); + } + + public void createExchange(Exchange exchange) throws AMQException + { + + } + + public void removeExchange(Exchange exchange) throws AMQException + { + + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + + } + + + public void createQueue(AMQQueue queue) throws AMQException + { + // Not requred to do anything + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + // Not required to do anything + } + + public void removeQueue(final AMQQueue queue) throws AMQException + { + // Not required to do anything + } + + public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + { + // Not required to do anything + } + + public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + { + // Not required to do anything + } + + public void beginTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public void commitTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public void abortTran(StoreContext context) throws AMQException + { + // Not required to do anything + } + + public boolean inTran(StoreContext context) + { + return false; + } + + public List createQueues() throws AMQException + { + return null; + } + + public Long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) + throws AMQException + { + checkNotClosed(); + List bodyList = _contentBodyMap.get(messageId); + + if (bodyList == null && lastContentBody) + { + _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); + } + else + { + if (bodyList == null) + { + bodyList = new ArrayList(); + _contentBodyMap.put(messageId, bodyList); + } + + bodyList.add(index, contentBody); + } + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) + throws AMQException + { + checkNotClosed(); + _metaDataMap.put(messageId, messageMetaData); + } + + public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + { + checkNotClosed(); + return _metaDataMap.get(messageId); + } + + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + { + checkNotClosed(); + List bodyList = _contentBodyMap.get(messageId); + return bodyList.get(index); + } + + public boolean isPersistent() + { + return false; + } + + private void checkNotClosed() throws MessageStoreClosedException + { + if (_closed.get()) + { + throw new MessageStoreClosedException(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java new file mode 100644 index 0000000000..5a1b54b298 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -0,0 +1,277 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +/** + * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues + * and exchanges in a transactional manner. + * + *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which + * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single + * transaction. + * + *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. + * + *

      + *
      CRC Card
      Responsibilities + *
      Accept transaction boundary demarcations: Begin, Commit, Abort. + *
      Store and remove queues. + *
      Store and remove exchanges. + *
      Store and remove messages. + *
      Bind and unbind queues to exchanges. + *
      Enqueue and dequeue messages to queues. + *
      Generate message identifiers. + *
      + */ +public interface MessageStore +{ + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param virtualHost The virtual host using by this store + * @param base The base element identifier from which all configuration items are relative. For example, if + * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param hostConfig The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * + * @throws Exception If the close fails. + */ + void close() throws Exception; + + /** + * Removes the specified message from the store in the given transactional store context. + * + * @param storeContext The transactional context to remove the message in. + * @param messageId Identifies the message to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; + + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws AMQException If the operation fails for any reason. + */ + void createExchange(Exchange exchange) throws AMQException; + + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws AMQException If the operation fails for any reason. + */ + void removeExchange(Exchange exchange) throws AMQException; + + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws AMQException If the operation fails for any reason. + */ + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @param arguments The additional arguments to the binding + * @throws AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; + + /** + * Removes the specified queue from the persistent store. + * + * @param queue The queue to remove. + * @throws AMQException If the operation fails for any reason. + */ + void removeQueue(final AMQQueue queue) throws AMQException; + + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param queue The queue to place the message on. + * @param messageId The message to enqueue. + * @throws AMQException If the operation fails for any reason. + */ + void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param context The transactional context for the operation. + * @param queue The queue to place the message on. + * @param messageId The message to dequeue. + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; + + /** + * Begins a transactional context. + * + * @param context The transactional context to begin. + * + * @throws AMQException If the operation fails for any reason. + */ + void beginTran(StoreContext context) throws AMQException; + + /** + * Commits all operations performed within a given transactional context. + * + * @param context The transactional context to commit all operations for. + * + * @throws AMQException If the operation fails for any reason. + */ + void commitTran(StoreContext context) throws AMQException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @param context The transactional context to abandon. + * + * @throws AMQException If the operation fails for any reason. + */ + void abortTran(StoreContext context) throws AMQException; + + /** + * Tests a transactional context to see if it has been begun but not yet committed or aborted. + * + * @param context The transactional context to test. + * + * @return true if the transactional context is live, false otherwise. + */ + boolean inTran(StoreContext context); + + /** + * Return a valid, currently unused message id. + * + * @return A fresh message id. + */ + Long getNewMessageId(); + + /** + * Stores a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param index The index of the data chunk. + * @param contentBody The content of the data chunk. + * @param lastContentBody Flag to indicate that this is the last such chunk for the message. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, + boolean lastContentBody) throws AMQException; + + /** + * Stores message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to store the data for. + * @param messageMetaData The message meta data to store. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; + + /** + * Retrieves message meta-data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the meta-data for. + * + * @return The message meta data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; + + /** + * Retrieves a chunk of message data. + * + * @param context The transactional context for the operation. + * @param messageId The message to get the data chunk for. + * @param index The offset index of the data chunk within the message. + * + * @return A chunk of message data. + * + * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; + + /** + * Is this store capable of persisting the data + * + * @return true if this store is capable of persisting data + */ + boolean isPersistent(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java new file mode 100644 index 0000000000..3d1538c7eb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreClosedException.java @@ -0,0 +1,36 @@ +package org.apache.qpid.server.store; + +import org.apache.qpid.AMQException;/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * NOTE: this class currently extends AMQException but + * we should be using AMQExceptions internally in the code base for Protocol errors hence + * the message store interface should throw a different super class which this should be + * moved to reflect + */ +public class MessageStoreClosedException extends AMQException +{ + public MessageStoreClosedException() + { + super("Message store closed"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java new file mode 100644 index 0000000000..fdb56a1a55 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.log4j.Logger; + +/** + * A context that the store can use to associate with a transactional context. For example, it could store + * some kind of txn id. + * + * @author Apache Software Foundation + */ +public class StoreContext +{ + private static final Logger _logger = Logger.getLogger(StoreContext.class); + + private String _name; + private Object _payload; + + public StoreContext() + { + _name = "StoreContext"; + } + + public StoreContext(String name) + { + _name = name; + } + + public Object getPayload() + { + return _payload; + } + + public void setPayload(Object payload) + { + if(_logger.isDebugEnabled()) + { + _logger.debug("public void setPayload(Object payload = " + payload + "): called"); + } + _payload = payload; + } + + /** + * Prints out the transactional context as a string, mainly for debugging purposes. + * + * @return The transactional context as a string. + */ + public String toString() + { + return "<_name = " + _name + ", _payload = " + _payload + ">"; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java new file mode 100644 index 0000000000..fbc8b3af7d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java @@ -0,0 +1,29 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.AMQException; + +public interface ClientDeliveryMethod +{ + void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java new file mode 100644 index 0000000000..e2ed4104de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java @@ -0,0 +1,28 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; + +public interface RecordDeliveryMethod +{ + void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java new file mode 100644 index 0000000000..9419572399 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -0,0 +1,96 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; + +public interface Subscription +{ + + + public static enum State + { + ACTIVE, + SUSPENDED, + CLOSED + } + + public static interface StateListener + { + public void stateChange(Subscription sub, State oldState, State newState); + } + + AMQQueue getQueue(); + + QueueEntry.SubscriptionAcquiredState getOwningState(); + + void setQueue(AMQQueue queue); + + AMQChannel getChannel(); + + AMQShortString getConsumerTag(); + + boolean isSuspended(); + + boolean hasInterest(QueueEntry msg); + + boolean isAutoClose(); + + boolean isClosed(); + + boolean isBrowser(); + + void close(); + + boolean filtersMessages(); + + void send(QueueEntry msg) throws AMQException; + + void queueDeleted(AMQQueue queue); + + + boolean wouldSuspend(QueueEntry msg); + + void getSendLock(); + void releaseSendLock(); + + void resend(final QueueEntry entry) throws AMQException; + + void restoreCredit(final QueueEntry queueEntry); + + void setStateListener(final StateListener listener); + + public State getState(); + + QueueEntry getLastSeenEntry(); + + boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); + + + boolean isActive(); + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java new file mode 100644 index 0000000000..ce0362d73f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; + +/** + * 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, + AMQShortString consumerTag, + boolean acks, + FieldTable filters, + boolean noLocal, FlowCreditManager creditManager) throws AMQException; + + + Subscription createSubscription(AMQChannel channel, + AMQProtocolSession protocolSession, + AMQShortString consumerTag, + boolean acks, + FieldTable filters, + boolean noLocal, + FlowCreditManager creditManager, + ClientDeliveryMethod clientMethod, + RecordDeliveryMethod recordMethod + ) + throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java new file mode 100644 index 0000000000..5badbad642 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java @@ -0,0 +1,103 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactory; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.common.AMQPFilterTypes; + +public class SubscriptionFactoryImpl implements SubscriptionFactory +{ + + /* private SubscriptionFactoryImpl() + { + + }*/ + + public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession, + AMQShortString consumerTag, boolean acks, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager) throws AMQException + { + AMQChannel channel = protocolSession.getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session"); + } + ClientDeliveryMethod clientMethod = channel.getClientDeliveryMethod(); + RecordDeliveryMethod recordMethod = channel.getRecordDeliveryMethod(); + + + return createSubscription(channel, protocolSession, consumerTag, acks, filters, + noLocal, + creditManager, + clientMethod, + recordMethod + ); + } + + public Subscription createSubscription(final AMQChannel channel, + final AMQProtocolSession protocolSession, + final AMQShortString consumerTag, + final boolean acks, + final FieldTable filters, + final boolean noLocal, + final FlowCreditManager creditManager, + final ClientDeliveryMethod clientMethod, + final RecordDeliveryMethod recordMethod + ) + throws AMQException + { + boolean isBrowser; + + if (filters != null) + { + Boolean isBrowserObj = (Boolean) filters.get(AMQPFilterTypes.NO_CONSUME.getValue()); + isBrowser = (isBrowserObj != null) && isBrowserObj.booleanValue(); + } + else + { + isBrowser = false; + } + + if(isBrowser) + { + return new SubscriptionImpl.BrowserSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + else if(acks) + { + return new SubscriptionImpl.AckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + else + { + return new SubscriptionImpl.NoAckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod); + } + } + + + public static final SubscriptionFactoryImpl INSTANCE = new SubscriptionFactoryImpl(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java new file mode 100644 index 0000000000..a616c2ea35 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -0,0 +1,617 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.StoreContext; + +/** + * Encapsulation of a supscription to a queue.

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

      + */ +public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener +{ + + private StateListener _stateListener = new StateListener() + { + + public void stateChange(Subscription sub, State oldState, State newState) + { + + } + }; + + + private final AtomicReference _state = new AtomicReference(State.ACTIVE); + private final AtomicReference _queueContext = new AtomicReference(null); + private final ClientDeliveryMethod _deliveryMethod; + private final RecordDeliveryMethod _recordMethod; + + private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final Lock _stateChangeLock; + + static final class BrowserSubscription extends SubscriptionImpl + { + public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + + public boolean isBrowser() + { + return true; + } + + /** + * 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 The message to send + * @throws AMQException + */ + @Override + public void send(QueueEntry msg) throws AMQException + { + // We don't decrement the reference here as we don't want to consume the message + // but we do want to send it to the client. + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + sendToClient(msg, deliveryTag); + } + + } + + @Override + public boolean wouldSuspend(QueueEntry msg) + { + return false; + } + + } + + public static class NoAckSubscription extends SubscriptionImpl + { + public NoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + + public boolean isBrowser() + { + return false; + } + + /** + * 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 entry The message to send + * @throws AMQException + */ + @Override + public void send(QueueEntry entry) throws AMQException + { + + StoreContext storeContext = getChannel().getStoreContext(); + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + entry.dequeue(storeContext); + + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + + sendToClient(entry, deliveryTag); + + } + entry.dispose(storeContext); + } + finally + { + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. + // Is this what we want? + + entry.setDeliveredToSubscription(); + } + } + + @Override + public boolean wouldSuspend(QueueEntry msg) + { + return false; + } + + } + + static final class AckSubscription extends SubscriptionImpl + { + public AckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + + public boolean isBrowser() + { + return false; + } + + + /** + * 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 entry The message to send + * @throws AMQException + */ + @Override + public void send(QueueEntry entry) throws AMQException + { + + try + { // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); + + + recordMessageDelivery(entry, deliveryTag); + sendToClient(entry, deliveryTag); + + + } + } + finally + { + //Only set delivered if it actually was writen successfully.. + // using a try->finally would set it even if an error occured. + // Is this what we want? + + entry.setDeliveredToSubscription(); + } + } + + + } + + + private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); + + private final AMQChannel _channel; + + private final AMQShortString _consumerTag; + + + private final boolean _noLocal; + + private final FlowCreditManager _creditManager; + + private FilterManager _filters; + + private final Boolean _autoClose; + + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + private AMQQueue _queue; + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + + + + public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable arguments, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + + _channel = channel; + _consumerTag = consumerTag; + + _creditManager = creditManager; + creditManager.addStateListener(this); + + _noLocal = noLocal; + + + _filters = FilterManagerFactory.createManager(arguments); + + _deliveryMethod = deliveryMethod; + _recordMethod = recordMethod; + + + _stateChangeLock = new ReentrantLock(); + + + if (arguments != null) + { + Object autoClose = arguments.get(AMQPFilterTypes.AUTO_CLOSE.getValue()); + if (autoClose != null) + { + _autoClose = (Boolean) autoClose; + } + else + { + _autoClose = false; + } + } + else + { + _autoClose = false; + } + + + } + + + + public synchronized void setQueue(AMQQueue queue) + { + if(getQueue() != null) + { + throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); + } + _queue = queue; + } + + public String toString() + { + String subscriber = "[channel=" + _channel + + ", consumerTag=" + _consumerTag + + ", session=" + getProtocolSession().getKey() ; + + return subscriber + "]"; + } + + /** + * 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 The message to send + * @throws AMQException + */ + abstract public void send(QueueEntry msg) throws AMQException; + + + public boolean isSuspended() + { + return !isActive() || _channel.isSuspended() || _deleted.get(); + } + + /** + * Callback indicating that a queue has been deleted. + * + * @param queue The queue to delete + */ + public void queueDeleted(AMQQueue queue) + { + _deleted.set(true); +// _channel.queueDeleted(queue); + } + + public boolean filtersMessages() + { + return _filters != null || _noLocal; + } + + public boolean hasInterest(QueueEntry entry) + { + //check that the message hasn't been rejected + if (entry.isRejectedBy(this)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); + } +// return false; + } + + + + //todo - client id should be recoreded and this test removed but handled below + if (_noLocal) + { + final Object publisherId = entry.getMessage().getPublisherClientInstance(); + + // We don't want local messages so check to see if message is one we sent + Object localInstance; + + if (publisherId != null && (getProtocolSession().getClientProperties() != null) && + (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + { + if(publisherId.equals(localInstance)) + { + return false; + } + } + else + { + + localInstance = getProtocolSession().getClientIdentifier(); + //todo - client id should be recoreded and this test removed but handled here + + + if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) + { + return false; + } + } + + + } + + + if (_logger.isDebugEnabled()) + { + _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity()); + } + return checkFilters(entry); + + } + + private String id = String.valueOf(System.identityHashCode(this)); + + private String debugIdentity() + { + return id; + } + + private boolean checkFilters(QueueEntry msg) + { + return (_filters == null) || _filters.allAllow(msg.getMessage()); + } + + public boolean isAutoClose() + { + return _autoClose; + } + + public FlowCreditManager getCreditManager() + { + return _creditManager; + } + + + public void close() + { + boolean closed = false; + State state = getState(); + + _stateChangeLock.lock(); + try + { + while(!closed && state != State.CLOSED) + { + closed = _state.compareAndSet(state, State.CLOSED); + if(!closed) + { + state = getState(); + } + else + { + _stateListener.stateChange(this,state, State.CLOSED); + } + } + _creditManager.removeListener(this); + } + finally + { + _stateChangeLock.unlock(); + } + + + if (closed) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Called close() on a closed subscription"); + } + + return; + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing subscription (" + debugIdentity() + "):" + this); + } + } + + public boolean isClosed() + { + return getState() == State.CLOSED; + } + + + public boolean wouldSuspend(QueueEntry msg) + { + return !_creditManager.useCreditForMessage(msg.getMessage());//_channel.wouldSuspend(msg.getMessage()); + } + + public void getSendLock() + { + _stateChangeLock.lock(); + } + + public void releaseSendLock() + { + _stateChangeLock.unlock(); + } + + public void resend(final QueueEntry entry) throws AMQException + { + _queue.resend(entry, this); + } + + public AMQChannel getChannel() + { + return _channel; + } + + public AMQShortString getConsumerTag() + { + return _consumerTag; + } + + public AMQProtocolSession getProtocolSession() + { + return _channel.getProtocolSession(); + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void restoreCredit(final QueueEntry queueEntry) + { + _creditManager.addCredit(1, queueEntry.getSize()); + } + + + public void creditStateChanged(boolean hasCredit) + { + + if(hasCredit) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + else + { + // this is a hack to get round the issue of increasing bytes credit + _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE); + } + } + else + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + } + } + + public State getState() + { + return _state.get(); + } + + + public void setStateListener(final StateListener listener) + { + _stateListener = listener; + } + + + public QueueEntry getLastSeenEntry() + { + return _queueContext.get(); + } + + public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) + { + return _queueContext.compareAndSet(expected,newvalue); + } + + + protected void sendToClient(final QueueEntry entry, final long deliveryTag) + throws AMQException + { + _deliveryMethod.deliverToClient(this,entry,deliveryTag); + } + + + protected void recordMessageDelivery(final QueueEntry entry, final long deliveryTag) + { + _recordMethod.recordMessageDelivery(this,entry,deliveryTag); + } + + + public boolean isActive() + { + return getState() == State.ACTIVE; + } + + public QueueEntry.SubscriptionAcquiredState getOwningState() + { + return _owningState; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java new file mode 100644 index 0000000000..3fbb6bfa4a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java @@ -0,0 +1,247 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.subscription.Subscription; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.nio.ByteBuffer; + +public class SubscriptionList +{ + + private final SubscriptionNode _head = new SubscriptionNode(); + + private AtomicReference _tail = new AtomicReference(_head); + private final AMQQueue _queue; + private AtomicInteger _size = new AtomicInteger(); + + + public final class SubscriptionNode + { + private final AtomicBoolean _deleted = new AtomicBoolean(); + private final AtomicReference _next = new AtomicReference(); + private final Subscription _sub; + + + public SubscriptionNode() + { + + _sub = null; + _deleted.set(true); + } + + public SubscriptionNode(final Subscription sub) + { + _sub = sub; + } + + + public SubscriptionNode getNext() + { + + SubscriptionNode next = nextNode(); + while(next != null && next.isDeleted()) + { + + final SubscriptionNode newNext = next.nextNode(); + if(newNext != null) + { + _next.compareAndSet(next, newNext); + next = nextNode(); + } + else + { + next = null; + } + + } + return next; + } + + private SubscriptionNode nextNode() + { + return _next.get(); + } + + public boolean isDeleted() + { + return _deleted.get(); + } + + + public boolean delete() + { + if(_deleted.compareAndSet(false,true)) + { + _size.decrementAndGet(); + advanceHead(); + return true; + } + else + { + return false; + } + } + + + public Subscription getSubscription() + { + return _sub; + } + } + + + public SubscriptionList(AMQQueue queue) + { + _queue = queue; + } + + private void advanceHead() + { + SubscriptionNode head = _head.nextNode(); + while(head._next.get() != null && head.isDeleted()) + { + + final SubscriptionNode newhead = head.nextNode(); + if(newhead != null) + { + _head._next.compareAndSet(head, newhead); + } + head = _head.nextNode(); + } + } + + + public SubscriptionNode add(Subscription sub) + { + SubscriptionNode node = new SubscriptionNode(sub); + for (;;) + { + SubscriptionNode tail = _tail.get(); + SubscriptionNode next = tail.nextNode(); + if (tail == _tail.get()) + { + if (next == null) + { + if (tail._next.compareAndSet(null, node)) + { + _tail.compareAndSet(tail, node); + _size.incrementAndGet(); + return node; + } + } + else + { + _tail.compareAndSet(tail, next); + } + } + } + + } + + public boolean remove(Subscription sub) + { + SubscriptionNode node = _head.getNext(); + while(node != null) + { + if(sub.equals(node._sub) && node.delete()) + { + return true; + } + node = node.getNext(); + } + return false; + } + + + public class SubscriptionNodeIterator + { + + private SubscriptionNode _lastNode; + + SubscriptionNodeIterator(SubscriptionNode startNode) + { + _lastNode = startNode; + } + + + public boolean atTail() + { + return _lastNode.nextNode() == null; + } + + public SubscriptionNode getNode() + { + + return _lastNode; + + } + + public boolean advance() + { + + if(!atTail()) + { + SubscriptionNode nextNode = _lastNode.nextNode(); + while(nextNode.isDeleted() && nextNode.nextNode() != null) + { + nextNode = nextNode.nextNode(); + } + _lastNode = nextNode; + return true; + + } + else + { + return false; + } + + } + + } + + + public SubscriptionNodeIterator iterator() + { + return new SubscriptionNodeIterator(_head); + } + + + public SubscriptionNode getHead() + { + return _head; + } + + public int size() + { + return _size.get(); + } + + + +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java new file mode 100644 index 0000000000..bdd27f2d1c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -0,0 +1,705 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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 java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoFilterAdapter; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoSession; +import org.apache.mina.util.BlockingQueue; +import org.apache.mina.util.ByteBufferUtil; +import org.apache.mina.util.IdentityHashSet; +import org.apache.mina.util.Queue; +import org.apache.mina.util.Stack; + +/** + * 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); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java new file mode 100644 index 0000000000..3c71282c57 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -0,0 +1,293 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ack.TxAck; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +import java.util.List; +import java.util.ArrayList; + +/** A transactional context that only supports local transactions. */ +public class LocalTransactionalContext implements TransactionalContext +{ + private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); + + private final TxnBuffer _txnBuffer = new TxnBuffer(); + + private final List _postCommitDeliveryList = new ArrayList(); + + /** + * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are + * consolidated into a single operation + */ + private TxAck _ackOp; + + private boolean _inTran = false; + + /** Are there messages to deliver. NOT Has the message been delivered */ + private boolean _messageDelivered = false; + private final AMQChannel _channel; + + + private abstract class DeliveryAction + { + + abstract public void process() throws AMQException; + + } + + private class RequeueAction extends DeliveryAction + { + public QueueEntry entry; + + public RequeueAction(QueueEntry entry) + { + this.entry = entry; + } + + public void process() throws AMQException + { + entry.requeue(getStoreContext()); + } + } + + private class PublishAction extends DeliveryAction + { + private final AMQQueue _queue; + private final AMQMessage _message; + + public PublishAction(final AMQQueue queue, final AMQMessage message) + { + _queue = queue; + _message = message; + } + + public void process() throws AMQException + { + + _message.incrementReference(); + try + { + QueueEntry entry = _queue.enqueue(getStoreContext(),_message); + + if(entry.immediateAndNotDelivered()) + { + getReturnMessages().add(new NoConsumersException(_message)); + } + } + finally + { + _message.decrementReference(getStoreContext()); + } + } + } + + public LocalTransactionalContext(final AMQChannel channel) + { + _channel = channel; + } + + public StoreContext getStoreContext() + { + return _channel.getStoreContext(); + } + + public List getReturnMessages() + { + return _channel.getReturnMessages(); + } + + public MessageStore getMessageStore() + { + return _channel.getMessageStore(); + } + + + public void rollback() throws AMQException + { + _txnBuffer.rollback(getStoreContext()); + // Hack to deal with uncommitted non-transactional writes + if (getMessageStore().inTran(getStoreContext())) + { + getMessageStore().abortTran(getStoreContext()); + _inTran = false; + } + + _postCommitDeliveryList.clear(); + } + + public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException + { + // A publication will result in the enlisting of several + // TxnOps. The first is an op that will store the message. + // Following that (and ordering is important), an op will + // be added for every queue onto which the message is + // enqueued. + _postCommitDeliveryList.add(new PublishAction(queue, message)); + _messageDelivered = true; + + } + + public void requeue(QueueEntry entry) throws AMQException + { + _postCommitDeliveryList.add(new RequeueAction(entry)); + _messageDelivered = true; + + } + + + private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); + } + } + + public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + // check that the tag exists to give early failure + if (!multiple || (deliveryTag > 0)) + { + checkAck(deliveryTag, unacknowledgedMessageMap); + } + // we use a single txn op for all acks and update this op + // as new acks come in. If this is the first ack in the txn + // we will need to create and enlist the op. + if (_ackOp == null) + { + _ackOp = new TxAck(unacknowledgedMessageMap); + _txnBuffer.enlist(_ackOp); + } + // update the op to include this ack request + if (multiple && (deliveryTag == 0)) + { + // if have signalled to ack all, that refers only + // to all at this time + _ackOp.update(lastDeliveryTag, multiple); + } + else + { + _ackOp.update(deliveryTag, multiple); + } + if(!_inTran && _ackOp.checkPersistent()) + { + beginTranIfNecessary(); + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + // Not required in this transactional context + } + + public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + // Not required in this transactional context + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + if (_log.isDebugEnabled()) + { + _log.debug("Starting transaction on message store: " + this); + } + + getMessageStore().beginTran(getStoreContext()); + _inTran = true; + } + } + + public void commit() throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Committing transactional context: " + this); + } + + if (_ackOp != null) + { + + _messageDelivered = true; + _ackOp.consolidate(); + // already enlisted, after commit will reset regardless of outcome + _ackOp = null; + } + + if (_messageDelivered && _inTran) + { + _txnBuffer.enlist(new StoreMessageOperation(getMessageStore())); + } + // fixme fail commit here ... QPID-440 + try + { + _txnBuffer.commit(getStoreContext()); + } + finally + { + _messageDelivered = false; + _inTran = getMessageStore().inTran(getStoreContext()); + } + + try + { + postCommitDelivery(); + } + catch (AMQException e) + { + // OK so what do we do now...? + _log.error("Failed to deliver messages following txn commit: " + e, e); + } + } + + private void postCommitDelivery() throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Performing post commit delivery"); + } + + try + { + for (DeliveryAction dd : _postCommitDeliveryList) + { + dd.process(); + } + } + finally + { + _postCommitDeliveryList.clear(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java new file mode 100644 index 0000000000..28af36e3db --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -0,0 +1,213 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** @author Apache Software Foundation */ +public class NonTransactionalContext implements TransactionalContext +{ + private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); + + /** Channel is useful for logging */ + private final AMQChannel _channel; + + /** Where to put undeliverable messages */ + private final List _returnMessages; + + + + private final MessageStore _messageStore; + + private final StoreContext _storeContext; + + /** Whether we are in a transaction */ + private boolean _inTran; + + public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, + List returnMessages) + { + _channel = channel; + _storeContext = storeContext; + _returnMessages = returnMessages; + _messageStore = messageStore; + + } + + + public StoreContext getStoreContext() + { + return _storeContext; + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(_storeContext); + _inTran = true; + } + } + + public void commit() throws AMQException + { + // Does not apply to this context + } + + public void rollback() throws AMQException + { + // Does not apply to this context + } + + public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException + { + QueueEntry entry = queue.enqueue(_storeContext, message); + + //following check implements the functionality + //required by the 'immediate' flag: + if(entry.immediateAndNotDelivered()) + { + _returnMessages.add(new NoConsumersException(entry.getMessage())); + } + + } + + public void requeue(QueueEntry entry) throws AMQException + { + entry.requeue(_storeContext); + } + + public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, + boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) + throws AMQException + { + + final boolean debug = _log.isDebugEnabled(); + ; + if (multiple) + { + if (deliveryTag == 0) + { + + //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, + // tells the server to acknowledge all outstanding mesages. + _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + + unacknowledgedMessageMap.size()); + unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException + { + if (debug) + { + _log.debug("Discarding message: " + message.getMessage().getMessageId()); + } + if(message.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } + //Message has been ack so discard it. This will dequeue and decrement the reference. + message.discard(_storeContext); + + return false; + } + + public void visitComplete() + { + unacknowledgedMessageMap.clear(); + } + }); + } + else + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + } + + unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext); + } + } + else + { + QueueEntry msg; + msg = unacknowledgedMessageMap.get(deliveryTag); + + if (msg == null) + { + _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + + _channel.getChannelId()); + throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + + _channel.getChannelId()); + } + + if (debug) + { + _log.debug("Discarding message: " + msg.getMessage().getMessageId()); + } + if(msg.getMessage().isPersistent()) + { + beginTranIfNecessary(); + } + + //Message has been ack so discard it. This will dequeue and decrement the reference. + msg.discard(_storeContext); + + unacknowledgedMessageMap.remove(deliveryTag); + + + if (debug) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + + msg.getMessage().getMessageId()); + } + } + if(_inTran) + { + _messageStore.commitTran(_storeContext); + _inTran = false; + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + if (persistent) + { + _messageStore.commitTran(_storeContext); + _inTran = false; + } + } + + public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException + { + _channel.processReturns(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java new file mode 100644 index 0000000000..0e4d6c2030 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +/** + * A transactional operation to store messages in an underlying persistent store. When this operation + * commits it will do everything to ensure that all messages are safely committed to persistent + * storage. + */ +public class StoreMessageOperation implements TxnOp +{ + private final MessageStore _messsageStore; + + public StoreMessageOperation(MessageStore messageStore) + { + _messsageStore = messageStore; + } + + public void prepare(StoreContext context) throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit(StoreContext context) throws AMQException + { + _messsageStore.commitTran(context); + } + + public void rollback(StoreContext context) throws AMQException + { + _messsageStore.abortTran(context); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java new file mode 100644 index 0000000000..647ba66fb4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java @@ -0,0 +1,179 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.StoreContext; + +/** + * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. + * Different levels of transactional support for the delivery of messages may be provided by different implementations + * of this interface. + * + *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. + * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} + * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. + * + *

      + *
      CRC Card
      Responsibilities + *
      Explicitly accept a transaction start notification. + *
      Commit all pending operations in a transaction. + *
      Rollback all pending operations in a transaction. + *
      Deliver a message to a queue as part of a transaction. + *
      Redeliver a message to a queue as part of a transaction. + *
      Mark a message as acknowledged as part of a transaction. + *
      Accept notification that a message has been completely received as part of a transaction. + *
      Accept notification that a message has been fully processed as part of a transaction. + *
      Associate a message store context with this transaction context. + *
      + * + * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional + * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them + * somewhere else, a seperate interface for example. + * + * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides + * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any + * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean + * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be + * conceptually neater. + * + * For example: + *

      + * public interface Transactional
      + * {
      + *    public void commit();
      + *    public void rollback();
      + * }
      + *
      + * public interface TransactionalQueue extends Transactional, SizeableQueue
      + * {}
      + *
      + * public class Queues
      + * {
      + *    ...
      + *    // For transactional messaging, take a transactional view onto the queue.
      + *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      + *
      + *    // For non-transactional messaging, take a non-transactional view onto the queue.
      + *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      + * }
      + * 
      + */ +public interface TransactionalContext +{ + /** + * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} + * should automatically begin the next transaction in the chain. + * + * @throws AMQException If the transaction cannot be started for any reason. + */ + void beginTranIfNecessary() throws AMQException; + + /** + * Makes all pending operations on the transaction permanent and visible. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ + void commit() throws AMQException; + + /** + * Erases all pending operations on the transaction. + * + * @throws AMQException If the transaction cannot be committed for any reason. + */ + void rollback() throws AMQException; + + /** + * Delivers the specified message to the specified queue. + * + *

      This is an 'enqueue' operation. + * + * @param queue + * @param message The message to deliver + * @throws AMQException If the message cannot be delivered for any reason. + */ + void deliver(final AMQQueue queue, AMQMessage message) throws AMQException; + + /** + * Requeues the specified message entry (message queue pair) + * + * + * @param queueEntry The message,queue pair + * + * @throws AMQException If the message cannot be delivered for any reason. + */ + void requeue(QueueEntry queueEntry) throws AMQException; + + + /** + * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by + * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' + * flag is set, in which case an acknowledgement up to the latest delivered message should be done. + * + *

      This is a 'dequeue' operation. + * + * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement + * up to the latest message. + * @param lastDeliveryTag The latest message delivered. + * @param multiple true if all message ids up the acknowledged one or latest delivered, are + * to be acknowledged, false otherwise. + * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message + * from. + * + * @throws AMQException If the message cannot be acknowledged for any reason. + */ + void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + + /** + * Notifies the transactional context that a message has been fully received. The actual message that was received + * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, + * flushing its data to disk. + * + * @param persistent true if the received message is persistent, false otherwise. + * + * @throws AMQException If the fully received event cannot be processed for any reason. + */ + void messageFullyReceived(boolean persistent) throws AMQException; + + /** + * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual + * message that was delivered is not specified. This event may be used to trigger a process related to the + * outcome of the delivery of the message, for example, cleaning up failed deliveries. + * + * @param protocolSession The protocol session of the deliverable message. + * + * @throws AMQException If the message processed event cannot be handled for any reason. + */ + void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; + + /** + * Gets the message store context associated with this transactional context. + * + * @return The message store context associated with this transactional context. + */ + StoreContext getStoreContext(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java new file mode 100644 index 0000000000..46a68b6a23 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -0,0 +1,109 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; + +/** Holds a list of TxnOp instance representing transactional operations. */ +public class TxnBuffer +{ + private final List _ops = new ArrayList(); + private static final Logger _log = Logger.getLogger(TxnBuffer.class); + + public TxnBuffer() + { + } + + public void commit(StoreContext context) throws AMQException + { + if (_log.isDebugEnabled()) + { + _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); + } + + if (prepare(context)) + { + for (TxnOp op : _ops) + { + op.commit(context); + } + } + _ops.clear(); + } + + private boolean prepare(StoreContext context) throws AMQException + { + for (int i = 0; i < _ops.size(); i++) + { + TxnOp op = _ops.get(i); + try + { + op.prepare(context); + } + catch (AMQException e) + { + undoPrepare(i); + throw e; + } + catch (RuntimeException e) + { + undoPrepare(i); + throw e; + } + } + return true; + } + + private void undoPrepare(int lastPrepared) + { + //compensate previously prepared ops + for (int j = 0; j < lastPrepared; j++) + { + _ops.get(j).undoPrepare(); + } + } + + + + public void rollback(StoreContext context) throws AMQException + { + for (TxnOp op : _ops) + { + op.rollback(context); + } + _ops.clear(); + } + + public void enlist(TxnOp op) + { + _ops.add(op); + } + + public void cancel(TxnOp op) + { + _ops.remove(op); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java new file mode 100644 index 0000000000..919c078cf0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; + +/** + * This provides the abstraction of an individual operation within a + * transaction. It is used by the TxnBuffer class. + */ +public interface TxnOp +{ + /** + * Do the part of the operation that updates persistent state + */ + public void prepare(StoreContext context) throws AMQException; + /** + * Complete the operation started by prepare. Can now update in + * memory state or make netork transfers. + */ + public void commit(StoreContext context) throws AMQException; + /** + * This is not the same as rollback. Unfortunately the use of an + * in memory reference count as a locking mechanism and a test for + * whether a message should be deleted means that as things are, + * handling an acknowledgement unavoidably alters both memory and + * persistent state on prepare. This is needed to 'compensate' or + * undo the in-memory change if the peristent update of later ops + * fails. + */ + public void undoPrepare(); + /** + * Rolls back the operation. + */ + public void rollback(StoreContext context) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java new file mode 100644 index 0000000000..e730e2f3c3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java @@ -0,0 +1,131 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +public class CircularBuffer implements Iterable +{ + + private static final Logger _logger = Logger.getLogger(CircularBuffer.class); + + 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) + { + _logger.info(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); + _logger.info(buffer); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java new file mode 100644 index 0000000000..cf5e71a6e2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue +{ + public int size() + { + if (isEmpty()) + { + return 0; + } + else + { + return 1; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java new file mode 100644 index 0000000000..eda97e0ed2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +/** + * Dynamic proxy that records invocations in a fixed size circular buffer, + * dumping details on hitting an exception. + *

      + * Useful in debugging. + *

      + */ +public class LoggingProxy implements InvocationHandler +{ + private final Object _target; + private final CircularBuffer _log; + + public LoggingProxy(Object target, int size) + { + _target = target; + _log = new CircularBuffer(size); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + try + { + entered(method, args); + Object result = method.invoke(_target, args); + returned(method, result); + return result; + } + catch(InvocationTargetException e) + { + dump(); + throw e.getTargetException(); + } + } + + void dump() + { + _log.dump(); + } + + CircularBuffer getBuffer() + { + return _log; + } + + private synchronized void entered(Method method, Object[] args) + { + if (args == null) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); + } + } + + private synchronized void returned(Method method, Object result) + { + if (method.getReturnType() == Void.TYPE) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); + } + } + + public Object getProxy(Class... c) + { + return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); + } + + public int getBufferSize() { + return _log.size(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java new file mode 100644 index 0000000000..eda2d3a94e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Properties; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.MapConfiguration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +public class NullApplicationRegistry extends ApplicationRegistry +{ + public NullApplicationRegistry() throws ConfigurationException + { + super(new ServerConfiguration(new PropertiesConfiguration())); + } + + public void initialise() throws Exception + { + _logger.info("Initialising NullApplicationRegistry"); + + _configuration.setHousekeepingExpiredMessageCheckPeriod(200); + + Properties users = new Properties(); + + users.put("guest", "guest"); + + _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); + + _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + + _managedObjectRegistry = new NoopManagedObjectRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(); + PropertiesConfiguration vhostProps = new PropertiesConfiguration(); + VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); + VirtualHost dummyHost = new VirtualHost(hostConfig); + _virtualHostRegistry.registerVirtualHost(dummyHost); + _virtualHostRegistry.setDefaultVirtualHostName("test"); + _pluginManager = new PluginManager(""); + + } + + public Collection getVirtualHostNames() + { + String[] hosts = {"test"}; + return Arrays.asList(hosts); + } +} + + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java new file mode 100644 index 0000000000..f4c81fbbb8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.io.IOException; + +import org.apache.qpid.server.management.MBeanAttribute; + +/** + * The management interface exposed to allow management of an Exchange. + * @version 0.1 + */ +public interface ManagedVirtualHost +{ + static final String TYPE = "VirtualHost"; + static final int VERSION = 1; + + /** + * Returns the name of the managed virtualHost. + * @return the name of the exchange. + * @throws java.io.IOException + */ + @MBeanAttribute(name="Name", description= TYPE + " Name") + String getName() throws IOException; + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java new file mode 100644 index 0000000000..0ae0594de8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -0,0 +1,593 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.configuration.ExchangeConfiguration; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.connection.ConnectionRegistry; +import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreContext; + +import javax.management.NotCompliantMBeanException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class VirtualHost implements Accessable +{ + private static final Logger _logger = Logger.getLogger(VirtualHost.class); + + private final String _name; + + private ConnectionRegistry _connectionRegistry; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private ACLManager _accessManager; + + private final Timer _houseKeepingTimer; + private VirtualHostConfiguration _configuration; + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + public IConnectionRegistry getConnectionRegistry() + { + return _connectionRegistry; + } + + public VirtualHostConfiguration getConfiguration() + { + return _configuration; + } + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHost getVirtualHost() + { + return VirtualHost.this; + } + + } // End of MBean class + + /** + * Normal Constructor + * + * @param hostConfig + * + * @throws Exception + */ + public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception + { + this(hostConfig, null); + } + + public VirtualHost(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception + { + _configuration = hostConfig; + _name = hostConfig.getName(); + + if (_name == null || _name.length() == 0) + { + throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); + } + + _virtualHostMBean = new VirtualHostMBean(); + + _connectionRegistry = new ConnectionRegistry(this); + + _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + + _queueRegistry = new DefaultQueueRegistry(this); + + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + + _exchangeRegistry = new DefaultExchangeRegistry(this); + + //Create a temporary RT to store the durable entries from the config file + // so we can replay them in to the real _RT after it has been loaded. + /// This should be removed after the _RT has been fully split from the the TL + + StartupRoutingTable configFileRT = new StartupRoutingTable(); + + _messageStore = configFileRT; + + // This needs to be after the RT has been defined as it creates the default durable exchanges. + _exchangeRegistry.initialise(); + initialiseModel(hostConfig); + + if (store != null) + { + _messageStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config + // file and write them in to the new routing Table. + for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) + { + _messageStore.createQueue(cqt.queue, cqt.arguments); + } + + for (Exchange exchange : configFileRT.exchange) + { + _messageStore.createExchange(exchange); + } + + for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) + { + _messageStore.bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); + } + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); + + _accessManager = ApplicationRegistry.getInstance().getAccessManager(); + _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); + } + + private void initialiseHouseKeeping(long period) + { + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ + if (period != 0L) + { + class RemoveExpiredMessagesTask extends TimerTask + { + public void run() + { + for (AMQQueue q : _queueRegistry.getQueues()) + { + + try + { + q.checkMessageStatus(); + } + catch (AMQException e) + { + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + throw new RuntimeException(e); + } + } + } + } + + _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), + period / 2, + period); + } + } + + private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception + { + String messageStoreClass = hostConfig.getMessageStoreClass(); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + MessageStore messageStore = (MessageStore) o; + messageStore.configure(this, "store", hostConfig); + _messageStore = messageStore; + } + + private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException + { + _logger.debug("Loading configuration for virtualhost: " + config.getName()); + + List exchangeNames = config.getExchanges(); + + for (Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(config.getExchangeConfiguration(exchangeName)); + } + + String[] queueNames = config.getQueueNames(); + + for (Object queueNameObj : queueNames) + { + String queueName = String.valueOf(queueNameObj); + configureQueue(config.getQueueConfiguration(queueName)); + } + } + + private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException + { + AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); + + Exchange exchange; + exchange = _exchangeRegistry.getExchange(exchangeName); + if (exchange == null) + { + + AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); + boolean durable = exchangeConfiguration.getDurable(); + boolean autodelete = exchangeConfiguration.getAutoDelete(); + + Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); + _exchangeRegistry.registerExchange(newExchange); + } + } + + private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException + { + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); + + if (queue.isDurable()) + { + _messageStore.createQueue(queue); + } + + String exchangeName = queueConfiguration.getExchange(); + + Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if (exchange == null) + { + exchange = _exchangeRegistry.getDefaultExchange(); + } + + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } + + List routingKeys = queueConfiguration.getRoutingKeys(); + if (routingKeys == null || routingKeys.isEmpty()) + { + routingKeys = Collections.singletonList(queue.getName()); + } + + for (Object routingKeyNameObj : routingKeys) + { + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); + } + queue.bind(exchange, routingKey, null); + } + + if (exchange != _exchangeRegistry.getDefaultExchange()) + { + queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + } + } + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ApplicationRegistry getApplicationRegistry() + { + throw new UnsupportedOperationException(); + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public ACLManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + + //Stop Connections + _connectionRegistry.close(); + + //Stop the Queues processing + if (_queueRegistry != null) + { + for (AMQQueue queue : _queueRegistry.getQueues()) + { + queue.stop(); + } + } + + //Stop Housekeeping + if (_houseKeepingTimer != null) + { + _houseKeepingTimer.cancel(); + } + + //Close MessageStore + if (_messageStore != null) + { + _messageStore.close(); + } + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } + + /** + * Temporary Startup RT class to record the creation of persistent queues / exchanges. + * + * + * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. + * This should be removed after the _RT has been fully split from the the TL + */ + private class StartupRoutingTable implements MessageStore + { + public List exchange = new LinkedList(); + public List queue = new LinkedList(); + public List bindings = new LinkedList(); + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + } + + public void close() throws Exception + { + } + + public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (exchange.isDurable()) + { + this.exchange.add(exchange); + } + } + + public void removeExchange(Exchange exchange) throws AMQException + { + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + if (exchange.isDurable() && queue.isDurable()) + { + bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); + } + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + } + + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + if (queue.isDurable()) + { + this.queue.add(new CreateQueueTuple(queue, arguments)); + } + } + + public void removeQueue(AMQQueue queue) throws AMQException + { + } + + public void enqueueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void beginTran(StoreContext context) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void commitTran(StoreContext context) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void abortTran(StoreContext context) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean inTran(StoreContext context) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Long getNewMessageId() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isPersistent() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + private class CreateQueueTuple + { + public AMQQueue queue; + public FieldTable arguments; + + public CreateQueueTuple(AMQQueue queue, FieldTable arguments) + { + this.queue = queue; + this.arguments = arguments; + } + } + + private class CreateBindingTuple + { + public AMQQueue queue; + public FieldTable arguments; + public Exchange exchange; + public AMQShortString routingKey; + + public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + { + this.exchange = exchange; + this.routingKey = routingKey; + this.queue = queue; + arguments = args; + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java new file mode 100644 index 0000000000..27917fac8a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -0,0 +1,70 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class VirtualHostRegistry +{ + private final Map _registry = new ConcurrentHashMap(); + + + private String _defaultVirtualHostName; + + public synchronized void registerVirtualHost(VirtualHost host) throws Exception + { + if(_registry.containsKey(host.getName())) + { + throw new Exception("Virtual Host with name " + host.getName() + " already registered."); + } + _registry.put(host.getName(),host); + } + + public VirtualHost getVirtualHost(String name) + { + if(name == null || name.trim().length() == 0 ) + { + name = getDefaultVirtualHostName(); + } + + return _registry.get(name); + } + + private String getDefaultVirtualHostName() + { + return _defaultVirtualHostName; + } + + public void setDefaultVirtualHostName(String defaultVirtualHostName) + { + _defaultVirtualHostName = defaultVirtualHostName; + } + + + public Collection getVirtualHosts() + { + return new ArrayList(_registry.values()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java new file mode 100644 index 0000000000..faa7b85d58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -0,0 +1,652 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.commands.Clear; +import org.apache.qpid.tools.messagestore.commands.Command; +import org.apache.qpid.tools.messagestore.commands.Copy; +import org.apache.qpid.tools.messagestore.commands.Dump; +import org.apache.qpid.tools.messagestore.commands.Help; +import org.apache.qpid.tools.messagestore.commands.List; +import org.apache.qpid.tools.messagestore.commands.Load; +import org.apache.qpid.tools.messagestore.commands.Quit; +import org.apache.qpid.tools.messagestore.commands.Select; +import org.apache.qpid.tools.messagestore.commands.Show; +import org.apache.qpid.tools.messagestore.commands.Move; +import org.apache.qpid.tools.messagestore.commands.Purge; +import org.apache.qpid.tools.utils.CommandParser; +import org.apache.qpid.tools.utils.Console; +import org.apache.qpid.tools.utils.SimpleCommandParser; +import org.apache.qpid.tools.utils.SimpleConsole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * MessageStoreTool. + */ +public class MessageStoreTool +{ + /** Text outputted at the start of each console.*/ + private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances"; + + /** I/O Wrapper. */ + protected Console _console; + + /** Batch mode flag. */ + protected boolean _batchMode; + + /** Internal State object. */ + private State _state = new State(); + + private HashMap _commands = new HashMap(); + + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class); + + /** Loaded configuration file. */ + private Configuration _config; + + /** Control used for main run loop. */ + private boolean _running = true; + private boolean _initialised = false; + + //---------------------------------------------------------------------------------------------------/ + + public static void main(String[] args) throws Configuration.InitException + { + + MessageStoreTool tool = new MessageStoreTool(args); + + tool.start(); + } + + + public MessageStoreTool(String[] args) throws Configuration.InitException + { + this(args, System.in, System.out); + } + + public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException + { + BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in)); + BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out)); + + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this))); + _batchMode = false; + + _console = new SimpleConsole(consoleWriter, consoleReader); + + _config = new Configuration(); + + setOptions(); + _config.processCommandline(args); + } + + + private void setOptions() + { + 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 By " + + "default looks for a file named " + + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME) + .withLongOpt("config") + .create("c"); + + _config.setOption(help); + _config.setOption(version); + _config.setOption(configFile); + } + + public State getState() + { + return _state; + } + + public Map getCommands() + { + return _commands; + } + + public void setConfigurationFile(String configfile) throws Configuration.InitException + { + _config.loadConfig(new File(configfile)); + setup(); + } + + public Console getConsole() + { + return _console; + } + + public void setConsole(Console console) + { + _console = console; + } + + /** + * Simple ShutdownHook to cleanly shutdown the databases + */ + class ShutdownHook implements Runnable + { + MessageStoreTool _tool; + + ShutdownHook(MessageStoreTool messageStoreTool) + { + _tool = messageStoreTool; + } + + public void run() + { + _tool.quit(); + } + } + + public void quit() + { + _running = false; + + if (_initialised) + { + ApplicationRegistry.remove(1); + } + + _console.println("...exiting"); + + _console.close(); + } + + public void setBatchMode(boolean batchmode) + { + _batchMode = batchmode; + } + + /** + * Main loop + */ + protected void start() + { + setup(); + + if (!_initialised) + { + System.exit(1); + } + + _console.println(""); + + _console.println(BOILER_PLATE); + + runCLI(); + } + + private void setup() + { + loadDefaultVirtualHosts(); + + loadCommands(); + + _state.clearAll(); + } + + private void loadCommands() + { + _commands.clear(); + //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands + _commands.put("close", new Clear(this)); + _commands.put("copy", new Copy(this)); + _commands.put("dump", new Dump(this)); + _commands.put("help", new Help(this)); + _commands.put("list", new List(this)); + _commands.put("load", new Load(this)); + _commands.put("move", new Move(this)); + _commands.put("purge", new Purge(this)); + _commands.put("quit", new Quit(this)); + _commands.put("select", new Select(this)); + _commands.put("show", new Show(this)); + } + + private void loadDefaultVirtualHosts() + { + final File configFile = _config.getConfigFile(); + + loadVirtualHosts(configFile); + } + + private void loadVirtualHosts(File configFile) + { + + if (!configFile.exists()) + { + _devlog.error("Config file not found:" + configFile.getAbsolutePath()); + return; + } + else + { + _devlog.debug("using config file :" + configFile.getAbsolutePath()); + } + + try + { + ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile); + + ApplicationRegistry.remove(1); + + ApplicationRegistry.initialise(registry); + + checkMessageStores(); + _initialised = true; + } + catch (ConfigurationException e) + { + _console.println("Unable to load configuration due to configuration error: " + e.getMessage()); + e.printStackTrace(); + } + catch (Exception e) + { + _console.println("Unable to load configuration due to: " + e.getMessage()); + e.printStackTrace(); + } + + + } + + private void checkMessageStores() + { + Collection vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts(); + + boolean warning = false; + for (VirtualHost vhost : vhosts) + { + if (vhost.getMessageStore() instanceof MemoryMessageStore) + { + _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. " + + "Changes will not persist."); + warning = true; + } + } + + if (warning) + { + _console.println(""); + _console.println("Please ensure you are using the correct config file currently using '" + + _config.getConfigFile().getAbsolutePath() + "'"); + _console.println("New config file can be specifed by 'load ' or -c on the commandline."); + _console.println(""); + } + } + + private void runCLI() + { + while (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + String[] args = _console.readCommand(); + + while (args != null) + { + exec(args); + + if (_running) + { + if (!_batchMode) + { + printPrompt(); + } + + args = _console.readCommand(); + } + } + } + } + + private void printPrompt() + { + _console.print(prompt()); + } + + + /** + * Execute a script (batch mode). + * + * @param script The file script + */ + protected void runScripts(String script) + { + //Store Current State + boolean oldBatch = _batchMode; + CommandParser oldParser = _console.getCommandParser(); + setBatchMode(true); + + try + { + _devlog.debug("Running script '" + script + "'"); + + _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script)))); + + start(); + } + catch (java.io.FileNotFoundException e) + { + _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage()); + } + + //Restore previous state + _console.setCommandParser(oldParser); + setBatchMode(oldBatch); + } + + public String prompt() + { + String state = _state.toString(); + if (state != null && state.length() != 0) + { + return state + ":bdb$ "; + } + else + { + return "bdb$ "; + } + } + + /** + * Execute the command. + * + * @param args [command, arg0, arg1...]. + */ + protected void exec(String[] args) + { + // Comment lines start with a # + if (args.length == 0 || args[0].startsWith("#")) + { + return; + } + + final String command = args[0]; + + Command cmd = _commands.get(command); + + if (cmd == null) + { + _console.println("Command not understood: " + command); + } + else + { + cmd.execute(args); + } + } + + + /** + * Displays usage info. + */ + protected static void help() + { + System.out.println(BOILER_PLATE); + System.out.println("Usage: java " + MessageStoreTool.class + " [Options]"); + System.out.println(" [-c ] : Defaults to \"$QPID_HOME/etc/config.xml\""); + } + + + /** + * This class is used to store the current state of the tool. + * + * This is then interrogated by the various commands to augment their behaviour. + * + * + */ + public class State + { + private VirtualHost _vhost = null; + private AMQQueue _queue = null; + private Exchange _exchange = null; + private java.util.List _msgids = null; + + public State() + { + } + + public void setQueue(AMQQueue queue) + { + _queue = queue; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public void setVhost(VirtualHost vhost) + { + _vhost = vhost; + } + + public VirtualHost getVhost() + { + return _vhost; + } + + public Exchange getExchange() + { + return _exchange; + } + + public void setExchange(Exchange exchange) + { + _exchange = exchange; + } + + public String toString() + { + StringBuilder status = new StringBuilder(); + + if (_vhost != null) + { + status.append(_vhost.getName()); + + if (_exchange != null) + { + status.append("["); + status.append(_exchange.getName()); + status.append("]"); + + if (_queue != null) + { + status.append("->'"); + status.append(_queue.getName()); + status.append("'"); + + if (_msgids != null) + { + status.append(printMessages()); + } + } + } + } + + return status.toString(); + } + + + public String printMessages() + { + StringBuilder sb = new StringBuilder(); + + Long previous = null; + + Long start = null; + for (Long id : _msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(id); + start = null; + } + else + { + sb.append(","); + sb.append(previous); + } + } + } + + previous = id; + } + + if (start != null) + { + sb.append(","); + sb.append(start); + sb.append("-"); + sb.append(_msgids.get(_msgids.size() - 1)); + } + else + { + sb.append(","); + sb.append(previous); + } + + // surround list in () + sb.replace(0, 1, "("); + sb.append(")"); + return sb.toString(); + } + + public void clearAll() + { + _vhost = null; + clearExchange(); + } + + public void clearExchange() + { + _exchange = null; + clearQueue(); + } + + public void clearQueue() + { + _queue = null; + clearMessages(); + } + + public void clearMessages() + { + _msgids = null; + } + + /** + * A common location to provide parsing of the message id string + * utilised by a number of the commands. + * The String is comma separated list of ids that can be individual ids + * or a range (4-10) + * + * @param msgString string of msg ids to parse 1,2,4-10 + */ + public void setMessages(String msgString) + { + StringTokenizer tok = new StringTokenizer(msgString, ","); + + if (tok.hasMoreTokens()) + { + _msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + _msgids.add(l); + } + } + } + else + { + _msgids.add(Long.parseLong(next)); + } + } + + } + + public void setMessages(java.util.List msgids) + { + _msgids = msgids; + } + + public java.util.List getMessages() + { + return _msgids; + } + }//Class State + +}//Class MessageStoreTool diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java new file mode 100644 index 0000000000..5444197cb4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +public abstract class AbstractCommand implements Command +{ + protected Console _console; + protected MessageStoreTool _tool; + + public AbstractCommand(MessageStoreTool tool) + { + _console = tool.getConsole(); + _tool = tool; + } + + public void setOutput(Console out) + { + _console = out; + } + + protected void commandError(String message, String[] args) + { + _console.print(getCommand() + " : " + message); + + if (args != null) + { + for (int i = 1; i < args.length; i++) + { + _console.print(args[i]); + } + } + _console.println(""); + _console.println(help()); + } + + + public abstract String help(); + + public abstract String usage(); + + public abstract String getCommand(); + + + public abstract void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java new file mode 100644 index 0000000000..b0006b3fe6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Clear extends AbstractCommand +{ + public Clear(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Clears any selection."; + } + + public String usage() + { + return "clear [ all | virtualhost | exchange | queue | msgs ]"; + } + + public String getCommand() + { + return "clear"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 1) + { + doClose("all"); + } + else + { + doClose(args[1]); + } + } + + private void doClose(String type) + { + if (type.equals("virtualhost") + || type.equals("all")) + { + _tool.getState().clearAll(); + } + + if (type.equals("exchange")) + { + _tool.getState().clearExchange(); + } + + if (type.equals("queue")) + { + _tool.getState().clearQueue(); + } + + if (type.equals("msgs")) + { + _tool.getState().clearMessages(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java new file mode 100644 index 0000000000..bfa775a34a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.utils.Console; + +public interface Command +{ + public void setOutput(Console out); + + public String help(); + + public abstract String usage(); + + String getCommand(); + + public void execute(String... args); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java new file mode 100644 index 0000000000..0869d9a497 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.server.queue.AMQQueue; + +public class Copy extends Move +{ + public Copy(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Copy messages between queues.";/*\n" + + "The currently selected message set will be copied to the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; */ + } + + public String usage() + { + return "copy to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "copy"; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java new file mode 100644 index 0000000000..731f6140f9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.commons.codec.binary.Hex; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntryImpl; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class Dump extends Show +{ + private static final int LINE_SIZE = 8; + private static final String DEFAULT_ENCODING = "utf-8"; + private static final boolean SPACE_BYTES = true; + private static final String BYTE_SPACER = " "; + private static final String NON_PRINTING_ASCII_CHAR = "?"; + + protected boolean _content = true; + + public Dump(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Dump selected message content. Default: show=content"; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; + } + + public String getCommand() + { + return "dump"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _content = arg.contains("content") || arg.contains("all"); + } + } + + parseArgs(args); + } + + performShow(); + } + + + protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + List display = new LinkedList(); + + List hex = new LinkedList(); + List ascii = new LinkedList(); + display.add(hex); + display.add(ascii); + + for (QueueEntry entry : messages) + { + AMQMessage msg = entry.getMessage(); + if (!includeMsg(msg, msgids)) + { + continue; + } + + //Add divider between messages + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + // Show general message information + hex.add(Show.Columns.ID.name()); + ascii.add(msg.getMessageId().toString()); + + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + if (showRouting) + { + addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); + } + if (showHeaders) + { + addShowInformation(hex, ascii, msg, "Headers", false, true, false); + } + if (showMessageHeaders) + { + addShowInformation(hex, ascii, msg, null, false, false, true); + } + + // Add Content Body seciont + hex.add("Content Body"); + ascii.add(""); + hex.add(Console.ROW_DIVIDER); + ascii.add(Console.ROW_DIVIDER); + + Iterator bodies = msg.getContentBodyIterator(); + if (bodies.hasNext()) + { + + hex.add("Hex"); + hex.add(Console.ROW_DIVIDER); + + + ascii.add("ASCII"); + ascii.add(Console.ROW_DIVIDER); + + while (bodies.hasNext()) + { + ContentChunk chunk = (ContentChunk) bodies.next(); + + //Duplicate so we don't destroy original data :) + ByteBuffer hexBuffer = chunk.getData().duplicate(); + + ByteBuffer charBuffer = hexBuffer.duplicate(); + + Hex hexencoder = new Hex(); + + while (hexBuffer.hasRemaining()) + { + byte[] line = new byte[LINE_SIZE]; + + int bufsize = hexBuffer.remaining(); + if (bufsize < LINE_SIZE) + { + hexBuffer.get(line, 0, bufsize); + } + else + { + bufsize = line.length; + hexBuffer.get(line); + } + + byte[] encoded = hexencoder.encode(line); + + try + { + String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); + String hexLine = ""; + + int strKength = encStr.length(); + for (int c = 0; c < strKength; c++) + { + hexLine += encStr.charAt(c); + + if (c % 2 == 1 && SPACE_BYTES) + { + hexLine += BYTE_SPACER; + } + } + + hex.add(hexLine); + } + catch (UnsupportedEncodingException e) + { + _console.println(e.getMessage()); + return null; + } + } + + while (charBuffer.hasRemaining()) + { + String asciiLine = ""; + + for (int pos = 0; pos < LINE_SIZE; pos++) + { + if (charBuffer.hasRemaining()) + { + byte ch = charBuffer.get(); + + if (isPrintable(ch)) + { + asciiLine += (char) ch; + } + else + { + asciiLine += NON_PRINTING_ASCII_CHAR; + } + + if (SPACE_BYTES) + { + asciiLine += BYTE_SPACER; + } + } + else + { + break; + } + } + + ascii.add(asciiLine); + } + } + } + else + { + List result = new LinkedList(); + + display.add(result); + result.add("No ContentBodies"); + } + } + + // if hex is empty then we have no data to display + if (hex.size() == 0) + { + return null; + } + + return display; + } + + private void addShowInformation(List column1, List column2, AMQMessage msg, + String title, boolean routing, boolean headers, boolean messageHeaders) + { + List single = new LinkedList(); + single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE)); + + List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); + + //Reformat data + if (title != null) + { + column1.add(title); + column2.add(""); + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + // look at all columns in the routing Data + for (List item : routingData) + { + // the item should be: + // Title + // *divider + // value + // otherwise we can't reason about the correct value + if (item.size() == 3) + { + //Filter out the columns we are not interested in. + + String columnName = item.get(0).toString(); + + if (!(columnName.equals(Show.Columns.ID.name()) + || columnName.equals(Show.Columns.Size.name()))) + { + column1.add(columnName); + column2.add(item.get(2).toString()); + } + } + } + column1.add(Console.ROW_DIVIDER); + column2.add(Console.ROW_DIVIDER); + } + + private boolean isPrintable(byte c) + { + return c > 31 && c < 127; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java new file mode 100644 index 0000000000..0f9546541b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.Map; + +public class Help extends AbstractCommand +{ + public Help(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Provides detailed help on commands."; + } + + public String getCommand() + { + return "help"; + } + + public String usage() + { + return "help []"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + Command command = _tool.getCommands().get(args[1]); + if (command != null) + { + _console.println(command.help()); + _console.println("Usage:" + command.usage()); + } + else + { + commandError("Command not found: ", args); + } + } + else + { + java.util.List data = new LinkedList(); + + java.util.List commandName = new LinkedList(); + java.util.List commandDescription = new LinkedList(); + + data.add(commandName); + data.add(commandDescription); + + //Set up Headers + commandName.add("Command"); + commandDescription.add("Description"); + + commandName.add(Console.ROW_DIVIDER); + commandDescription.add(Console.ROW_DIVIDER); + + //Add current Commands with descriptions + Map commands = _tool.getCommands(); + + for (Command command : commands.values()) + { + commandName.add(command.getCommand()); + commandDescription.add(command.help()); + } + + _console.printMap("Available Commands", data); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java new file mode 100644 index 0000000000..df8b59ec19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -0,0 +1,314 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.Collection; +import java.util.LinkedList; + +public class List extends AbstractCommand +{ + + public List(MessageStoreTool tool) + { + super(tool); + } + + public void setOutput(Console out) + { + _console = out; + } + + public String help() + { + return "list available items."; + } + + public String usage() + { + return "list queues [] | exchanges | bindings [] | all"; + } + + public String getCommand() + { + return "list"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 1) + { + if ((args[1].equals("exchanges")) + || (args[1].equals("queues")) + || (args[1].equals("bindings")) + || (args[1].equals("all"))) + { + if (args.length == 2) + { + doList(args[1]); + } + else if (args.length == 3) + { + doList(args[1], args[2]); + } + } + else + { + commandError("Unknown options. ", args); + } + } + else if (args.length < 2) + { + doList("all"); + } + else + { + doList(args[1]); + } + } + + private void doList(String... listItem) + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + listVirtualHosts(); + return; + } + + VirtualHost vhost = _tool.getState().getVhost(); + + java.util.List data = null; + + if (listItem[0].equals("queues")) + { + if (listItem.length > 1) + { + data = listQueues(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + data = listQueues(vhost, exchange); + } + } + + if (listItem[0].equals("exchanges")) + { + data = listExchanges(vhost); + } + + if (listItem[0].equals("bindings")) + { + + if (listItem.length > 1) + { + data = listBindings(vhost, new AMQShortString(listItem[1])); + } + else + { + Exchange exchange = _tool.getState().getExchange(); + + data = listBindings(vhost, exchange); + } + } + + if (data != null) + { + if (data.size() == 1) + { + _console.println("No '" + listItem[0] + "' to display,"); + } + else + { + _console.displayList(true, data.toArray(new String[0])); + } + } + + + if (listItem[0].equals("all")) + { + + boolean displayed = false; + Exchange exchange = _tool.getState().getExchange(); + + //Do the display here for each one so that they are pretty printed + data = listQueues(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (exchange == null) + { + data = listExchanges(vhost); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + } + + data = listBindings(vhost, exchange); + if (data != null) + { + displayed = true; + _console.displayList(true, data.toArray(new String[0])); + } + + if (!displayed) + { + _console.println("Nothing to list"); + } + } + } + + private void listVirtualHosts() + { + Collection vhosts = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHosts(); + + String[] data = new String[vhosts.size() + 1]; + + data[0] = "Available VirtualHosts"; + + int index = 1; + for (VirtualHost vhost : vhosts) + { + data[index] = vhost.getName(); + index++; + } + + _console.displayList(true, data); + } + + private java.util.List listBindings(VirtualHost vhost, AMQShortString exchangeName) + { + return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listBindings(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueueNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Current Bindings"); + + for (AMQShortString queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.toString()); + } + } + else + { + data.add(queue.toString()); + } + } + + return data; + } + + private java.util.List listExchanges(VirtualHost vhost) + { + Collection queues = vhost.getExchangeRegistry().getExchangeNames(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Exchanges"); + + for (AMQShortString queue : queues) + { + data.add(queue.toString()); + } + + return data; + } + + private java.util.List listQueues(VirtualHost vhost, AMQShortString exchangeName) + { + return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName)); + } + + private java.util.List listQueues(VirtualHost vhost, Exchange exchange) + { + Collection queues = vhost.getQueueRegistry().getQueues(); + + if (queues == null || queues.size() == 0) + { + return null; + } + + java.util.List data = new LinkedList(); + + data.add("Available Queues"); + + for (AMQQueue queue : queues) + { + if (exchange != null) + { + if (exchange.isBound(queue)) + { + data.add(queue.getName().toString()); + } + } + else + { + data.add(queue.getName().toString()); + } + } + + if (exchange != null) + { + if (queues.size() == 1) + { + return null; + } + } + + return data; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java new file mode 100644 index 0000000000..244a311c30 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.configuration.Configuration; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Load extends AbstractCommand +{ + public Load(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Loads specified broker configuration file."; + } + + public String usage() + { + return "load "; + } + + public String getCommand() + { + return "load"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length > 2) + { + _console.print("load " + args[1] + ": additional options not understood:"); + for (int i = 2; i < args.length; i++) + { + _console.print(args[i] + " "); + } + _console.println(""); + } + else if (args.length < 2) + { + _console.println("Enter Configuration file."); + String input = _console.readln(); + if (input != null) + { + doLoad(input); + } + else + { + _console.println("Did not recognise config file."); + } + } + else + { + doLoad(args[1]); + } + } + + private void doLoad(String configfile) + { + _console.println("Loading Configuration:" + configfile); + + try + { + _tool.setConfigurationFile(configfile); + } + catch (Configuration.InitException e) + { + _console.println("Unable to open config file due to: '" + e.getMessage() + "'"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java new file mode 100644 index 0000000000..a8dd58ca83 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.queue.QueueEntryImpl; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.List; + +public class Move extends AbstractCommand +{ + + /** + * Since the Coopy command is not associated with a real channel we can safely create our own store context + * for use in the few methods that require one. + */ + protected StoreContext _storeContext = new StoreContext(); + + public Move(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Move messages between queues.";/*\n" + + "The currently selected message set will be moved to the specifed queue.\n" + + "Alternatively the values can be provided on the command line.";*/ + } + + public String usage() + { + return "move to= [from=] [msgids=]"; + } + + public String getCommand() + { + return "move"; + } + + public void execute(String... args) + { + AMQQueue toQueue = null; + AMQQueue fromQueue = _tool.getState().getQueue(); + java.util.List msgids = _tool.getState().getMessages(); + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("to=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("from=")) + { + String queueName = arg.substring(arg.indexOf("=") + 1); + fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + } + + if (arg.startsWith("msgids=")) + { + String msgidStr = arg.substring(arg.indexOf("=") + 1); + + // Record the current message selection + java.util.List currentIDs = _tool.getState().getMessages(); + + // Use the ToolState class to perform the messasge parsing + _tool.getState().setMessages(msgidStr); + msgids = _tool.getState().getMessages(); + + // Reset the original selection of messages + _tool.getState().setMessages(currentIDs); + } + } + } + + if (!checkRequirements(fromQueue, toQueue, msgids)) + { + return; + } + + processIDs(fromQueue, toQueue, msgids); + } + + private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + Long previous = null; + Long start = null; + + if (msgids == null) + { + msgids = allMessageIDs(fromQueue); + } + + if (msgids == null || msgids.size() == 0) + { + _console.println("No Messages to move."); + return; + } + + for (long id : msgids) + { + if (previous != null) + { + if (id == previous + 1) + { + if (start == null) + { + start = previous; + } + } + else + { + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, id, toQueue); + start = null; + } + else + { + //move a single id + doCommand(fromQueue, id, id, toQueue); + } + } + } + + previous = id; + } + + if (start != null) + { + //move a range of ids + doCommand(fromQueue, start, previous, toQueue); + } + } + + private List allMessageIDs(AMQQueue fromQueue) + { + List ids = new LinkedList(); + + if (fromQueue != null) + { + List messages = fromQueue.getMessagesOnTheQueue(); + if (messages != null) + { + for (QueueEntry msg : messages) + { + ids.add(msg.getMessage().getMessageId()); + } + } + } + + return ids; + } + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List msgids) + { + if (toQueue == null) + { + _console.println("Destination queue not specifed."); + _console.println(usage()); + return false; + } + + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) + { + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java new file mode 100644 index 0000000000..5e99997863 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.server.queue.AMQQueue; + +public class Purge extends Move +{ + public Purge(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Purge messages from a queue.\n" + + "The currently selected message set will be purged from the specifed queue.\n" + + "Alternatively the values can be provided on the command line."; + } + + public String usage() + { + return "purge from= [msgids=]"; + } + + public String getCommand() + { + return "purge"; + } + + + protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List msgids) + { + if (fromQueue == null) + { + _console.println("Source queue not specifed."); + _console.println(usage()); + return false; + } + + return true; + } + + protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) + { + fromQueue.removeMessagesFromQueue(start, end, _storeContext); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java new file mode 100644 index 0000000000..a81bc07c38 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +public class Quit extends AbstractCommand +{ + public Quit(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Quit the tool."; + } + + public String usage() + { + return "quit"; + } + + public String getCommand() + { + return "quit"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals("quit"); + + _tool.quit(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java new file mode 100644 index 0000000000..ff59568374 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.tools.messagestore.MessageStoreTool; + +import java.util.LinkedList; +import java.util.StringTokenizer; + +public class Select extends AbstractCommand +{ + + public Select(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Perform a selection."; + } + + public String usage() + { + return "select virtualhost |exchange |queue | msg id="; + } + + public String getCommand() + { + return "select"; + } + + public void execute(String... args) + { + assert args.length > 2; + assert args[0].equals("select"); + + if (args.length < 3) + { + if (args[1].equals("show")) + { + doSelect(args[1], null); + } + else + { + _console.print("select : unknown command:"); + _console.println(help()); + } + } + else + { + if (args[1].equals("virtualhost") + || args[1].equals("vhost") + || args[1].equals("exchange") + || args[1].equals("queue") + || args[1].equals("msg") + ) + { + doSelect(args[1], args[2]); + } + else + { + _console.println(help()); + } + } + } + + private void doSelect(String type, String item) + { + if (type.equals("virtualhost")) + { + + VirtualHost vhost = ApplicationRegistry.getInstance() + .getVirtualHostRegistry().getVirtualHost(item); + + if (vhost == null) + { + _console.println("Virtualhost '" + item + "' not found."); + } + else + { + _tool.getState().setVhost(vhost); + } + } + + if (type.equals("exchange")) + { + + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + + Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item)); + + if (exchange == null) + { + _console.println("Exchange '" + item + "' not found."); + } + else + { + _tool.getState().setExchange(exchange); + } + + if (_tool.getState().getQueue() != null) + { + if (!exchange.isBound(_tool.getState().getQueue())) + { + _tool.getState().setQueue(null); + } + } + } + + if (type.equals("queue")) + { + VirtualHost vhost = _tool.getState().getVhost(); + + if (vhost == null) + { + _console.println("No Virtualhost open. Open a Virtualhost first."); + return; + } + + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item)); + + if (queue == null) + { + _console.println("Queue '" + item + "' not found."); + } + else + { + _tool.getState().setQueue(queue); + + if (_tool.getState().getExchange() == null) + { + for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames()) + { + Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName); + if (exchange.isBound(queue)) + { + _tool.getState().setExchange(exchange); + break; + } + } + } + + //remove the message selection + _tool.getState().setMessages((java.util.List) null); + } + } + + if (type.equals("msg")) + { + if (item.startsWith("id=")) + { + StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ","); + + java.util.List msgids = null; + + if (tok.hasMoreTokens()) + { + msgids = new LinkedList(); + } + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + if (next.contains("-")) + { + Long start = Long.parseLong(next.substring(0, next.indexOf("-"))); + Long end = Long.parseLong(next.substring(next.indexOf("-") + 1)); + + if (end >= start) + { + for (long l = start; l <= end; l++) + { + msgids.add(l); + } + } + } + else + { + msgids.add(Long.parseLong(next)); + } + } + + _tool.getState().setMessages(msgids); + } + + } + + if (type.equals("show")) + { + _console.println(_tool.getState().toString()); + if (_tool.getState().getMessages() != null) + { + _console.print("Msgs:"); + for (Long l : _tool.getState().getMessages()) + { + _console.print(" " + l); + } + _console.println(""); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java new file mode 100644 index 0000000000..2fa017fc64 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -0,0 +1,515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.messagestore.commands; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntryImpl; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.tools.messagestore.MessageStoreTool; +import org.apache.qpid.tools.utils.Console; + +import java.util.LinkedList; +import java.util.List; + +public class Show extends AbstractCommand +{ + protected boolean _amqHeaders = false; + protected boolean _routing = false; + protected boolean _msgHeaders = false; + + public Show(MessageStoreTool tool) + { + super(tool); + } + + public String help() + { + return "Shows the messages headers."; + } + + public String usage() + { + return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=]"; + } + + public String getCommand() + { + return "show"; + } + + public void execute(String... args) + { + assert args.length > 0; + assert args[0].equals(getCommand()); + + if (args.length < 2) + { + parseArgs("all"); + } + else + { + parseArgs(args); + } + + performShow(); + } + + protected void parseArgs(String... args) + { + List msgids = null; + + if (args.length >= 2) + { + for (String arg : args) + { + if (arg.startsWith("show=")) + { + _msgHeaders = arg.contains("msgheaders") || arg.contains("all"); + _amqHeaders = arg.contains("amqheaders") || arg.contains("all"); + _routing = arg.contains("routing") || arg.contains("all"); + } + + if (arg.startsWith("id=")) + { + _tool.getState().setMessages(msgids); + } + }//for args + }// if args > 2 + } + + protected void performShow() + { + if (_tool.getState().getVhost() == null) + { + _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first."); + return; + } + + AMQQueue _queue = _tool.getState().getQueue(); + + List msgids = _tool.getState().getMessages(); + + if (_queue != null) + { + List messages = _queue.getMessagesOnTheQueue(); + if (messages == null || messages.size() == 0) + { + _console.println("No messages on queue"); + return; + } + + List data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders); + if (data != null) + { + _console.printMap(null, data); + } + else + { + String message = "No data to display."; + if (msgids != null) + { + message += " Is message selection correct? " + _tool.getState().printMessages(); + } + _console.println(message); + } + + } + else + { + _console.println("No Queue specified to show."); + } + } + + /** + * Create the list data for display from the messages. + * + * @param msgids The list of message ids to display + * @param messages A list of messages to format and display. + * @param showHeaders should the header info be shown + * @param showRouting show the routing info be shown + * @param showMessageHeaders show the msg headers be shown + * @return the formated data lists for printing + */ + protected List createMessageData(List msgids, List messages, boolean showHeaders, boolean showRouting, + boolean showMessageHeaders) + { + + // Currenly exposed message properties +// //Printing the content Body +// msg.getContentBodyIterator(); +// //Print the Headers +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId(); +// +// //Print out all the property names +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); +// +// msg.getMessageId(); +// msg.getSize(); +// msg.getArrivalTime(); + +// msg.getDeliveredSubscription(); +// msg.getDeliveredToConsumer(); +// msg.getMessageHandle(); +// msg.getMessageId(); +// msg.getMessagePublishInfo(); +// msg.getPublisher(); + +// msg.getStoreContext(); +// msg.isAllContentReceived(); +// msg.isPersistent(); +// msg.isRedelivered(); +// msg.isRejectedBy(); +// msg.isTaken(); + + //Header setup + + List data = new LinkedList(); + + List id = new LinkedList(); + data.add(id); + id.add(Columns.ID.name()); + id.add(Console.ROW_DIVIDER); + + List exchange = new LinkedList(); + List routingkey = new LinkedList(); + List immediate = new LinkedList(); + List mandatory = new LinkedList(); + if (showRouting) + { + data.add(exchange); + exchange.add(Columns.Exchange.name()); + exchange.add(Console.ROW_DIVIDER); + + data.add(routingkey); + routingkey.add(Columns.RoutingKey.name()); + routingkey.add(Console.ROW_DIVIDER); + + data.add(immediate); + immediate.add(Columns.isImmediate.name()); + immediate.add(Console.ROW_DIVIDER); + + data.add(mandatory); + mandatory.add(Columns.isMandatory.name()); + mandatory.add(Console.ROW_DIVIDER); + } + + List size = new LinkedList(); + List appid = new LinkedList(); + List clusterid = new LinkedList(); + List contenttype = new LinkedList(); + List correlationid = new LinkedList(); + List deliverymode = new LinkedList(); + List encoding = new LinkedList(); + List arrival = new LinkedList(); + List expiration = new LinkedList(); + List priority = new LinkedList(); + List propertyflag = new LinkedList(); + List replyto = new LinkedList(); + List timestamp = new LinkedList(); + List type = new LinkedList(); + List userid = new LinkedList(); + List ispersitent = new LinkedList(); + List isredelivered = new LinkedList(); + List isdelivered = new LinkedList(); + + data.add(size); + size.add(Columns.Size.name()); + size.add(Console.ROW_DIVIDER); + + if (showHeaders) + { + data.add(ispersitent); + ispersitent.add(Columns.isPersistent.name()); + ispersitent.add(Console.ROW_DIVIDER); + + data.add(isredelivered); + isredelivered.add(Columns.isRedelivered.name()); + isredelivered.add(Console.ROW_DIVIDER); + + data.add(isdelivered); + isdelivered.add(Columns.isDelivered.name()); + isdelivered.add(Console.ROW_DIVIDER); + + data.add(appid); + appid.add(Columns.App_ID.name()); + appid.add(Console.ROW_DIVIDER); + + data.add(clusterid); + clusterid.add(Columns.Cluster_ID.name()); + clusterid.add(Console.ROW_DIVIDER); + + data.add(contenttype); + contenttype.add(Columns.Content_Type.name()); + contenttype.add(Console.ROW_DIVIDER); + + data.add(correlationid); + correlationid.add(Columns.Correlation_ID.name()); + correlationid.add(Console.ROW_DIVIDER); + + data.add(deliverymode); + deliverymode.add(Columns.Delivery_Mode.name()); + deliverymode.add(Console.ROW_DIVIDER); + + data.add(encoding); + encoding.add(Columns.Encoding.name()); + encoding.add(Console.ROW_DIVIDER); + + data.add(arrival); + expiration.add(Columns.Arrival.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(expiration); + expiration.add(Columns.Expiration.name()); + expiration.add(Console.ROW_DIVIDER); + + data.add(priority); + priority.add(Columns.Priority.name()); + priority.add(Console.ROW_DIVIDER); + + data.add(propertyflag); + propertyflag.add(Columns.Property_Flag.name()); + propertyflag.add(Console.ROW_DIVIDER); + + data.add(replyto); + replyto.add(Columns.ReplyTo.name()); + replyto.add(Console.ROW_DIVIDER); + + data.add(timestamp); + timestamp.add(Columns.Timestamp.name()); + timestamp.add(Console.ROW_DIVIDER); + + data.add(type); + type.add(Columns.Type.name()); + type.add(Console.ROW_DIVIDER); + + data.add(userid); + userid.add(Columns.UserID.name()); + userid.add(Console.ROW_DIVIDER); + } + + List msgHeaders = new LinkedList(); + if (showMessageHeaders) + { + data.add(msgHeaders); + msgHeaders.add(Columns.MsgHeaders.name()); + msgHeaders.add(Console.ROW_DIVIDER); + } + + //Add create the table of data + for (QueueEntry entry : messages) + { + AMQMessage msg = entry.getMessage(); + if (!includeMsg(msg, msgids)) + { + continue; + } + + id.add(msg.getMessageId().toString()); + + size.add("" + msg.getSize()); + + arrival.add("" + msg.getArrivalTime()); + + try + { + ispersitent.add(msg.isPersistent() ? "true" : "false"); + } + catch (AMQException e) + { + ispersitent.add("n/a"); + } + + isredelivered.add(msg.isRedelivered() ? "true" : "false"); + + isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + +// msg.getMessageHandle(); + + BasicContentHeaderProperties headers = null; + + try + { + headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + } + catch (AMQException e) + { + //ignore +// commandError("Unable to read properties for message: " + e.getMessage(), null); + } + + if (headers != null) + { + String appidS = headers.getAppIdAsString(); + appid.add(appidS == null ? "null" : appidS); + + String clusterS = headers.getClusterIdAsString(); + clusterid.add(clusterS == null ? "null" : clusterS); + + String contentS = headers.getContentTypeAsString(); + contenttype.add(contentS == null ? "null" : contentS); + + String correlationS = headers.getCorrelationIdAsString(); + correlationid.add(correlationS == null ? "null" : correlationS); + + deliverymode.add("" + headers.getDeliveryMode()); + + AMQShortString encodeSS = headers.getEncoding(); + encoding.add(encodeSS == null ? "null" : encodeSS.toString()); + + expiration.add("" + headers.getExpiration()); + + FieldTable headerFT = headers.getHeaders(); + msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString()); + + priority.add("" + headers.getPriority()); + propertyflag.add("" + headers.getPropertyFlags()); + + AMQShortString replytoSS = headers.getReplyTo(); + replyto.add(replytoSS == null ? "null" : replytoSS.toString()); + + timestamp.add("" + headers.getTimestamp()); + + AMQShortString typeSS = headers.getType(); + type.add(typeSS == null ? "null" : typeSS.toString()); + + AMQShortString useridSS = headers.getUserId(); + userid.add(useridSS == null ? "null" : useridSS.toString()); + + MessagePublishInfo info = null; + try + { + info = msg.getMessagePublishInfo(); + } + catch (AMQException e) + { + //ignore + } + + if (info != null) + { + AMQShortString exchangeSS = info.getExchange(); + exchange.add(exchangeSS == null ? "null" : exchangeSS.toString()); + + AMQShortString routingkeySS = info.getRoutingKey(); + routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString()); + + immediate.add(info.isImmediate() ? "true" : "false"); + mandatory.add(info.isMandatory() ? "true" : "false"); + } + +// msg.getPublisher(); -- only used in clustering +// msg.getStoreContext(); +// msg.isAllContentReceived(); + + }// if headers!=null + +// need to access internal map and do lookups. +// msg.isTaken(); +// msg.getDeliveredSubscription(); +// msg.isRejectedBy(); + + } + + // if id only had the header and the divider in it then we have no data to display + if (id.size() == 2) + { + return null; + } + return data; + } + + protected boolean includeMsg(AMQMessage msg, List msgids) + { + if (msgids == null) + { + return true; + } + + Long msgid = msg.getMessageId(); + + boolean found = false; + + if (msgids != null) + { + //check msgid is in msgids + for (Long l : msgids) + { + if (l.equals(msgid)) + { + found = true; + break; + } + } + } + return found; + } + + public enum Columns + { + ID, + Size, + Exchange, + RoutingKey, + isImmediate, + isMandatory, + isPersistent, + isRedelivered, + isDelivered, + App_ID, + Cluster_ID, + Content_Type, + Correlation_ID, + Delivery_Mode, + Encoding, + Arrival, + Expiration, + Priority, + Property_Flag, + ReplyTo, + Timestamp, + Type, + UserID, + MsgHeaders + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java new file mode 100644 index 0000000000..c27c52eb8e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd "); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java new file mode 100644 index 0000000000..986fea32cc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +public interface CommandParser +{ + /** + * If there is more than one command received on the last parse request. + * + * Subsequent calls to parse will utilise this input rather than reading new data from the input source + * @return boolean + */ + boolean more(); + + /** + * True if the currently parsed command has been requested as a background operation + * + * @return boolean + */ + boolean isBackground(); + + /** + * Parses user commands, and groups tokens in the + * String[] format that all Java main's love. + * + * If more than one command is provided in one input line then the more() method will return true. + * A subsequent call to parse() will continue to parse that input line before reading new input. + * + * @return input split in args[] format; null if eof. + * @throws java.io.IOException if there is a problem reading from the input stream + */ + String[] parse() throws java.io.IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java new file mode 100644 index 0000000000..cf457d1ea5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.util.List; + +public interface Console +{ + public enum CellFormat + { + CENTRED, LEFT, RIGHT + } + + public static String ROW_DIVIDER = "*divider"; + + public void print(String... message); + + public void println(String... message); + + public String readln(); + + /** + * Reads and parses the command line. + * + * + * @return The next command or null + */ + public String[] readCommand(); + + public CommandParser getCommandParser(); + + public void setCommandParser(CommandParser parser); + + /** + * + * Prints the list of String nicely. + * + * +-------------+ + * | Heading | + * +-------------+ + * | Item 1 | + * | Item 2 | + * | Item 3 | + * +-------------+ + * + * @param hasTitle should list[0] be used as a heading + * @param list The list of Strings to display + */ + public void displayList(boolean hasTitle, String... list); + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * +----------------------------+ (*divider) + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + void printMap(String title, List entries); + + + public void close(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java new file mode 100644 index 0000000000..09444ccdd7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.StringTokenizer; + +public class SimpleCommandParser implements CommandParser +{ + private static final String COMMAND_SEPERATOR = ";"; + + /** Input source of commands */ + protected BufferedReader _reader; + + /** The next list of commands from the command line */ + private StringBuilder _nextCommand = null; + + public SimpleCommandParser(BufferedReader reader) + { + _reader = reader; + } + + public boolean more() + { + return _nextCommand != null; + } + + public boolean isBackground() + { + return false; + } + + public String[] parse() throws IOException + { + String[] commands = null; + + String input = null; + + if (_nextCommand == null) + { + input = _reader.readLine(); + } + else + { + input = _nextCommand.toString(); + _nextCommand = null; + } + + if (input == null) + { + return null; + } + + StringTokenizer tok = new StringTokenizer(input, " "); + + int tokenCount = tok.countTokens(); + int index = 0; + + if (tokenCount > 0) + { + commands = new String[tokenCount]; + boolean commandComplete = false; + + while (tok.hasMoreTokens()) + { + String next = tok.nextToken(); + + if (next.equals(COMMAND_SEPERATOR)) + { + commandComplete = true; + _nextCommand = new StringBuilder(); + continue; + } + + if (commandComplete) + { + _nextCommand.append(next); + _nextCommand.append(" "); + } + else + { + commands[index] = next; + index++; + } + } + + } + + //Reduce the String[] if not all the tokens were used in this command. + // i.e. there is more than one command on the line. + if (index != tokenCount) + { + String[] shortCommands = new String[index]; + System.arraycopy(commands, 0, shortCommands, 0, index); + return shortCommands; + } + else + { + return commands; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java new file mode 100644 index 0000000000..ec080a4611 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.tools.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +public class SimpleConsole implements Console +{ + /** SLF4J Logger. */ + private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); + + /** Console Writer. */ + protected static BufferedWriter _consoleWriter; + + /** Console Reader. */ + protected static BufferedReader _consoleReader; + + /** Parser for command-line input. */ + protected CommandParser _parser; + + public SimpleConsole(BufferedWriter writer, BufferedReader reader) + { + _consoleWriter = writer; + _consoleReader = reader; + _parser = new SimpleCommandParser(_consoleReader); + } + + public void print(String... message) + { + try + { + for (String s : message) + { + _consoleWriter.write(s); + } + _consoleWriter.flush(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); + } + + } + + public void println(String... message) + { + print(message); + print(System.getProperty("line.separator")); + } + + + public String readln() + { + try + { + return _consoleReader.readLine(); + } + catch (IOException e) + { + _devlog.debug("Unable to read input due to:" + e.getMessage()); + return null; + } + } + + public String[] readCommand() + { + try + { + return _parser.parse(); + } + catch (IOException e) + { + _devlog.error("Error reading command:" + e.getMessage()); + return new String[0]; + } + } + + public CommandParser getCommandParser() + { + return _parser; + } + + public void setCommandParser(CommandParser parser) + { + _parser = parser; + } + + public void displayList(boolean hasTitle, String... list) + { + java.util.List data = new LinkedList(); + + java.util.List values = new LinkedList(); + + data.add(values); + + for (String value : list) + { + values.add(value); + } + + if (hasTitle) + { + values.add(1, "*divider"); + } + + printMap(null, data); + } + + /** + * + * Prints the list of String nicely. + * + * +----------------------------+ + * | Heading | + * +----------------------------+ + * | title | title | .. + * +----------------------------+ + * | Item 2 | value 2 | .. + * | Item 3 | value 2 | .. + * +----------------------------+ + * + * @param title The title to display if any + * @param entries the entries to display in a map. + */ + public void printMap(String title, java.util.List entries) + { + try + { + int columns = entries.size(); + + int[] columnWidth = new int[columns]; + + // calculate row count + int rowMax = 0; + + //the longest item + int itemMax = 0; + + for (int i = 0; i < columns; i++) + { + int columnIRowMax = entries.get(i).size(); + + if (columnIRowMax > rowMax) + { + rowMax = columnIRowMax; + } + for (Object values : entries.get(i)) + { + if (values.toString().equals(Console.ROW_DIVIDER)) + { + continue; + } + + int itemLength = values.toString().length(); + + //note for single width + if (itemLength > itemMax) + { + itemMax = itemLength; + } + + //note for mulit width + if (itemLength > columnWidth[i]) + { + columnWidth[i] = itemLength; + } + + } + } + + int tableWidth = 0; + + + for (int i = 0; i < columns; i++) + { + // plus 2 for the space padding + columnWidth[i] += 2; + } + for (int size : columnWidth) + { + tableWidth += size; + } + tableWidth += (columns - 1); + + if (title != null) + { + if (title.length() > tableWidth) + { + tableWidth = title.length(); + } + + printCellRow("+", "-", tableWidth); + + printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0); + _consoleWriter.newLine(); + + } + + //put top line | or bottom of title + printCellRow("+", "-", tableWidth); + + //print the table data + int row = 0; + + for (; row < rowMax; row++) + { + for (int i = 0; i < columns; i++) + { + java.util.List columnData = entries.get(i); + + String value; + // does this column have a value for this row + if (columnData.size() > row) + { + value = " " + columnData.get(row).toString() + " "; + } + else + { + value = " "; + } + + if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " ")) + { + printCellRow("+", "-", tableWidth); + //move on to the next row + break; + } + else + { + printCell(CellFormat.LEFT, "|", columnWidth[i], value, i); + } + + // if it is the last row then do a new line. + if (i == columns - 1) + { + _consoleWriter.newLine(); + } + } + } + + printCellRow("+", "-", tableWidth); + + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to write."); + } + } + + public void close() + { + + try + { + _consoleReader.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close reader."); + } + + try + { + + _consoleWriter.close(); + } + catch (IOException e) + { + _devlog.error(e.getMessage() + ": Occured whilst trying to close writer."); + } + + } + + private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException + { + int pad = cellWidth - cell.length(); + + if (column == 0) + { + _consoleWriter.write(edge); + } + + switch (format) + { + case CENTRED: + printPad(" ", pad / 2); + break; + case RIGHT: + printPad(" ", pad); + break; + } + + _consoleWriter.write(cell); + + + switch (format) + { + case CENTRED: + // if pad isn't even put the extra one on the right + if (pad % 2 == 0) + { + printPad(" ", pad / 2); + } + else + { + printPad(" ", (pad / 2) + 1); + } + break; + case LEFT: + printPad(" ", pad); + break; + } + + + _consoleWriter.write(edge); + + } + + private void printCellRow(String edge, String mid, int cellWidth) throws IOException + { + _consoleWriter.write(edge); + + printPad(mid, cellWidth); + + _consoleWriter.write(edge); + _consoleWriter.newLine(); + } + + private void printPad(String padChar, int count) throws IOException + { + for (int i = 0; i < count; i++) + { + _consoleWriter.write(padChar); + } + } + + +} -- cgit v1.2.1 From 001766f4732ec8ab46b5b8550070e59e550daa97 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 15 Apr 2009 15:55:36 +0000 Subject: QPID-1812: Fix firewall rule parsing, add test for this. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765250 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/security/access/plugins/network/FirewallPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 85026121ab..810be8ae22 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -55,7 +55,7 @@ public class FirewallPlugin extends AbstractACLPlugin public ACLPlugin newInstance(Configuration config) throws ConfigurationException { FirewallPlugin plugin = new FirewallPlugin(); - plugin.setConfiguration(config); + plugin.setConfiguration(config.subset("firewall")); return plugin; } }; @@ -245,7 +245,7 @@ public class FirewallPlugin extends AbstractACLPlugin } CompositeConfiguration finalConfig = new CompositeConfiguration(config); - List subFiles = config.getList("firewall.xml[@fileName]"); + List subFiles = config.getList("xml[@fileName]"); for (Object subFile : subFiles) { finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); -- cgit v1.2.1 From 876cec5277477a813ce41e848728d1deeba57536 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:21:57 +0000 Subject: QPID-1814 : Relax Derby so that it does not error if you create an existing Exchange or Queue git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765593 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 77 ++++++++++++++-------- 1 file changed, 50 insertions(+), 27 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index e7f9c777c9..47d9311453 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -104,9 +104,12 @@ public class DerbyMessageStore implements MessageStore private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; + private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; private static final String SELECT_FROM_BINDINGS = "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + private static final String FIND_BINDING = + "SELECT * FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ? "; private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; @@ -631,29 +634,41 @@ public class DerbyMessageStore implements MessageStore try { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + + PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); stmt.setString(1, exchange.getName().toString() ); stmt.setString(2, queue.getName().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); - if(args != null) - { - /* This would be the Java 6 way of setting a Blob - Blob blobArgs = conn.createBlob(); - blobArgs.setBytes(0, args.getDataAsBytes()); - stmt.setBlob(4, blobArgs); - */ - byte[] bytes = args.getDataAsBytes(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - stmt.setBinaryStream(4, bis, bytes.length); - } - else + + ResultSet rs = stmt.executeQuery(); + + // If this binding is not already in the store then create it. + if (!rs.next()) { - stmt.setNull(4, Types.BLOB); - } + stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + stmt.setString(1, exchange.getName().toString() ); + stmt.setString(2, queue.getName().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + if(args != null) + { + /* This would be the Java 6 way of setting a Blob + Blob blobArgs = conn.createBlob(); + blobArgs.setBytes(0, args.getDataAsBytes()); + stmt.setBlob(4, blobArgs); + */ + byte[] bytes = args.getDataAsBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + stmt.setBinaryStream(4, bis, bytes.length); + } + else + { + stmt.setNull(4, Types.BLOB); + } - stmt.executeUpdate(); - conn.commit(); - stmt.close(); + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } } catch (SQLException e) { @@ -744,19 +759,27 @@ public class DerbyMessageStore implements MessageStore { Connection conn = newConnection(); - PreparedStatement stmt = - conn.prepareStatement(INSERT_INTO_QUEUE); - + PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); stmt.setString(1, queue.getName().toString()); - stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); - stmt.execute(); + ResultSet rs = stmt.executeQuery(); - stmt.close(); + // If we don't have any data in the result set then we can add this queue + if (!rs.next()) + { + stmt = conn.prepareStatement(INSERT_INTO_QUEUE); - conn.commit(); + stmt.setString(1, queue.getName().toString()); + stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); - conn.close(); + stmt.execute(); + + stmt.close(); + + conn.commit(); + + conn.close(); + } } catch (SQLException e) { @@ -889,7 +912,7 @@ public class DerbyMessageStore implements MessageStore if (_logger.isDebugEnabled()) { - _logger.debug("Dequeuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); + _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]"); } } catch (SQLException e) -- cgit v1.2.1 From 919ecacd18445a8d55d735772185e1e03c8acd60 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:22:52 +0000 Subject: QPID-1814 : Don't always attempt to create the default exchanges in the persistent store as they are always created first. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765596 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/virtualhost/VirtualHost.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 0ae0594de8..649e84cb50 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -183,6 +183,15 @@ public class VirtualHost implements Accessable // This needs to be after the RT has been defined as it creates the default durable exchanges. _exchangeRegistry.initialise(); + + // We don't need to store the Default queues in the store as we always + // create them first on start up so don't clear them from the startup + // configuration here. This also ensures that we don't attempt to + // perform a createExchange twice with the same details in the + // MessageStore(RoutingTable) as some instances may not like that. + // Derby being one. + configFileRT.exchange.clear(); + initialiseModel(hostConfig); if (store != null) -- cgit v1.2.1 From 7d67ca405dbcca6f2d8a0393f5f035e48c10a22d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:23:35 +0000 Subject: QPID-1815 : Ensure Derby store looks up existing queues/exchanges in the virtualhost on recovery git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765597 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 47d9311453..5c0672d783 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -356,9 +356,16 @@ public class DerbyMessageStore implements MessageStore String queueName = rs.getString(1); String owner = rs.getString(2); AMQShortString queueNameShortString = new AMQShortString(queueName); - AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, - null); - _virtualHost.getQueueRegistry().registerQueue(q); + + AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + if (q == null) + { + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + null); + _virtualHost.getQueueRegistry().registerQueue(q); + } + queueMap.put(queueNameShortString,q); } @@ -394,8 +401,13 @@ public class DerbyMessageStore implements MessageStore String type = rs.getString(2); boolean autoDelete = rs.getShort(3) != 0; - exchange = _virtualHost.getExchangeFactory().createExchange(new AMQShortString(exchangeName), new AMQShortString(type), true, autoDelete, 0); - _virtualHost.getExchangeRegistry().registerExchange(exchange); + AMQShortString exchangeNameSS = new AMQShortString(exchangeName); + exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS); + if (exchange == null) + { + exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + } exchanges.add(exchange); } -- cgit v1.2.1 From b8c12102dc971a13703a3c909e9b6bdddabff6a3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:25:05 +0000 Subject: QPID-1813 : Check the value of _sessionIdentifier and return null if it is null rather than an NPE. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765600 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQMessage.java | 24 ++++++++++++++++++++-- .../qpid/server/subscription/SubscriptionImpl.java | 8 +++----- 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index a485649410..b987dae16d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -457,12 +457,32 @@ public class AMQMessage implements Filterable public Object getPublisherClientInstance() { - return _sessionIdentifier.getSessionInstance(); + //todo store sessionIdentifier/client id with message in store + //Currently the _sessionIdentifier will be null if the message has been + // restored from a message Store + if (_sessionIdentifier == null) + { + return null; + } + else + { + return _sessionIdentifier.getSessionInstance(); + } } public Object getPublisherIdentifier() { - return _sessionIdentifier.getSessionIdentifier(); + //todo store sessionIdentifier/client id with message in store + //Currently the _sessionIdentifier will be null if the message has been + // restored from a message Store + if (_sessionIdentifier == null) + { + return null; + } + else + { + return _sessionIdentifier.getSessionIdentifier(); + } } public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index a616c2ea35..7aa9d1e3af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -382,11 +382,10 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage // return false; } - - - //todo - client id should be recoreded and this test removed but handled below if (_noLocal) { + //todo - client id should be recoreded so we don't have to handle + // the case where this is null. final Object publisherId = entry.getMessage().getPublisherClientInstance(); // We don't want local messages so check to see if message is one we sent @@ -404,9 +403,8 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage { localInstance = getProtocolSession().getClientIdentifier(); - //todo - client id should be recoreded and this test removed but handled here - + //todo - client id should be recoreded so we don't have to do the null check if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) { return false; -- cgit v1.2.1 From 99549d769fc94c35eb6ccbc837e0ce6dffa398b0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:27:28 +0000 Subject: QPID-1813 : Provide test that uses the DerbyMessageStore to check NoLocal functionality after a broker restart. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765604 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 5c0672d783..20ef80e00e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -154,8 +154,9 @@ public class DerbyMessageStore implements MessageStore _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + //Update to pick up QPID_WORK and use that as the default location not just derbyDB final String databasePath = config.getStoreConfiguration().getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); - + File environmentPath = new File(databasePath); if (!environmentPath.exists()) { -- cgit v1.2.1 From dfe10b31f6bcdb207222b3546768d01140942701 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 16 Apr 2009 12:29:53 +0000 Subject: QPID-1813/QPID-1817 : Removed the new properties from the test-provider as this will affect all tests. The NoLocalAfterRecoveryTest now updates a ConnectionURL based on the JNDI data and uses that to start a connection. NLART also provides a default location for the derbyDB store as the DMS class does not correctly attempt to put the store in QPID_WORK. This will be re-addressed when ServerConfiguration is again available from a VHC object. ConnectionTest was updated to remove the literal values for the BrokerDetail options. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@765608 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 20ef80e00e..9695571371 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -67,7 +67,7 @@ public class DerbyMessageStore implements MessageStore private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); - private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; + public static final String ENVIRONMENT_PATH_PROPERTY = "environment-path"; private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver"; @@ -155,7 +155,7 @@ public class DerbyMessageStore implements MessageStore QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); //Update to pick up QPID_WORK and use that as the default location not just derbyDB - final String databasePath = config.getStoreConfiguration().getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + final String databasePath = config.getStoreConfiguration().getString(ENVIRONMENT_PATH_PROPERTY, "derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) -- cgit v1.2.1 From 1727e9afd4de91736cb1012126f6b8d9e1fa1ab0 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 17 Apr 2009 13:47:08 +0000 Subject: QPID-1820: configure queues on creation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@766004 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 84b59456cb..7509350e65 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -38,7 +38,6 @@ public class AMQQueueFactory VirtualHost virtualHost, final FieldTable arguments) throws AMQException { - final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; AMQQueue q = null; @@ -53,6 +52,7 @@ public class AMQQueueFactory //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); + q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString())); return q; } -- cgit v1.2.1 From 56f22efa8a0e8201dc2ad495f2fef74bfa048c4d Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Fri, 17 Apr 2009 14:23:03 +0000 Subject: Eat IllegalArgumentException when creating the signal handler, fixes startup on Windows. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@766025 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/ServerConfiguration.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 28a07e7ebf..24add696b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -100,7 +100,15 @@ public class ServerConfiguration implements SignalHandler { this(parseConfig(configurationURL)); _configFile = configurationURL; - sun.misc.Signal.handle(new sun.misc.Signal("HUP"), this); + try + { + Signal sig = new sun.misc.Signal("HUP"); + sun.misc.Signal.handle(sig, this); + } + catch (IllegalArgumentException e) + { + // We're on something that doesn't handle SIGHUP, how sad, Windows. + } } public ServerConfiguration(Configuration conf) throws ConfigurationException -- cgit v1.2.1 From 995f9588cdac264428d319910f22c4202a7aca1a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 17 Apr 2009 15:20:15 +0000 Subject: QPID-1798: Update AMQQueueMBean to use new constant value of DeliveryMode, replacing previously incorrect literal value used in conditional statement and thus preventing the reversal of delivery mode status. Also update other broker classes making similar comparisons using a literal value to use a constant. merged from trunk r764026, as changes were lost during /broker 0.5-fix process. Excludes changes to sections no longer present, and changes still present in /common from previous commit. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@766047 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 3 ++- .../src/main/java/org/apache/qpid/server/queue/IncomingMessage.java | 4 ++-- .../main/java/org/apache/qpid/server/queue/TransientMessageData.java | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index c8ead67b1f..a6beb6cbf5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -428,7 +428,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); + list.add("JMSDeliveryMode = " + + ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); list.add("JMSPriority = " + headerProperties.getPriority()); list.add("JMSType = " + headerProperties.getType()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 091baf2751..d5e0b4d187 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -282,9 +282,9 @@ public class IncomingMessage implements Filterable public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == + BasicContentHeaderProperties.PERSISTENT; } public boolean isRedelivered() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java index 9b91c71a1d..b09283b11f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java @@ -120,8 +120,8 @@ public class TransientMessageData public boolean isPersistent() { - //todo remove literal values to a constant file such as AMQConstants in common return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == + BasicContentHeaderProperties.PERSISTENT; } } -- cgit v1.2.1 From b577edcbb54e4f8bc3342ba574059364fe809d9d Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 23 Apr 2009 16:05:34 +0000 Subject: QPID-1826: Ensure that server-wide configuration variables in virtualhosts.xml are honored. Add sample-flattened parse tree from M4 and test to ensure that values are parsed appropriately. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@767951 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 125 ++++++++++++--------- 1 file changed, 71 insertions(+), 54 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 24add696b3..9d7936f0c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -47,7 +47,7 @@ import sun.misc.SignalHandler; public class ServerConfiguration implements SignalHandler { - private static Configuration _config; + private Configuration _config; private static final int DEFAULT_FRAME_SIZE = 65536; private static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; @@ -113,11 +113,11 @@ public class ServerConfiguration implements SignalHandler public ServerConfiguration(Configuration conf) throws ConfigurationException { - _config = conf; + setConfig(conf); substituteEnvironmentVariables(); - _jmxPort = _config.getInt("management.jmxport", 8999); + _jmxPort = getConfig().getInt("management.jmxport", 8999); _securityConfiguration = new SecurityConfiguration(conf.subset("security")); setupVirtualHosts(conf); @@ -150,6 +150,13 @@ public class ServerConfiguration implements SignalHandler VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name)); _virtualHosts.put(vhostConfig.getName(), vhostConfig); } + // Grab things other than the virtualhosts themselves + Iterator keys = vhostConfiguration.getKeys(); + while (keys.hasNext()) + { + String key = (String) keys.next(); + conf.setProperty(key, vhostConfiguration.getProperty(key)); + } } } } @@ -161,7 +168,7 @@ public class ServerConfiguration implements SignalHandler String val = System.getenv(var.getKey()); if (val != null) { - _config.setProperty(var.getValue(), val); + getConfig().setProperty(var.getValue(), val); } } } @@ -246,6 +253,16 @@ public class ServerConfiguration implements SignalHandler } } + public void setConfig(Configuration _config) + { + this._config = _config; + } + + public Configuration getConfig() + { + return _config; + } + public String getQpidWork() { return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); @@ -263,7 +280,7 @@ public class ServerConfiguration implements SignalHandler public boolean getPlatformMbeanserver() { - return _config.getBoolean("management.platform-mbeanserver", true); + return getConfig().getBoolean("management.platform-mbeanserver", true); } public String[] getVirtualHosts() @@ -273,7 +290,7 @@ public class ServerConfiguration implements SignalHandler public String getPluginDirectory() { - return _config.getString("plugin-directory"); + return getConfig().getString("plugin-directory"); } public VirtualHostConfiguration getVirtualHostConfig(String name) @@ -283,84 +300,84 @@ public class ServerConfiguration implements SignalHandler public List getPrincipalDatabaseNames() { - return _config.getList("security.principal-databases.principal-database.name"); + return getConfig().getList("security.principal-databases.principal-database.name"); } public List getPrincipalDatabaseClass() { - return _config.getList("security.principal-databases.principal-database.class"); + return getConfig().getList("security.principal-databases.principal-database.class"); } public List getPrincipalDatabaseAttributeNames(int index) { String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name"; - return _config.getList(name); + return getConfig().getList(name); } public List getPrincipalDatabaseAttributeValues(int index) { String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value"; - return _config.getList(name); + return getConfig().getList(name); } public List getManagementPrincipalDBs() { - return _config.getList("security.jmx.principal-database"); + return getConfig().getList("security.jmx.principal-database"); } public List getManagementAccessList() { - return _config.getList("security.jmx.access"); + return getConfig().getList("security.jmx.access"); } public int getFrameSize() { - return _config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + return getConfig().getInt("advanced.framesize", DEFAULT_FRAME_SIZE); } public boolean getProtectIOEnabled() { - return _config.getBoolean("broker.connector.protectio.enabled", false); + return getConfig().getBoolean("broker.connector.protectio.enabled", false); } public int getBufferReadLimit() { - return _config.getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); + return getConfig().getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); } public int getBufferWriteLimit() { - return _config.getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); + return getConfig().getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); } public boolean getSynchedClocks() { - return _config.getBoolean("advanced.synced-clocks", false); + return getConfig().getBoolean("advanced.synced-clocks", false); } public boolean getMsgAuth() { - return _config.getBoolean("security.msg-auth", false); + return getConfig().getBoolean("security.msg-auth", false); } public String getJMXPrincipalDatabase() { - return _config.getString("security.jmx.principal-database"); + return getConfig().getString("security.jmx.principal-database"); } public String getManagementKeyStorePath() { - return _config.getString("management.ssl.keyStorePath", null); + return getConfig().getString("management.ssl.keyStorePath", null); } public boolean getManagementSSLEnabled() { - return _config.getBoolean("management.ssl.enabled", true); + return getConfig().getBoolean("management.ssl.enabled", true); } public String getManagementKeyStorePassword() { - return _config.getString("management.ssl.keyStorePassword"); + return getConfig().getString("management.ssl.keyStorePassword"); } public SecurityConfiguration getSecurityConfiguration() @@ -370,158 +387,158 @@ public class ServerConfiguration implements SignalHandler public boolean getQueueAutoRegister() { - return _config.getBoolean("queue.auto_register", true); + return getConfig().getBoolean("queue.auto_register", true); } public boolean getManagementEnabled() { - return _config.getBoolean("management.enabled", true); + return getConfig().getBoolean("management.enabled", true); } public void setManagementEnabled(boolean enabled) { - _config.setProperty("management.enabled", enabled); + getConfig().setProperty("management.enabled", enabled); } public int getHeartBeatDelay() { - return _config.getInt("heartbeat.delay", 5); + return getConfig().getInt("heartbeat.delay", 5); } public double getHeartBeatTimeout() { - return _config.getDouble("heartbeat.timeoutFactor", 2.0); + return getConfig().getDouble("heartbeat.timeoutFactor", 2.0); } public int getDeliveryPoolSize() { - return _config.getInt("delivery.poolsize", 0); + return getConfig().getInt("delivery.poolsize", 0); } public long getMaximumMessageAge() { - return _config.getLong("maximumMessageAge", 0); + return getConfig().getLong("maximumMessageAge", 0); } public long getMaximumMessageCount() { - return _config.getLong("maximumMessageCount", 0); + return getConfig().getLong("maximumMessageCount", 0); } public long getMaximumQueueDepth() { - return _config.getLong("maximumQueueDepth", 0); + return getConfig().getLong("maximumQueueDepth", 0); } public long getMaximumMessageSize() { - return _config.getLong("maximumMessageSize", 0); + return getConfig().getLong("maximumMessageSize", 0); } public long getMinimumAlertRepeatGap() { - return _config.getLong("minimumAlertRepeatGap", 0); + return getConfig().getLong("minimumAlertRepeatGap", 0); } public int getProcessors() { - return _config.getInt("connector.processors", 4); + return getConfig().getInt("connector.processors", 4); } public int getPort() { - return _config.getInt("connector.port", DEFAULT_PORT); + return getConfig().getInt("connector.port", DEFAULT_PORT); } public String getBind() { - return _config.getString("connector.bind", "wildcard"); + return getConfig().getString("connector.bind", "wildcard"); } public int getReceiveBufferSize() { - return _config.getInt("connector.socketReceiveBuffer", 32767); + return getConfig().getInt("connector.socketReceiveBuffer", 32767); } public int getWriteBufferSize() { - return _config.getInt("connector.socketWriteBuffer", 32767); + return getConfig().getInt("connector.socketWriteBuffer", 32767); } public boolean getTcpNoDelay() { - return _config.getBoolean("connector.tcpNoDelay", true); + return getConfig().getBoolean("connector.tcpNoDelay", true); } public boolean getEnableExecutorPool() { - return _config.getBoolean("advanced.filterchain[@enableExecutorPool]", false); + return getConfig().getBoolean("advanced.filterchain[@enableExecutorPool]", false); } public boolean getEnablePooledAllocator() { - return _config.getBoolean("advanced.enablePooledAllocator", false); + return getConfig().getBoolean("advanced.enablePooledAllocator", false); } public boolean getEnableDirectBuffers() { - return _config.getBoolean("advanced.enableDirectBuffers", false); + return getConfig().getBoolean("advanced.enableDirectBuffers", false); } public boolean getEnableSSL() { - return _config.getBoolean("connector.ssl.enabled", false); + return getConfig().getBoolean("connector.ssl.enabled", false); } public boolean getSSLOnly() { - return _config.getBoolean("connector.ssl.sslOnly", true); + return getConfig().getBoolean("connector.ssl.sslOnly", true); } public int getSSLPort() { - return _config.getInt("connector.ssl.port", DEFAUL_SSL_PORT); + return getConfig().getInt("connector.ssl.port", DEFAUL_SSL_PORT); } public String getKeystorePath() { - return _config.getString("connector.ssl.keystorePath", "none"); + return getConfig().getString("connector.ssl.keystorePath", "none"); } public String getKeystorePassword() { - return _config.getString("connector.ssl.keystorePassword", "none"); + return getConfig().getString("connector.ssl.keystorePassword", "none"); } public String getCertType() { - return _config.getString("connector.ssl.certType", "SunX509"); + return getConfig().getString("connector.ssl.certType", "SunX509"); } public boolean getQpidNIO() { - return _config.getBoolean("connector.qpidnio", false); + return getConfig().getBoolean("connector.qpidnio", false); } public boolean getUseBiasedWrites() { - return _config.getBoolean("advanced.useWriteBiasedPool", false); + return getConfig().getBoolean("advanced.useWriteBiasedPool", false); } public String getDefaultVirtualHost() { - return _config.getString("virtualhosts.default"); + return getConfig().getString("virtualhosts.default"); } public void setHousekeepingExpiredMessageCheckPeriod(long value) { - _config.setProperty("housekeeping.expiredMessageCheckPeriod", value); + getConfig().setProperty("housekeeping.expiredMessageCheckPeriod", value); } public long getHousekeepingCheckPeriod() { - return _config.getLong("housekeeping.checkPeriod", - _config.getLong("housekeeping.expiredMessageCheckPeriod", + return getConfig().getLong("housekeeping.checkPeriod", + getConfig().getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } } -- cgit v1.2.1 From 4926c771e378a82d20a4e5b295d35e58064ba519 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 23 Apr 2009 17:35:43 +0000 Subject: QPID-1826: brown paper bag commit git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@767989 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/ServerConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 9d7936f0c6..e0d325a5b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -155,7 +155,7 @@ public class ServerConfiguration implements SignalHandler while (keys.hasNext()) { String key = (String) keys.next(); - conf.setProperty(key, vhostConfiguration.getProperty(key)); + conf.setProperty("virtualhosts."+key, vhostConfiguration.getProperty(key)); } } } -- cgit v1.2.1 From c54cb56e0ab47bba8aca105e94164eb33c52b2d0 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Wed, 3 Jun 2009 18:54:37 +0000 Subject: Fixed QPID-1888 for the java broker. Also fixed a bug caught by the new selector test where message ids were being set to the string 'ID:null' when message-ids are disabled. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781507 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/filter/PropertyExpression.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index b30c70dac3..946274f936 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -63,6 +63,8 @@ public class PropertyExpression implements Expression JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression()); + JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new MessageIDExpression()); + JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression()); JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression()); -- cgit v1.2.1 From 1ab5653475db88228b6e86013e68a176c1e8008a Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Mon, 22 Jun 2009 14:41:10 +0000 Subject: QPID-1924: Make DerbyMessageStore honor $QPID_WORK. DerbyMessageStore: pick up QPID_WORK FailoverBaseCase: set QPID_WORK for the second broker QpidTestCase: pass on QPID_WORK git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@787254 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 9695571371..18269fa5e8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -155,7 +155,7 @@ public class DerbyMessageStore implements MessageStore QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); //Update to pick up QPID_WORK and use that as the default location not just derbyDB - final String databasePath = config.getStoreConfiguration().getString(ENVIRONMENT_PATH_PROPERTY, "derbyDB"); + final String databasePath = config.getStoreConfiguration().getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) -- cgit v1.2.1 From 165e64979e09cbc2a1812623d1ff0a56046af3f7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 11 Jul 2009 17:16:16 +0000 Subject: QPID-1927: move mbean interfaces to management-common, make broker module depend on management-common, modify build system to copy management-common.jar when required (eg for binary releases). QPID-1928: remove unused AMQException throws clause and import from ManagedQueue,UserManagement. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793206 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 6 +- .../management/ConfigurationManagement.java | 43 ---- .../management/ConfigurationManagementMBean.java | 3 +- .../qpid/server/exchange/AbstractExchange.java | 1 + .../qpid/server/exchange/DirectExchange.java | 4 +- .../qpid/server/exchange/FanoutExchange.java | 4 +- .../qpid/server/exchange/HeadersExchange.java | 4 +- .../qpid/server/exchange/ManagedExchange.java | 99 --------- .../apache/qpid/server/exchange/TopicExchange.java | 4 +- .../logging/management/LoggingManagement.java | 136 ------------ .../logging/management/LoggingManagementMBean.java | 3 +- .../qpid/server/management/MBeanAttribute.java | 41 ---- .../qpid/server/management/MBeanConstructor.java | 39 ---- .../qpid/server/management/MBeanDescription.java | 38 ---- .../qpid/server/management/MBeanIntrospector.java | 6 + .../management/MBeanInvocationHandlerImpl.java | 6 +- .../qpid/server/management/MBeanOperation.java | 43 ---- .../server/management/MBeanOperationParameter.java | 37 ---- .../qpid/server/management/ManagedBroker.java | 98 --------- .../server/protocol/AMQProtocolSessionMBean.java | 5 +- .../qpid/server/protocol/ManagedConnection.java | 136 ------------ .../apache/qpid/server/queue/AMQQueueMBean.java | 5 +- .../org/apache/qpid/server/queue/ManagedQueue.java | 245 --------------------- .../access/management/AMQUserManagementMBean.java | 6 +- .../security/access/management/UserManagement.java | 121 ---------- .../server/virtualhost/ManagedVirtualHost.java | 2 +- 26 files changed, 35 insertions(+), 1100 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 11d2c27eab..e29c2b52b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -44,13 +44,13 @@ import javax.management.ObjectName; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java deleted file mode 100644 index 8e4bf01c6a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagement.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.management; - -import javax.management.MBeanOperationInfo; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.management.MBeanOperation; - -public interface ConfigurationManagement -{ - - String TYPE = "ConfigurationManagement"; - int VERSION = 1; - - /** - * Reload the - * @throws ConfigurationException - */ - @MBeanOperation(name="reloadSecurityConfiguration", - description = "Force a reload of the security configuration sections", - impact = MBeanOperationInfo.ACTION) - void reloadSecurityConfiguration() throws ConfigurationException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java index ead6053d70..1541d3d892 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.configuration.management; import javax.management.NotCompliantMBeanException; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.management.common.mbeans.ConfigurationManagement; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -41,7 +42,7 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co } @Override - public void reloadSecurityConfiguration() throws ConfigurationException + public void reloadSecurityConfiguration() throws Exception { ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 30af09ce4b..393822790a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -33,6 +33,7 @@ import javax.management.openmbean.ArrayType; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedExchange; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index e9af92bad8..8eba14d8b6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -34,12 +34,12 @@ import javax.management.openmbean.TabularDataSupport; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index e9fd4d548b..35a7dfa1d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -22,12 +22,12 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 1ee1f35de6..f66e041f13 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -29,8 +31,6 @@ import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java deleted file mode 100644 index 317ff385ab..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The management interface exposed to allow management of an Exchange. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedExchange -{ - static final String TYPE = "Exchange"; - static final int VERSION = 1; - - /** - * Returns the name of the managed exchange. - * @return the name of the exchange. - * @throws IOException - */ - @MBeanAttribute(name="Name", description=TYPE + " Name") - String getName() throws IOException; - - @MBeanAttribute(name="ExchangeType", description="Exchange Type") - String getExchangeType() throws IOException; - - @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") - Integer getTicketNo() throws IOException; - - /** - * Tells if the exchange is durable or not. - * @return true if the exchange is durable. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description="true if Exchange is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the exchange is set for autodelete or not. - * @return true if the exchange is set as autodelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") - boolean isAutoDelete() throws IOException; - - // Operations - - /** - * Returns all the bindings this exchange has with the queues. - * @return the bindings with the exchange. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="bindings", description="view the queue bindings for this exchange") - TabularData bindings() throws IOException, JMException; - - /** - * Creates new binding with the given queue and binding. - * @param queueName - * @param binding - * @throws JMException - */ - @MBeanOperation(name="createNewBinding", - description="create a new binding with this exchange", - impact= MBeanOperationInfo.ACTION) - void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName, - @MBeanOperationParameter(name="Binding", description="New binding")String binding) - throws JMException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index bc303a219d..aaf3bbdcaa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -23,13 +23,13 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortStringTokenizer; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java deleted file mode 100644 index f723ab206c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagement.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.management; - -import java.io.IOException; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -public interface LoggingManagement -{ - String TYPE = "LoggingManagement"; - int VERSION = 1; - - //TabularType and contained CompositeType key/description information - String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"}; - String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"}; - String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]}; - - /** - * Attribute to represent the log4j xml configuration file's LogWatch interval. - * @return The logwatch interval in seconds. - */ - @MBeanAttribute(name="Log4jLogWatchInterval", - description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.") - Integer getLog4jLogWatchInterval(); - - /** - * Attribute to represent the available log4j logger output levels. - * @return The logging level names. - */ - @MBeanAttribute(name="AvailableLoggerLevels", description = "The values to which log output level can be set.") - String[] getAvailableLoggerLevels(); - - - //****** log4j runtime operations ****** // - - /** - * Sets the level of an active Log4J logger - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Retrieves a TabularData set of the active log4j loggers and their levels - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - */ - @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " + - "for active log4j logger's.", impact = MBeanOperationInfo.INFO) - TabularData viewEffectiveRuntimeLoggerLevels(); - - /** - * Sets the level of the active Log4J RootLogger - * @param level The level to set the RootLogger to - * @return True if successful, false if unsuccessful (eg if an invalid level is specified) - */ - @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.", - impact = MBeanOperationInfo.ACTION) - boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level); - - /** - * Attribute to represent the level of the active Log4J RootLogger - * @return The level of the RootLogger. - */ - @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.") - String getRuntimeRootLoggerLevel(); - - - //****** log4j XML configuration file operations ****** // - - /** - * Updates the level of an existing Log4J logger within the xml configuration file - * @param logger The name of the logger - * @param level The level to set the logger to - * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " + - "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger, - @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file - * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO) - TabularData viewConfigFileLoggerLevels() throws IOException; - - /** - * Updates the level of the Log4J RootLogger within the xml configuration file if it is present - * @param level The level to set the logger to - * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined) - * @throws IOException if there is an error parsing the configuration file. - */ - @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " + - "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION) - boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException; - - /** - * Attribute to represent the level of the Log4J RootLogger within the xml configuration file - * @return The level of the RootLogger, or null if it is not present - */ - @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " + - "in the log4j xml configuration file.") - String getConfigFileRootLoggerLevel() throws IOException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index cd3f85f8ca..3cebb1353b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -26,7 +26,8 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.management.common.mbeans.LoggingManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.log4j.Level; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java deleted file mode 100644 index 7d42297699..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean attributes. This should be used with getter or setter - * methods of attributes. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanAttribute -{ - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java deleted file mode 100644 index 9138e03085..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean constructors. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.CONSTRUCTOR) -@Inherited -public @interface MBeanConstructor -{ - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java deleted file mode 100644 index 448fed3280..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean class. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -public @interface MBeanDescription { - String value(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java index 0c2ec2aebd..9c2a455897 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -32,6 +32,12 @@ import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.NotCompliantMBeanException; +import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter; + /** * This class is a utility class to introspect the MBean class and the management * interface class for various purposes. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index e9b4d85e66..a68934d358 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.server.management; -import org.apache.qpid.server.configuration.management.ConfigurationManagement; -import org.apache.qpid.server.logging.management.LoggingManagement; -import org.apache.qpid.server.security.access.management.UserManagement; +import org.apache.qpid.management.common.mbeans.ConfigurationManagement; +import org.apache.qpid.management.common.mbeans.LoggingManagement; +import org.apache.qpid.management.common.mbeans.UserManagement; import org.apache.log4j.Logger; import javax.management.remote.MBeanServerForwarder; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java deleted file mode 100644 index a2dca3e51d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.management.MBeanOperationInfo; - -/** - * Annotation for MBean operations. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanOperation -{ - String name(); - String description(); - int impact() default MBeanOperationInfo.INFO; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java deleted file mode 100644 index aba5ec70d8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for MBean operation parameters. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface MBeanOperationParameter { - String name(); - String description(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java deleted file mode 100644 index c18417fc43..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.management; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; - -import org.apache.qpid.server.exchange.ManagedExchange; -import org.apache.qpid.server.queue.ManagedQueue; - -/** - * The ManagedBroker is the management interface to expose management - * features of the Broker. - * - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedBroker -{ - static final String TYPE = "VirtualHostManager"; - - static final int VERSION = 1 ; - - /** - * Creates a new Exchange. - * @param name - * @param type - * @param durable - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) - void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, - @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) - throws IOException, JMException; - - /** - * unregisters all the channels, queuebindings etc and unregisters - * this exchange from managed objects. - * @param exchange - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="unregisterExchange", - description="Unregisters all the related channels and queuebindings of this exchange", - impact= MBeanOperationInfo.ACTION) - void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange) - throws IOException, JMException; - - /** - * Create a new Queue on the Broker server - * @param queueName - * @param durable - * @param owner - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) - void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, - @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) - throws IOException, JMException; - - /** - * Unregisters the Queue bindings, removes the subscriptions and unregisters - * from the managed objects. - * @param queueName - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteQueue", - description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", - impact= MBeanOperationInfo.ACTION) - void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName) - throws IOException, JMException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 5dd3cc075a..9f7c74ba5e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -60,11 +60,12 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ConnectionCloseBody; import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedObject; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java deleted file mode 100644 index e75b09a0cb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.util.Date; -import java.security.Principal; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of Connections. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedConnection -{ - static final String TYPE = "Connection"; - static final int VERSION = 1; - - @MBeanAttribute(name = "ClientId", description = "Client Id") - String getClientId(); - - @MBeanAttribute(name = "AuthorizedId", description = "User Name") - String getAuthorizedId(); - - @MBeanAttribute(name = "Version", description = "Client Version") - String getVersion(); - - /** - * Tells the remote address of this connection. - * @return remote address - */ - @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address") - String getRemoteAddress(); - - /** - * Tells the last time, the IO operation was done. - * @return last IO time. - */ - @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done") - Date getLastIoTime(); - - /** - * Tells the total number of bytes written till now. - * @return number of bytes written. - * - @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") - Long getWrittenBytes(); - */ - /** - * Tells the total number of bytes read till now. - * @return number of bytes read. - * - @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") - Long getReadBytes(); - */ - - /** - * Threshold high value for no of channels. This is useful in setting notifications or - * taking required action is there are more channels being created. - * @return threshold limit for no of channels - */ - Long getMaximumNumberOfChannels(); - - /** - * Sets the threshold high value for number of channels for a connection - * @param value - */ - @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection") - void setMaximumNumberOfChannels(Long value); - - //********** Operations *****************// - - /** - * channel details of all the channels opened for this connection. - * @return general channel details - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="channels", description="Channel details for this connection") - TabularData channels() throws IOException, JMException; - - /** - * Commits the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="commitTransaction", - description="Commits the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Rollsback the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="rollbackTransactions", - description="Rollsback the transactions for given channel Id, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Closes all the related channels and unregisters this connection from managed objects. - */ - @MBeanOperation(name="closeConnection", - description="Closes this connection and all related channels", - impact= MBeanOperationInfo.ACTION) - void closeConnection() throws Exception; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index a6beb6cbf5..392e2c64ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -30,9 +30,10 @@ import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.store.StoreContext; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java deleted file mode 100644 index 579656893b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.io.IOException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -/** - * The management interface exposed to allow management of a queue. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedQueue -{ - static final String TYPE = "Queue"; - static final int VERSION = 2; - - /** - * Returns the Name of the ManagedQueue. - * @return the name of the managedQueue. - * @throws IOException - */ - @MBeanAttribute(name="Name", description = TYPE + " Name") - String getName() throws IOException; - - /** - * Total number of messages on the queue, which are yet to be delivered to the consumer(s). - * @return number of undelivered message in the Queue. - * @throws IOException - */ - @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue") - Integer getMessageCount() throws IOException; - - /** - * Tells the total number of messages receieved by the queue since startup. - * @return total number of messages received. - * @throws IOException - */ - @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup") - Long getReceivedMessageCount() throws IOException; - - /** - * Size of messages in the queue - * @return - * @throws IOException - */ - @MBeanAttribute(name="QueueDepth", description="The total size(Bytes) of messages in the queue") - Long getQueueDepth() throws IOException, JMException; - - /** - * Returns the total number of active subscribers to the queue. - * @return the number of active subscribers - * @throws IOException - */ - @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") - Integer getActiveConsumerCount() throws IOException; - - /** - * Returns the total number of subscribers to the queue. - * @return the number of subscribers. - * @throws IOException - */ - @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") - Integer getConsumerCount() throws IOException; - - /** - * Tells the Owner of the ManagedQueue. - * @return the owner's name. - * @throws IOException - */ - @MBeanAttribute(name="Owner", description = "Owner") - String getOwner() throws IOException; - - /** - * Tells whether this ManagedQueue is durable or not. - * @return true if this ManagedQueue is a durable queue. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the ManagedQueue is set to AutoDelete. - * @return true if the ManagedQueue is set to AutoDelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") - boolean isAutoDelete() throws IOException; - - /** - * Returns the maximum age of a message (expiration time) in milliseconds - * @return the maximum age - * @throws IOException - */ - Long getMaximumMessageAge() throws IOException; - - /** - * Sets the maximum age of a message in milliseconds - * @param age maximum age of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value(milliseconds) for message age") - void setMaximumMessageAge(Long age) throws IOException; - - /** - * Returns the maximum size of a message (in Bytes) allowed to be accepted by the - * ManagedQueue. This is useful in setting notifications or taking - * appropriate action, if the size of the message received is more than - * the allowed size. - * @return the maximum size of a message allowed to be aceepted by the - * ManagedQueue. - * @throws IOException - */ - Long getMaximumMessageSize() throws IOException; - - /** - * Sets the maximum size of the message (in Bytes) that is allowed to be - * accepted by the Queue. - * @param size maximum size of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(Bytes) for a message size") - void setMaximumMessageSize(Long size) throws IOException; - - /** - * Tells the maximum number of messages that can be stored in the queue. - * This is useful in setting the notifications or taking required - * action is the number of message increase this limit. - * @return maximum muber of message allowed to be stored in the queue. - * @throws IOException - */ - Long getMaximumMessageCount() throws IOException; - - /** - * Sets the maximum number of messages allowed to be stored in the queue. - * @param value the maximum number of messages allowed to be stored in the queue. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue") - void setMaximumMessageCount(Long value) throws IOException; - - /** - * This is useful for setting notifications or taking required action if the size of messages - * stored in the queue increases over this limit. - * @return threshold high value for Queue Depth - * @throws IOException - */ - Long getMaximumQueueDepth() throws IOException; - - /** - * Sets the maximum size of all the messages together, that can be stored - * in the queue. - * @param value - * @throws IOException - */ - @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth") - void setMaximumQueueDepth(Long value) throws IOException; - - - //********** Operations *****************// - - - /** - * Returns a subset of all the messages stored in the queue. The messages - * are returned based on the given index numbers. - * @param fromIndex - * @param toIndex - * @return - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="viewMessages", - description="Message headers for messages in this queue within given index range. eg. from index 1 - 100") - TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, - @MBeanOperationParameter(name="to index", description="to index")int toIndex) - throws IOException, JMException, AMQException; - - @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id") - CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) - throws IOException, JMException; - - /** - * Deletes the first message from top. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top", - impact= MBeanOperationInfo.ACTION) - void deleteMessageFromTop() throws IOException, JMException; - - /** - * Clears the queue by deleting all the undelivered messages from the queue. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="clearQueue", - description="Clears the queue by deleting all the undelivered messages from the queue", - impact= MBeanOperationInfo.ACTION) - void clearQueue() throws IOException, JMException; - - /** - * Moves the messages in given range of message Ids to given Queue. QPID-170 - * @param fromMessageId first in the range of message ids - * @param toMessageId last in the range of message ids - * @param toQueue where the messages are to be moved - * @throws IOException - * @throws JMException - * @throws AMQException - */ - @MBeanOperation(name="moveMessages", - description="You can move messages to another queue from this queue ", - impact= MBeanOperationInfo.ACTION) - void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId, - @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, - @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) - throws IOException, JMException, AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 121f571abe..b71484f0b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.server.security.access.management; -import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanOperation; import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.access.management.UserManagement; import org.apache.log4j.Logger; import org.apache.commons.configuration.ConfigurationException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java deleted file mode 100644 index 9fcdd4cd17..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.management; - -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.AMQException; - -import javax.management.openmbean.TabularData; -import javax.management.openmbean.CompositeData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.io.IOException; - -public interface UserManagement -{ - - String TYPE = "UserManagement"; - int VERSION = 2; - - //********** Operations *****************// - /** - * set password for user - * - * @param username The username to create - * @param password The password for the user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setPassword", description = "Set password for user.", - impact = MBeanOperationInfo.ACTION) - boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password); - - /** - * set rights for users with given details - * - * @param username The username to create - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "setRights", description = "Set access rights for user.", - impact = MBeanOperationInfo.ACTION) - boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * Create users with given details - * - * @param username The username to create - * @param password The password for the user - * @param read The set of permission to give the new user - * @param write The set of permission to give the new user - * @param admin The set of permission to give the new user - * - * @return The result of the operation - */ - @MBeanOperation(name = "createUser", description = "Create new user from system.", - impact = MBeanOperationInfo.ACTION) - boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, - @MBeanOperationParameter(name = "password", description = "Password")char[] password, - @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, - @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write, - @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); - - /** - * View users returns all the users that are currently available to the system. - * - * @param username The user to delete - * - * @return The result of the operation - */ - @MBeanOperation(name = "deleteUser", description = "Delete user from system.", - impact = MBeanOperationInfo.ACTION) - boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); - - - /** - * Reload the date from disk - * - * @return The result of the operation - */ - @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.", - impact = MBeanOperationInfo.ACTION) - boolean reloadData(); - - /** - * View users returns all the users that are currently available to the system. - * - * @return a table of users data (Username, read, write, admin) - */ - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.", - impact = MBeanOperationInfo.INFO) - TabularData viewUsers(); - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index f4c81fbbb8..2f0c56cc86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -22,7 +22,7 @@ package org.apache.qpid.server.virtualhost; import java.io.IOException; -import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute; /** * The management interface exposed to allow management of an Exchange. -- cgit v1.2.1 From 8a34bd2928c662a7adfc0dc4d21aabee1cde379d Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 13 Jul 2009 08:54:27 +0000 Subject: QPID-1930: expose UserManagement composite/tabular type keys through the management interface for reference, and add warning about future alterations to ensure compatibility git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793499 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/management/AMQUserManagementMBean.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index b71484f0b2..25c3754462 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -71,28 +71,22 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana // Setup for the TabularType static TabularType _userlistDataType; // Datatype for representing User Lists - static CompositeType _userDataType; // Composite type for representing User - static String[] _userItemNames = {"Username", "read", "write", "admin"}; static { - String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", - "Management Console Write Permission", "Management Console Admin Permission"}; - OpenType[] userItemTypes = new OpenType[4]; // User item types. userItemTypes[0] = SimpleType.STRING; // For Username userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin - String[] userDataIndex = {_userItemNames[0]}; try { _userDataType = - new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); + new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, userItemTypes); - _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); + _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX); } catch (OpenDataException e) { @@ -327,7 +321,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } Object[] itemData = {user.getName(), read, write, admin}; - CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); + CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES, itemData); userList.put(messageData); } } -- cgit v1.2.1 From 260f26b1b33f5f69991b91d58a8bd9af9999914e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 13 Jul 2009 08:57:15 +0000 Subject: QPID-1932: expose Queue tabular/composite key values through the management interface git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793504 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueueMBean.java | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 392e2c64ba..6beb018d6f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -81,15 +81,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method - private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; - private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; + private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. // OpenMBean data types for viewMessageContent method private static CompositeType _msgContentType = null; - private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; @@ -133,18 +131,19 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = - new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes, - _msgContentAttributeTypes); + _msgContentType = new CompositeType("Message Content", "AMQ Message Content", + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS, + _msgContentAttributeTypes); _msgAttributeTypes[0] = SimpleType.LONG; // For message id _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes _msgAttributeTypes[2] = SimpleType.LONG; // For size _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - _messageDataType = - new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); + _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, + VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, + VIEW_MSGS_TABULAR_UNIQUE_INDEX); } public String getObjectInstanceName() @@ -368,7 +367,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); } catch (AMQException e) { @@ -402,7 +401,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; - CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); _messageList.put(messageData); } } -- cgit v1.2.1 From ab517e5cae6ca72947969e4f7019dc6b0ef56142 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 13 Jul 2009 10:21:19 +0000 Subject: QPID-1943: expose exchange mbeans tabular/composite key values through the management interface git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793531 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/AbstractExchange.java | 11 +++-------- .../java/org/apache/qpid/server/exchange/DirectExchange.java | 2 +- .../java/org/apache/qpid/server/exchange/FanoutExchange.java | 2 +- .../java/org/apache/qpid/server/exchange/HeadersExchange.java | 10 +++------- .../java/org/apache/qpid/server/exchange/TopicExchange.java | 2 +- 5 files changed, 9 insertions(+), 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 393822790a..247558bb34 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -69,8 +69,6 @@ public abstract class AbstractExchange implements Exchange, Managable protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange { // open mbean data types for representing exchange bindings - protected String[] _bindingItemNames; - protected String[] _bindingItemIndexNames; protected OpenType[] _bindingItemTypes; protected CompositeType _bindingDataType; protected TabularType _bindinglistDataType; @@ -82,17 +80,14 @@ public abstract class AbstractExchange implements Exchange, Managable } protected void init() throws OpenDataException - { - _bindingItemNames = new String[]{"Binding Key", "Queue Names"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; - + { _bindingItemTypes = new OpenType[2]; _bindingItemTypes[0] = SimpleType.STRING; _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, TABULAR_UNIQUE_INDEX); } public ManagedObject getParentObject() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 8eba14d8b6..4b609f592b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -114,7 +114,7 @@ public class DirectExchange extends AbstractExchange } Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 35a7dfa1d9..23c716a0db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -77,7 +77,7 @@ public class FanoutExchange extends AbstractExchange String queueName = queue.getName().toString(); Object[] bindingItemValues = {queueName, new String[]{queueName}}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index f66e041f13..fc667db17b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -84,8 +84,6 @@ public class HeadersExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - - public static final ExchangeType TYPE = new ExchangeType() { @@ -137,17 +135,15 @@ public class HeadersExchange extends AbstractExchange */ protected void init() throws OpenDataException { - _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"}; - _bindingItemIndexNames = new String[]{_bindingItemNames[0]}; _bindingItemTypes = new OpenType[3]; _bindingItemTypes[0] = SimpleType.INTEGER; _bindingItemTypes[1] = SimpleType.STRING; _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - _bindingItemNames, _bindingItemNames, _bindingItemTypes); + HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, _bindingItemIndexNames); + _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); } public TabularData bindings() throws OpenDataException @@ -180,7 +176,7 @@ public class HeadersExchange extends AbstractExchange Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index aaf3bbdcaa..be7a1dc196 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -336,7 +336,7 @@ public class TopicExchange extends AbstractExchange for(Map.Entry> entry : bindingData.entrySet()) { Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues); + CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingCompositeData); } -- cgit v1.2.1 From b41e8cc0db2d481b21f6ea5a1a25b3e51e61064e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 13 Jul 2009 10:23:22 +0000 Subject: QPID-1944: expose Connection tabular/composite data key values through management interface git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793533 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 9f7c74ba5e..65235ba9b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -79,9 +79,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed private String _name = null; // openmbean data types for representing the channel attributes - private static final String[] _channelAtttibuteNames = - { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; - private static final String[] _indexNames = { _channelAtttibuteNames[0] }; + private static final OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; private static CompositeType _channelType = null; // represents the data type for channel data @@ -119,9 +117,9 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed private static void init() throws OpenDataException { _channelType = - new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, + new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); + _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX); } public String getClientId() @@ -247,7 +245,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed channel.getUnacknowledgedMessageMap().size() }; - CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); + CompositeData channelData = new CompositeDataSupport(_channelType, COMPOSITE_ITEM_NAMES, itemValues); channelsList.put(channelData); } -- cgit v1.2.1 From 635f3c2171cd42e1c59fdc3de80aa26a55f101ae Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 13 Jul 2009 10:25:13 +0000 Subject: QPID-1941: ensure old queue entry is deleted as well as dequeued, so it is not later gathered by the viewMessages() method which checks for non-deletion git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@793535 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 09258682bd..08daf715ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -885,7 +885,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for (QueueEntry entry : entries) { toQueue.enqueue(storeContext, entry.getMessage()); - + entry.delete(); } } catch (MessageCleanupException e) -- cgit v1.2.1 From 14192f8547fa5ec83642846252c5371932b6f9fc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 16 Jul 2009 12:59:15 +0000 Subject: QPID-1946: add server information mbean to expose version info for the broker and its JMX management API git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@794660 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 5 ++ .../management/ServerInformationMBean.java | 71 ++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 49619ac5b0..e402dd6956 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -50,6 +50,7 @@ import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; +import org.apache.qpid.server.information.management.ServerInformationMBean; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; @@ -273,6 +274,10 @@ public class Main ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); configMBean.register(); + ServerInformationMBean sysInfoMBean = + new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion()); + sysInfoMBean.register(); + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues // that are causing the broker build to pick up the wrong properties file and hence say // Starting Qpid Client diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java new file mode 100644 index 0000000000..6247404d90 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.information.management; + +import java.io.IOException; + +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; + +import javax.management.JMException; + +/** MBean class for the ServerInformationMBean. */ +@MBeanDescription("Server Information Interface") +public class ServerInformationMBean extends AMQManagedObject implements ServerInformation +{ + private String buildVersion; + private String productVersion; + + public ServerInformationMBean(String buildVersion, String productVersion) throws JMException + { + super(ServerInformation.class, ServerInformation.TYPE, ServerInformation.VERSION); + this.buildVersion = buildVersion; + this.productVersion = productVersion; + } + + public String getObjectInstanceName() + { + return ServerInformation.TYPE; + } + + public Integer getManagementApiMajorVersion() throws IOException + { + return QPID_JMX_API_MAJOR_VERSION; + } + + public Integer getManagementApiMinorVersion() throws IOException + { + return QPID_JMX_API_MINOR_VERSION; + } + + public String getBuildVersion() throws IOException + { + return buildVersion; + } + + public String getProductVersion() throws IOException + { + return productVersion; + } + + +} -- cgit v1.2.1 From 96b013f6670b450311f2cd669bab5ed5a3f07d32 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 17 Jul 2009 14:00:57 +0000 Subject: QPID-1990: add the messages queue position to the viewMessages() operation results, update management console QueueOperations tab accordingly git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@795089 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 6beb018d6f..785b668687 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -82,7 +82,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private String _queueName = null; // OpenMBean data types for viewMessages method - private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private static OpenType[] _msgAttributeTypes = new OpenType[5]; // AMQ message attribute types. private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. @@ -139,6 +139,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes _msgAttributeTypes[2] = SimpleType.LONG; // For size _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + _msgAttributeTypes[4] = SimpleType.LONG; // For queue position _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes); @@ -396,11 +397,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que // Create the tabular list of message header contents for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) { + long position = i; AMQMessage msg = list.get(i - 1).getMessage(); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered(), position}; CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); _messageList.put(messageData); } -- cgit v1.2.1 From 270c4f63c40417af21c7fb72ef1b027d9dfc5987 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 21 Jul 2009 09:05:21 +0000 Subject: QPID-1961: expand viewMessages() queue operation to support long parameters, deprecate previous int version. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796196 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 11 +++++++ .../apache/qpid/server/queue/AMQQueueMBean.java | 32 +++++++++++++++---- .../apache/qpid/server/queue/SimpleAMQQueue.java | 37 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 014b348822..4643326df3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -112,6 +112,17 @@ public interface AMQQueue extends Managable, Comparable List getMessagesOnTheQueue(int num, int offest); QueueEntry getMessageOnTheQueue(long messageId); + + /** + * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. + * + * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. + * Using 0 in the 'to' field will return an empty list regardless of the 'from' value. + * @param fromPosition + * @param toPosition + * @return + */ + public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition); void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 785b668687..77c45d6d16 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -380,25 +380,45 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que /** * Returns the header contents of the messages stored in this queue in tabular form. + * Deprecated as of Qpid JMX API 1.3 */ + @Deprecated public TabularData viewMessages(int beginIndex, int endIndex) throws JMException { - if ((beginIndex > endIndex) || (beginIndex < 1)) + return viewMessages((long)beginIndex,(long)endIndex); + } + + + /** + * Returns the header contents of the messages stored in this queue in tabular form. + * @param startPosition The queue position of the first message to be viewed + * @param endPosition The queue position of the last message to be viewed + */ + public TabularData viewMessages(long startPosition, long endPosition) throws JMException + { + if ((startPosition > endPosition) || (startPosition < 1)) { - throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); } + + if ((endPosition - startPosition) > Integer.MAX_VALUE) + { + throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size"); + } - List list = _queue.getMessagesOnTheQueue(); + List list = _queue.getMessagesRangeOnTheQueue(startPosition,endPosition); TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); try { // Create the tabular list of message header contents - for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) + int size = list.size(); + + for (int i = 0; i < size ; i++) { - long position = i; - AMQMessage msg = list.get(i - 1).getMessage(); + long position = startPosition + i; + AMQMessage msg = list.get(i).getMessage(); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 08daf715ef..e994967dc5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -813,6 +813,43 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return entryList; } + + /** + * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. + * + * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. + * Using 0 in the 'to' field will return an empty list regardless of the 'from' value. + * @param fromPosition + * @param toPosition + * @return + */ + public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) + { + List queueEntries = new ArrayList(); + + QueueEntryIterator it = _entries.iterator(); + + long index = 1; + for ( ; index < fromPosition && !it.atTail(); index++) + { + it.advance(); + } + + if(index < fromPosition) + { + //The queue does not contain enough entries to reach our range. + //return the empty list. + return queueEntries; + } + + for ( ; index <= toPosition && !it.atTail(); index++) + { + it.advance(); + queueEntries.add(it.getNode()); + } + + return queueEntries; + } public void moveMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, -- cgit v1.2.1 From f74099c4e879616196245567c48ff85abba0aeae Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 21 Jul 2009 09:12:28 +0000 Subject: QPID-1968: Expose deleteMessages() queue operation through the JMX MBean interface, add test for deleteMessages() git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796203 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueueMBean.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 77c45d6d16..f12430e4f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -478,12 +478,28 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { if ((fromMessageId > toMessageId) || (fromMessageId < 1)) { - throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); } + /** + * @see ManagedQueue#deleteMessages + * @param fromMessageId + * @param toMessageId + * @throws JMException + */ + public void deleteMessages(long fromMessageId, long toMessageId) throws JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); + } + + _queue.removeMessagesFromQueue(fromMessageId, toMessageId, _storeContext); + } + /** * returns Notifications sent by this MBean. */ -- cgit v1.2.1 From e09f7acc4739e03e79bd9e04f1330787251a1531 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 21 Jul 2009 09:13:06 +0000 Subject: QPID-1981: Expose copyMessages() queue operation through the JMX MBean interface git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796204 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueueMBean.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index f12430e4f0..e450a2060e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -500,6 +500,23 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _queue.removeMessagesFromQueue(fromMessageId, toMessageId, _storeContext); } + /** + * @see ManagedQueue#copyMessages + * @param fromMessageId + * @param toMessageId + * @param toQueueName + * @throws JMException + */ + public void copyMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); + } + + _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + } + /** * returns Notifications sent by this MBean. */ -- cgit v1.2.1 From ba01534206bc194dab376f25fcc3fa3687d0dc2c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 09:52:02 +0000 Subject: QPID-1992 : Addition of new Broker Logging Framework Provided static CurrentActor for accessing ThreadLocal. Included Test to validate setting of ThreadLocals. Added Test for AMQPActor Added getRootMessageLogger() to IApplicationRegistry Adjusted *ProtocolSessions to start counting at 0. Allowed Setting of Vhost on the MockProtocolSession Created a fixed Principle in MockProtocolSession Changes to MockProtocolSession, prevent NPEs when the AMQPActor creates its log string. Converted CurrentActor to use a Stack allowing a variety of actors to take their turn on a thread. Improved package structure Added testing for Actors Moved FileMonitorTools functionality to FileUtils and provided a Test Converted Log4jMessageLoggerTest to a proper UnitTest Moved Test cases to test package Updated other broker tests to set the authenticated user before setting the virtualhost, Whilst the logging could output null as the username it would be better if the tests correctly set the authorizedID. Update to include tests for disabled logging Fully tested LogSubjects Updated MockAMQQueue to be able to take a Virtualhost as per a normal Queue. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796650 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 17 ++- .../qpid/server/handler/ChannelOpenHandler.java | 7 +- .../apache/qpid/server/logging/BrokerMessages.java | 34 ++++++ .../org/apache/qpid/server/logging/LogActor.java | 43 ++++++++ .../org/apache/qpid/server/logging/LogMessage.java | 26 +++++ .../org/apache/qpid/server/logging/LogSubject.java | 37 +++++++ .../qpid/server/logging/RawMessageLogger.java | 44 ++++++++ .../qpid/server/logging/RootMessageLogger.java | 56 ++++++++++ .../qpid/server/logging/RootMessageLoggerImpl.java | 52 ++++++++++ .../server/logging/actors/AMQPChannelActor.java | 79 ++++++++++++++ .../server/logging/actors/AMQPConnectionActor.java | 115 +++++++++++++++++++++ .../qpid/server/logging/actors/AbstractActor.java | 45 ++++++++ .../qpid/server/logging/actors/CurrentActor.java | 54 ++++++++++ .../server/logging/actors/ManagementActor.java | 57 ++++++++++ .../logging/rawloggers/Log4jMessageLogger.java | 55 ++++++++++ .../logging/subjects/AbstractLogSubject.java | 64 ++++++++++++ .../server/logging/subjects/BindingLogSubject.java | 62 +++++++++++ .../server/logging/subjects/ChannelLogSubject.java | 54 ++++++++++ .../logging/subjects/ConnectionLogSubject.java | 48 +++++++++ .../logging/subjects/ExchangeLogSubject.java | 46 +++++++++ .../server/logging/subjects/QueueLogSubject.java | 45 ++++++++ .../logging/subjects/SubscriptionLogSubject.java | 49 +++++++++ .../server/protocol/AMQMinaProtocolSession.java | 54 ++++++++-- .../qpid/server/protocol/AMQProtocolSession.java | 3 + .../apache/qpid/server/queue/SimpleAMQQueue.java | 10 ++ .../qpid/server/registry/ApplicationRegistry.java | 8 ++ .../ConfigurationFileApplicationRegistry.java | 7 +- .../qpid/server/registry/IApplicationRegistry.java | 3 + .../qpid/server/subscription/Subscription.java | 2 + .../qpid/server/subscription/SubscriptionImpl.java | 11 ++ .../qpid/server/util/NullApplicationRegistry.java | 21 ++-- .../server/virtualhost/VirtualHostRegistry.java | 14 +++ 32 files changed, 1202 insertions(+), 20 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/BrokerMessages.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index e0d325a5b0..fc16b75e1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -94,6 +94,7 @@ public class ServerConfiguration implements SignalHandler envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer"); envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay"); envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator"); + envVarMap.put("QPID_STATUS-UPDATES", "status-updates"); } public ServerConfiguration(File configurationURL) throws ConfigurationException @@ -186,7 +187,12 @@ public class ServerConfiguration implements SignalHandler } return conf; } - + + public boolean getStatusEnabled() + { + return getConfig().getBoolean("status-updates", true); + } + // 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 @@ -541,4 +547,13 @@ public class ServerConfiguration implements SignalHandler getConfig().getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } + + public boolean getStatusUpdates() + { + // Retrieve the setting from configuration but default to on. + String value = getConfig().getString("status-updates", "on"); + + return value.equalsIgnoreCase("on"); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index 054674aed4..5d7adc6371 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -54,8 +54,11 @@ public class ChannelOpenHandler implements StateAwareMethodListener + * This is responsible for correctly formatting the LogActor String in the log + *

      + * [con:1(user@127.0.0.1/)/ch:1] + *

      + * To do this it requires access to the IO Layers as well as a Channel + */ +public class AMQPChannelActor extends AbstractActor +{ + + /** + * Create a new ChannelActor + * + * @param channel The Channel for this LogActor + * @param rootLogger The root Logger that this LogActor should use + */ + public AMQPChannelActor(AMQChannel channel, RootMessageLogger rootLogger) + { + super(rootLogger); + + AMQProtocolSession session = channel.getProtocolSession(); + + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ChannelLogSubject.CHANNEL_FORMAT : + * con:{0}({1}@{2}/{3})/ch:{4} + * + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + _logString = "[" + MessageFormat.format(ChannelLogSubject.CHANNEL_FORMAT, + session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress(), + session.getVirtualHost().getName(), + channel.getChannelId()) + + "] "; + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java new file mode 100644 index 0000000000..432b1d8203 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +import java.text.MessageFormat; + +/** + * An AMQPConnectionActor represtents a connectionthrough the AMQP port. + *

      + * This is responsible for correctly formatting the LogActor String in the log + *

      + * [ con:1(user@127.0.0.1/) ] + *

      + * To do this it requires access to the IO Layers. + */ +public class AMQPConnectionActor extends AbstractActor +{ + /** + * 0 - Connection ID + * 1 - Remote Address + */ + public static String SOCKET_FORMAT = "con:{0}({1})"; + + /** + * LOG FORMAT for the ConnectionLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + */ + public static final String USER_FORMAT = "con:{0}({1}@{2})"; + + public AMQPConnectionActor(AMQProtocolSession session, RootMessageLogger rootLogger) + { + super(rootLogger); + + _logString = "[" + MessageFormat.format(SOCKET_FORMAT, + session.getSessionID(), + session.getRemoteAddress()) + + + "] "; + } + + /** + * Call when the connection has been authorized so that the logString + * can be updated with the new user identity. + * + * @param session the authorized session + */ + public void connectionAuthorized(AMQProtocolSession session) + { + _logString = "[" + MessageFormat.format(USER_FORMAT, + session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress()) + + "] "; + + } + + /** + * Called once the user has been authenticated and they are now selecting + * the virtual host they wish to use. + * + * @param session the session that now has a virtualhost associated with it. + */ + public void virtualHostSelected(AMQProtocolSession session) + { + + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ConnectionLogSubject.CONNECTION_FORMAT : + * con:{0}({1}@{2}/{3}) + * + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, + session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress(), + session.getVirtualHost().getName()) + + "] "; + + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java new file mode 100644 index 0000000000..95f2dc9ff6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogMessage; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.RootMessageLogger; + +public abstract class AbstractActor implements LogActor +{ + protected String _logString; + protected RootMessageLogger _rootLogger; + + public AbstractActor(RootMessageLogger rootLogger) + { + _rootLogger = rootLogger; + } + + public void message(LogSubject subject, LogMessage message) + { + if (_rootLogger.isMessageEnabled(this, subject)) + { + _rootLogger.rawMessage(_logString + String.valueOf(subject) + message); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java new file mode 100644 index 0000000000..221e57eebb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.LogActor; + +import java.util.LinkedList; +import java.util.Deque; + +public class CurrentActor +{ + private static final ThreadLocal> _currentActor = new ThreadLocal>() + { + protected Deque initialValue() + { + return new LinkedList(); + } + }; + + public static void set(LogActor actor) + { + Deque stack = _currentActor.get(); + stack.addFirst(actor); + } + + public static void remove() + { + Deque stack = _currentActor.get(); + stack.remove(); + } + + public static LogActor get() + { + return _currentActor.get().peek(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java new file mode 100644 index 0000000000..58d55a13bb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.RootMessageLogger; + +import java.text.MessageFormat; +import java.security.Principal; + +public class ManagementActor extends AbstractActor +{ + + /** + * LOG FORMAT for the ManagementActor, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + */ + public static final String MANAGEMENT_FORMAT = "mng:{0}({1}@{2})"; + + /** + * //todo Correct interface to provide connection details + * @param user + * @param rootLogger The RootLogger to use for this Actor + */ + public ManagementActor(Principal user, RootMessageLogger rootLogger) + { + super(rootLogger); + + _logString = "["+ MessageFormat.format(MANAGEMENT_FORMAT, + "", + user.getName(), + "") + + "] "; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java new file mode 100644 index 0000000000..3774155626 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging.rawloggers; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.RawMessageLogger; + +public class Log4jMessageLogger implements RawMessageLogger +{ + public static final String DEFAULT_LEVEL = "INFO"; + public static final String DEFAULT_LOGGER = "qpid.message"; + private Level _level; + private Logger _rawMessageLogger; + + public Log4jMessageLogger() + { + this(DEFAULT_LEVEL, DEFAULT_LOGGER); + } + + public Log4jMessageLogger(String level, String logger) + { + _level = Level.toLevel(level); + + _rawMessageLogger = Logger.getLogger(logger); + } + + public void rawMessage(String message) + { + rawMessage(message, null); + } + + public void rawMessage(String message, Throwable throwable) + { + _rawMessageLogger.log(_level, message, throwable); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java new file mode 100644 index 0000000000..4fb5bdcc93 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.logging.LogSubject; + +import java.text.MessageFormat; + +/** + * The LogSubjects all have a similar requriement to format their output and + * provide the String value. + * + * This Abstract LogSubject provides this basic functionality, allowing the + * actual LogSubjects to provide their formating and data. + */ +public abstract class AbstractLogSubject implements LogSubject +{ + /** + * The logString that will be returned via toString + */ + protected String logString; + + /** + * Set the toString logging of this LogSubject. Based on a format provided + * by format and the var args. + * @param format The Message to format + * @param args The values to put in to the message. + */ + protected void setLogStringWithFormat(String format, Object... args) + { + logString = "[" + MessageFormat.format(format, args) + "] "; + } + + /** + * ToString is how the Logging infrastructure will get the text for this + * LogSubject + * + * @return String representing this LogSubject + */ + @Override + public String toString() + { + return logString; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java new file mode 100644 index 0000000000..fd171fea5a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java @@ -0,0 +1,62 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +public class BindingLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the ChannelLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Virtualhost Name + * 1 - Exchange Type + * 2 - Exchange Name + * 3 - Queue Name + * 4 - Binding RoutingKey + */ + protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})"; + + /** + * Create a BindingLogSubject that Logs in the following format. + * + * [ vh(/)/ex(amq.direct)/qu(testQueue)/bd(testQueue) ] + * + * @param routingKey + * @param exchange + * @param queue + */ + public BindingLogSubject(AMQShortString routingKey, Exchange exchange, + AMQQueue queue) + { + setLogStringWithFormat(BINDING_FORMAT, queue.getVirtualHost().getName(), + exchange.getType(), + exchange.getName(), + queue.getName(), + routingKey); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java new file mode 100644 index 0000000000..1b22de6d01 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +public class ChannelLogSubject extends AbstractLogSubject +{ + /** + * LOG FORMAT for the ChannelLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + * 4 - Channel ID + */ + public static String CHANNEL_FORMAT = ConnectionLogSubject.CONNECTION_FORMAT + + "/ch:{4}"; + + public ChannelLogSubject(AMQChannel channel) + { + AMQProtocolSession session = channel.getProtocolSession(); + + // Provide the value for the 4th replacement. + setLogStringWithFormat(CHANNEL_FORMAT, + session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress(), + session.getVirtualHost().getName(), + channel.getChannelId()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java new file mode 100644 index 0000000000..e07dbcda23 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.protocol.AMQProtocolSession; + +/** The Connection LogSubject */ +public class ConnectionLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the ConnectionLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + public static final String CONNECTION_FORMAT = "con:{0}({1}@{2}/{3})"; + + public ConnectionLogSubject(AMQProtocolSession session) + { + setLogStringWithFormat(CONNECTION_FORMAT, session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress(), + session.getVirtualHost().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java new file mode 100644 index 0000000000..21e5f5e4ce --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ExchangeLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the ExchangeLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Virtualhost Name + * 1 - Exchange Type + * 2 - Exchange Name + */ + protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})"; + + /** Create an ExchangeLogSubject that Logs in the following format. */ + public ExchangeLogSubject(Exchange exchange, VirtualHost vhost) + { + setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), + exchange.getType(), exchange.getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java new file mode 100644 index 0000000000..89f31ef477 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.queue.AMQQueue; + +public class QueueLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the ExchangeLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Virtualhost name + * 1 - queue name + */ + protected static String BINDING_FORMAT = "vh(/{0})/qu({1})"; + + /** Create an QueueLogSubject that Logs in the following format. */ + public QueueLogSubject(AMQQueue queue) + { + setLogStringWithFormat(BINDING_FORMAT, + queue.getVirtualHost().getName(), + queue.getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java new file mode 100644 index 0000000000..b68ef2e9a9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.subscription.Subscription; + +public class SubscriptionLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the SubscriptionLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Subscription ID + * 1 - queue name + */ + protected static String BINDING_FORMAT = "sub:{0}(qu({1}))"; + + /** + * Create an QueueLogSubject that Logs in the following format. + * + * @param subscription + */ + public SubscriptionLogSubject(Subscription subscription) + { + + setLogStringWithFormat(BINDING_FORMAT, subscription.getSubscriptionID(), + subscription.getQueue().getName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 205ca73f13..e46a52f3bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -21,26 +21,39 @@ package org.apache.qpid.server.protocol; import org.apache.log4j.Logger; - +import org.apache.mina.common.CloseFuture; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoServiceConfig; import org.apache.mina.common.IoSession; -import org.apache.mina.common.CloseFuture; import org.apache.mina.transport.vmpipe.VmPipeAddress; - import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodDispatcher; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; +import org.apache.qpid.server.logging.actors.AMQPConnectionActor; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -54,7 +67,6 @@ import org.apache.qpid.transport.Sender; import javax.management.JMException; import javax.security.sasl.SaslServer; - import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.Principal; @@ -64,6 +76,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicLong; public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { @@ -71,6 +84,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + private static final AtomicLong idGenerator = new AtomicLong(0); + // to save boxing the channelId and looking up in a map... cache in an array the low numbered // channels. This value must be of the form 2^x - 1. private static final int CHANNEL_CACHE_SIZE = 0xff; @@ -120,6 +135,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L; private org.apache.mina.common.WriteFuture _lastWriteFuture; + // Create a simple ID that increments for ever new Session + private final long _sessionID = idGenerator.getAndIncrement(); + + private AMQPConnectionActor _actor; + public ManagedObject getManagedObject() { return _managedObject; @@ -134,6 +154,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _codecFactory = codecFactory; + _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); + try { IoServiceConfig config = session.getServiceConfig(); @@ -158,6 +180,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _codecFactory = codecFactory; + _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); } private AMQProtocolSessionMBean createMBean() throws AMQException @@ -183,6 +206,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable return (AMQProtocolSession) minaProtocolSession.getAttachment(); } + public long getSessionID() + { + return _sessionID; + } + public void dataBlockReceived(AMQDataBlock message) throws Exception { _lastReceived = message; @@ -235,6 +263,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } } + CurrentActor.set(_actor); try { body.handle(channelId, this); @@ -244,7 +273,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable closeChannel(channelId); throw e; } - + finally + { + CurrentActor.remove(); + } } private void protocolInitiationReceived(ProtocolInitiation pi) @@ -796,6 +828,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { _virtualHost = virtualHost; + _actor.virtualHostSelected(this); + _virtualHost.getConnectionRegistry().registerConnection(this); _managedObject = createMBean(); @@ -820,6 +854,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable public void setAuthorizedID(Principal authorizedID) { _authorizedID = authorizedID; + + // Let the actor know that this connection is now Authorized + _actor.connectionAuthorized(this); } public Principal getAuthorizedID() @@ -827,6 +864,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable return _authorizedID; } + public SocketAddress getRemoteAddress() + { + return _minaProtocolSession.getRemoteAddress(); + } + public MethodRegistry getMethodRegistry() { return MethodRegistry.getMethodRegistry(getProtocolVersion()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 1bac601225..f721730d9c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -36,6 +36,7 @@ import java.security.Principal; public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { + long getSessionID(); public static final class ProtocolSessionIdentifier { @@ -198,6 +199,8 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession /** @return a Principal that was used to authorized this session */ Principal getAuthorizedID(); + public java.net.SocketAddress getRemoteAddress(); + public MethodRegistry getMethodRegistry(); public MethodDispatcher getMethodDispatcher(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index e994967dc5..8c66508307 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -202,6 +202,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException { + exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { @@ -209,6 +210,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _bindings.addBinding(routingKey, arguments, exchange); +// ExchangeBinding binding = new ExchangeBinding(routingKey, exchange, arguments); + + //fixme MR logging in progress +// _bindings.addBinding(binding); +// +// if (_logger.isMessageEnabled(binding)) +// { +// _logger.message(binding, "QM-1001 : Created Binding"); +// } } public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 22b4623ae1..b58b849133 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -35,6 +35,7 @@ import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.logging.RootMessageLogger; /** * An abstract application registry that provides access to configuration information and handles the @@ -70,6 +71,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected PluginManager _pluginManager; + protected RootMessageLogger _rootMessageLogger; + static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -287,4 +290,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _pluginManager; } + public RootMessageLogger getRootMessageLogger() + { + return _rootMessageLogger; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 39164883f9..31a85b878a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -33,6 +33,8 @@ import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalD import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { @@ -44,9 +46,12 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, + new Log4jMessageLogger()); + initialiseManagedObjectRegistry(); - _virtualHostRegistry = new VirtualHostRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(this); _pluginManager = new PluginManager(_configuration.getPluginDirectory()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index bbfda3addc..7d17639f22 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -33,6 +33,7 @@ import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.mina.common.IoAcceptor; public interface IApplicationRegistry @@ -69,6 +70,8 @@ public interface IApplicationRegistry PluginManager getPluginManager(); + RootMessageLogger getRootMessageLogger(); + /** * Register any acceptors for this registry * @param bindAddress The address that the acceptor has been bound with diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 9419572399..19eabce9ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -52,6 +52,8 @@ public interface Subscription AMQShortString getConsumerTag(); + long getSubscriptionID(); + boolean isSuspended(); boolean hasInterest(QueueEntry msg); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 7aa9d1e3af..51da884d1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.subscription; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -66,6 +67,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); private final Lock _stateChangeLock; + private static final AtomicLong idGenerator = new AtomicLong(0); + // Create a simple ID that increments for ever new Subscription + private final long _subscriptionID = idGenerator.getAndIncrement(); + + static final class BrowserSubscription extends SubscriptionImpl { public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, @@ -526,6 +532,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _consumerTag; } + public long getSubscriptionID() + { + return _subscriptionID; + } + public AMQProtocolSession getProtocolSession() { return _channel.getProtocolSession(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index eda2d3a94e..9ef1e029d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -20,17 +20,12 @@ */ package org.apache.qpid.server.util; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Properties; - -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -41,6 +36,10 @@ import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticat import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import java.util.Arrays; +import java.util.Collection; +import java.util.Properties; + public class NullApplicationRegistry extends ApplicationRegistry { public NullApplicationRegistry() throws ConfigurationException @@ -51,9 +50,11 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { _logger.info("Initialising NullApplicationRegistry"); - + + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); + _configuration.setHousekeepingExpiredMessageCheckPeriod(200); - + Properties users = new Properties(); users.put("guest", "guest"); @@ -65,7 +66,7 @@ public class NullApplicationRegistry extends ApplicationRegistry _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); _managedObjectRegistry = new NoopManagedObjectRegistry(); - _virtualHostRegistry = new VirtualHostRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(this); PropertiesConfiguration vhostProps = new PropertiesConfiguration(); VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); VirtualHost dummyHost = new VirtualHost(hostConfig); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 27917fac8a..5543adbeb5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -20,6 +20,9 @@ */ package org.apache.qpid.server.virtualhost; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; + import java.util.ArrayList; import java.util.Collection; import java.util.Map; @@ -32,6 +35,12 @@ public class VirtualHostRegistry private String _defaultVirtualHostName; + private ApplicationRegistry _applicationRegistry; + + public VirtualHostRegistry(ApplicationRegistry applicationRegistry) + { + _applicationRegistry = applicationRegistry; + } public synchronized void registerVirtualHost(VirtualHost host) throws Exception { @@ -67,4 +76,9 @@ public class VirtualHostRegistry { return new ArrayList(_registry.values()); } + + public ApplicationRegistry getApplicationRegistry() + { + return _applicationRegistry; + } } -- cgit v1.2.1 From d139781cb32f784696056f4f00efba09f4da9c6b Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 22 Jul 2009 13:09:44 +0000 Subject: QPID-1967: collect possible Exchange Type values from the broker instead of relying on default set within the management console git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796693 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index e29c2b52b7..d7583d9c59 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -37,6 +37,9 @@ */ package org.apache.qpid.server; +import java.io.IOException; +import java.util.ArrayList; + import javax.management.JMException; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; @@ -50,6 +53,7 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; @@ -91,6 +95,22 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr return _virtualHostMBean.getVirtualHost().getName(); } + /** + * Returns an array of the exchange types available for creation. + * @since Qpid JMX API 1.3 + * @throws IOException + */ + public String[] getExchangeTypes() throws IOException + { + ArrayList exchangeTypes = new ArrayList(); + for(ExchangeType ex : _exchangeFactory.getRegisteredTypes()) + { + exchangeTypes.add(ex.getName().toString()); + } + + return exchangeTypes.toArray(new String[0]); + } + /** * Creates new exchange and registers it with the registry. * -- cgit v1.2.1 From 1afb75a5046cabd50d79d4fed6e9368d9fc41b11 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 17:03:08 +0000 Subject: QPID-1992 : Removed couple of unused imports git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796795 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java | 1 - 1 file changed, 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java index 3170040a77..4a486ae17e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java @@ -24,7 +24,6 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHost; import java.text.MessageFormat; -- cgit v1.2.1 From 7185412d97631d37c6deda80c21e856d36e6d368 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 17:06:52 +0000 Subject: QPID-1980 : Update to ServerConfiguration provided by Keith Chow, Updated ServerconfigurationTest Added ServerConfigurationFileTest that verifies the string value is loadable from the systest config file. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796796 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 58 +++++++++++++--------- 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index fc16b75e1a..0bb4c050a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Locale; import java.util.Map.Entry; import org.apache.commons.configuration.CompositeConfiguration; @@ -37,7 +38,6 @@ import org.apache.qpid.server.configuration.management.ConfigurationManagementMB import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,9 +49,13 @@ public class ServerConfiguration implements SignalHandler private Configuration _config; + // Default Configuration values + //todo make these all public, to make validation of configuration easier. + public static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; + public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; + public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; + private static final int DEFAULT_FRAME_SIZE = 65536; - private static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; - private static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; private static final int DEFAULT_PORT = 5672; private static final int DEFAUL_SSL_PORT = 8672; private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; @@ -63,15 +67,21 @@ public class ServerConfiguration implements SignalHandler private SecurityConfiguration _securityConfiguration = null; private File _configFile; - + private Logger _log = LoggerFactory.getLogger(this.getClass()); private ConfigurationManagementMBean _mbean; - + // Map of environment variables to config items private static final Map envVarMap = new HashMap(); - + + // Configuration values to be read from the configuration file + //todo Move all properties to static values to ensure system testing can be performed. + public static final String CONNECTOR_PROTECTIO_ENABLED = "connector.protectio.enabled"; + public static final String CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE = "connector.protectio.readBufferLimitSize"; + public static final String CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE = "connector.protectio.writeBufferLimitSize"; + { envVarMap.put("QPID_PORT", "connector.port"); envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers"); @@ -96,16 +106,16 @@ public class ServerConfiguration implements SignalHandler envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator"); envVarMap.put("QPID_STATUS-UPDATES", "status-updates"); } - + public ServerConfiguration(File configurationURL) throws ConfigurationException { this(parseConfig(configurationURL)); _configFile = configurationURL; - try + try { Signal sig = new sun.misc.Signal("HUP"); sun.misc.Signal.handle(sig, this); - } + } catch (IllegalArgumentException e) { // We're on something that doesn't handle SIGHUP, how sad, Windows. @@ -115,16 +125,16 @@ public class ServerConfiguration implements SignalHandler public ServerConfiguration(Configuration conf) throws ConfigurationException { setConfig(conf); - + substituteEnvironmentVariables(); - + _jmxPort = getConfig().getInt("management.jmxport", 8999); _securityConfiguration = new SecurityConfiguration(conf.subset("security")); setupVirtualHosts(conf); - + } - + private void setupVirtualHosts(Configuration conf) throws ConfigurationException { List vhosts = conf.getList("virtualhosts"); @@ -140,7 +150,7 @@ public class ServerConfiguration implements SignalHandler { String name = (String) hosts.get(j); // Add the keys of the virtual host to the main config then bail out - + Configuration myConf = vhostConfiguration.subset("virtualhost." + name); Iterator k = myConf.getKeys(); while (k.hasNext()) @@ -169,13 +179,13 @@ public class ServerConfiguration implements SignalHandler String val = System.getenv(var.getKey()); if (val != null) { - getConfig().setProperty(var.getValue(), val); + getConfig().setProperty(var.getValue(), val); } } } private final static Configuration parseConfig(File file) throws ConfigurationException - { + { ConfigurationFactory factory = new ConfigurationFactory(); factory.setConfigurationFileName(file.getAbsolutePath()); Configuration conf = factory.getConfiguration(); @@ -202,7 +212,7 @@ public class ServerConfiguration implements SignalHandler return super.interpolate(obj); } } - + private final static Configuration flatConfig(File file) throws ConfigurationException { // We have to override the interpolate methods so that @@ -238,7 +248,7 @@ public class ServerConfiguration implements SignalHandler catch (ConfigurationException e) { _log.error("Could not reload configuration file", e); - } + } } public void reparseConfigFile() throws ConfigurationException @@ -248,7 +258,7 @@ public class ServerConfiguration implements SignalHandler Configuration newConfig = parseConfig(_configFile); _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); ApplicationRegistry.getInstance().getAccessManager().configurePlugins(_securityConfiguration); - + VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); for (String hostname : _virtualHosts.keySet()) { @@ -343,17 +353,17 @@ public class ServerConfiguration implements SignalHandler public boolean getProtectIOEnabled() { - return getConfig().getBoolean("broker.connector.protectio.enabled", false); + return getConfig().getBoolean(CONNECTOR_PROTECTIO_ENABLED, DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED); } public int getBufferReadLimit() { - return getConfig().getInt("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE); + return getConfig().getInt(CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_READ_LIMIT_SIZE); } public int getBufferWriteLimit() { - return getConfig().getInt("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE); + return getConfig().getInt(CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_WRITE_LIMIT_SIZE); } public boolean getSynchedClocks() @@ -543,8 +553,8 @@ public class ServerConfiguration implements SignalHandler public long getHousekeepingCheckPeriod() { - return getConfig().getLong("housekeeping.checkPeriod", - getConfig().getLong("housekeeping.expiredMessageCheckPeriod", + return getConfig().getLong("housekeeping.checkPeriod", + getConfig().getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } -- cgit v1.2.1 From 24cc42d10857f671423d347aeaa5002d11c5de82 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 17:09:19 +0000 Subject: QPID-1992 : Corrected duplication in ServerConfiguration for StatusUpdates and so renamed method getStatusUpdatesEnabled Ensured tested in ServerConfiguration[File]Test and removed standalone test that replicated functionality. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796798 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 22 +++++++++++----------- .../qpid/server/logging/RootMessageLoggerImpl.java | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 0bb4c050a3..e4ce042891 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -54,6 +54,7 @@ public class ServerConfiguration implements SignalHandler public static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; + public static final String DEFAULT_STATUS_UPDATES = "on"; private static final int DEFAULT_FRAME_SIZE = 65536; private static final int DEFAULT_PORT = 5672; @@ -81,6 +82,7 @@ public class ServerConfiguration implements SignalHandler public static final String CONNECTOR_PROTECTIO_ENABLED = "connector.protectio.enabled"; public static final String CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE = "connector.protectio.readBufferLimitSize"; public static final String CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE = "connector.protectio.writeBufferLimitSize"; + public static final String STATUS_UPDATES = "status-updates"; { envVarMap.put("QPID_PORT", "connector.port"); @@ -198,9 +200,16 @@ public class ServerConfiguration implements SignalHandler return conf; } - public boolean getStatusEnabled() + /** + * Check the configuration file to see if status updates are enabled. + * @return true if status updates are enabled + */ + public boolean getStatusUpdatesEnabled() { - return getConfig().getBoolean("status-updates", true); + // Retrieve the setting from configuration but default to on. + String value = getConfig().getString(STATUS_UPDATES, DEFAULT_STATUS_UPDATES); + + return value.equalsIgnoreCase("on"); } // Our configuration class needs to make the interpolate method @@ -557,13 +566,4 @@ public class ServerConfiguration implements SignalHandler getConfig().getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } - - public boolean getStatusUpdates() - { - // Retrieve the setting from configuration but default to on. - String value = getConfig().getString("status-updates", "on"); - - return value.equalsIgnoreCase("on"); - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java index 9270c316b6..1c2b4e4046 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java @@ -31,7 +31,7 @@ public class RootMessageLoggerImpl implements RootMessageLogger public RootMessageLoggerImpl(ServerConfiguration configuration, RawMessageLogger rawLogger) { - _enabled = configuration.getStatusUpdates(); + _enabled = configuration.getStatusUpdatesEnabled(); _rawLogger = rawLogger; } -- cgit v1.2.1 From f9f7fdc64cce0afd37d2c420fc37619b6eb35731 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 17:10:21 +0000 Subject: QPID-2001 : Provide a locale configuration option to allow the localisation of logging as part of providing fixed log messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796799 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index e4ce042891..e56f1cda12 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -55,6 +55,7 @@ public class ServerConfiguration implements SignalHandler public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; public static final String DEFAULT_STATUS_UPDATES = "on"; + public static final String DEFAULT_ADVANCED_LOCALE = Locale.US.toString(); private static final int DEFAULT_FRAME_SIZE = 65536; private static final int DEFAULT_PORT = 5672; @@ -83,6 +84,7 @@ public class ServerConfiguration implements SignalHandler public static final String CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE = "connector.protectio.readBufferLimitSize"; public static final String CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE = "connector.protectio.writeBufferLimitSize"; public static final String STATUS_UPDATES = "status-updates"; + public static final String ADVANCED_LOCALE = "advanced.locale"; { envVarMap.put("QPID_PORT", "connector.port"); @@ -212,6 +214,46 @@ public class ServerConfiguration implements SignalHandler return value.equalsIgnoreCase("on"); } + /** + * The currently defined {@see Locale} for this broker + * @return the configuration defined locale + */ + public Locale getLocale() + { + + String localeString = getConfig().getString(ADVANCED_LOCALE, DEFAULT_ADVANCED_LOCALE); + // Expecting locale of format langauge_country_variant + + String[] parts = localeString.split("_"); + + Locale locale = null; + switch (parts.length) + { + case 1: + locale = new Locale(localeString); + break; + case 2: + locale = new Locale(parts[0], parts[1]); + break; + default: + String variant = parts[2]; + // If we have a variant such as the Java doc suggests for Spanish + // Traditional_WIN we may end up with more than 3 parts on a + // split with '_'. So we should recombine the variant. + if (parts.length > 3) + { + for (int index = 3; index < parts.length; index++) + { + variant = variant + "_" + parts[index]; + } + } + + locale = new Locale(parts[0], parts[1], variant); + } + + return locale; + } + // Our configuration class needs to make the interpolate method // public so it can be called below from the config method. private static class MyConfiguration extends CompositeConfiguration -- cgit v1.2.1 From 9fec22f37a0e46d0f253c6a3b6183cf720e1e758 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 22 Jul 2009 17:11:51 +0000 Subject: QPID-2001 : Add Default en_US messages logging along with a Velocity Template to generate static Messages classes that can be used for compile time vaildation of logging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@796800 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/logging/BrokerMessages.java | 34 --------- .../logging/messages/LogMessages_en_US.properties | 82 ++++++++++++++++++++++ 2 files changed, 82 insertions(+), 34 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/BrokerMessages.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/BrokerMessages.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/BrokerMessages.java deleted file mode 100644 index e9cc7449cd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/BrokerMessages.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging; - -public class BrokerMessages -{ - - public static LogMessage BRK_1001(String version, String build) - { - return new LogMessage() - { - - }; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties new file mode 100644 index 0000000000..868a611134 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -0,0 +1,82 @@ +#Broker +# 0 - Version +# 1 = Build +BRK-1001 = Startup : Version: {0} Build: {1} +# 0 - Transport +# 1 - Port +BRK-1002 = Starting : Listening on {0} port {1,number} +# 0 - Transport +# 1 - Port +BRK-1003 = Shuting down : {0} port {1,number} +BRK-1004 = Ready +BRK-1005 = Stopped +# 0 - path +BRK-1006 = Using configuration : {0} +# 0 - path +BRK-1007 = Using logging configuration : {0} + +#ManagementConsole +MNG-1001 = Startup +# 0 - Service +# 1 - Port +MNG-1002 = Starting : {0} : Listening on port {1,number} +# 0 - Service +# 1 - Port +MNG-1003 = Shuting down : {0} : port {1,number} +MNG-1004 = Ready +MNG-1005 = Stopped +# 0 - Path +MNG-1006 = Using SSL Keystore : {0} + +#VirtualHost +# 0 - name +VHT-1001 = Created : {0} +VHT-1002 = Closed + +#MessageStore +# 0 - name +MST-1001 = Created : {0} +# 0 - path +MST-1002 = Store location : {0} +MST-1003 = Closed +MST-1004 = Recovery Start +# 0 - queue name +MST-1005 = Recovery Start : {0} +# 0 - count +# 1 - queue count +MST-1006 = Recovered {0,number} messages for queue {0} +MST-1007 = Recovery Complete +# 0 - queue name +MST-1008 = Recovery Complete : {0} + +#Connection +# 0 - Client id +# 1 - Protocol Version +CON-1001 = Open : Client ID {0} : Protocol Version : {1} +CON-1002 = Close + +#Channel +# 0 - count +CHN-1001 = Create : Prefetch {0,number} +# 0 - flow +CHN-1002 = Flow {0} +CHN-1003 = Close + +#Queue +# 0 - owner +QUE-1001 = Create : Owner:{0} [AutoDelete] [Durable|Transient] [Priority:] +QUE-1002 = Deleted + +#Exchange +# 0 - type +# 1 - name +EXH-1001 = Create : [Durable] Type:{0} Name:{1} +EXH-1002 = Deleted + +#Binding +BND-1001 = Create [: Arguments : ] +BND-1002 = Deleted + +#Subscription +SUB-1001 = Create : [Durable] [Arguments : ] +SUB-1002 = Close -- cgit v1.2.1 From 5acf1ab5dcea0250320321c4e51dd19133514f37 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 23 Jul 2009 12:57:53 +0000 Subject: QPID-2001 : Fully Tested LogMessages Added TestBlankSubject to be able to easily identify log message Updatd LogMessasges based on issues found. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@797050 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/messages/LogMessages_en_US.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 868a611134..d393614191 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -4,10 +4,10 @@ BRK-1001 = Startup : Version: {0} Build: {1} # 0 - Transport # 1 - Port -BRK-1002 = Starting : Listening on {0} port {1,number} +BRK-1002 = Starting : Listening on {0} port {1, number, #} # 0 - Transport # 1 - Port -BRK-1003 = Shuting down : {0} port {1,number} +BRK-1003 = Shuting down : {0} port {1, number, #} BRK-1004 = Ready BRK-1005 = Stopped # 0 - path @@ -19,10 +19,10 @@ BRK-1007 = Using logging configuration : {0} MNG-1001 = Startup # 0 - Service # 1 - Port -MNG-1002 = Starting : {0} : Listening on port {1,number} +MNG-1002 = Starting : {0} : Listening on port {1, number, #} # 0 - Service # 1 - Port -MNG-1003 = Shuting down : {0} : port {1,number} +MNG-1003 = Shuting down : {0} : port {1, number, #} MNG-1004 = Ready MNG-1005 = Stopped # 0 - Path @@ -44,7 +44,7 @@ MST-1004 = Recovery Start MST-1005 = Recovery Start : {0} # 0 - count # 1 - queue count -MST-1006 = Recovered {0,number} messages for queue {0} +MST-1006 = Recovered {0,number} messages for queue {1} MST-1007 = Recovery Complete # 0 - queue name MST-1008 = Recovery Complete : {0} @@ -57,7 +57,7 @@ CON-1002 = Close #Channel # 0 - count -CHN-1001 = Create : Prefetch {0,number} +CHN-1001 = Create : Prefetch {0, number} # 0 - flow CHN-1002 = Flow {0} CHN-1003 = Close -- cgit v1.2.1 From e72790686cd57c7c069ca5e3a9807681f9e987cb Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 24 Jul 2009 09:32:11 +0000 Subject: QPID-2005: make the fanout exchange mbean return a single wildcard binding entry with all queues listed. Modify the management console to auto-select the wildcard binding when the exchange is viewed. Also, suppress the warning on entering no binding key when creating a fanout exchange binding, but auto-fill the field with the wildcard for clarity. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@797387 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/exchange/FanoutExchange.java | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 23c716a0db..fcaec8bdd0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -59,6 +59,8 @@ public class FanoutExchange extends AbstractExchange @MBeanDescription("Management Bean for Fanout Exchange") private final class FanoutExchangeMBean extends ExchangeMBean { + private static final String BINDING_KEY_SUBSTITUTE = "*"; + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") public FanoutExchangeMBean() throws JMException { @@ -71,15 +73,23 @@ public class FanoutExchange extends AbstractExchange { _bindingList = new TabularDataSupport(_bindinglistDataType); + + if(_queues.isEmpty()) + { + return _bindingList; + } + + ArrayList queueNames = new ArrayList(); for (AMQQueue queue : _queues) { String queueName = queue.getName().toString(); - - Object[] bindingItemValues = {queueName, new String[]{queueName}}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); + queueNames.add(queueName); } + + Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + _bindingList.put(bindingData); return _bindingList; } @@ -94,7 +104,7 @@ public class FanoutExchange extends AbstractExchange try { - queue.bind(FanoutExchange.this, new AMQShortString(binding), null); + queue.bind(FanoutExchange.this, new AMQShortString(BINDING_KEY_SUBSTITUTE), null); } catch (AMQException ex) { -- cgit v1.2.1 From e28e61ac208c9a873c52a5fc2ce2505f50c22377 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 24 Jul 2009 11:32:40 +0000 Subject: QPID-2001 : Update to provide control of options in messages. Update to improve formatting of generated code Inclusion of more documentation Defaulted generation to use US locale Removed duplicate messages in MST that were added to while the option solution was being discussed. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@797421 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/messages/LogMessages_en_US.properties | 212 +++++++++++++++++++-- 1 file changed, 198 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index d393614191..8e9ee3720c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -1,13 +1,198 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# LogMessages used within the Java Broker as originally defined on the wiki: +# +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded through a ResourceBundle named LogMessages. the en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is requried then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat peforms its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addtion of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexepcted. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formating. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the first and final stage of processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# paramters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important is it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java +# Currently the following classes are created and are populated with the +# messages that bear their 3-digit type identifier: +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# BRK-1003 = Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage BRK_1003(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain paramters +# however nesting of options is not permitted. Identification is performed on +# first matchings so give the message: +# Msg = Log Message [option1] [option2] +# Two options will be identifed and enabled to select text 'option1 and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# The final processing that is done in the generation is the conversion of the +# property name. As a '-' is an illegal character in the method name it is +# converted to '_' This processing gives the final method signature as follows: +# Message._(,) +# #Broker # 0 - Version # 1 = Build BRK-1001 = Startup : Version: {0} Build: {1} # 0 - Transport # 1 - Port -BRK-1002 = Starting : Listening on {0} port {1, number, #} +BRK-1002 = Starting : Listening on {0} port {1,number,#} # 0 - Transport # 1 - Port -BRK-1003 = Shuting down : {0} port {1, number, #} +BRK-1003 = Shuting down : {0} port {1,number,#} BRK-1004 = Ready BRK-1005 = Stopped # 0 - path @@ -19,10 +204,10 @@ BRK-1007 = Using logging configuration : {0} MNG-1001 = Startup # 0 - Service # 1 - Port -MNG-1002 = Starting : {0} : Listening on port {1, number, #} +MNG-1002 = Starting : {0} : Listening on port {1,number,#} # 0 - Service # 1 - Port -MNG-1003 = Shuting down : {0} : port {1, number, #} +MNG-1003 = Shuting down : {0} : port {1,number,#} MNG-1004 = Ready MNG-1005 = Stopped # 0 - Path @@ -39,20 +224,18 @@ MST-1001 = Created : {0} # 0 - path MST-1002 = Store location : {0} MST-1003 = Closed -MST-1004 = Recovery Start # 0 - queue name -MST-1005 = Recovery Start : {0} +MST-1004 = Recovery Start[ : {0}] # 0 - count # 1 - queue count -MST-1006 = Recovered {0,number} messages for queue {1} -MST-1007 = Recovery Complete +MST-1005 = Recovered {0,number} messages for queue {1} # 0 - queue name -MST-1008 = Recovery Complete : {0} +MST-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id # 1 - Protocol Version -CON-1001 = Open : Client ID {0} : Protocol Version : {1} +CON-1001 = Open : Client ID {0}[ : Protocol Version : {1}] CON-1002 = Close #Channel @@ -64,19 +247,20 @@ CHN-1003 = Close #Queue # 0 - owner -QUE-1001 = Create : Owner:{0} [AutoDelete] [Durable|Transient] [Priority:] +# 1 - priority +QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted #Exchange # 0 - type # 1 - name -EXH-1001 = Create : [Durable] Type:{0} Name:{1} +EXH-1001 = Create :[ Durable] Type: {0} Name: {1} EXH-1002 = Deleted #Binding -BND-1001 = Create [: Arguments : ] +BND-1001 = Create[ : Arguments : {0}] BND-1002 = Deleted #Subscription -SUB-1001 = Create : [Durable] [Arguments : ] +SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close -- cgit v1.2.1 From 129087777a777b62c7ab2b5428c08addd7bb5d17 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 24 Jul 2009 14:21:06 +0000 Subject: QPID-2000: add a method to the VirtualHostManager MBean to retrieve a Map keyed by Queue names in the vhost, with values indicating their respective depths in bytes git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@797473 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 27 +++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index d7583d9c59..306dce1057 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -39,6 +39,8 @@ package org.apache.qpid.server; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import javax.management.JMException; import javax.management.MBeanException; @@ -75,7 +77,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final MessageStore _messageStore; private final VirtualHost.VirtualHostMBean _virtualHostMBean; - + @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { @@ -111,6 +113,29 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr return exchangeTypes.toArray(new String[0]); } + /** + * Returns a Map keyed by QueueName, detailing its associated QueueDepth in bytes. + * @since Qpid JMX API 1.3 + * @throws IOException + */ + public Map viewQueueNamesDepths() throws IOException + { + Map queueDepthMap = new HashMap(_queueRegistry.getQueues().size()); + + String queueName; + Long queueDepth; + + for(AMQQueue queue : _queueRegistry.getQueues()) + { + queueName = queue.getName().toString(); + queueDepth = queue.getQueueDepth(); + + queueDepthMap.put(queueName,queueDepth); + } + + return queueDepthMap; + } + /** * Creates new exchange and registers it with the registry. * -- cgit v1.2.1 From f3949615036dd5804e7fc778dab8bb2983c3625b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:18:25 +0000 Subject: QPID-2011 : Updated AlertingTest to use new LogMonitoring class and corrected failures in test. Failures corrected by: - Ensuring message count is as expected after first publication - Validating that the max count alert level is correctly changed (when InVM) - Validate that the log file does not contain alerts after restart - Validate that alerting occurs after extra messages have been published - Modified QPID_WORK (using QTC.setSystemProperty so it is only set for that test run) to ensure each test has a clean store. Additions to QpidTestCase: - Ability to enable persistence on a given virtualhost. Currently it tries to set the JBoss BerkelyDB store failing back to Qpid's DerbyDB store. - Ability to set properties in the configuration file, this involves re-writting the config files so that both inVM and external java brokers will correctly function with the desired configuration. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800356 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index e56f1cda12..90b4590d4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -256,7 +256,7 @@ public class ServerConfiguration implements SignalHandler // 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 static class MyConfiguration extends CompositeConfiguration { public String interpolate(String obj) { @@ -264,7 +264,7 @@ public class ServerConfiguration implements SignalHandler } } - private final static Configuration flatConfig(File file) throws ConfigurationException + public final static Configuration flatConfig(File file) throws ConfigurationException { // We have to override the interpolate methods so that // interpolation takes place accross the entirety of the -- cgit v1.2.1 From cef7932c4e2adfa3a0c71a2baecb2661c236a632 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:19:13 +0000 Subject: QPID-2001 : Added missing MessageStoreLogSubject and corresponding test git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800357 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/subjects/MessagesStoreLogSubject.java | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java new file mode 100644 index 0000000000..8a8708eb25 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class MessagesStoreLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the MessagesStoreLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Virtualhost Name + * 1 - Message Store Type + */ + protected static String BINDING_FORMAT = "vh(/{0})/ms({1})"; + + /** Create an ExchangeLogSubject that Logs in the following format. */ + public MessagesStoreLogSubject(VirtualHost vhost) + { + setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), + vhost.getMessageStore().getClass().getSimpleName()); + } +} -- cgit v1.2.1 From 602baf13406ee41ea6df3abbf0d033a2e4016671 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:21:43 +0000 Subject: QPID-2001 : Corrected MSLSubject, extracting the Store from the vhost fails to retrieve the right value during startup. So better to explicitly specify the vhost and message store. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800360 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java index 8a8708eb25..28d64de74e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.store.MessageStore; public class MessagesStoreLogSubject extends AbstractLogSubject { @@ -36,9 +37,9 @@ public class MessagesStoreLogSubject extends AbstractLogSubject protected static String BINDING_FORMAT = "vh(/{0})/ms({1})"; /** Create an ExchangeLogSubject that Logs in the following format. */ - public MessagesStoreLogSubject(VirtualHost vhost) + public MessagesStoreLogSubject(VirtualHost vhost, MessageStore store) { setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), - vhost.getMessageStore().getClass().getSimpleName()); + store.getClass().getSimpleName()); } } -- cgit v1.2.1 From 30d0d257c7f9783f33c2cf4fa0709226be2cec45 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:23:18 +0000 Subject: QPID-2002 : Enable LogActors to log solely about themselves. Situations such as startup would necesitate this, or when a new connection is being created. The addition of a ConnetionSubject would be unnecessary. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800362 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/RootMessageLogger.java | 8 ++++++++ .../org/apache/qpid/server/logging/RootMessageLoggerImpl.java | 5 +++++ .../org/apache/qpid/server/logging/actors/AbstractActor.java | 9 +++++++++ 3 files changed, 22 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java index cd7992faa7..5ac5eab6c4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java @@ -37,6 +37,14 @@ public interface RootMessageLogger */ boolean isMessageEnabled(LogActor actor, LogSubject subject); + /** + * Determine if the LogActor should be generating log messages. + * + * @param actor The actor requesting the logging + * + * @return boolean true if the message should be logged. + */ + boolean isMessageEnabled(LogActor actor); /** * Log the raw message to the configured logger. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java index 1c2b4e4046..a3bf276d1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java @@ -40,6 +40,11 @@ public class RootMessageLoggerImpl implements RootMessageLogger return _enabled; } + public boolean isMessageEnabled(LogActor actor) + { + return _enabled; + } + public void rawMessage(String message) { _rawLogger.rawMessage(MESSAGE + message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 95f2dc9ff6..4a9c6cbb2f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -42,4 +42,13 @@ public abstract class AbstractActor implements LogActor _rootLogger.rawMessage(_logString + String.valueOf(subject) + message); } } + + public void message(LogMessage message) + { + if (_rootLogger.isMessageEnabled(this)) + { + _rootLogger.rawMessage(_logString + message); + } + } + } -- cgit v1.2.1 From e72532f91ff54db52f3822897764625ee12344e1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:24:29 +0000 Subject: QPID-2002 : Change CON-1001 to make client ID optional so that the various stages of Open can be correctly logged. Client ID is not initially provided so we would be unable to log the protocol negotiation without removing this Modified ProtocolVersion Template to include a toString value to make it easier to log. There are two templates to update one in gentools/templ.java and one in common/templates Exposed verification methods to allow systests to reuse the code git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800363 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/messages/LogMessages_en_US.properties | 2 +- .../server/protocol/AMQMinaProtocolSession.java | 77 ++++++++++++++-------- 2 files changed, 50 insertions(+), 29 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 8e9ee3720c..d9f95ecb8e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -235,7 +235,7 @@ MST-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id # 1 - Protocol Version -CON-1001 = Open : Client ID {0}[ : Protocol Version : {1}] +CON-1001 = Open[ : Client ID : {0}][ : Protocol Version : {1}] CON-1002 = Close #Channel diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index e46a52f3bf..c84408e680 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -54,6 +54,9 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; import org.apache.qpid.server.logging.actors.AMQPConnectionActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.output.ProtocolOutputConverter; @@ -139,6 +142,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable private final long _sessionID = idGenerator.getAndIncrement(); private AMQPConnectionActor _actor; + private LogSubject _logSubject; public ManagedObject getManagedObject() { @@ -156,6 +160,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); + _actor.message(ConnectionMessages.CON_1001(null, null, false, false)); + try { IoServiceConfig config = session.getServiceConfig(); @@ -171,6 +177,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } } + // This is only used by two tests that do provide null values for stateManager + // so we can safely remove this and refactor. public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, AMQStateManager stateManager) throws AMQException { @@ -236,42 +244,45 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); - if (_logger.isDebugEnabled()) - { - _logger.debug("Frame Received: " + frame); - } - - // Check that this channel is not closing - if (channelAwaitingClosure(channelId)) + CurrentActor.set(_actor); + try { - if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) + if (_logger.isDebugEnabled()) { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); - } + _logger.debug("Frame Received: " + frame); } - else + + // Check that this channel is not closing + if (channelAwaitingClosure(channelId)) { - if (_logger.isInfoEnabled()) + if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) { - _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); + } } + else + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); + } - closeProtocolSession(); - return; + closeProtocolSession(); + return; + } } - } - CurrentActor.set(_actor); - try - { - body.handle(channelId, this); - } - catch (AMQException e) - { - closeChannel(channelId); - throw e; + try + { + body.handle(channelId, this); + } + catch (AMQException e) + { + closeChannel(channelId); + throw e; + } } finally { @@ -285,6 +296,9 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); try { + // Log incomming protocol negotiation request + _actor.message(ConnectionMessages.CON_1001(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); + ProtocolVersion pv = pi.checkVersion(); // Fails if not correct // This sets the protocol version (and hence framing classes) for this session. @@ -643,6 +657,8 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable if (!_closed) { _closed = true; + + _actor.message(ConnectionMessages.CON_1002()); if (_virtualHost != null) { @@ -770,7 +786,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) { - setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE))); + String clientID = _clientProperties.getString(CLIENT_PROPERTIES_INSTANCE); + setContextKey(new AMQShortString(clientID)); + + // Log the Opening of the connection for this client + _actor.message(ConnectionMessages.CON_1001(clientID, _protocolVersion.toString(), true, true)); } if (_clientProperties.getString(ClientProperties.version.toString()) != null) @@ -829,6 +849,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable _virtualHost = virtualHost; _actor.virtualHostSelected(this); + _logSubject = new ConnectionLogSubject(this); _virtualHost.getConnectionRegistry().registerConnection(this); -- cgit v1.2.1 From 601c4d2bee2e7e02bad427d9c836bdc6e107cd26 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:25:40 +0000 Subject: Removed stale constructor, updated two test cases to use other constructor, there is no impact as the tests were passing in null for the removed parameter git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800365 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/protocol/AMQMinaProtocolSession.java | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index c84408e680..1da5b1c26e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -177,20 +177,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable } } - // This is only used by two tests that do provide null values for stateManager - // so we can safely remove this and refactor. - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory, - AMQStateManager stateManager) throws AMQException - { - _stateManager = stateManager; - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); - } - private AMQProtocolSessionMBean createMBean() throws AMQException { try -- cgit v1.2.1 From 4377b1a6910c7dc0c18060349e2fd6ca704b94ff Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:26:33 +0000 Subject: QPID-2002 : Added message(LogMessage message) to the LogActor Interface and the ability to retrieve the RootMessageLogger git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800366 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/LogActor.java | 19 ++++++++++++++++++- .../qpid/server/logging/actors/AbstractActor.java | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java index 203a5d160d..d5683b3c7b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java @@ -40,4 +40,21 @@ public interface LogActor * @param message The message to log */ public void message(LogSubject subject, LogMessage message); -} \ No newline at end of file + + /** + * Logs the specified LogMessage against this actor + * + * Currently logging has a global setting however this will later be revised and + * as such the LogActor will need to take into consideration any new configuration + * as a means of enabling the logging of LogActors and LogSubjects. + * + * @param message The message to log + */ + public void message(LogMessage message); + + /** + * + * @return the RootMessageLogger that is currently in use by this LogActor. + */ + RootMessageLogger getRootMessageLogger(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 4a9c6cbb2f..8d96739eeb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -51,4 +51,9 @@ public abstract class AbstractActor implements LogActor } } + public RootMessageLogger getRootMessageLogger() + { + return _rootLogger; + } + } -- cgit v1.2.1 From 014ebe841ae307d4077a45cb522b49fe758ce9d5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:27:39 +0000 Subject: QPID-2002: Added testing of Channel Logging git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800368 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 28 +++++++++++++++++++++- .../logging/messages/LogMessages_en_US.properties | 4 ++-- .../server/protocol/AMQMinaProtocolSession.java | 17 ++++++++++++- .../qpid/server/protocol/AMQProtocolSession.java | 4 ++++ 4 files changed, 49 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index aa390d6c26..2a46ee53b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -57,6 +57,12 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.txn.LocalTransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.ChannelMessages; +import org.apache.qpid.server.logging.subjects.ChannelLogSubject; +import org.apache.qpid.server.logging.actors.AMQPChannelActor; +import org.apache.qpid.server.logging.actors.CurrentActor; public class AMQChannel { @@ -111,13 +117,22 @@ public class AMQChannel // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - private boolean _closing; + private boolean _closing; + + private LogActor _actor; + private LogSubject _logSubject; public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException { _session = session; _channelId = channelId; + + _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); + _logSubject = new ChannelLogSubject(this); + + _actor.message(ChannelMessages.CHN_1001()); + _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); @@ -371,6 +386,8 @@ public class AMQChannel private void setClosing(boolean closing) { _closing = closing; + + CurrentActor.get().message(_logSubject, ChannelMessages.CHN_1003()); } private void unsubscribeAllConsumers() throws AMQException @@ -774,6 +791,8 @@ public class AMQChannel boolean wasSuspended = _suspended.getAndSet(suspended); if (wasSuspended != suspended) { + _actor.message(_logSubject, ChannelMessages.CHN_1002(suspended ? "Stopped" : "Started")); + if (wasSuspended) { // may need to deliver queued messages @@ -865,6 +884,8 @@ public class AMQChannel public void setCredit(final long prefetchSize, final int prefetchCount) { + //fixme +// _actor.message(ChannelMessages.CHN_100X(prefetchSize, prefetchCount); _creditManager.setCreditLimits(prefetchSize, prefetchCount); } @@ -906,4 +927,9 @@ public class AMQChannel { return _recordDeliveryMethod; } + + public LogActor getLogActor() + { + return _actor; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index d9f95ecb8e..24df17683f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -239,8 +239,8 @@ CON-1001 = Open[ : Client ID : {0}][ : Protocol Version : {1}] CON-1002 = Close #Channel -# 0 - count -CHN-1001 = Create : Prefetch {0, number} +CHN-1001 = Create +# : Prefetch Size {0,number} : Count {1,number} # 0 - flow CHN-1002 = Flow {0} CHN-1003 = Close diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 1da5b1c26e..e8ea56bafd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -56,6 +56,7 @@ import org.apache.qpid.server.logging.actors.AMQPConnectionActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; @@ -205,6 +206,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable return _sessionID; } + public LogActor getLogActor() + { + return _actor; + } + public void dataBlockReceived(AMQDataBlock message) throws Exception { _lastReceived = message; @@ -230,7 +236,16 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); - CurrentActor.set(_actor); + //Look up the Channel's Actor and set that as the current actor + // If that is not available then we can use the ConnectionActor + // that is associated with this AMQMPSession. + LogActor channelActor = null; + if (_channelMap.get(channelId) != null) + { + channelActor = _channelMap.get(channelId).getLogActor(); + } + CurrentActor.set(channelActor == null ? _actor : channelActor); + try { if (_logger.isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index f721730d9c..fff406bb3d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -28,6 +28,8 @@ import org.apache.qpid.framing.*; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -38,6 +40,8 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { long getSessionID(); + LogActor getLogActor(); + public static final class ProtocolSessionIdentifier { private final Object _sessionIdentifier; -- cgit v1.2.1 From d34021e41a74d37dee0c61df74d1d93a662f267b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:30:01 +0000 Subject: Removed unused method that only throws an Exception git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800371 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 649e84cb50..ad1e8a580e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -88,7 +88,7 @@ public class VirtualHost implements Accessable private final Timer _houseKeepingTimer; private VirtualHostConfiguration _configuration; - + public void setAccessableName(String name) { _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" @@ -386,11 +386,6 @@ public class VirtualHost implements Accessable return _exchangeFactory; } - public ApplicationRegistry getApplicationRegistry() - { - throw new UnsupportedOperationException(); - } - public MessageStore getMessageStore() { return _messageStore; -- cgit v1.2.1 From c727fd05a439ee6f955b15ca18acd0ccc46e59bd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 3 Aug 2009 13:33:05 +0000 Subject: QPID-2002 : Updates to integrate Logging with test ant test runs. MaxChannelsTest/AMQProtoSessionMBean - Ensured CurrentActor is correctly set and removed. Log4jMessageLogger - Correctly Set log level to ensure messages are logged. AbstractActor - Null validation of RootLogger Log4jMessasgeLoggerTest - Updated and removed erroneous tests that were based on inherited log levels. AbstractTestLogSubject - Updated to correctly parse IP given by the use of InternalTestProtocolSession TestApplicationRegistry - Created RootMessageLogger git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@800374 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/AbstractActor.java | 4 +++ .../logging/rawloggers/Log4jMessageLogger.java | 1 + .../server/protocol/AMQProtocolSessionMBean.java | 42 +++++++++++++++++++--- 3 files changed, 42 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 8d96739eeb..4502710dd6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -32,6 +32,10 @@ public abstract class AbstractActor implements LogActor public AbstractActor(RootMessageLogger rootLogger) { + if(rootLogger == null) + { + throw new NullPointerException("RootMessageLogger cannot be null"); + } _rootLogger = rootLogger; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java index 3774155626..f996576f31 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java @@ -41,6 +41,7 @@ public class Log4jMessageLogger implements RawMessageLogger _level = Level.toLevel(level); _rawMessageLogger = Logger.getLogger(logger); + _rawMessageLogger.setLevel(_level); } public void rawMessage(String message) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 65235ba9b9..225a01386b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -65,6 +65,8 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; @@ -185,6 +187,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void commitTransactions(int channelId) throws JMException { + CurrentActor.set(getLogActor()); try { AMQChannel channel = _session.getChannel(channelId); @@ -199,6 +202,10 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new MBeanException(ex, ex.toString()); } + finally + { + CurrentActor.remove(); + } } /** @@ -209,6 +216,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void rollbackTransactions(int channelId) throws JMException { + CurrentActor.set(getLogActor()); try { AMQChannel channel = _session.getChannel(channelId); @@ -223,6 +231,10 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new MBeanException(ex, ex.toString()); } + finally + { + CurrentActor.remove(); + } } /** @@ -269,18 +281,38 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed 0, 0); - _session.writeFrame(responseBody.generateFrame(0)); - + CurrentActor.set(getLogActor()); try { - _session.closeSession(); + _session.writeFrame(responseBody.generateFrame(0)); + + try + { + + _session.closeSession(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } } - catch (AMQException ex) + finally { - throw new MBeanException(ex, ex.toString()); + CurrentActor.remove(); } } + /** + * Return the LogActor for this MBean Session + * //fixme currently simply returning the managed sessions LogActor, should + * be the ManagementActor + * @return + */ + private LogActor getLogActor() + { + return _session.getLogActor(); + } + @Override public MBeanNotificationInfo[] getNotificationInfo() { -- cgit v1.2.1 From 8dd5f83bc7dd0e099627f20c62afa050af0e6335 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:23:55 +0000 Subject: QPID-2002 : Add Queue Creation logging git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801557 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 49 +++++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 8c66508307..47a0a1d830 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -29,6 +29,10 @@ import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.subjects.QueueLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.QueueMessages; /* * @@ -113,6 +117,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private AtomicReference _asynchronousRunner = new AtomicReference(null); private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); + private LogSubject _logSubject; protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -148,6 +153,28 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); + _logSubject = new QueueLogSubject(this); + + // Log the correct creation message + + // Extract the number of priorities for this Queue. + // Leave it as 0 if we are a SimpleQueueEntryList + int priorities = 0; + if (entryListFactory instanceof PriorityQueueList) + { + PriorityQueueList priorityFactory = (PriorityQueueList) entryListFactory; + priorities = priorityFactory.getPriorities(); + } + + // Log the creation of this Queue. + // The priorities display is toggled on if we set priorities > 0 + CurrentActor.get().message(_logSubject, + QueueMessages.QUE_1001(String.valueOf(_owner), + priorities, + autoDelete, + durable, !durable, + priorities > 0)); + try { _managedObject = new AMQQueueMBean(this); @@ -429,7 +456,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _managedObject.checkForNotification(entry.getMessage()); - + return entry; } @@ -823,11 +850,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return entryList; } - + /** * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. - * - * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. + * + * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. * Using 0 in the 'to' field will return an empty list regardless of the 'from' value. * @param fromPosition * @param toPosition @@ -836,7 +863,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) { List queueEntries = new ArrayList(); - + QueueEntryIterator it = _entries.iterator(); long index = 1; @@ -844,20 +871,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { it.advance(); } - + if(index < fromPosition) { //The queue does not contain enough entries to reach our range. //return the empty list. return queueEntries; } - + for ( ; index <= toPosition && !it.atTail(); index++) { it.advance(); queueEntries.add(it.getNode()); } - + return queueEntries; } @@ -1244,7 +1271,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener while (!sub.isSuspended() && !atTail && iterations != 0) { - try + try { sub.getSendLock(); atTail = attemptDelivery(sub); @@ -1479,8 +1506,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (!node.isDeleted() && node.expired() && node.acquire()) { node.discard(storeContext); - } - else + } + else { _managedObject.checkForNotification(node.getMessage()); } -- cgit v1.2.1 From cf1d99773dbfb66c7d0b3c141530b01b69fa0576 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:26:56 +0000 Subject: QPID-2028 : Ensure all Non QpidTestCase System tests correctly clean up by removing the ApplicationRegistry they create. The biggest offenders are the broker tests which are not pure unit tests. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801561 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ApplicationRegistry.java | 10 ++- .../qpid/server/util/NullApplicationRegistry.java | 87 ---------------------- 2 files changed, 9 insertions(+), 88 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index b58b849133..edad8e53aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -36,6 +36,7 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; /** * An abstract application registry that provides access to configuration information and handles the @@ -114,12 +115,19 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + /** + * Method to cleanly shutdown the default registry running in this JVM + */ + public static void remove() + { + remove(DEFAULT_INSTANCE); + } + /** * Method to cleanly shutdown specified registry running in this JVM * * @param instanceID the instance to shutdown */ - public static void remove(int instanceID) { try diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java deleted file mode 100644 index 9ef1e029d3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.logging.RootMessageLoggerImpl; -import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.plugins.AllowAll; -import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Properties; - -public class NullApplicationRegistry extends ApplicationRegistry -{ - public NullApplicationRegistry() throws ConfigurationException - { - super(new ServerConfiguration(new PropertiesConfiguration())); - } - - public void initialise() throws Exception - { - _logger.info("Initialising NullApplicationRegistry"); - - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); - - _configuration.setHousekeepingExpiredMessageCheckPeriod(200); - - Properties users = new Properties(); - - users.put("guest", "guest"); - - _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); - - _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _managedObjectRegistry = new NoopManagedObjectRegistry(); - _virtualHostRegistry = new VirtualHostRegistry(this); - PropertiesConfiguration vhostProps = new PropertiesConfiguration(); - VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); - VirtualHost dummyHost = new VirtualHost(hostConfig); - _virtualHostRegistry.registerVirtualHost(dummyHost); - _virtualHostRegistry.setDefaultVirtualHostName("test"); - _pluginManager = new PluginManager(""); - - } - - public Collection getVirtualHostNames() - { - String[] hosts = {"test"}; - return Arrays.asList(hosts); - } -} - - - -- cgit v1.2.1 From bb4f5e794da724e2d971a6c2813c71dbdfe747cc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:29:07 +0000 Subject: QPID-2002 : Add Queue Logging Tests. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801564 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 47a0a1d830..763a0506e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -160,10 +160,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Extract the number of priorities for this Queue. // Leave it as 0 if we are a SimpleQueueEntryList int priorities = 0; - if (entryListFactory instanceof PriorityQueueList) + if (entryListFactory instanceof PriorityQueueList.Factory) { - PriorityQueueList priorityFactory = (PriorityQueueList) entryListFactory; - priorities = priorityFactory.getPriorities(); + priorities = ((PriorityQueueList)_entries).getPriorities(); } // Log the creation of this Queue. @@ -1165,6 +1164,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.clear(); stop(); + + //Log Queue Deletion + CurrentActor.get().message(_logSubject, QueueMessages.QUE_1002()); + } return getMessageCount(); -- cgit v1.2.1 From 5d8692eb57c42ddc403bfa04559464f4c8465b22 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:34:20 +0000 Subject: QPID-2002, QPID-2012 : Provide Broker Startup Logging using a SystemOutMessageLogger until we have loaded the main configuration and then re-initialise with that configuration git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801567 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 102 ++++++++++++--------- .../server/logging/StartupRootMessageLogger.java | 42 +++++++++ .../qpid/server/logging/actors/BrokerActor.java | 39 ++++++++ .../logging/rawloggers/SystemOutMessageLogger.java | 40 ++++++++ .../ConfigurationFileApplicationRegistry.java | 14 ++- 5 files changed, 189 insertions(+), 48 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index e402dd6956..34125ae25a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,14 +20,6 @@ */ package org.apache.qpid.server; -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; - -import javax.management.NotCompliantMBeanException; - import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -51,12 +43,22 @@ import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.information.management.ServerInformationMBean; +import org.apache.qpid.server.logging.StartupRootMessageLogger; +import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; import org.apache.qpid.server.protocol.AMQPProtocolProvider; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; + /** * Main entry point for AMQPD. * @@ -191,7 +193,9 @@ public class Main { try { + CurrentActor.set(new BrokerActor(new StartupRootMessageLogger())); startup(); + CurrentActor.remove(); } catch (InitException e) { @@ -233,7 +237,7 @@ public class Main } else { - System.out.println("Using configuration file " + configFile.getAbsolutePath()); + CurrentActor.get().message(BrokerMessages.BRK_1006(configFile.getAbsolutePath())); } String logConfig = commandLine.getOptionValue("l"); @@ -268,52 +272,62 @@ public class Main updateManagementPort(serverConfig, commandLine.getOptionValue("m")); ApplicationRegistry.initialise(config); - - configureLoggingManagementMBean(logConfigFile, logWatchTime); - ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); - configMBean.register(); - - ServerInformationMBean sysInfoMBean = - new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion()); - sysInfoMBean.register(); - - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues - // that are causing the broker build to pick up the wrong properties file and hence say - // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); + // AR.initialise() sets its own actor so we now need to set the actor + // for the remainder of the startup + CurrentActor.set(new BrokerActor(config.getRootMessageLogger())); + try{ + configureLoggingManagementMBean(logConfigFile, logWatchTime); - ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); + ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); + configMBean.register(); - // 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 (!serverConfig.getEnablePooledAllocator()) - { - ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); - } + ServerInformationMBean sysInfoMBean = + new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion()); + sysInfoMBean.register(); - if(serverConfig.getUseBiasedWrites()) - { - System.setProperty("org.apache.qpid.use_write_biased_pool","true"); - } + //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues + // that are causing the broker build to pick up the wrong properties file and hence say + // Starting Qpid Client + _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); - int port = serverConfig.getPort(); + ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); - String portStr = commandLine.getOptionValue("p"); - if (portStr != null) - { - try + // 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 (!serverConfig.getEnablePooledAllocator()) { - port = Integer.parseInt(portStr); + ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); } - catch (NumberFormatException e) + + if (serverConfig.getUseBiasedWrites()) { - throw new InitException("Invalid port: " + portStr, e); + System.setProperty("org.apache.qpid.use_write_biased_pool", "true"); } + + int port = serverConfig.getPort(); + + String portStr = commandLine.getOptionValue("p"); + if (portStr != null) + { + try + { + port = Integer.parseInt(portStr); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + portStr, e); + } + } + + bind(port, serverConfig); + } + finally + { + // Startup is complete so remove the AR initialised Startup actor + CurrentActor.remove(); } - - bind(port, serverConfig); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java new file mode 100644 index 0000000000..0dffde50fa --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.rawloggers.SystemOutMessageLogger; + +public class StartupRootMessageLogger extends RootMessageLoggerImpl +{ + public StartupRootMessageLogger() throws ConfigurationException + { + super(new ServerConfiguration(new PropertiesConfiguration()), + new SystemOutMessageLogger()); + } + + @Override + public boolean isMessageEnabled(LogActor actor, LogSubject subject) + { + return true; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java new file mode 100644 index 0000000000..9b928accc0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.RootMessageLogger; + +public class BrokerActor extends AbstractActor +{ + + /** + * Create a new BrokerActor + * + * @param logger + */ + public BrokerActor(RootMessageLogger logger) + { + super(logger); + + _logString = "[Broker] "; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java new file mode 100644 index 0000000000..b9f0532d05 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.rawloggers; + +import org.apache.qpid.server.logging.RawMessageLogger; + +public class SystemOutMessageLogger implements RawMessageLogger +{ + public void rawMessage(String message) + { + rawMessage(message, null); + } + + public void rawMessage(String message, Throwable throwable) + { + System.out.println(message); + if (throwable != null) + { + throwable.printStackTrace(System.out); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 31a85b878a..043c048f51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -20,11 +20,13 @@ */ package org.apache.qpid.server.registry; -import java.io.File; - import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.AMQException; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -33,8 +35,8 @@ import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalD import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.logging.RootMessageLoggerImpl; -import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; + +import java.io.File; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { @@ -48,6 +50,8 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); + // Set the Actor for current log messages + CurrentActor.set(new BrokerActor(_rootMessageLogger)); initialiseManagedObjectRegistry(); @@ -67,6 +71,8 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry initialiseVirtualHosts(); + // Startup complete pop the current actor + CurrentActor.remove(); } private void initialiseVirtualHosts() throws Exception -- cgit v1.2.1 From 94cd727da1bafaf5258991c275b7e786b5e81a99 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:38:14 +0000 Subject: QPID-2002 : Javadoc'd CurrentActor git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801571 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/CurrentActor.java | 56 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java index 221e57eebb..374550a72b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java @@ -25,28 +25,82 @@ import org.apache.qpid.server.logging.LogActor; import java.util.LinkedList; import java.util.Deque; +/** + * The CurrentActor is a ThreadLocal wrapper that allows threads in the broker + * to retrieve an actor to perform logging. This approach is used so for two + * reasons: + * 1) We do not have to pass a logging actor around the system + * 2) We can set new actors at the point we have enough information. i.e. + * - Set a low level ConnectionActor when processing bytes from the wire. + * - Set a ChannelActor when we are processing the frame + * - Set a SubscriptionActor when we are handling the subscription. + * + * The code performing the logging need not worry about what type of actor is + * currently set so can perform its logging. The resulting log entry though will + * contain customised details from the the currently set Actor. + * + * The Actor model also allows the pre-creation of fixed messages so the + * performance impact of the additional logging data is minimised. + * + * This class does not perform any checks to ensure that there is an Actor set + * when calling remove or get. As a result the application developer must ensure + * that they have called set before they attempt to use the actor via get or + * remove the set actor. + * + * The checking of the return via get should not be done as the logging is + * desired. It is preferable to cause the NullPointerException to highlight the + * programming error rather than miss a log message. + * + * The same is true for the remove. A NPE will occur if no set has been called + * highlighting the programming error. + * + */ public class CurrentActor { + /** + * The ThreadLocal variable with initialiser + */ private static final ThreadLocal> _currentActor = new ThreadLocal>() { + // Initialise the CurrentActor to be an empty List protected Deque initialValue() { return new LinkedList(); } }; + /** + * Set a new LogActor to be the Current Actor + * + * This pushes the Actor in to the LIFO Queue + * + * @param actor The new LogActor + */ public static void set(LogActor actor) { Deque stack = _currentActor.get(); stack.addFirst(actor); } + /** + * Remove the current LogActor. + * + * Calling remove without calling set will result in a NoSuchElementException. + * + */ public static void remove() { Deque stack = _currentActor.get(); - stack.remove(); + stack.removeFirst(); } + /** + * Return the current head of the list of LogActors. + * + * If there has been no set call then this will return Null. + * + * @return Current LogActor + */ public static LogActor get() { return _currentActor.get().peek(); -- cgit v1.2.1 From 7697d047267d136b1c9666232920248969096a56 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:39:28 +0000 Subject: QPID-2002: MessageStore Logging , DerbyMS Does not have Queue Recovery logging just yet as its approach to recovery does not provide the requried details. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801572 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/subjects/MessageStoreLogSubject.java | 45 ++++++++++++ .../logging/subjects/MessagesStoreLogSubject.java | 45 ------------ .../qpid/server/store/AbstractMessageStore.java | 44 ++++++++++++ .../qpid/server/store/DerbyMessageStore.java | 81 ++++++++++++---------- .../qpid/server/store/MemoryMessageStore.java | 23 +++--- 5 files changed, 143 insertions(+), 95 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java new file mode 100644 index 0000000000..e11cbba4f4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.subjects; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.store.MessageStore; + +public class MessageStoreLogSubject extends AbstractLogSubject +{ + + /** + * LOG FORMAT for the MessagesStoreLogSubject, + * Uses a MessageFormat call to insert the requried values according to + * these indicies: + * + * 0 - Virtualhost Name + * 1 - Message Store Type + */ + protected static String BINDING_FORMAT = "vh(/{0})/ms({1})"; + + /** Create an ExchangeLogSubject that Logs in the following format. */ + public MessageStoreLogSubject(VirtualHost vhost, MessageStore store) + { + setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), + store.getClass().getSimpleName()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java deleted file mode 100644 index 28d64de74e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessagesStoreLogSubject.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging.subjects; - -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.store.MessageStore; - -public class MessagesStoreLogSubject extends AbstractLogSubject -{ - - /** - * LOG FORMAT for the MessagesStoreLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Virtualhost Name - * 1 - Message Store Type - */ - protected static String BINDING_FORMAT = "vh(/{0})/ms({1})"; - - /** Create an ExchangeLogSubject that Logs in the following format. */ - public MessagesStoreLogSubject(VirtualHost vhost, MessageStore store) - { - setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), - store.getClass().getSimpleName()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java new file mode 100644 index 0000000000..fd2d09b777 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.LogSubject; + +public abstract class AbstractMessageStore implements MessageStore +{ + protected LogSubject _logSubject; + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception + { + _logSubject = new MessageStoreLogSubject(virtualHost, this); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + } + + public void close() throws Exception + { + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 18269fa5e8..90de1aa8fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -20,49 +20,51 @@ */ package org.apache.qpid.server.store; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.MessageHandleFactory; import org.apache.qpid.server.queue.MessageMetaData; import org.apache.qpid.server.queue.QueueRegistry; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.virtualhost.VirtualHost; -import java.io.File; import java.io.ByteArrayInputStream; -import java.sql.DriverManager; -import java.sql.Driver; +import java.io.File; +import java.sql.Blob; import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.Driver; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.sql.Blob; +import java.sql.SQLException; +import java.sql.Statement; import java.sql.Types; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.List; import java.util.ArrayList; -import java.util.Map; import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; -public class DerbyMessageStore implements MessageStore +public class DerbyMessageStore extends AbstractMessageStore { private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); @@ -145,6 +147,8 @@ public class DerbyMessageStore implements MessageStore public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { + super.configure(virtualHost,base,config); + stateTransition(State.INITIAL, State.CONFIGURING); initialiseDriver(); @@ -167,12 +171,15 @@ public class DerbyMessageStore implements MessageStore } } + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); + createOrOpenDatabase(databasePath); // this recovers durable queues and persistent messages recover(); + stateTransition(State.RECOVERING, State.STARTED); } @@ -187,6 +194,7 @@ public class DerbyMessageStore implements MessageStore private void createOrOpenDatabase(final String environmentPath) throws SQLException { + //fixme this the _vhost name should not be added here. _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; Connection conn = newConnection(); @@ -309,7 +317,8 @@ public class DerbyMessageStore implements MessageStore { stateTransition(State.CONFIGURING, State.RECOVERING); - _logger.info("Recovering persistent state..."); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(null, false)); + StoreContext context = new StoreContext(); try @@ -324,9 +333,10 @@ public class DerbyMessageStore implements MessageStore beginTran(context); deliverMessages(context, queues); - _logger.info("Persistent state recovered successfully"); commitTran(context); + //Recovery Complete + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(null, false)); } finally { @@ -335,6 +345,7 @@ public class DerbyMessageStore implements MessageStore abortTran(context); } } + } catch (SQLException e) { @@ -342,6 +353,7 @@ public class DerbyMessageStore implements MessageStore throw new AMQException("Error recovering persistent state: " + e, e); } + } private Map loadQueues() throws SQLException, AMQException @@ -486,6 +498,8 @@ public class DerbyMessageStore implements MessageStore public void close() throws Exception { _closed.getAndSet(true); + + super.close(); } public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException @@ -1353,7 +1367,6 @@ public class DerbyMessageStore implements MessageStore public void process() throws AMQException { _queue.enqueue(_context, _message); - } } @@ -1371,7 +1384,6 @@ public class DerbyMessageStore implements MessageStore Connection conn = null; try { - if(inLocaltran) { conn = getConnection(context); @@ -1381,7 +1393,6 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); } - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); long maxId = 1; @@ -1390,15 +1401,10 @@ public class DerbyMessageStore implements MessageStore Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); - while (rs.next()) { - - - AMQShortString queueName = new AMQShortString(rs.getString(1)); - AMQQueue queue = queues.get(queueName); if (queue == null) { @@ -1406,6 +1412,9 @@ public class DerbyMessageStore implements MessageStore _virtualHost.getQueueRegistry().registerQueue(queue); queues.put(queueName, queue); + + //Log Recovery Start + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1004(String.valueOf(queue.getName()), true)); } long messageId = rs.getLong(2); @@ -1436,11 +1445,9 @@ public class DerbyMessageStore implements MessageStore } queueRecoveries.put(queueName, ++count); - } actions.add(new ProcessAction(queue, context, message)); - } for(ProcessAction action : actions) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 4691f02952..87ec66030d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -31,6 +31,10 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 +public class MemoryMessageStore extends AbstractMessageStore { private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -55,27 +59,18 @@ public class MemoryMessageStore implements MessageStore private final AtomicLong _messageId = new AtomicLong(1); private AtomicBoolean _closed = new AtomicBoolean(false); + private LogSubject _logSubject; - public void configure() + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { - _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); - _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); - _contentBodyMap = new ConcurrentHashMap>(DEFAULT_HASHTABLE_CAPACITY); - } + super.configure(virtualHost,base,config); - public void configure(String base, VirtualHostConfiguration config) - { int hashtableCapacity = config.getStoreConfiguration().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(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - configure(base, config); - } - public void close() throws Exception { _closed.getAndSet(true); @@ -89,6 +84,8 @@ public class MemoryMessageStore implements MessageStore _contentBodyMap.clear(); _contentBodyMap = null; } + + super.close(); } public void removeMessage(StoreContext context, Long messageId) throws AMQException -- cgit v1.2.1 From 5790989fd05cc3694fab20804f719f38093dfd55 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:40:25 +0000 Subject: QPID-2002 : Updates to Test ARs to correctly remove the CurrentActor on close. Update to CFAR to ensure that an Actor is set during shutdown. Update to TestLogActor's log Name and corrected CurrentActorTest's testname. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801573 13f79535-47bb-0310-9956-ffa450edef68 --- .../registry/ConfigurationFileApplicationRegistry.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 043c048f51..25202460c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -71,10 +71,25 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry initialiseVirtualHosts(); - // Startup complete pop the current actor + // Startup complete pop the current actor CurrentActor.remove(); } + @Override + public void close() throws Exception + { + //Set the Actor for Broker Shutdown + CurrentActor.set(new BrokerActor(_rootMessageLogger)); + try + { + super.close(); + } + finally + { + CurrentActor.remove(); + } + } + private void initialiseVirtualHosts() throws Exception { for (String name : _configuration.getVirtualHosts()) -- cgit v1.2.1 From c1dd3ceae904404af5e36bbddfd5a043e397fffe Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 09:43:12 +0000 Subject: QPID-2002 : Completion of BrokerLoggingTest, the shutdown tests have been excluded due to QPID-2031. An update to the LogMessages.vm templates and ApplicationRegistry was requried. This is because BrokerMessages is loaded before the ApplicationRegistry is initialised. As a result the NullApplicationRegistry is created which should not be used. The AR is loaded to discover the current Locale. There were a couple of options here. Either always use the Default Locale and have the AR loading set that or add the ability to check if the AR has been configured. I chose the latter as knowing if an AR exists may be useful for our testing framework. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801575 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 24 +++++++++--- .../qpid/server/registry/ApplicationRegistry.java | 24 +++++++++--- .../qpid/server/registry/IApplicationRegistry.java | 3 +- .../apache/qpid/server/transport/QpidAcceptor.java | 44 ++++++++++++++++++++++ 4 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 34125ae25a..ff604bdc82 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -52,6 +52,7 @@ 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.transport.QpidAcceptor; import java.io.File; import java.io.IOException; @@ -71,7 +72,7 @@ public class Main private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; public static final String QPID_HOME = "QPID_HOME"; private static final int IPV4_ADDRESS_LENGTH = 4; @@ -273,6 +274,11 @@ public class Main ApplicationRegistry.initialise(config); + // We have already loaded the BrokerMessages class by this point so we + // need to refresh the locale setting incase we had a different value in + // the configuration. + BrokerMessages.reload(); + // AR.initialise() sets its own actor so we now need to set the actor // for the remainder of the startup CurrentActor.set(new BrokerActor(config.getRootMessageLogger())); @@ -292,6 +298,8 @@ public class Main _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); + CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); + ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); // the MINA default is currently to use the pooled allocator although this may change in future @@ -400,7 +408,7 @@ public class Main bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); } - bind(acceptor, bindAddress, handler, sconfig); + bind(new QpidAcceptor(acceptor,"TCP"), bindAddress, handler, sconfig); //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); @@ -412,7 +420,7 @@ public class Main try { - bind(acceptor, new InetSocketAddress(config.getSSLPort()), handler, sconfig); + bind(new QpidAcceptor(acceptor, "TCP/SSL"), new InetSocketAddress(config.getSSLPort()), handler, sconfig); //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid.AMQP listening on SSL port " + config.getSSLPort()); @@ -427,6 +435,9 @@ public class Main //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); + + CurrentActor.get().message(BrokerMessages.BRK_1004()); + } catch (Exception e) { @@ -446,9 +457,11 @@ public class Main * * @throws IOException from the acceptor.bind command */ - private void bind(IoAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException + private void bind(QpidAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException { - acceptor.bind(bindAddress, handler, sconfig); + acceptor.getIoAcceptor().bind(bindAddress, handler, sconfig); + + CurrentActor.get().message(BrokerMessages.BRK_1002(acceptor.toString(), bindAddress.getPort())); ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor); } @@ -491,6 +504,7 @@ public class Main { if (logConfigFile.exists() && logConfigFile.canRead()) { + CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index edad8e53aa..b6137e83de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -26,7 +26,6 @@ import java.util.Map; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; -import org.apache.mina.common.IoAcceptor; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -36,7 +35,9 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.transport.QpidAcceptor; /** * An abstract application registry that provides access to configuration information and handles the @@ -58,7 +59,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; - protected final Map _acceptors = new HashMap(); + protected final Map _acceptors = new HashMap(); protected ManagedObjectRegistry _managedObjectRegistry; @@ -115,6 +116,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + public static boolean isConfigured() + { + return isConfigured(DEFAULT_INSTANCE); + } + + public static boolean isConfigured(int instanceID) + { + return _instanceMap.containsKey(instanceID); + } + /** * Method to cleanly shutdown the default registry running in this JVM */ @@ -236,6 +247,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } // _pluginManager.close(); + + CurrentActor.get().message(BrokerMessages.BRK_1005()); } private void unbind() @@ -244,8 +257,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { for (InetSocketAddress bindAddress : _acceptors.keySet()) { - IoAcceptor acceptor = _acceptors.get(bindAddress); - acceptor.unbind(bindAddress); + QpidAcceptor acceptor = _acceptors.get(bindAddress); + acceptor.getIoAcceptor().unbind(bindAddress); + CurrentActor.get().message(BrokerMessages.BRK_1003(acceptor.toString(), bindAddress.getPort())); } } } @@ -255,7 +269,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _configuration; } - public void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor) + public void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor) { synchronized (_acceptors) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 7d17639f22..ddb3fce5d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.mina.common.IoAcceptor; public interface IApplicationRegistry @@ -77,6 +78,6 @@ public interface IApplicationRegistry * @param bindAddress The address that the acceptor has been bound with * @param acceptor The acceptor in use */ - void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor); + void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java new file mode 100644 index 0000000000..61cc7cdeb6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.mina.common.IoAcceptor; + +public class QpidAcceptor +{ + IoAcceptor _acceptor; + String _protocol; + public QpidAcceptor(IoAcceptor acceptor, String protocol) + { + _acceptor = acceptor; + _protocol = protocol; + } + + public IoAcceptor getIoAcceptor() + { + return _acceptor; + } + + public String toString() + { + return _protocol; + } +} -- cgit v1.2.1 From a9f9562f9c8c868489af9fbd7b21c8c06ad803f3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 16:53:17 +0000 Subject: QPID-2002 : Add toString functionality to Filters for displaying in Subscription arguments. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801712 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/filter/JMSSelectorFilter.java | 6 +++++ .../qpid/server/filter/NoConsumerFilter.java | 6 +++++ .../qpid/server/filter/SimpleFilterManager.java | 28 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 96c9353872..4adf5eb9ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -53,4 +53,10 @@ public class JMSSelectorFilter implements MessageFilter { return _selector; } + + @Override + public String toString() + { + return "JMSSelector("+_selector+")"; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java index f1b3b2511d..65ddf19fc4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java @@ -39,4 +39,10 @@ public class NoConsumerFilter implements MessageFilter return true; } + @Override + public String toString() + { + return "NoConsumer"; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index cb738e1489..b037f57787 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; public class SimpleFilterManager implements FilterManager @@ -32,6 +31,7 @@ public class SimpleFilterManager implements FilterManager private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); private final ConcurrentLinkedQueue> _filters; + private String _toString = ""; public SimpleFilterManager() { @@ -42,11 +42,13 @@ public class SimpleFilterManager implements FilterManager public void add(MessageFilter filter) { _filters.add(filter); + updateStringValue(); } public void remove(MessageFilter filter) { _filters.remove(filter); + updateStringValue(); } public boolean allAllow(Filterable msg) @@ -74,4 +76,28 @@ public class SimpleFilterManager implements FilterManager { return !_filters.isEmpty(); } + + + @Override + public String toString() + { + return _toString; + } + + private void updateStringValue() + { + StringBuilder toString = new StringBuilder(); + for (MessageFilter filter : _filters) + { + toString.append(filter.toString()); + toString.append(","); + } + + if (_filters.size() > 0) + { + //Remove the last ',' + toString.deleteCharAt(toString.length()-1); + } + _toString = toString.toString(); + } } -- cgit v1.2.1 From eaea4f51a8925a985a4b41447aa70bb859117eaa Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 16:54:46 +0000 Subject: QPID-2002 : Added exclusive parameter to subscription.setQueue to allow improved logging. Value should be retained in the Subscription for MC display git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801715 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 2 +- .../src/main/java/org/apache/qpid/server/subscription/Subscription.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 763a0506e3..46b2cf8fb4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -296,7 +296,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (!isDeleted()) { - subscription.setQueue(this); + subscription.setQueue(this, exclusive); _subscriptionList.add(subscription); if (isDeleted()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 19eabce9ff..5001b0baf1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -46,7 +46,7 @@ public interface Subscription QueueEntry.SubscriptionAcquiredState getOwningState(); - void setQueue(AMQQueue queue); + void setQueue(AMQQueue queue, boolean exclusive); AMQChannel getChannel(); -- cgit v1.2.1 From 2961082abeeeaae95c18c1714368012c0b640b76 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 16:57:12 +0000 Subject: QPID-2002 : SubscriptionLogging Tests, update to SubscriptionImpl for new exclusive flag on setQueue git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801719 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/subscription/SubscriptionImpl.java | 70 +++++++++++++++------- 1 file changed, 50 insertions(+), 20 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 51da884d1e..a959944434 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -33,6 +33,10 @@ import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.SubscriptionMessages; +import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.subscription.Subscription; @@ -63,14 +67,14 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final AtomicReference _queueContext = new AtomicReference(null); private final ClientDeliveryMethod _deliveryMethod; private final RecordDeliveryMethod _recordMethod; - + private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); private final Lock _stateChangeLock; private static final AtomicLong idGenerator = new AtomicLong(0); // Create a simple ID that increments for ever new Subscription private final long _subscriptionID = idGenerator.getAndIncrement(); - + private LogSubject _logSubject; static final class BrowserSubscription extends SubscriptionImpl { @@ -278,7 +282,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage - + public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession, AMQShortString consumerTag, FieldTable arguments, boolean noLocal, FlowCreditManager creditManager, @@ -327,13 +331,51 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage - public synchronized void setQueue(AMQQueue queue) + public synchronized void setQueue(AMQQueue queue, boolean exclusive) { if(getQueue() != null) { throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); } _queue = queue; + + _logSubject = new SubscriptionLogSubject(this); + + if (CurrentActor.get().getRootMessageLogger(). + isMessageEnabled(CurrentActor.get(), _logSubject)) + { + // Get the string value of the filters + String filterLogString = null; + if (_filters != null && _filters.hasFilters()) + { + filterLogString = _filters.toString(); + } + + if (isAutoClose()) + { + if (filterLogString == null) + { + filterLogString = ""; + } + else + { + filterLogString += ","; + } + filterLogString += "AutoClose"; + } + + if (isBrowser()) + { + // We do not need to check for null here as all Browsers are AutoClose + filterLogString +=",Browser"; + } + + CurrentActor.get(). + message(_logSubject, + SubscriptionMessages.SUB_1001(filterLogString, + queue.isDurable() && exclusive, + filterLogString != null)); + } } public String toString() @@ -480,20 +522,8 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } - if (closed) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Called close() on a closed subscription"); - } - - return; - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing subscription (" + debugIdentity() + "):" + this); - } + //Log Subscription closed + CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_1002()); } public boolean isClosed() @@ -544,7 +574,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public AMQQueue getQueue() { - return _queue; + return _queue; } public void restoreCredit(final QueueEntry queueEntry) @@ -555,7 +585,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public void creditStateChanged(boolean hasCredit) { - + if(hasCredit) { if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) -- cgit v1.2.1 From 9129f2a0b1011347c8e0d35a1d24d65f2a934252 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 16:57:50 +0000 Subject: QPID-2002: Added Exchange Logging and test git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801720 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/AbstractExchange.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 247558bb34..bb70ce556b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -41,6 +41,10 @@ import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ExchangeMessages; +import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; +import org.apache.qpid.server.logging.LogSubject; public abstract class AbstractExchange implements Exchange, Managable { @@ -61,6 +65,9 @@ public abstract class AbstractExchange implements Exchange, Managable */ protected boolean _autoDelete; + //The logSubject for ths exchange + private LogSubject _logSubject; + /** * Abstract MBean class. This has some of the methods implemented from * management intrerface for exchanges. Any implementaion of an @@ -160,6 +167,10 @@ public abstract class AbstractExchange implements Exchange, Managable _ticket = ticket; _exchangeMbean = createMBean(); _exchangeMbean.register(); + _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); + + // Log Exchange creation + CurrentActor.get().message(ExchangeMessages.EXH_1001(String.valueOf(getType()), String.valueOf(name), durable)); } public boolean isDurable() @@ -183,6 +194,8 @@ public abstract class AbstractExchange implements Exchange, Managable { _exchangeMbean.unregister(); } + + CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_1002()); } public String toString() -- cgit v1.2.1 From 19df22c7e0600730febfaa1c89cf327dc84e98eb Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 17:00:04 +0000 Subject: QPID-2002 : Add Binding Logging Messages with test git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801723 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/ExchangeBinding.java | 21 ++++++++++++++------- .../apache/qpid/server/queue/ExchangeBindings.java | 4 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java index a2fcab9e73..7584a3b7cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java @@ -21,6 +21,10 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BindingMessages; +import org.apache.qpid.server.logging.subjects.BindingLogSubject; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; @@ -31,23 +35,26 @@ public class ExchangeBinding private final AMQShortString _routingKey; private final FieldTable _arguments; - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); + private LogSubject _logSubject; - ExchangeBinding(AMQShortString routingKey, Exchange exchange) - { - this(routingKey, exchange, EMPTY_ARGUMENTS); - } - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments) + ExchangeBinding(AMQShortString routingKey, Exchange exchange, AMQQueue queue, FieldTable arguments) { _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; _exchange = exchange; _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; + _logSubject = new BindingLogSubject(routingKey,exchange,queue); + + CurrentActor.get().message(_logSubject, BindingMessages.BND_1001(_arguments.toString(), arguments != null)); } + + void unbind(AMQQueue queue) throws AMQException { _exchange.deregisterQueue(_routingKey, queue, _arguments); + + CurrentActor.get().message(_logSubject, BindingMessages.BND_1002()); } public Exchange getExchange() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java index fb839c1783..89262aee59 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -52,13 +52,13 @@ class ExchangeBindings */ void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - _bindings.add(new ExchangeBinding(routingKey, exchange, arguments)); + _bindings.add(new ExchangeBinding(routingKey, exchange, _queue, arguments)); } public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) { - return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments)); + return _bindings.remove(new ExchangeBinding(routingKey, exchange, _queue, arguments)); } -- cgit v1.2.1 From d793cd4d6d1873af383a8f1dbd2aa4383f0be546 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 6 Aug 2009 17:01:48 +0000 Subject: QPID-2002, QPID-2001 : Add new SubscriptionActor to perform Subscription close logging on the Subscription Flush thread. Alternative would be to create a Virtualhost Logger. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@801725 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/actors/SubscriptionActor.java | 42 ++++++++++++++++++++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 15 ++++---- .../qpid/server/subscription/Subscription.java | 3 +- .../qpid/server/subscription/SubscriptionImpl.java | 10 +++++- 4 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java new file mode 100644 index 0000000000..ab33a29eac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.subscription.Subscription; + +import java.text.MessageFormat; + +public class SubscriptionActor extends AbstractActor +{ + public static String SUBSCRIBER_FORMAT = "sub:{0}(vh({1})/qu({2}))"; + + public SubscriptionActor(RootMessageLogger logger, Subscription subscription) + { + super(logger); + + _logString = "[" + MessageFormat.format(SUBSCRIBER_FORMAT, + subscription.getSubscriptionID(), + subscription.getQueue().getVirtualHost().getName(), + subscription.getQueue().getName()) + + "] "; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 46b2cf8fb4..929045599b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -236,15 +236,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _bindings.addBinding(routingKey, arguments, exchange); -// ExchangeBinding binding = new ExchangeBinding(routingKey, exchange, arguments); - - //fixme MR logging in progress -// _bindings.addBinding(binding); -// -// if (_logger.isMessageEnabled(binding)) -// { -// _logger.message(binding, "QM-1001 : Created Binding"); -// } } public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException @@ -1238,6 +1229,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean complete = false; try { + CurrentActor.set(_sub.getLogActor()); complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); } @@ -1245,11 +1237,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _logger.error(e); } + finally + { + CurrentActor.remove(); + } if (!complete && !_sub.isSuspended()) { _asyncDelivery.execute(this); } + } public boolean isRead() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 5001b0baf1..c9042325bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -23,12 +23,13 @@ package org.apache.qpid.server.subscription; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; public interface Subscription { - + LogActor getLogActor(); public static enum State { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index a959944434..54bd568bca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -34,12 +34,13 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; @@ -75,6 +76,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage // Create a simple ID that increments for ever new Subscription private final long _subscriptionID = idGenerator.getAndIncrement(); private LogSubject _logSubject; + private LogActor _logActor; static final class BrowserSubscription extends SubscriptionImpl { @@ -340,6 +342,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _queue = queue; _logSubject = new SubscriptionLogSubject(this); + _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); if (CurrentActor.get().getRootMessageLogger(). isMessageEnabled(CurrentActor.get(), _logSubject)) @@ -572,6 +575,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _channel.getProtocolSession(); } + public LogActor getLogActor() + { + return _logActor; + } + public AMQQueue getQueue() { return _queue; -- cgit v1.2.1 From d842936d7be5778499dcd0c204eca8150b84819b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 Aug 2009 18:03:56 +0000 Subject: QPID-2002 : MessageStore Logging updates to include queue counts from persistent stores git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802113 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 33 +++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 90de1aa8fa..c014739324 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -95,6 +95,7 @@ public class DerbyMessageStore extends AbstractMessageStore private String _connectionURL; + Map _queueRecoveries = new TreeMap(); private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; @@ -380,6 +381,11 @@ public class DerbyMessageStore extends AbstractMessageStore } queueMap.put(queueNameShortString,q); + + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(String.valueOf(q.getName()), true)); + + //Record that we have a queue for recovery + _queueRecoveries.put(new AMQShortString(queueName), 0); } return queueMap; @@ -1378,7 +1384,6 @@ public class DerbyMessageStore extends AbstractMessageStore Map msgMap = new HashMap(); List actions = new ArrayList(); - Map queueRecoveries = new TreeMap(); final boolean inLocaltran = inTran(context); Connection conn = null; @@ -1436,17 +1441,14 @@ public class DerbyMessageStore extends AbstractMessageStore _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); } - if (_logger.isInfoEnabled()) + Integer count = _queueRecoveries.get(queueName); + if (count == null) { - Integer count = queueRecoveries.get(queueName); - if (count == null) - { - count = 0; - } - - queueRecoveries.put(queueName, ++count); + count = 0; } + _queueRecoveries.put(queueName, ++count); + actions.add(new ProcessAction(queue, context, message)); } @@ -1472,8 +1474,19 @@ public class DerbyMessageStore extends AbstractMessageStore if (_logger.isInfoEnabled()) { - _logger.info("Recovered message counts: " + queueRecoveries); + _logger.info("Recovered message counts: " + _queueRecoveries); } + + for(Map.Entry entry : _queueRecoveries.entrySet()) + { + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1005(entry.getValue(), String.valueOf(entry.getKey()))); + + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(String.valueOf(entry.getKey()), true)); + } + + // Free the memory + _queueRecoveries = null; + } private Connection getConnection(final StoreContext context) -- cgit v1.2.1 From 822b3505a908f6042017cb057d197659e0f6c9f2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 Aug 2009 18:13:47 +0000 Subject: QPID-2002: Broker Start messages were not being printed at earlier enough. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802127 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java | 2 -- .../qpid/server/registry/ConfigurationFileApplicationRegistry.java | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index ff604bdc82..eac027afc6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -298,8 +298,6 @@ public class Main _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); - ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); // the MINA default is currently to use the pooled allocator although this may change in future diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 25202460c0..a049d1eb09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -22,8 +22,10 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.AMQException; +import org.apache.qpid.common.QpidProperties; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; @@ -53,6 +55,8 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry // Set the Actor for current log messages CurrentActor.set(new BrokerActor(_rootMessageLogger)); + CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); + initialiseManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(this); -- cgit v1.2.1 From 2687de858888b2fd2b9ac8ccf2b17359c016b555 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 Aug 2009 18:14:30 +0000 Subject: QPID-2002 : Addition of Management Logging git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802128 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/management/JMXManagedObjectRegistry.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 5a113de5be..38272db845 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -27,6 +27,8 @@ import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; import javax.management.JMException; import javax.management.MBeanServer; @@ -91,6 +93,9 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry public void start() throws IOException, ConfigurationException { + + CurrentActor.get().message(ManagementConsoleMessages.MNG_1001()); + //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) { @@ -160,6 +165,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); + + CurrentActor.get().message(ManagementConsoleMessages.MNG_1006(ksf.getAbsolutePath())); } //check the key store password is set @@ -186,6 +193,10 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry (port +PORT_EXPORT_OFFSET) + ") with SSL"); _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + (port +PORT_EXPORT_OFFSET) + ") with SSL"); + + CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("SSL RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + } else { @@ -195,6 +206,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server @@ -233,7 +246,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry try { //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent - _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); + _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); } catch (AlreadyBoundException abe) { @@ -263,6 +276,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); cs.setMBeanServerForwarder(mbsf); cs.start(); + + CurrentActor.get().message(ManagementConsoleMessages.MNG_1004()); } /* @@ -366,6 +381,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage()); } } + + CurrentActor.get().message(ManagementConsoleMessages.MNG_1005()); } } -- cgit v1.2.1 From e78fb963c19eaa78108ad2c54798627bb53eca6d Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 9 Aug 2009 21:06:47 +0000 Subject: QPID-2015: Add 2 new methods to the VirtualHostManager to retrieve attribute names/values for every Queue in the vhost in a single call. Remove previous viewQueueNamesDepths() method. Add new ManagedQueue attribute names constants, and a test to ensure any attributes added to the Queue MBeans in future are also added to the constants. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802601 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 67 ++++++++++++++++++---- .../org/apache/qpid/server/queue/AMQQueue.java | 3 + 2 files changed, 58 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 306dce1057..14f64d2879 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -39,8 +39,8 @@ package org.apache.qpid.server; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import java.util.Collections; +import java.util.List; import javax.management.JMException; import javax.management.MBeanException; @@ -50,6 +50,7 @@ import javax.management.ObjectName; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.exchange.Exchange; @@ -60,6 +61,7 @@ import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.AMQQueueMBean; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -114,26 +116,67 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } /** - * Returns a Map keyed by QueueName, detailing its associated QueueDepth in bytes. + * Returns a list containing the names of the attributes available for the Queue mbeans. * @since Qpid JMX API 1.3 * @throws IOException */ - public Map viewQueueNamesDepths() throws IOException + public List retrieveQueueAttributeNames() throws IOException { - Map queueDepthMap = new HashMap(_queueRegistry.getQueues().size()); + List attributeList = new ArrayList(); + for(String attr : ManagedQueue.QUEUE_ATTRIBUTES) + { + attributeList.add(attr); + } - String queueName; - Long queueDepth; + Collections.sort(attributeList); + return attributeList; + } + + /** + * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost. + * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-". + * @since Qpid JMX API 1.3 + * @throws IOException + */ + public List> retrieveQueueAttributeValues(String[] attributes) throws IOException + { + if(_queueRegistry.getQueues().size() == 0) + { + return new ArrayList>(); + } + + List> queueAttributesList = new ArrayList>(_queueRegistry.getQueues().size()); + + int attributesLength = attributes.length; + for(AMQQueue queue : _queueRegistry.getQueues()) { - queueName = queue.getName().toString(); - queueDepth = queue.getQueueDepth(); + AMQQueueMBean mbean = (AMQQueueMBean) queue.getManagedObject(); - queueDepthMap.put(queueName,queueDepth); + if(mbean == null) + { + continue; + } + + List attributeValues = new ArrayList(attributesLength); + + for(int i=0; i < attributesLength; i++) + { + try + { + attributeValues.add(mbean.getAttribute(attributes[i])); + } + catch (Exception e) + { + attributeValues.add(new String("-")); + } + } + + queueAttributesList.add(attributeValues); } - - return queueDepthMap; + + return queueAttributesList; } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 4643326df3..2a692344d0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; @@ -228,4 +229,6 @@ public interface AMQQueue extends Managable, Comparable } void configure(QueueConfiguration config); + + ManagedObject getManagedObject(); } -- cgit v1.2.1 From 8bb3446353548453b09fbd5718469d4b8bd34f4f Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 9 Aug 2009 21:33:15 +0000 Subject: QPID-2036: replace the getMessagesRangeOnTheQueue() implementation with a QueueEntryFilter based version that correctly excludes the final message if it has been deleted, and is in general easier to reason about than the previous version git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802615 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 37 +++++++++------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 929045599b..43790b59d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -852,30 +852,23 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener */ public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) { - List queueEntries = new ArrayList(); - - QueueEntryIterator it = _entries.iterator(); - - long index = 1; - for ( ; index < fromPosition && !it.atTail(); index++) - { - it.advance(); - } - - if(index < fromPosition) - { - //The queue does not contain enough entries to reach our range. - //return the empty list. - return queueEntries; - } - - for ( ; index <= toPosition && !it.atTail(); index++) + List entries = getMessagesOnTheQueue(new QueueEntryFilter() { - it.advance(); - queueEntries.add(it.getNode()); - } + private long position = 0; + + public boolean accept(QueueEntry entry) + { + position++; + return (position >= fromPosition) && (position <= toPosition); + } - return queueEntries; + public boolean filterComplete() + { + return position >= toPosition; + } + }); + + return entries; } public void moveMessagesToAnotherQueue(final long fromMessageId, -- cgit v1.2.1 From 335e875366d7cb8775c623e3541b2976172ebd12 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Sun, 9 Aug 2009 23:26:10 +0000 Subject: QPID-2002 : Added new message CHN-1004, to allow the reporting of prefetch sizes. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802625 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 3 +-- .../apache/qpid/server/logging/messages/LogMessages_en_US.properties | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 2a46ee53b4..add5e64ee8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -884,8 +884,7 @@ public class AMQChannel public void setCredit(final long prefetchSize, final int prefetchCount) { - //fixme -// _actor.message(ChannelMessages.CHN_100X(prefetchSize, prefetchCount); + _actor.message(ChannelMessages.CHN_1004(prefetchSize, prefetchCount)); _creditManager.setCreditLimits(prefetchSize, prefetchCount); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 24df17683f..d2a5810f3b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -240,10 +240,12 @@ CON-1002 = Close #Channel CHN-1001 = Create -# : Prefetch Size {0,number} : Count {1,number} # 0 - flow CHN-1002 = Flow {0} CHN-1003 = Close +# 0 - bytes allowed in prefetch +# 1 - number of messagse. +CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} #Queue # 0 - owner -- cgit v1.2.1 From 0c73c218cf7428d87e0df8c2552b3a1f1738f071 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Sun, 9 Aug 2009 23:26:38 +0000 Subject: Removed Java 6 dependency on Deque. Used Stack instead. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802626 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/CurrentActor.java | 57 ++++++++++++---------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java index 374550a72b..df4da2a79e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java @@ -22,8 +22,8 @@ package org.apache.qpid.server.logging.actors; import org.apache.qpid.server.logging.LogActor; -import java.util.LinkedList; -import java.util.Deque; +import java.util.EmptyStackException; +import java.util.Stack; /** * The CurrentActor is a ThreadLocal wrapper that allows threads in the broker @@ -31,78 +31,81 @@ import java.util.Deque; * reasons: * 1) We do not have to pass a logging actor around the system * 2) We can set new actors at the point we have enough information. i.e. - * - Set a low level ConnectionActor when processing bytes from the wire. - * - Set a ChannelActor when we are processing the frame - * - Set a SubscriptionActor when we are handling the subscription. - * + * - Set a low level ConnectionActor when processing bytes from the wire. + * - Set a ChannelActor when we are processing the frame + * - Set a SubscriptionActor when we are handling the subscription. + *

      * The code performing the logging need not worry about what type of actor is * currently set so can perform its logging. The resulting log entry though will * contain customised details from the the currently set Actor. - * + *

      * The Actor model also allows the pre-creation of fixed messages so the * performance impact of the additional logging data is minimised. - * + *

      * This class does not perform any checks to ensure that there is an Actor set * when calling remove or get. As a result the application developer must ensure * that they have called set before they attempt to use the actor via get or * remove the set actor. - * + *

      * The checking of the return via get should not be done as the logging is * desired. It is preferable to cause the NullPointerException to highlight the * programming error rather than miss a log message. - * + *

      * The same is true for the remove. A NPE will occur if no set has been called * highlighting the programming error. - * */ public class CurrentActor { - /** - * The ThreadLocal variable with initialiser - */ - private static final ThreadLocal> _currentActor = new ThreadLocal>() + /** The ThreadLocal variable with initialiser */ + private static final ThreadLocal> _currentActor = new ThreadLocal>() { // Initialise the CurrentActor to be an empty List - protected Deque initialValue() + protected Stack initialValue() { - return new LinkedList(); + return new Stack(); } }; /** * Set a new LogActor to be the Current Actor - * + *

      * This pushes the Actor in to the LIFO Queue * * @param actor The new LogActor */ public static void set(LogActor actor) { - Deque stack = _currentActor.get(); - stack.addFirst(actor); + Stack stack = _currentActor.get(); + stack.push(actor); } /** * Remove the current LogActor. - * - * Calling remove without calling set will result in a NoSuchElementException. - * + *

      + * Calling remove without calling set will result in an EmptyStackException. */ public static void remove() { - Deque stack = _currentActor.get(); - stack.removeFirst(); + Stack stack = _currentActor.get(); + stack.pop(); } /** * Return the current head of the list of LogActors. - * + *

      * If there has been no set call then this will return Null. * * @return Current LogActor */ public static LogActor get() { - return _currentActor.get().peek(); + try + { + return _currentActor.get().peek(); + } + catch (EmptyStackException ese) + { + return null; + } } } -- cgit v1.2.1 From 22b938c17b8dfb181e84784e6467f936422119e1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Sun, 9 Aug 2009 23:27:09 +0000 Subject: QPID-2002 : Add VirtualHost logging and testing, again shutdown testing must be excluded due to the way we stop test brokers. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802627 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/virtualhost/VirtualHost.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index ad1e8a580e..fa6b2285eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -29,6 +29,9 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.configuration.ExchangeConfiguration; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; @@ -155,6 +158,8 @@ public class VirtualHost implements Accessable _configuration = hostConfig; _name = hostConfig.getName(); + CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); + if (_name == null || _name.length() == 0) { throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); @@ -427,6 +432,8 @@ public class VirtualHost implements Accessable { _messageStore.close(); } + + CurrentActor.get().message(VirtualHostMessages.VHT_1002()); } public ManagedObject getBrokerMBean() -- cgit v1.2.1 From 9d4cbbe253442fc625a4d2bf61314df7fa26e842 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 10 Aug 2009 15:01:01 +0000 Subject: QPID-2018: Updated AMQQueueMBean to make use of the AMQQueue clearQueue return value to report the number of messages deleted. Updated management console accordingly, also indicating that it is only non-acquired messaes that are cleared git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@802819 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index e450a2060e..d340c9a91f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -307,13 +307,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que } /** + * Clears the queue of non-acquired messages + * + * @return the number of messages deleted * @see AMQQueue#clearQueue */ - public void clearQueue() throws JMException + public Long clearQueue() throws JMException { try { - _queue.clearQueue(_storeContext); + return _queue.clearQueue(_storeContext); } catch (AMQException ex) { -- cgit v1.2.1 From 93a5650c98e345deb4e50204a7ac65f0eb19482d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 17:59:08 +0000 Subject: QPID-2002 : Added test to ensure that the ResourceBundle is loadable even if the current Locale is not one that has a specific file. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803630 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/messages/LogMessages.properties | 102 +++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties new file mode 100644 index 0000000000..15ab56bcec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -0,0 +1,102 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +#Broker +# 0 - Version +# 1 = Build +BRK-1001 = Startup : Version: {0} Build: {1} +# 0 - Transport +# 1 - Port +BRK-1002 = Starting : Listening on {0} port {1,number,#} +# 0 - Transport +# 1 - Port +BRK-1003 = Shuting down : {0} port {1,number,#} +BRK-1004 = Ready +BRK-1005 = Stopped +# 0 - path +BRK-1006 = Using configuration : {0} +# 0 - path +BRK-1007 = Using logging configuration : {0} + +#ManagementConsole +MNG-1001 = Startup +# 0 - Service +# 1 - Port +MNG-1002 = Starting : {0} : Listening on port {1,number,#} +# 0 - Service +# 1 - Port +MNG-1003 = Shuting down : {0} : port {1,number,#} +MNG-1004 = Ready +MNG-1005 = Stopped +# 0 - Path +MNG-1006 = Using SSL Keystore : {0} + +#VirtualHost +# 0 - name +VHT-1001 = Created : {0} +VHT-1002 = Closed + +#MessageStore +# 0 - name +MST-1001 = Created : {0} +# 0 - path +MST-1002 = Store location : {0} +MST-1003 = Closed +# 0 - queue name +MST-1004 = Recovery Start[ : {0}] +# 0 - count +# 1 - queue count +MST-1005 = Recovered {0,number} messages for queue {1} +# 0 - queue name +MST-1006 = Recovery Complete[ : {0}] + +#Connection +# 0 - Client id +# 1 - Protocol Version +CON-1001 = Open[ : Client ID : {0}][ : Protocol Version : {1}] +CON-1002 = Close + +#Channel +CHN-1001 = Create +# 0 - flow +CHN-1002 = Flow {0} +CHN-1003 = Close +# 0 - bytes allowed in prefetch +# 1 - number of messagse. +CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} + +#Queue +# 0 - owner +# 1 - priority +QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +QUE-1002 = Deleted + +#Exchange +# 0 - type +# 1 - name +EXH-1001 = Create :[ Durable] Type: {0} Name: {1} +EXH-1002 = Deleted + +#Binding +BND-1001 = Create[ : Arguments : {0}] +BND-1002 = Deleted + +#Subscription +SUB-1001 = Create[ : Durable][ : Arguments : {0}] +SUB-1002 = Close -- cgit v1.2.1 From 7f0ceb58143f90dd12d3504e211eb2054c25f488 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:03:00 +0000 Subject: QPID-2002 : Made owner an optional value on the queue log message Update tests to ensure Owner is not present git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803635 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/messages/LogMessages.properties | 2 +- .../apache/qpid/server/logging/messages/LogMessages_en_US.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index 15ab56bcec..2cd2149712 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -84,7 +84,7 @@ CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} #Queue # 0 - owner # 1 - priority -QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted #Exchange diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index d2a5810f3b..5fc8c82e15 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -250,7 +250,7 @@ CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} #Queue # 0 - owner # 1 - priority -QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted #Exchange -- cgit v1.2.1 From 4c86290c98f282e053b90ae9236651c9422bc4c3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:04:17 +0000 Subject: Updated SAMQQ to only display owner when it is non-null git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803636 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 43790b59d7..82dd4b0195 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -170,6 +170,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener CurrentActor.get().message(_logSubject, QueueMessages.QUE_1001(String.valueOf(_owner), priorities, + _owner != null, autoDelete, durable, !durable, priorities > 0)); -- cgit v1.2.1 From 0a0eb533a2de22c0c27732034e97be617e361e2f Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:05:34 +0000 Subject: QPID-2002 : Addition of a QueueActor to be set during running of the processQueue thread Made QueueLogSubject public so it can be reused by QueueActor Updated SAMQQ to create a QueueActor for use during the processQueue thread run git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803638 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/QueueActor.java | 52 ++++++++++++++++++++++ .../server/logging/subjects/QueueLogSubject.java | 4 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 10 +++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java new file mode 100644 index 0000000000..acac447ff6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.subjects.QueueLogSubject; +import org.apache.qpid.server.queue.AMQQueue; + +import java.text.MessageFormat; + +/** + * This Actor is used when while the queue is performing an asynchronous process + * of its queue. + */ +public class QueueActor extends AbstractActor +{ + + /** + * Create an QueueLogSubject that Logs in the following format. + * + * @param queue The queue that this Actor is working for + * @param rootLogger the Root logger to use. + */ + public QueueActor(AMQQueue queue, RootMessageLogger rootLogger) + { + super(rootLogger); + + _logString = "[" + MessageFormat.format(QueueLogSubject.LOG_FORMAT, + queue.getVirtualHost().getName(), + queue.getName()) + "] "; + + } +} + \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java index 89f31ef477..b132d9e93f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -33,12 +33,12 @@ public class QueueLogSubject extends AbstractLogSubject * 0 - Virtualhost name * 1 - queue name */ - protected static String BINDING_FORMAT = "vh(/{0})/qu({1})"; + public static String LOG_FORMAT = "vh(/{0})/qu({1})"; /** Create an QueueLogSubject that Logs in the following format. */ public QueueLogSubject(AMQQueue queue) { - setLogStringWithFormat(BINDING_FORMAT, + setLogStringWithFormat(LOG_FORMAT, queue.getVirtualHost().getName(), queue.getName()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 82dd4b0195..b14b92b014 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -30,8 +30,10 @@ import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.QueueActor; import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.messages.QueueMessages; /* @@ -118,6 +120,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); private LogSubject _logSubject; + private LogActor _logActor; protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -154,6 +157,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); _logSubject = new QueueLogSubject(this); + _logActor = new QueueActor(this, CurrentActor.get().getRootMessageLogger()); // Log the correct creation message @@ -1189,12 +1193,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { try { + CurrentActor.set(_logActor); processQueue(this); } catch (AMQException e) { _logger.error(e); } + finally + { + CurrentActor.remove(); + } + } -- cgit v1.2.1 From 19551c7503e23bfc655df20e366b8a9324a700c6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:06:35 +0000 Subject: QPID-2002 : Added new SUB-1003 Message with testing git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803639 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/messages/LogMessages.properties | 2 ++ .../apache/qpid/server/logging/messages/LogMessages_en_US.properties | 1 + .../main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java | 2 ++ 3 files changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index 2cd2149712..3380bf2aa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -100,3 +100,5 @@ BND-1002 = Deleted #Subscription SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close +# 0 - The current subscription state +SUB-1003 = State : {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 5fc8c82e15..6d358652b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -266,3 +266,4 @@ BND-1002 = Deleted #Subscription SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close +SUB-1003 = State : {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 54bd568bca..b34ef1c382 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -599,6 +599,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) { _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); } else { @@ -611,6 +612,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) { _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); } } } -- cgit v1.2.1 From 20ddeae6df6f62505b11339d049ab36561bd0f04 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:14:26 +0000 Subject: QPID-2002 : Added Logging of management console connection open and close events git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803647 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/messages/LogMessages.properties | 3 ++ .../logging/messages/LogMessages_en_US.properties | 3 ++ .../management/JMXManagedObjectRegistry.java | 18 ++++++++++++ .../management/MBeanInvocationHandlerImpl.java | 33 +++++++++++++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index 3380bf2aa6..eafcb43cc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -46,6 +46,9 @@ MNG-1004 = Ready MNG-1005 = Stopped # 0 - Path MNG-1006 = Using SSL Keystore : {0} +MNG-1007 = Open : User {0} +MNG-1008 = Close + #VirtualHost # 0 - name diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 6d358652b8..5ced7cc0b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -212,6 +212,9 @@ MNG-1004 = Ready MNG-1005 = Stopped # 0 - Path MNG-1006 = Using SSL Keystore : {0} +MNG-1007 = Open : User {0} +MNG-1008 = Close + #VirtualHost # 0 - name diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 38272db845..5ffcee77f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -34,9 +34,16 @@ import javax.management.JMException; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; +import javax.management.NotificationListener; +import javax.management.MalformedObjectNameException; +import javax.management.NotificationFilter; +import javax.management.NotificationFilterSupport; +import javax.management.InstanceNotFoundException; +import javax.management.relation.MBeanServerNotificationFilter; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.JMXConnectionNotification; import javax.management.remote.rmi.RMIConnectorServer; import javax.management.remote.rmi.RMIJRMPServerImpl; import javax.management.remote.rmi.RMIServerImpl; @@ -47,6 +54,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.management.ManagementFactory; +import java.lang.reflect.Proxy; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; @@ -275,8 +283,18 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); cs.setMBeanServerForwarder(mbsf); + + NotificationFilterSupport filter = new NotificationFilterSupport(); + filter.enableType(JMXConnectionNotification.OPENED); + filter.enableType(JMXConnectionNotification.CLOSED); + filter.enableType(JMXConnectionNotification.FAILED); + // Get the handler that is used by the above MBInvocationHandler Proxy. + // which is the MBeanInvocationHandlerImpl and so also a NotificationListener + cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null); + cs.start(); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1004()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index a68934d358..20410ba5ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -23,15 +23,23 @@ package org.apache.qpid.server.management; import org.apache.qpid.management.common.mbeans.ConfigurationManagement; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.logging.messages.ConnectionMessages; +import org.apache.qpid.server.logging.LogActor; import org.apache.log4j.Logger; import javax.management.remote.MBeanServerForwarder; import javax.management.remote.JMXPrincipal; +import javax.management.remote.JMXConnectionNotification; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.JMException; +import javax.management.NotificationListener; +import javax.management.Notification; import javax.security.auth.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; @@ -49,7 +57,7 @@ import java.util.Properties; * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite * and admin users. */ -public class MBeanInvocationHandlerImpl implements InvocationHandler +public class MBeanInvocationHandlerImpl implements InvocationHandler, NotificationListener { private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); @@ -59,6 +67,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; private MBeanServer _mbs; private static Properties _userRoles = new Properties(); + private static ManagementActor _logActor; private static HashSet _adminOnlyMethods = new HashSet(); { @@ -72,6 +81,9 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler final InvocationHandler handler = new MBeanInvocationHandlerImpl(); final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + + _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); + Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); return MBeanServerForwarder.class.cast(proxy); } @@ -254,4 +266,23 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler return false; } + + public void handleNotification(Notification notification, Object handback) + { + // only RMI Connections are serviced here, Local API atta + // rmi://169.24.29.116 guest 3 + String[] connectionData = ((JMXConnectionNotification) notification).getConnectionId().split(" "); + String user = connectionData[1]; + + if (notification.getType().equals(JMXConnectionNotification.OPENED)) + { + _logActor.message(ManagementConsoleMessages.MNG_1007(user)); + } + else if (notification.getType().equals(JMXConnectionNotification.CLOSED) || + notification.getType().equals(JMXConnectionNotification.FAILED)) + { + _logActor.message(ManagementConsoleMessages.MNG_1008()); + } + } } + -- cgit v1.2.1 From 3cd183b2e170ab0c7f190ff45a0a55bcd3478007 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:15:21 +0000 Subject: QPID-2002 : Updated ManagementActor to derive logString from the current thread git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803648 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/actors/ManagementActor.java | 68 +++++++++++++++++----- 1 file changed, 55 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java index 58d55a13bb..2ad0f69fd6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java @@ -20,13 +20,27 @@ */ package org.apache.qpid.server.logging.actors; +import org.apache.qpid.server.logging.LogMessage; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.RootMessageLogger; import java.text.MessageFormat; -import java.security.Principal; +/** + * NOTE: This actor is not thread safe. + * + * Sharing of a ManagementActor instance between threads may result in an + * incorrect actor value being logged. + * + * This is due to the fact that calls to message will dynamically query the + * thread name and use that to set the log format during each message() call. + * + * This is currently not an issue as each MBean operation creates a new Actor + * that is unique for each operation. + */ public class ManagementActor extends AbstractActor { + String _lastThreadName = null; /** * LOG FORMAT for the ManagementActor, @@ -37,21 +51,49 @@ public class ManagementActor extends AbstractActor * 1 - User ID * 2 - IP */ - public static final String MANAGEMENT_FORMAT = "mng:{0}({1}@{2})"; + public static final String MANAGEMENT_FORMAT = "mng:{0}({1})"; - /** - * //todo Correct interface to provide connection details - * @param user - * @param rootLogger The RootLogger to use for this Actor - */ - public ManagementActor(Principal user, RootMessageLogger rootLogger) + /** @param rootLogger The RootLogger to use for this Actor */ + public ManagementActor(RootMessageLogger rootLogger) { super(rootLogger); - _logString = "["+ MessageFormat.format(MANAGEMENT_FORMAT, - "", - user.getName(), - "") - + "] "; } + + private void updateLogString() + { + String currentName = Thread.currentThread().getName(); + + // Record the last thread name so we don't have to recreate the log string + if (!currentName.equals(_lastThreadName)) + { + _lastThreadName = currentName; + + System.err.println(currentName); + // Management Threads have this format. + //RMI TCP Connection(2)-169.24.29.116 + String connectionID = currentName.split("\\(")[1].split("\\)")[0]; + String ip = currentName.split("-")[1]; + + _logString = "[" + MessageFormat.format(MANAGEMENT_FORMAT, + connectionID, + ip) + + "] "; + } + } + + @Override + public void message(LogSubject subject, LogMessage message) + { + updateLogString(); + super.message(subject, message); + } + + @Override + public void message(LogMessage message) + { + updateLogString(); + super.message(message); + } + } -- cgit v1.2.1 From 0f4bde67479c5ee459cd2687903f932bcd0dd8c6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:17:26 +0000 Subject: QPID-2002 : Addition of JMX Management interface logging using the new Logging Interfaces git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803649 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 24 ++++++++++++- .../qpid/server/exchange/DirectExchange.java | 7 ++++ .../qpid/server/exchange/FanoutExchange.java | 7 ++++ .../apache/qpid/server/exchange/TopicExchange.java | 7 ++++ .../qpid/server/management/AMQManagedObject.java | 9 +++++ .../server/protocol/AMQMinaProtocolSession.java | 2 +- .../server/protocol/AMQProtocolSessionMBean.java | 39 +++++++++++++--------- .../apache/qpid/server/queue/ExchangeBinding.java | 2 +- 8 files changed, 79 insertions(+), 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 14f64d2879..2afd3c1dc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -65,6 +65,8 @@ import org.apache.qpid.server.queue.AMQQueueMBean; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; /** * This MBean implements the broker management interface and exposes the @@ -79,7 +81,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final MessageStore _messageStore; private final VirtualHost.VirtualHostMBean _virtualHostMBean; - + @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException { @@ -189,6 +191,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr */ public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException { + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { synchronized (_exchangeRegistry) @@ -210,6 +213,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { throw new MBeanException(ex, "Error in creating exchange " + exchangeName); } + finally + { + CurrentActor.remove(); + } } /** @@ -225,6 +232,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr // boolean inUse = false; // Check if there are queue-bindings with the exchange and unregister // when there are no bindings. + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); @@ -233,6 +241,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); } + finally + { + CurrentActor.remove(); + } } /** @@ -252,6 +264,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr throw new JMException("The queue \"" + queueName + "\" already exists."); } + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { AMQShortString ownerShortString = null; @@ -275,6 +288,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr jme.initCause(ex); throw new MBeanException(jme, "Error in creating queue " + queueName); } + finally + { + CurrentActor.remove(); + } } private VirtualHost getVirtualHost() @@ -296,6 +313,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr throw new JMException("The Queue " + queueName + " is not a registerd queue."); } + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { queue.delete(); @@ -308,6 +326,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr jme.initCause(ex); throw new MBeanException(jme, "Error in deleting queue " + queueName); } + finally + { + CurrentActor.remove(); + } } public ManagedObject getParentObject() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 4b609f592b..3567cdff85 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -43,6 +43,8 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; public class DirectExchange extends AbstractExchange { @@ -129,6 +131,7 @@ public class DirectExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { queue.bind(DirectExchange.this, new AMQShortString(binding), null); @@ -137,6 +140,10 @@ public class DirectExchange extends AbstractExchange { throw new MBeanException(ex); } + finally + { + CurrentActor.remove(); + } } }// End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index fcaec8bdd0..7fa438587c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -31,6 +31,8 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; import javax.management.MBeanException; @@ -102,6 +104,7 @@ public class FanoutExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { queue.bind(FanoutExchange.this, new AMQShortString(BINDING_KEY_SUBSTITUTE), null); @@ -110,6 +113,10 @@ public class FanoutExchange extends AbstractExchange { throw new MBeanException(ex); } + finally + { + CurrentActor.remove(); + } } } // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index be7a1dc196..31db1148c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -37,6 +37,8 @@ import org.apache.qpid.server.exchange.topic.TopicParser; import org.apache.qpid.server.exchange.topic.TopicMatcherResult; import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.filter.JMSSelectorFilter; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; import javax.management.MBeanException; @@ -351,6 +353,7 @@ public class TopicExchange extends AbstractExchange throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); } + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { queue.bind(TopicExchange.this, new AMQShortString(binding), null); @@ -359,6 +362,10 @@ public class TopicExchange extends AbstractExchange { throw new MBeanException(ex); } + finally + { + CurrentActor.remove(); + } } } // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java index c6e07f6f48..594ae24502 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.server.management; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.LogActor; + import javax.management.ListenerNotFoundException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; @@ -50,10 +54,15 @@ public abstract class AMQManagedObject extends DefaultManagedObject protected MBeanInfo _mbeanInfo; + protected LogActor _logActor; + protected AMQManagedObject(Class managementInterface, String typeName, int version) throws NotCompliantMBeanException { super(managementInterface, typeName, version); + // CurrentActor will be defined as these objects are created during + // broker startup. + _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); buildMBeanInfo(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index e8ea56bafd..dc12fdeff7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -659,7 +659,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { _closed = true; - _actor.message(ConnectionMessages.CON_1002()); + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); if (_virtualHost != null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 225a01386b..81dbeeded2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -66,7 +66,9 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; @@ -187,7 +189,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void commitTransactions(int channelId) throws JMException { - CurrentActor.set(getLogActor()); + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { AMQChannel channel = _session.getChannel(channelId); @@ -216,7 +218,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ public void rollbackTransactions(int channelId) throws JMException { - CurrentActor.set(getLogActor()); + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { AMQChannel channel = _session.getChannel(channelId); @@ -281,7 +283,22 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed 0, 0); - CurrentActor.set(getLogActor()); + // This seems ugly but because we use closeConnection in both normal + // broker operation and as part of the management interface it cannot + // be avoided. The Current Actor will be null when this method is + // called via the Management interface. This is because we allow the + // Local API connection with JConsole. If we did not allow that option + // then the CurrentActor could be set in our JMX Proxy object. + // As it is we need to set the CurrentActor on all MBean methods + // Ideally we would not have a single method that can be called from + // two contexts. + boolean removeActor = false; + if (CurrentActor.get() == null) + { + removeActor = true; + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); + } + try { _session.writeFrame(responseBody.generateFrame(0)); @@ -298,21 +315,13 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed } finally { - CurrentActor.remove(); + if (removeActor) + { + CurrentActor.remove(); + } } } - /** - * Return the LogActor for this MBean Session - * //fixme currently simply returning the managed sessions LogActor, should - * be the ManagementActor - * @return - */ - private LogActor getLogActor() - { - return _session.getLogActor(); - } - @Override public MBeanNotificationInfo[] getNotificationInfo() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java index 7584a3b7cc..6e87cfbb76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java @@ -45,7 +45,7 @@ public class ExchangeBinding _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; _logSubject = new BindingLogSubject(routingKey,exchange,queue); - CurrentActor.get().message(_logSubject, BindingMessages.BND_1001(_arguments.toString(), arguments != null)); + CurrentActor.get().message(_logSubject, BindingMessages.BND_1001(String.valueOf(_arguments), arguments != null)); } -- cgit v1.2.1 From e1121bef3a604e82725b6dc2d5522a437952e146 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:20:16 +0000 Subject: QPID-2002 : Ensure that we set the logging actor correctly when mina signals the connection closed git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803650 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java index 0dbefd8798..16b85e67b3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -48,6 +48,7 @@ import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.ssl.SSLContextFactory; /** @@ -175,12 +176,17 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter { try { + CurrentActor.set(amqProtocolSession.getLogActor()); amqProtocolSession.closeSession(); } catch (AMQException e) { _logger.error("Caught AMQException whilst closingSession:" + e); } + finally + { + CurrentActor.remove(); + } } } -- cgit v1.2.1 From 97bcb39a728140aa34edcf20722289c8f9f8f754 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:22:11 +0000 Subject: QPID-2002 : Defensive update incase the thread name is not as expected. In all production environments it has shown to be but as the other tests highlight it will fail if the name is not as expected. Better to be defensive that just broken. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803651 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/actors/ManagementActor.java | 35 +++++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java index 2ad0f69fd6..85fbb8f1ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java @@ -64,21 +64,40 @@ public class ManagementActor extends AbstractActor { String currentName = Thread.currentThread().getName(); + String actor; // Record the last thread name so we don't have to recreate the log string if (!currentName.equals(_lastThreadName)) { _lastThreadName = currentName; - System.err.println(currentName); - // Management Threads have this format. + // Management Thread names have this format. //RMI TCP Connection(2)-169.24.29.116 - String connectionID = currentName.split("\\(")[1].split("\\)")[0]; - String ip = currentName.split("-")[1]; + // This is true for both LocalAPI and JMX Connections + // However to be defensive lets test. + + String[] split = currentName.split("\\("); + if (split.length == 2) + { + String connectionID = split[1].split("\\)")[0]; + String ip = currentName.split("-")[1]; + + actor = MessageFormat.format(MANAGEMENT_FORMAT, + connectionID, + ip); + } + else + { + // This is a precautionary path as it is not expected to occur + // however rather than adjusting the thread name of the two + // tests that will use this it is safer all round to do this. + // it is also currently used by tests : + // AMQBrokerManagerMBeanTest + // ExchangeMBeanTest + actor = currentName; + } + + _logString = "[" + actor + "] "; - _logString = "[" + MessageFormat.format(MANAGEMENT_FORMAT, - connectionID, - ip) - + "] "; } } -- cgit v1.2.1 From c3792b6920ceb464e5d1c098931fe63ac64f5645 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 12 Aug 2009 18:23:04 +0000 Subject: Move closure logging to the end when things have been closed rather than before it is closed git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803652 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/protocol/AMQMinaProtocolSession.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index dc12fdeff7..7bc4365152 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -657,10 +657,6 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { if (!_closed) { - _closed = true; - - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); - if (_virtualHost != null) { _virtualHost.getConnectionRegistry().deregisterConnection(this); @@ -676,6 +672,10 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable { task.doTask(this); } + + _closed = true; + + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); } } -- cgit v1.2.1 From e998b312406f35cd49eee45c0701ade51953b748 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 14 Aug 2009 12:50:36 +0000 Subject: QPID-2001 : Default Locale should be the VMs locale not en_US. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804201 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/ServerConfiguration.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 90b4590d4c..7ea7738189 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -55,7 +55,6 @@ public class ServerConfiguration implements SignalHandler public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; public static final String DEFAULT_STATUS_UPDATES = "on"; - public static final String DEFAULT_ADVANCED_LOCALE = Locale.US.toString(); private static final int DEFAULT_FRAME_SIZE = 65536; private static final int DEFAULT_PORT = 5672; @@ -150,7 +149,7 @@ public class ServerConfiguration implements SignalHandler { XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); List hosts = vhostConfiguration.getList("virtualhost.name"); - for (int j = 0; j < hosts.size(); j++) + for (int j = 0; j < hosts.size(); j++) { String name = (String) hosts.get(j); // Add the keys of the virtual host to the main config then bail out @@ -221,12 +220,18 @@ public class ServerConfiguration implements SignalHandler public Locale getLocale() { - String localeString = getConfig().getString(ADVANCED_LOCALE, DEFAULT_ADVANCED_LOCALE); + String localeString = getConfig().getString(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant + // If the configuration does not have a defined locale use the JVM default + if (localeString == null) + { + return Locale.getDefault(); + } + String[] parts = localeString.split("_"); - Locale locale = null; + Locale locale; switch (parts.length) { case 1: -- cgit v1.2.1 From b6dc0084d1ba75116fe832adaea231f2ba71aa1a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 16 Aug 2009 20:32:47 +0000 Subject: QPID-2051: Update startup scripts to disable the Log4J default initialisation process. Add QpidLog4JConfigurator that validates the XML file before allowing it to be applied. Alter startup behaviour to shut the broker down if the specified log4j XML file is present present but invalid. Uses the -Damqj.logging.level(defaults to info) with the log4j.properties file in the broker jar if the XML file is not found. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804765 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/xml/QpidLog4JConfigurator.java | 250 +++++++++++++++++++++ .../src/main/java/org/apache/qpid/server/Main.java | 43 +++- .../logging/management/LoggingManagementMBean.java | 104 +++++---- 3 files changed, 345 insertions(+), 52 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java new file mode 100644 index 0000000000..53134250ab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -0,0 +1,250 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.log4j.xml; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.management.LoggingManagementMBean; +import org.apache.qpid.server.logging.management.LoggingManagementMBean.QpidLog4JSaxErrorHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +/** + * Substitute for the Log4J XMLWatchdog (as used by DOMConfigurator.configureAndWatch) + * + * Extends the default behaviour with a strict parser check on the XML file before allowing the reconfiguration to proceed, + * ensuring that any parser error or warning prevents initiation of a configuration update by Log4J, which aborts mid-update + * upon fatal errors from the parser and proceeds in the event of 'regular' parser errors and warnings, in all cases allowing + * startup to proceed with whatever half-baked configuration then exists. + */ +public class QpidLog4JConfigurator +{ + //lock to protect access to the configuration file + private static final ReentrantLock LOCK = new ReentrantLock(); + private static Logger _logger; + + private QpidLog4JConfigurator() + { + //no instances + } + + public static void configure(String filename) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + try + { + LOCK.lock(); + + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + DOMConfigurator.configure(filename); + } + finally + { + LOCK.unlock(); + } + } + + public static void configureAndWatch(String filename, long delay) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename); + watchdog.setDelay(delay); + watchdog.start(); + } + + private static void strictlyParseXMLConfigFile(String fileName) throws IOException, SAXException, + ParserConfigurationException + { + try + { + LOCK.lock(); + + //check file was specified, exists, and is readable + if(fileName == null) + { + throw new IOException("Provided log4j XML configuration filename was null"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + throw new IOException("The log4j XML configuration file does not exist: " + fileName); + } + else if (!configFile.canRead()) + { + throw new IOException("The log4j XML configuration file is not readable: " + fileName); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); + + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + docBuilder.parse(fileName); + } + finally + { + LOCK.unlock(); + } + } + + private static class QpidLog4JXMLWatchdog extends XMLWatchdog + { + public QpidLog4JXMLWatchdog(String filename) + { + super(filename); + } + + public void doOnChange() + { + try + { + LOCK.lock(); + + try + { + strictlyParseXMLConfigFile(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Parsing the log4j XML configuration file generated errors/warnings. " + + "The new configuration was not applied. Correct the issues to prompt " + + "another update attempt: " + e.getMessage()); + } + return; + } + + try + { + checkLoggerLevels(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Errors were found when validating the logger level values in the " + + "log4j XML configuration file. The new configuration was not applied. " + + "Correct the issues to prompt another update attempt: " + e.getMessage()); + } + return; + } + + //everything checked was ok, let the normal update process proceed + super.doOnChange(); + + //a configuration has now been applied, enable logging for future attempts + if(_logger == null) + { + _logger = Logger.getLogger(QpidLog4JConfigurator.class); + } + + _logger.info("Applied log4j configuration from: " + filename); + } + finally + { + LOCK.unlock(); + } + + } + } + + protected static void checkLoggerLevels(String filename) throws IllegalLoggerLevelException, IOException + { + //check that the logger levels specified in the XML are actually valid + + try + { + LOCK.lock(); + + Map loggersLevels; + loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename); + + for (String loggerName : loggersLevels.keySet()) + { + String levelString = loggersLevels.get(loggerName); + checkLevel(loggerName,levelString); + } + + //check the root logger level + String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); + checkLevel("Root", rootLoggerlevelString); + } + finally + { + LOCK.unlock(); + } + } + + private static void checkLevel(String loggerName, String levelString) throws IllegalLoggerLevelException + { + if("null".equalsIgnoreCase(levelString) || "inherited".equalsIgnoreCase(levelString)) + { + //the string "null" signals to inherit from a parent logger + return; + } + + Level level = Level.toLevel(levelString); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (level.equals(Level.DEBUG) && !(levelString.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new IllegalLoggerLevelException("Level '" + levelString + "' specified for Logger '" + loggerName + "' is invalid"); + } + } + + public static class IllegalLoggerLevelException extends Exception + { + private static final long serialVersionUID = 1L; + + public IllegalLoggerLevelException(String msg) + { + super(msg); + } + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index eac027afc6..8566ba6270 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -27,9 +27,9 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.FixedSizeByteBufferAllocator; import org.apache.mina.common.IoAcceptor; @@ -56,9 +56,11 @@ import org.apache.qpid.server.transport.QpidAcceptor; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.Properties; /** * Main entry point for AMQPD. @@ -200,7 +202,7 @@ public class Main } catch (InitException e) { - System.out.println(e.getMessage()); + System.out.println("Initialisation Error : " + e.getMessage()); _brokerLogger.error("Initialisation Error : " + e.getMessage()); shutdown(1); } @@ -498,7 +500,7 @@ public class Main return ip; } - private void configureLogging(File logConfigFile, int logWatchTime) + private void configureLogging(File logConfigFile, int logWatchTime) throws InitException, IOException { if (logConfigFile.exists() && logConfigFile.canRead()) { @@ -509,18 +511,43 @@ public class Main System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds - DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); + try + { + QpidLog4JConfigurator.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } else { - DOMConfigurator.configure(logConfigFile.getAbsolutePath()); + try + { + QpidLog4JConfigurator.configure(logConfigFile.getPath()); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } } else { System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); - System.err.println("Using basic log4j configuration"); - BasicConfigurator.configure(); + System.err.println("Using the fallback internal log4j.properties configuration"); + + InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties"); + if(propsFile == null) + { + throw new IOException("Unable to load the fallback internal log4j.properties configuration file"); + } + else + { + Properties fallbackProps = new Properties(); + fallbackProps.load(propsFile); + PropertyConfigurator.configure(fallbackProps); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 3cebb1353b..396e81e690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -24,7 +24,9 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; @@ -34,6 +36,8 @@ import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.Log4jEntityResolver; +import org.apache.log4j.xml.QpidLog4JConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -244,46 +248,50 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - private class SaxErrorHandler implements ErrorHandler + public static class QpidLog4JSaxErrorHandler implements ErrorHandler { - public void error(SAXParseException e) throws SAXException { - throw new SAXException("Error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Error parsing XML file", e)); } public void fatalError(SAXParseException e) throws SAXException { - throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Fatal error parsing XML file", e)); } public void warning(SAXParseException e) throws SAXException { - throw new SAXException("Warning parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Warning parsing XML file", e)); + } + + private static String constructMessage(final String msg, final SAXParseException ex) + { + return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); } } //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private synchronized Document parseConfigFile(String fileName) throws IOException + private static synchronized Document parseConfigFile(String fileName) throws IOException { //check file was specified, exists, and is readable if(fileName == null) { - _logger.warn("No log4j XML configuration file has been set"); - throw new IOException("No log4j XML configuration file has been set"); + _logger.warn("Provided log4j XML configuration filename is null"); + throw new IOException("Provided log4j XML configuration filename is null"); } File configFile = new File(fileName); if (!configFile.exists()) { - _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); - throw new IOException("Specified log4j XML configuration file does not exist"); + _logger.warn("The log4j XML configuration file could not be found: " + fileName); + throw new IOException("The log4j XML configuration file could not be found"); } else if (!configFile.canRead()) { - _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); - throw new IOException("Specified log4j XML configuration file is not readable"); + _logger.warn("The log4j XML configuration file is not readable: " + fileName); + throw new IOException("The log4j XML configuration file is not readable"); } //parse it @@ -291,7 +299,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM DocumentBuilder docBuilder; Document doc; - ErrorHandler errHandler = new SaxErrorHandler(); + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); try { docFactory.setValidating(true); @@ -315,14 +323,14 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM catch (IOException e) { _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file", e); + throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage()); } return doc; } - private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + private static synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException { File log4jConfigFile = new File(log4jConfigFileName); @@ -389,20 +397,11 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM * and not the only possible child element. */ - - public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + public static synchronized Map retrieveConfigFileLoggersLevels(String fileName) throws IOException { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + HashMap loggerLevelList = new HashMap(); //retrieve the 'category' element nodes NodeList categoryElements = doc.getElementsByTagName("category"); @@ -436,17 +435,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM continue; } - try - { - Object[] itemData = {categoryName, priority}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } + loggerLevelList.put(categoryName, priority); } //retrieve the 'logger' element nodes @@ -467,6 +456,30 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM Element levelElement = (Element) levelElements.item(0); level = levelElement.getAttribute("value").toUpperCase(); + loggerLevelList.put(loggerName, level); + } + + return loggerLevelList; + } + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Map levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); + + for (String loggerName : levels.keySet()) + { + String level = levels.get(loggerName); + try { Object[] itemData = {loggerName, level}; @@ -574,19 +587,17 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM * and not the only possible child element. */ - public synchronized String getConfigFileRootLoggerLevel() throws IOException + public static synchronized String retrieveConfigFileRootLoggerLevel(String fileName) throws IOException { - _logger.info("Getting root logger level from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); //retrieve the optional 'root' element node NodeList rootElements = doc.getElementsByTagName("root"); if (rootElements.getLength() == 0) { - //there is not root logger definition - return null; + //there is no root logger definition + return "N/A"; } Element rootElement = (Element) rootElements.item(0); @@ -618,6 +629,11 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } } + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName); + } + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException { //check that the specified level is a valid log4j Level -- cgit v1.2.1 From 65c3073fd7c2ab4ed116108f8b8a3440b409c134 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 16 Aug 2009 20:33:38 +0000 Subject: QPID-2051: Make the LoggingManagementMBean share the lock with QpidLog4JConfigurator,protecting against concurrent access/modifications to the logging configuration file by JMX clients and the WatchDog thread. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804766 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/xml/QpidLog4JConfigurator.java | 3 +- .../logging/management/LoggingManagementMBean.java | 689 +++++++++++---------- 2 files changed, 379 insertions(+), 313 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java index 53134250ab..aa6694b3b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -47,7 +47,8 @@ import org.xml.sax.SAXException; public class QpidLog4JConfigurator { //lock to protect access to the configuration file - private static final ReentrantLock LOCK = new ReentrantLock(); + //shared with LoggingManagementMBean + public static final ReentrantLock LOCK = new ReentrantLock(); private static Logger _logger; private QpidLog4JConfigurator() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 396e81e690..e1e6cb49b5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.logging.management; +import static org.apache.log4j.xml.QpidLog4JConfigurator.LOCK; + import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -214,22 +216,22 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM public synchronized boolean setRuntimeRootLoggerLevel(String level) { - Level newLevel; - try - { - newLevel = getLevel(level); - } - catch (Exception e) - { - return false; - } - - _logger.info("Setting RootLogger level to " + level); - - Logger log = Logger.getRootLogger(); - log.setLevel(newLevel); - - return true; + Level newLevel; + try + { + newLevel = getLevel(level); + } + catch (Exception e) + { + return false; + } + + _logger.info("Setting RootLogger level to " + level); + + Logger log = Logger.getRootLogger(); + log.setLevel(newLevel); + + return true; } //method to convert from a string to a log4j Level, throws exception if the given value is invalid @@ -274,114 +276,132 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. private static synchronized Document parseConfigFile(String fileName) throws IOException { - //check file was specified, exists, and is readable - if(fileName == null) + try { - _logger.warn("Provided log4j XML configuration filename is null"); - throw new IOException("Provided log4j XML configuration filename is null"); - } + LOCK.lock(); - File configFile = new File(fileName); + //check file was specified, exists, and is readable + if(fileName == null) + { + _logger.warn("Provided log4j XML configuration filename is null"); + throw new IOException("Provided log4j XML configuration filename is null"); + } - if (!configFile.exists()) - { - _logger.warn("The log4j XML configuration file could not be found: " + fileName); - throw new IOException("The log4j XML configuration file could not be found"); - } - else if (!configFile.canRead()) - { - _logger.warn("The log4j XML configuration file is not readable: " + fileName); - throw new IOException("The log4j XML configuration file is not readable"); - } + File configFile = new File(fileName); - //parse it - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder; - Document doc; + if (!configFile.exists()) + { + _logger.warn("The log4j XML configuration file could not be found: " + fileName); + throw new IOException("The log4j XML configuration file could not be found"); + } + else if (!configFile.canRead()) + { + _logger.warn("The log4j XML configuration file is not readable: " + fileName); + throw new IOException("The log4j XML configuration file is not readable"); + } - ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); - try - { - docFactory.setValidating(true); - docBuilder = docFactory.newDocumentBuilder(); - docBuilder.setErrorHandler(errHandler); - docBuilder.setEntityResolver(new Log4jEntityResolver()); - doc = docBuilder.parse(fileName); - } - catch (ParserConfigurationException e) - { - _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); - //recommended that MBeans should use java.* and javax.* exceptions only - throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); - } - catch (SAXException e) - { - _logger.warn("The specified log4j XML file is invalid: " + e); - //recommended that MBeans should use standard java.* and javax.* exceptions only - throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document doc; + + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); + try + { + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + doc = docBuilder.parse(fileName); + } + catch (ParserConfigurationException e) + { + _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e); + //recommended that MBeans should use java.* and javax.* exceptions only + throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage()); + } + catch (SAXException e) + { + _logger.warn("The specified log4j XML file is invalid: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The specified log4j XML file is invalid: " + e.getMessage()); + } + catch (IOException e) + { + _logger.warn("Unable to parse the specified log4j XML file" + e); + throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage()); + } + + return doc; } - catch (IOException e) + finally { - _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage()); + LOCK.unlock(); } - - return doc; } private static synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException { - File log4jConfigFile = new File(log4jConfigFileName); - - if (!log4jConfigFile.canWrite()) - { - _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); - throw new IOException("Specified log4j XML configuration file is not writable"); - } - - Transformer transformer = null; try { - transformer = TransformerFactory.newInstance().newTransformer(); - } - catch (Exception e) - { - _logger.warn("Could not create an XML transformer: " +e); - return false; - } + LOCK.lock(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); - DOMSource source = new DOMSource(doc); - - File tmp; - try - { - tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); - tmp.deleteOnExit(); - StreamResult result = new StreamResult(tmp); - transformer.transform(source, result); - } - catch (TransformerException e) - { - _logger.warn("Could not transform the XML into new file: " +e); - return false; - } - catch (IOException e) - { - _logger.warn("Could not create the new file: " +e); - return false; - } + File log4jConfigFile = new File(log4jConfigFileName); + + if (!log4jConfigFile.canWrite()) + { + _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); + throw new IOException("Specified log4j XML configuration file is not writable"); + } + + Transformer transformer = null; + try + { + transformer = TransformerFactory.newInstance().newTransformer(); + } + catch (Exception e) + { + _logger.warn("Could not create an XML transformer: " +e); + return false; + } - // Swap temp file in to replace existing configuration file. - File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); - if (old.exists()) + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); + DOMSource source = new DOMSource(doc); + + File tmp; + try + { + tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); + tmp.deleteOnExit(); + StreamResult result = new StreamResult(tmp); + transformer.transform(source, result); + } + catch (TransformerException e) + { + _logger.warn("Could not transform the XML into new file: " +e); + return false; + } + catch (IOException e) + { + _logger.warn("Could not create the new file: " +e); + return false; + } + + // Swap temp file in to replace existing configuration file. + File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + log4jConfigFile.renameTo(old); + return tmp.renameTo(log4jConfigFile); + } + finally { - old.delete(); + LOCK.unlock(); } - log4jConfigFile.renameTo(old); - return tmp.renameTo(log4jConfigFile); } @@ -399,180 +419,207 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM public static synchronized Map retrieveConfigFileLoggersLevels(String fileName) throws IOException { - Document doc = parseConfigFile(fileName); + try + { + LOCK.lock(); - HashMap loggerLevelList = new HashMap(); + Document doc = parseConfigFile(fileName); - //retrieve the 'category' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - - String categoryName; - String priority = null; - - for (int i = 0; i < categoryElements.getLength(); i++) - { - Element categoryElement = (Element) categoryElements.item(i); - categoryName = categoryElement.getAttribute("name"); + HashMap loggerLevelList = new HashMap(); - //retrieve the category's mandatory 'priority' or 'level' element's value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = categoryElement.getElementsByTagName("priority"); - NodeList levelElements = categoryElement.getElementsByTagName("level"); + //retrieve the 'category' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); - if (priorityElements.getLength() != 0) + String categoryName; + String priority = null; + + for (int i = 0; i < categoryElements.getLength(); i++) { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value").toUpperCase(); + Element categoryElement = (Element) categoryElements.item(i); + categoryName = categoryElement.getAttribute("name"); + + //retrieve the category's mandatory 'priority' or 'level' element's value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = categoryElement.getElementsByTagName("priority"); + NodeList levelElements = categoryElement.getElementsByTagName("level"); + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value"); + } + else if (levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value"); + } + else + { + //there is no exiting priority or level to view, move onto next category/logger + continue; + } + + loggerLevelList.put(categoryName, priority); } - else if (levelElements.getLength() != 0) + + //retrieve the 'logger' element nodes + NodeList loggerElements = doc.getElementsByTagName("logger"); + + String loggerName; + String level; + + for (int i = 0; i < loggerElements.getLength(); i++) { + Element loggerElement = (Element) loggerElements.item(i); + loggerName = loggerElement.getAttribute("name"); + + //retrieve the logger's mandatory 'level' element's value + //It may not be the only child node, so request by tag name. + NodeList levelElements = loggerElement.getElementsByTagName("level"); + Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value").toUpperCase(); - } - else - { - //there is no exiting priority or level to view, move onto next category/logger - continue; + level = levelElement.getAttribute("value"); + + loggerLevelList.put(loggerName, level); } - loggerLevelList.put(categoryName, priority); + return loggerLevelList; } - - //retrieve the 'logger' element nodes - NodeList loggerElements = doc.getElementsByTagName("logger"); - - String loggerName; - String level; - - for (int i = 0; i < loggerElements.getLength(); i++) + finally { - Element loggerElement = (Element) loggerElements.item(i); - loggerName = loggerElement.getAttribute("name"); - - //retrieve the logger's mandatory 'level' element's value - //It may not be the only child node, so request by tag name. - NodeList levelElements = loggerElement.getElementsByTagName("level"); - - Element levelElement = (Element) levelElements.item(0); - level = levelElement.getAttribute("value").toUpperCase(); - - loggerLevelList.put(loggerName, level); + LOCK.unlock(); } - - return loggerLevelList; } public synchronized TabularData viewConfigFileLoggerLevels() throws IOException { - if (_loggerLevelTabularType == null) + try { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); + LOCK.lock(); - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); - - Map levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); - - for (String loggerName : levels.keySet()) - { - String level = levels.get(loggerName); - - try + if (_loggerLevelTabularType == null) { - Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); + _logger.warn("TabluarData type not set up correctly"); + return null; } - catch (OpenDataException e) + + _logger.info("Getting logger levels from log4j configuration file"); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Map levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); + + for (String loggerName : levels.keySet()) { - _logger.warn("Unable to create logger level list due to :" + e); - return null; + String level = levels.get(loggerName); + + try + { + Object[] itemData = {loggerName, level.toUpperCase()}; + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + loggerLevelList.put(loggerData); + } + catch (OpenDataException e) + { + _logger.warn("Unable to create logger level list due to :" + e); + return null; + } } + + return loggerLevelList; + } + finally + { + LOCK.unlock(); } - - return loggerLevelList; } public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException { - //check that the specified level is a valid log4j Level try { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for logger '" + logger - + "' in log4j xml configuration file: " + _log4jConfigFileName); - - Document doc = parseConfigFile(_log4jConfigFileName); + LOCK.lock(); - //retrieve the 'category' and 'logger' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - NodeList loggerElements = doc.getElementsByTagName("logger"); - - //collect them into a single elements list - List logElements = new ArrayList(); - - for (int i = 0; i < categoryElements.getLength(); i++) - { - logElements.add((Element) categoryElements.item(i)); - } - for (int i = 0; i < loggerElements.getLength(); i++) - { - logElements.add((Element) loggerElements.item(i)); - } + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } - //try to locate the specified logger/category in the elements retrieved - Element logElement = null; - for (Element e : logElements) - { - if (e.getAttribute("name").equals(logger)) + _logger.info("Setting level to " + level + " for logger '" + logger + + "' in log4j xml configuration file: " + _log4jConfigFileName); + + Document doc = parseConfigFile(_log4jConfigFileName); + + //retrieve the 'category' and 'logger' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + NodeList loggerElements = doc.getElementsByTagName("logger"); + + //collect them into a single elements list + List logElements = new ArrayList(); + + for (int i = 0; i < categoryElements.getLength(); i++) { - logElement = e; - break; + logElements.add((Element) categoryElements.item(i)); + } + for (int i = 0; i < loggerElements.getLength(); i++) + { + logElements.add((Element) loggerElements.item(i)); } - } - if (logElement == null) - { - //no loggers/categories with given name found, does not exist to update - _logger.warn("Specified logger does not exist in the configuration file: " +logger); - return false; - } + //try to locate the specified logger/category in the elements retrieved + Element logElement = null; + for (Element e : logElements) + { + if (e.getAttribute("name").equals(logger)) + { + logElement = e; + break; + } + } - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = logElement.getElementsByTagName("priority"); - NodeList levelElements = logElement.getElementsByTagName("level"); + if (logElement == null) + { + //no loggers/categories with given name found, does not exist to update + _logger.warn("Specified logger does not exist in the configuration file: " +logger); + return false; + } - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = logElement.getElementsByTagName("priority"); + NodeList levelElements = logElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority or level element to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); } - else + finally { - //there is no exiting priority or level element to update - return false; + LOCK.unlock(); } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); } @@ -589,103 +636,121 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM public static synchronized String retrieveConfigFileRootLoggerLevel(String fileName) throws IOException { - Document doc = parseConfigFile(fileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) + try { - //there is no root logger definition - return "N/A"; - } + LOCK.lock(); - Element rootElement = (Element) rootElements.item(0); + Document doc = parseConfigFile(fileName); - //retrieve the optional 'priority' or 'level' element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); - String priority = null; - - if (priorityElements.getLength() != 0) - { - Element priorityElement = (Element) priorityElements.item(0); - priority = priorityElement.getAttribute("value"); - } - else if(levelElements.getLength() != 0) - { - Element levelElement = (Element) levelElements.item(0); - priority = levelElement.getAttribute("value"); - } + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); - if(priority != null) - { - return priority.toUpperCase(); + if (rootElements.getLength() == 0) + { + //there is no root logger definition + return "N/A"; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + String priority = null; + + if (priorityElements.getLength() != 0) + { + Element priorityElement = (Element) priorityElements.item(0); + priority = priorityElement.getAttribute("value"); + } + else if(levelElements.getLength() != 0) + { + Element levelElement = (Element) levelElements.item(0); + priority = levelElement.getAttribute("value"); + } + + if(priority != null) + { + return priority; + } + else + { + return "N/A"; + } } - else + finally { - return null; + LOCK.unlock(); } } public synchronized String getConfigFileRootLoggerLevel() throws IOException { - return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName); + return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName).toUpperCase(); } public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException { - //check that the specified level is a valid log4j Level try { - getLevel(level); - } - catch (Exception e) - { - //it isnt a valid level - return false; - } - - _logger.info("Setting level to " + level + " for the Root logger in " + - "log4j xml configuration file: " + _log4jConfigFileName); + LOCK.lock(); - Document doc = parseConfigFile(_log4jConfigFileName); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); + //check that the specified level is a valid log4j Level + try + { + getLevel(level); + } + catch (Exception e) + { + //it isnt a valid level + return false; + } - if (rootElements.getLength() == 0) - { - return false; - } + _logger.info("Setting level to " + level + " for the Root logger in " + + "log4j xml configuration file: " + _log4jConfigFileName); - Element rootElement = (Element) rootElements.item(0); + Document doc = parseConfigFile(_log4jConfigFileName); - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = rootElement.getElementsByTagName("priority"); - NodeList levelElements = rootElement.getElementsByTagName("level"); + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); + if (rootElements.getLength() == 0) + { + return false; + } + + Element rootElement = (Element) rootElements.item(0); + + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = rootElement.getElementsByTagName("priority"); + NodeList levelElements = rootElement.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + //there is no exiting priority/level to update + return false; + } + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + return writeUpdatedConfigFile(_log4jConfigFileName, doc); } - else + finally { - //there is no exiting priority/level to update - return false; + LOCK.unlock(); } - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - return writeUpdatedConfigFile(_log4jConfigFileName, doc); } } -- cgit v1.2.1 From b964a52247b0405f2f6da647bff3ac74ad2ab6c6 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 16 Aug 2009 20:35:30 +0000 Subject: QPID-2016: Add ability to reload the Log4J configuration file on request using the management console git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804767 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/management/LoggingManagementMBean.java | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index e1e6cb49b5..1ab9d913c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -753,4 +753,41 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM LOCK.unlock(); } } + + public synchronized void reloadConfigFile() throws IOException + { + try + { + LOCK.lock(); + + QpidLog4JConfigurator.configure(_log4jConfigFileName); + _logger.info("Applied log4j configuration from: " + _log4jConfigFileName); + } + catch (IllegalLoggerLevelException e) + { + _logger.warn("The log4j configuration reload request was aborted: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage()); + } + catch (ParserConfigurationException e) + { + _logger.warn("The log4j configuration reload request was aborted: " + e); + throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage()); + } + catch (SAXException e) + { + _logger.warn("The log4j configuration reload request was aborted: " + e); + //recommended that MBeans should use standard java.* and javax.* exceptions only + throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage()); + } + catch (IOException e) + { + _logger.warn("The log4j configuration reload request was aborted: " + e); + throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage()); + } + finally + { + LOCK.unlock(); + } + } } -- cgit v1.2.1 From 8a11b9f6df8882fb704955afcdfec3c1e14fd9bd Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 16 Aug 2009 20:36:33 +0000 Subject: QPID-2052: Enable setting Loggers to inherit their Level from an ancestor. Highlight the Runtime Loggers that have a level defined in the configuration file to aid inheritance visibility. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804768 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/management/LoggingManagementMBean.java | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 1ab9d913c8..ce7d08c8dc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -76,10 +76,12 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class); private String _log4jConfigFileName; private int _log4jLogWatchInterval; + private static final String INHERITED = "INHERITED"; private static final String[] LEVELS = new String[]{Level.ALL.toString(), Level.TRACE.toString(), Level.DEBUG.toString(), Level.INFO.toString(), Level.WARN.toString(), Level.ERROR.toString(), - Level.FATAL.toString(),Level.OFF.toString()}; + Level.FATAL.toString(),Level.OFF.toString(), + INHERITED}; static TabularType _loggerLevelTabularType; static CompositeType _loggerLevelCompositeType; @@ -225,6 +227,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM { return false; } + + if(newLevel == null) + { + //A null Level reference implies inheritance. Setting the runtime RootLogger + //to null is catastrophic (and prevented by Log4J at startup and runtime anyway). + return false; + } _logger.info("Setting RootLogger level to " + level); @@ -237,6 +246,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM //method to convert from a string to a log4j Level, throws exception if the given value is invalid private Level getLevel(String level) throws Exception { + if("null".equalsIgnoreCase(level) || INHERITED.equalsIgnoreCase(level)) + { + //the string "null" or "inherited" signals to inherit from a parent logger, + //using a null Level reference for the logger. + return null; + } + Level newLevel = Level.toLevel(level); //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. @@ -611,7 +627,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } //update the element with the new level/priority - levelElement.setAttribute("value", level); + levelElement.setAttribute("value", level.toLowerCase()); //output the new file return writeUpdatedConfigFile(_log4jConfigFileName, doc); @@ -699,7 +715,14 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM //check that the specified level is a valid log4j Level try { - getLevel(level); + Level newLevel = getLevel(level); + if(newLevel == null) + { + //A null Level reference implies inheritance. Setting the config file RootLogger + //to "null" or "inherited" just ensures it defaults to DEBUG at startup as Log4J + //prevents this catastrophic situation at startup and runtime anyway. + return false; + } } catch (Exception e) { -- cgit v1.2.1 From 8d243720ce877ef59db7572194b80a2c5d0737e8 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 16 Aug 2009 21:18:14 +0000 Subject: QPID-2039: close the JMXConnectorServer down during shutdown of the JMXManagedObjectRegistry git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@804781 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/JMXManagedObjectRegistry.java | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 5ffcee77f2..42b3b05ac5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -35,11 +35,7 @@ import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import javax.management.NotificationListener; -import javax.management.MalformedObjectNameException; -import javax.management.NotificationFilter; import javax.management.NotificationFilterSupport; -import javax.management.InstanceNotFoundException; -import javax.management.relation.MBeanServerNotificationFilter; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; @@ -82,6 +78,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry public static final int PORT_EXPORT_OFFSET = 100; private final MBeanServer _mbeanServer; + private JMXConnectorServer _cs; private Registry _rmiRegistry; @@ -120,7 +117,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry Map map = appRegistry.getDatabaseManager().getDatabases(); PrincipalDatabase db = map.get(jmxDatabaseName); - final JMXConnectorServer cs; HashMap env = new HashMap(); //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration @@ -246,7 +242,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET); - cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + _cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) { @Override public synchronized void start() throws IOException @@ -282,7 +278,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); - cs.setMBeanServerForwarder(mbsf); + _cs.setMBeanServerForwarder(mbsf); NotificationFilterSupport filter = new NotificationFilterSupport(); filter.enableType(JMXConnectionNotification.OPENED); @@ -290,9 +286,9 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry filter.enableType(JMXConnectionNotification.FAILED); // Get the handler that is used by the above MBInvocationHandler Proxy. // which is the MBeanInvocationHandlerImpl and so also a NotificationListener - cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null); + _cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null); - cs.start(); + _cs.start(); CurrentActor.get().message(ManagementConsoleMessages.MNG_1004()); @@ -377,6 +373,19 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry UnicastRemoteObject.unexportObject(_rmiRegistry, true); } + if (_cs != null) + { + // Stopping the JMX ConnectorServer + try + { + _cs.stop(); + } + catch (IOException e) + { + _log.warn("Error while closing the JMX ConnectorServer: " + e.getMessage()); + } + } + //ObjectName query to gather all Qpid related MBeans ObjectName mbeanNameQuery = null; try -- cgit v1.2.1 From 6064d7714f0745f618302982fb0df0509f70d6c4 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 Aug 2009 15:50:59 +0000 Subject: QPID-2040: update the save process for the plain password file. Only attempt the move if the new file is created successfully. Check if the rename/move succeeds, and if not attempt a copy instead git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805017 13f79535-47bb-0310-9956-ffa450edef68 --- .../PlainPasswordFilePrincipalDatabase.java | 47 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 5e4678a63b..6ec7cea4c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; +import org.apache.qpid.util.FileUtils; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -395,6 +396,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase BufferedReader reader = null; PrintStream writer = null; File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + tmp.deleteOnExit(); try { @@ -452,6 +454,11 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } } + catch(IOException e) + { + _logger.error("Unable to create the new password file: " + e); + throw new IOException("Unable to create the new password file" + e); + } finally { if (reader != null) @@ -463,17 +470,41 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase { writer.close(); } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + try + { + if(!_passwordFile.renameTo(old)) { - old.delete(); + FileUtils.copyCheckedEx(_passwordFile, old); } - _passwordFile.renameTo(old); - tmp.renameTo(_passwordFile); - tmp.delete(); } + catch (IOException e) + { + _logger.error("Could not backup the existing password file: " +e); + throw new IOException("Could not backup the existing password file: " + e); + } + + try + { + if(!tmp.renameTo(_passwordFile)) + { + FileUtils.copyCheckedEx(tmp, _passwordFile); + } + } + catch (IOException e) + { + _logger.error("Could not copy the new password file into place: " +e); + throw new IOException("Could not copy the new password file into place: " + e); + } + } finally { -- cgit v1.2.1 From b49c3877b8c0060d56e7c0f875e71248418e7964 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 Aug 2009 15:52:13 +0000 Subject: QPID-2041: update the save process for the B64 MD5 password file. Only attempt the move if the new file is created successfully. Check if the rename/move succeeds, and if not attempt a copy instead git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805018 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 46 ++++++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 3c211746e3..cd4eb0bec7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -25,6 +25,7 @@ import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; +import org.apache.qpid.util.FileUtils; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -428,6 +429,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase BufferedReader reader = null; PrintStream writer = null; File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + tmp.deleteOnExit(); try { @@ -501,6 +503,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } } } + catch(IOException e) + { + _logger.error("Unable to create the new password file: " + e); + throw new IOException("Unable to create the new password file" + e); + } finally { if (reader != null) @@ -512,16 +519,39 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { writer.close(); } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + try + { + if(!_passwordFile.renameTo(old)) { - old.delete(); + FileUtils.copyCheckedEx(_passwordFile, old); } - _passwordFile.renameTo(old); - tmp.renameTo(_passwordFile); - tmp.delete(); + } + catch (IOException e) + { + _logger.error("Could not backup the existing password file: " +e); + throw new IOException("Could not backup the existing password file: " + e); + } + + try + { + if(!tmp.renameTo(_passwordFile)) + { + FileUtils.copyCheckedEx(tmp, _passwordFile); + } + } + catch (IOException e) + { + _logger.error("Could not copy the new password file into place: " +e); + throw new IOException("Could not copy the new password file into place: " + e); } } finally -- cgit v1.2.1 From c6838c9481abaa164f5e839c6f718c616437edf1 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 Aug 2009 15:53:10 +0000 Subject: QPID-2042: update the save process for the access rights file. Check if the rename/move succeeds, and if not attempt a copy instead git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805019 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/management/AMQUserManagementMBean.java | 39 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 25c3754462..b6d2c3ab67 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -27,6 +27,7 @@ import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.util.FileUtils; import org.apache.log4j.Logger; import org.apache.commons.configuration.ConfigurationException; @@ -439,16 +440,44 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana // Create temporary file File tmp = File.createTempFile(_accessFile.getName(), ".tmp"); + tmp.deleteOnExit(); FileOutputStream output = new FileOutputStream(tmp); _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); output.close(); - // Rename new file to main file - tmp.renameTo(_accessFile); - - // delete tmp - tmp.delete(); + // Swap temp file to main rights file. + File old = new File(_accessFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + try + { + if(!_accessFile.renameTo(old)) + { + FileUtils.copyCheckedEx(_accessFile, old); + } + } + catch (IOException e) + { + _logger.warn("Could not backup the existing management rights file: " +e); + throw new IOException("Could not backup the existing management rights file: " +e); + } + + try + { + if(!tmp.renameTo(_accessFile)) + { + FileUtils.copyCheckedEx(tmp, _accessFile); + } + } + catch (IOException e) + { + _logger.warn("Could not copy the new management rights file into place: " +e); + throw new IOException("Could not copy the new management rights file into place" +e); + } } finally { -- cgit v1.2.1 From 45dec2e0b9238d1a870665abec3df9abbb2aad22 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 Aug 2009 15:53:56 +0000 Subject: QPID-2055: update the save process for the log4j configuration file. Check if the rename/move succeeds, and if not attempt a copy instead git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805020 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/management/LoggingManagementMBean.java | 37 +++++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index ce7d08c8dc..d98b14e4d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -33,6 +33,7 @@ import java.util.Map; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.util.FileUtils; import org.apache.log4j.Level; import org.apache.log4j.LogManager; @@ -397,12 +398,12 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM catch (TransformerException e) { _logger.warn("Could not transform the XML into new file: " +e); - return false; + throw new IOException("Could not transform the XML into new file: " +e); } catch (IOException e) { - _logger.warn("Could not create the new file: " +e); - return false; + _logger.warn("Could not create the new log4j XML file: " +e); + throw new IOException("Could not create the new log4j XML file: " +e); } // Swap temp file in to replace existing configuration file. @@ -411,8 +412,34 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM { old.delete(); } - log4jConfigFile.renameTo(old); - return tmp.renameTo(log4jConfigFile); + + try + { + if(!log4jConfigFile.renameTo(old)) + { + FileUtils.copyCheckedEx(log4jConfigFile, old); + } + } + catch (IOException e) + { + _logger.warn("Could not backup the existing log4j XML file: " +e); + throw new IOException("Could not backup the existing log4j XML file: " +e); + } + + try + { + if(!tmp.renameTo(log4jConfigFile)) + { + FileUtils.copyCheckedEx(tmp, log4jConfigFile); + } + } + catch (IOException e) + { + _logger.warn("Could not copy the new configuration into place: " +e); + throw new IOException("Could not copy the new configuration into place: " +e); + } + + return true; } finally { -- cgit v1.2.1 From d2a98d4dfc63fd606418f5bd433be514bbe20d01 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 Aug 2009 22:28:01 +0000 Subject: QPID-2051: relax the parser validation to only halt startup on fatal-errors in the xml file, and relax the level-check to allow undefined system properties. Move the Log4J initialisation override inside Main instead of the startup scripts, and have it check for -Dlog4j.configuration first before engaging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805188 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/xml/QpidLog4JConfigurator.java | 88 +++++++++++++++++++--- .../src/main/java/org/apache/qpid/server/Main.java | 17 ++++- .../logging/management/LoggingManagementMBean.java | 25 +----- 3 files changed, 93 insertions(+), 37 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java index aa6694b3b1..4afc209ba7 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -32,9 +32,9 @@ import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.qpid.server.logging.management.LoggingManagementMBean; -import org.apache.qpid.server.logging.management.LoggingManagementMBean.QpidLog4JSaxErrorHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; /** * Substitute for the Log4J XMLWatchdog (as used by DOMConfigurator.configureAndWatch) @@ -50,6 +50,7 @@ public class QpidLog4JConfigurator //shared with LoggingManagementMBean public static final ReentrantLock LOCK = new ReentrantLock(); private static Logger _logger; + private static DOMConfigurator domConfig = new DOMConfigurator(); private QpidLog4JConfigurator() { @@ -63,10 +64,15 @@ public class QpidLog4JConfigurator { LOCK.lock(); - strictlyParseXMLConfigFile(filename); + parseXMLConfigFile(filename); checkLoggerLevels(filename); DOMConfigurator.configure(filename); + + if(_logger == null) + { + _logger = Logger.getLogger(QpidLog4JConfigurator.class); + } } finally { @@ -77,7 +83,7 @@ public class QpidLog4JConfigurator public static void configureAndWatch(String filename, long delay) throws IOException, ParserConfigurationException, SAXException, IllegalLoggerLevelException { - strictlyParseXMLConfigFile(filename); + parseXMLConfigFile(filename); checkLoggerLevels(filename); QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename); @@ -85,7 +91,7 @@ public class QpidLog4JConfigurator watchdog.start(); } - private static void strictlyParseXMLConfigFile(String fileName) throws IOException, SAXException, + private static void parseXMLConfigFile(String fileName) throws IOException, SAXException, ParserConfigurationException { try @@ -127,6 +133,43 @@ public class QpidLog4JConfigurator } } + public static class QpidLog4JSaxErrorHandler implements ErrorHandler + { + public void error(SAXParseException e) throws SAXException + { + if(_logger != null) + { + _logger.warn(constructMessage("Error parsing XML file", e)); + } + else + { + System.err.println(constructMessage("Error parsing XML file", e)); + } + } + + public void fatalError(SAXParseException e) throws SAXException + { + throw new SAXException(constructMessage("Fatal error parsing XML file", e)); + } + + public void warning(SAXParseException e) throws SAXException + { + if(_logger != null) + { + _logger.warn(constructMessage("Warning parsing XML file", e)); + } + else + { + System.err.println(constructMessage("Warning parsing XML file", e)); + } + } + + private static String constructMessage(final String msg, final SAXParseException ex) + { + return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); + } + } + private static class QpidLog4JXMLWatchdog extends XMLWatchdog { public QpidLog4JXMLWatchdog(String filename) @@ -142,7 +185,7 @@ public class QpidLog4JConfigurator try { - strictlyParseXMLConfigFile(filename); + parseXMLConfigFile(filename); } catch (Exception e) { @@ -201,18 +244,43 @@ public class QpidLog4JConfigurator { LOCK.lock(); + //get the Logger levels to check Map loggersLevels; loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename); + //add the RootLogger to the list too + String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); + loggersLevels.put("Root", rootLoggerlevelString); + for (String loggerName : loggersLevels.keySet()) { String levelString = loggersLevels.get(loggerName); - checkLevel(loggerName,levelString); + + //let log4j replace any properties in the string + String log4jConfiguredString = domConfig.subst(levelString); + + if(log4jConfiguredString.equals("") & ! log4jConfiguredString.equals(levelString)) + { + //log4j has returned an empty string but this isnt what we gave it. + //There may have been an undefined property. Unlike an incorrect + //literal value, we will allow this case to proceed, but warn users. + + if(_logger != null) + { + _logger.warn("Unable to detect Level value from '" + levelString + +"' for logger '" + loggerName + "', Log4J will default this to DEBUG"); + } + else + { + System.err.println("Unable to detect Level value from '" + levelString + +"' for logger " + loggerName + ", Log4J will default this to DEBUG"); + } + + continue; + } + + checkLevel(loggerName,log4jConfiguredString); } - - //check the root logger level - String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); - checkLevel("Root", rootLoggerlevelString); } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 8566ba6270..f8deb95628 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -69,8 +69,8 @@ import java.util.Properties; @SuppressWarnings({"AccessStaticViaInstance"}) public class Main { - private static final Logger _logger = Logger.getLogger(Main.class); - public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker"); + private static Logger _logger; + private static Logger _brokerLogger; private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; @@ -468,7 +468,18 @@ public class Main public static void main(String[] args) { - + //if the -Dlog4j.configuration property has not been set, enable the init override + //to stop Log4J wondering off and picking up the first log4j.xml/properties file it + //finds from the classpath when we get the first Loggers + if(System.getProperty("log4j.configuration") == null) + { + System.setProperty("log4j.defaultInitOverride", "true"); + } + + //now that the override status is know, we can instantiate the Loggers + _logger = Logger.getLogger(Main.class); + _brokerLogger = Logger.getLogger("Qpid.Broker"); + new Main(args); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index d98b14e4d5..3c47cdd094 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -40,6 +40,7 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.Log4jEntityResolver; import org.apache.log4j.xml.QpidLog4JConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator.QpidLog4JSaxErrorHandler; import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -266,30 +267,6 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM return newLevel; } - //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - public static class QpidLog4JSaxErrorHandler implements ErrorHandler - { - public void error(SAXParseException e) throws SAXException - { - throw new SAXException(constructMessage("Error parsing XML file", e)); - } - - public void fatalError(SAXParseException e) throws SAXException - { - throw new SAXException(constructMessage("Fatal error parsing XML file", e)); - } - - public void warning(SAXParseException e) throws SAXException - { - throw new SAXException(constructMessage("Warning parsing XML file", e)); - } - - private static String constructMessage(final String msg, final SAXParseException ex) - { - return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); - } - } - //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. private static synchronized Document parseConfigFile(String fileName) throws IOException { -- cgit v1.2.1 From 1045b2dd455d5c5da61f6395c44c7486a7b149f6 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 18 Aug 2009 16:27:08 +0000 Subject: Always log subscription state changes in the same way. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@805482 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/subscription/SubscriptionImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index b34ef1c382..72d6afc65c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -599,7 +599,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) { _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); - CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); } else { @@ -612,9 +611,9 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) { _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); - CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); } } + CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); } public State getState() -- cgit v1.2.1 From d5f67b8aa920a0bed8fc80464a6308a81b22362c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 24 Aug 2009 02:34:25 +0000 Subject: QPID-2069: Allow empty values to be specified for keys when creating bindings in a Headers exchange via JMX, as the HeaderBindind supports this as specifying a match on key presence only git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@807050 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/exchange/HeadersExchange.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index fc667db17b..c5f5cd05e1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -204,11 +204,21 @@ public class HeadersExchange extends AbstractExchange for (int i = 0; i < bindings.length; i++) { String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length < 2) + if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2) { throw new JMException("Format for headers binding should be \"=,=\" "); } - bindingMap.setString(keyAndValue[0], keyAndValue[1]); + + if(keyAndValue.length ==1) + { + //no value was given, only a key. Use an empty value + //to signal match on key presence alone + bindingMap.setString(keyAndValue[0], ""); + } + else + { + bindingMap.setString(keyAndValue[0], keyAndValue[1]); + } } _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); -- cgit v1.2.1 From df4d772b23cb21d15e00952360d669e6358c2242 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Sep 2009 16:22:54 +0000 Subject: QPID-1992 : Ensure StartupRootMessageLogger always logs messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@811469 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/logging/StartupRootMessageLogger.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java index 0dffde50fa..bfb122985b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java @@ -39,4 +39,11 @@ public class StartupRootMessageLogger extends RootMessageLoggerImpl return true; } + @Override + public boolean isMessageEnabled(LogActor actor) + { + return true; + } + + } -- cgit v1.2.1 From f60d221977ee66d6921e6744446a3f3aff5d5a7e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Sep 2009 16:23:53 +0000 Subject: QPID-2002 : Add MNG-1003 messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@811470 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/management/JMXManagedObjectRegistry.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 42b3b05ac5..aea9ab43ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -379,6 +379,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry try { _cs.stop(); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI ConnectorServer", _cs.getAddress().getPort())); } catch (IOException e) { -- cgit v1.2.1 From 20eba4a2b29721d88606148761599ee587d7d036 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 9 Sep 2009 08:36:52 +0000 Subject: Remove unusued FirewallFactory class git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@812821 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/plugins/network/FirewallFactory.java | 45 ---------------------- 1 file changed, 45 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java deleted file mode 100644 index a1a399e5bf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins.network; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -public class FirewallFactory implements ACLPluginFactory -{ - - @Override - public ACLPlugin newInstance(Configuration config) throws ConfigurationException - { - FirewallPlugin plugin = new FirewallPlugin(); - plugin.setConfiguration(config); - return plugin; - } - - @Override - public boolean supportsTag(String name) - { - return name.equals("firewall"); - } - -} -- cgit v1.2.1 From e873ee22cbd98f79a5a7cda84155c394566104a2 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 9 Sep 2009 08:45:51 +0000 Subject: Remove some more unused code. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@812825 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/security/access/plugins/BasicACLPlugin.java | 6 ------ 1 file changed, 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java index f7e537b02b..a6fae053c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -120,10 +120,4 @@ public abstract class BasicACLPlugin implements ACLPlugin // no-op } - public boolean supportsTag(String name) - { - // This plugin doesn't support any tags - return false; - } - } -- cgit v1.2.1 From 4b59f06b5398d9a349b2c6054f28ca58ada84a6d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 10 Sep 2009 14:38:25 +0000 Subject: QPID-2091 : Updated ServerConfiguration and added test to ServerConfigurationTest. Merged virtualhost.xml with config.xml git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@813459 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 35 ++++++++++------------ 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 7ea7738189..ed9d8acc08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -147,32 +147,27 @@ public class ServerConfiguration implements SignalHandler Object thing = i.next(); if (thing instanceof String) { + //Open the Virtualhost.xml file and copy values in to main config XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); - List hosts = vhostConfiguration.getList("virtualhost.name"); - for (int j = 0; j < hosts.size(); j++) - { - String name = (String) hosts.get(j); - // Add the keys of the virtual host to the main config then bail out - - Configuration myConf = vhostConfiguration.subset("virtualhost." + name); - Iterator k = myConf.getKeys(); - while (k.hasNext()) - { - String key = (String) k.next(); - conf.setProperty("virtualhosts.virtualhost."+name+"."+key, myConf.getProperty(key)); - } - VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name)); - _virtualHosts.put(vhostConfig.getName(), vhostConfig); - } - // Grab things other than the virtualhosts themselves Iterator keys = vhostConfiguration.getKeys(); while (keys.hasNext()) { String key = (String) keys.next(); - conf.setProperty("virtualhosts."+key, vhostConfiguration.getProperty(key)); + conf.setProperty("virtualhosts." + key, vhostConfiguration.getProperty(key)); } } } + + List hosts = conf.getList("virtualhosts.virtualhost.name"); + for (int j = 0; j < hosts.size(); j++) + { + String name = (String) hosts.get(j); + // Add the keys of the virtual host to the main config then bail out + + VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost." + name)); + _virtualHosts.put(vhostConfig.getName(), vhostConfig); + } + } private void substituteEnvironmentVariables() @@ -202,7 +197,7 @@ public class ServerConfiguration implements SignalHandler } /** - * Check the configuration file to see if status updates are enabled. + * Check the configuration file to see if status updates are enabled. * @return true if status updates are enabled */ public boolean getStatusUpdatesEnabled() @@ -466,7 +461,7 @@ public class ServerConfiguration implements SignalHandler { return getConfig().getBoolean("management.enabled", true); } - + public void setManagementEnabled(boolean enabled) { getConfig().setProperty("management.enabled", enabled); -- cgit v1.2.1 From e19b7b8843ba53885656a22ae55f4bb7dc9db7ab Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 11 Sep 2009 12:23:28 +0000 Subject: QPID-2096 : Add a work around which stops durable exchanges being written to the message store. This will allow current DerbyStores to start up but will mean that the existence of the exchange in the configuration is its durability. Remove it from the config and it is gone. This differs from the way queues work. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@813796 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/virtualhost/VirtualHost.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index fa6b2285eb..9ab3592628 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -195,10 +195,22 @@ public class VirtualHost implements Accessable // perform a createExchange twice with the same details in the // MessageStore(RoutingTable) as some instances may not like that. // Derby being one. + // todo this can be removed with the resolution fo QPID-2096 configFileRT.exchange.clear(); initialiseModel(hostConfig); + //todo REMOVE Work Around for QPID-2096 + // This means that all durable exchanges declared in the configuration + // will not be stored in the MessageStore. + // They will still be created/registered/available on startup for as + // long as they are contained in the configuration. However, when they + // are removed from the configuration they will no longer exist. + // This differs from durable queues as they will be writen to to the + // store. After QPID-2096 has been resolved exchanges will mirror that + // functionality. + configFileRT.exchange.clear(); + if (store != null) { _messageStore = store; -- cgit v1.2.1 From 0ee4afcc8f02a1684f3864eacaaf6290507d1cd3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 11 Sep 2009 12:27:14 +0000 Subject: QPID-2093: Updated AMQBRokerManagerMBean to check if the queue is durable before performing store.deleteQueue(). Created ModelTest to validate the change, (testDeletionDurableViaJMX). To facility the testing, extracted JMX Operations from ManagementActorLoggingTest to a new JMXTestUtils and updated both ModelTest and MALT to use this interface. Updated 010(cpp) and 08(Java-InVM) excludes as the CPP does not have JMX and the InVM JMX is unreliable (see QPID-2097) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@813801 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 2afd3c1dc3..5cfa8066e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -317,8 +317,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr try { queue.delete(); - _messageStore.removeQueue(queue); - + if (queue.isDurable()) + { + _messageStore.removeQueue(queue); + } } catch (AMQException ex) { -- cgit v1.2.1 From 2765f90b4b80043f8f3d8e15afe14ad8e4cbd49e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 28 Sep 2009 15:48:48 +0000 Subject: QPID-2028 : Augment BrokerActor to allow the setting of the broker name. Updated ApplicationRegistries to pass the instanceID to the BrokerActor in an attempt to better identify what brokers are shutting down during our test runs. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@819605 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/logging/actors/BrokerActor.java | 8 ++++++++ .../org/apache/qpid/server/registry/ApplicationRegistry.java | 2 +- .../server/registry/ConfigurationFileApplicationRegistry.java | 10 +++++++--- .../org/apache/qpid/server/registry/IApplicationRegistry.java | 3 ++- 4 files changed, 18 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java index 9b928accc0..5d2762fd1d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java @@ -36,4 +36,12 @@ public class BrokerActor extends AbstractActor _logString = "[Broker] "; } + + public BrokerActor(String name, RootMessageLogger logger) + { + super(logger); + + _logString = "[Broker(" + name + ")] "; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index b6137e83de..7511b5c818 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -102,7 +102,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { - instance.initialise(); + instance.initialise(instanceID); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index a049d1eb09..831f928832 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -42,18 +42,22 @@ import java.io.File; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { + private String _registryName; public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { super(new ServerConfiguration(configurationURL)); } - public void initialise() throws Exception + public void initialise(int instanceID) throws Exception { _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); + + _registryName = String.valueOf(instanceID); + // Set the Actor for current log messages - CurrentActor.set(new BrokerActor(_rootMessageLogger)); + CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); @@ -83,7 +87,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void close() throws Exception { //Set the Actor for Broker Shutdown - CurrentActor.set(new BrokerActor(_rootMessageLogger)); + CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); try { super.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index ddb3fce5d2..92accb3499 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -43,8 +43,9 @@ public interface IApplicationRegistry * Initialise the application registry. All initialisation must be done in this method so that any components * that need access to the application registry itself for initialisation are able to use it. Attempting to * initialise in the constructor will lead to failures since the registry reference will not have been set. + * @param instanceID the instanceID that we can use to identify this AR. */ - void initialise() throws Exception; + void initialise(int instanceID) throws Exception; /** * Shutdown this Registry -- cgit v1.2.1 From 32b29014ad02b69e74485bf95bf8c7f0cb58c871 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:54:47 +0000 Subject: QPID-2116 : Ensure that AMQChannel correctly notifies all running Subscription deliveries that the Channel has been suspended. This is down by taking out the subcription sendLock on each subscription on this Channel. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820316 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 55 ++++++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index add5e64ee8..180f0a992c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -783,16 +783,31 @@ public class AMQChannel return _unacknowledgedMessageMap; } - + /** + * Called from the ChannelFlowHandler to suspend this Channel + * @param suspended boolean, should this Channel be suspended + */ public void setSuspended(boolean suspended) { - - boolean wasSuspended = _suspended.getAndSet(suspended); if (wasSuspended != suspended) { - _actor.message(_logSubject, ChannelMessages.CHN_1002(suspended ? "Stopped" : "Started")); + // Log Flow Started before we start the subscriptions + if (!suspended) + { + _actor.message(_logSubject, ChannelMessages.CHN_1002("Started")); + } + // This section takes two different approaches to perform to perform + // the same function. Ensuring that the Subscription has taken note + // of the change in Channel State + + // Here we have become unsuspended and so we ask each the queue to + // perform an Async delivery for each of the subscriptions in this + // Channel. The alternative would be to ensure that the subscription + // had received the change in suspension state. That way the logic + // behind decieding to start an async delivery was located with the + // Subscription. if (wasSuspended) { // may need to deliver queued messages @@ -801,6 +816,38 @@ public class AMQChannel s.getQueue().deliverAsync(s); } } + + + // Here we have become suspended so we need to ensure that each of + // the Subscriptions has noticed this change so that we can be sure + // they are not still sending messages. Again the code here is a + // very simplistic approach to ensure that the change of suspension + // has been noticed by each of the Subscriptions. Unlike the above + // case we don't actually need to do anything else. + if (!wasSuspended) + { + // may need to deliver queued messages + for (Subscription s : _tag2SubscriptionMap.values()) + { + try + { + s.getSendLock(); + } + finally + { + s.releaseSendLock(); + } + } + } + + + // Log Suspension only after we have confirmed all suspensions are + // stopped. + if (suspended) + { + _actor.message(_logSubject, ChannelMessages.CHN_1002("Stopped")); + } + } } -- cgit v1.2.1 From ef0d07f4c552aaa198011af2b2b4f6724c9ab579 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:55:26 +0000 Subject: Add toString to AbstractActor to allow actors to be used in debug log messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820317 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/actors/AbstractActor.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 4502710dd6..0059a48c06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -60,4 +60,9 @@ public abstract class AbstractActor implements LogActor return _rootLogger; } + public String toString() + { + return _logString; + } + } -- cgit v1.2.1 From 9dc92c03d0fb24075ace8a44550e565866b06b0d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:55:59 +0000 Subject: Prevent NPE in QueueEntryImpl.debugIdentity git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820318 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/QueueEntryImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index dbad5438dc..01b249b847 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -177,7 +177,15 @@ public class QueueEntryImpl implements QueueEntry public String debugIdentity() { - return getMessage().debugIdentity(); + AMQMessage message = getMessage(); + if (message == null) + { + return "null"; + } + else + { + return message.debugIdentity(); + } } -- cgit v1.2.1 From ce240e785c5d32a777fe5cbc2dc159274c604dec Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:56:33 +0000 Subject: Add debug logging to see what the next message the Subscription is going to look at. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820319 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/subscription/SubscriptionImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 72d6afc65c..2893e916cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -630,11 +630,19 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public QueueEntry getLastSeenEntry() { - return _queueContext.get(); + QueueEntry entry = _queueContext.get(); + + if(_logger.isDebugEnabled()) + { + _logger.debug(_logActor + ": lastSeenEntry: " + (entry == null ? "null" : entry.debugIdentity())); + } + + return entry; } public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) { + _logger.debug(debugIdentity() + " Setting Last Seen To:" + (newvalue == null ? "nullNV" : newvalue.debugIdentity())); return _queueContext.compareAndSet(expected,newvalue); } -- cgit v1.2.1 From 1a5c89fbce3ed0dee13826df137effad1ff12f88 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:57:24 +0000 Subject: QPID-2120 : Updated SimpleAMQQueue to ensure that the sub.isSuspended() check is done before any attempt to retrieve the getLastSeenNode(). This and the commits for QPID-1871,QPID-2116 are tested by RollbackOrderTest that now can be enabled for the Java profile. Additional changes were done to SAMQQ to improve readability and add some debug loggging. Performance testing should be done to identify any penality for this additional logging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820320 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 180 +++++++++++++-------- 1 file changed, 112 insertions(+), 68 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b14b92b014..9894efed20 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -508,8 +508,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throws AMQException { _deliveredMessages.incrementAndGet(); + if (_logger.isDebugEnabled()) + { + _logger.debug(sub + ": deliverMessage: " + entry.debugIdentity()); + } sub.send(entry); - } private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) @@ -1172,9 +1175,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void deliverAsync() { - _stateChangeCount.incrementAndGet(); - - Runner runner = new Runner(); + Runner runner = new Runner(_stateChangeCount.incrementAndGet()); if (_asynchronousRunner.compareAndSet(null, runner)) { @@ -1187,13 +1188,23 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery.execute(new SubFlushRunner(sub)); } + private class Runner implements ReadWriteRunnable { + String _name; + public Runner(long count) + { + _name = "QueueRunner-" + count + "-" + _logActor; + } + public void run() { + String originalName = Thread.currentThread().getName(); try { + Thread.currentThread().setName(_name); CurrentActor.set(_logActor); + processQueue(this); } catch (AMQException e) @@ -1203,9 +1214,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener finally { CurrentActor.remove(); + Thread.currentThread().setName(originalName); } - - } public boolean isRead() @@ -1217,6 +1227,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { return true; } + + public String toString() + { + return _name; + } } private class SubFlushRunner implements ReadWriteRunnable @@ -1230,27 +1245,36 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void run() { - boolean complete = false; - try - { - CurrentActor.set(_sub.getLogActor()); - complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); - } - catch (AMQException e) - { - _logger.error(e); + String originalName = Thread.currentThread().getName(); + try{ + Thread.currentThread().setName("SubFlushRunner-"+_sub); + + boolean complete = false; + try + { + CurrentActor.set(_sub.getLogActor()); + complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); + + } + catch (AMQException e) + { + _logger.error(e); + } + finally + { + CurrentActor.remove(); + } + if (!complete && !_sub.isSuspended()) + { + _asyncDelivery.execute(this); + } } finally { - CurrentActor.remove(); - } - if (!complete && !_sub.isSuspended()) - { - _asyncDelivery.execute(this); + Thread.currentThread().setName(originalName); } - } public boolean isRead() @@ -1278,7 +1302,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener try { sub.getSendLock(); - atTail = attemptDelivery(sub); + atTail = attemptDelivery(sub); if (atTail && sub.isAutoClose()) { unregisterSubscription(sub); @@ -1308,63 +1332,78 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return atTail; } + /** + * Attempt delivery for the given subscription. + * + * Looks up the next node for the subscription and attempts to deliver it. + * + * @param sub + * @return + * @throws AMQException + */ private boolean attemptDelivery(Subscription sub) throws AMQException { boolean atTail = false; boolean advanced = false; - boolean subActive = sub.isActive(); + boolean subActive = sub.isActive() && !sub.isSuspended(); if (subActive) { QueueEntry node = moveSubscriptionToNextNode(sub); + _logger.debug(sub + ": attempt delivery: " + node.debugIdentity()); if (!(node.isAcquired() || node.isDeleted())) { - if (!sub.isSuspended()) + if (sub.hasInterest(node)) { - if (sub.hasInterest(node)) + if (!sub.wouldSuspend(node)) { - if (!sub.wouldSuspend(node)) + if (!sub.isBrowser() && !node.acquire(sub)) { - if (!sub.isBrowser() && !node.acquire(sub)) - { - sub.restoreCredit(node); - } - else + sub.restoreCredit(node); + } + else + { + deliverMessage(sub, node); + + if (sub.isBrowser()) { - deliverMessage(sub, node); + QueueEntry newNode = _entries.next(node); - if (sub.isBrowser()) + if (newNode != null) { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - advanced = true; - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } + advanced = true; + sub.setLastSeenEntry(node, newNode); + node = sub.getLastSeenEntry(); } + } - - } - else // Not enough Credit for message and wouldSuspend - { - //QPID-1187 - Treat the subscription as suspended for this message - // and wait for the message to be removed to continue delivery. - subActive = false; - node.addStateChangeListener(new QueueEntryListener(sub, node)); } + } - else + else // Not enough Credit for message and wouldSuspend { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - } + //QPID-1187 - Treat the subscription as suspended for this message + // and wait for the message to be removed to continue delivery. + + // 2009-09-30 : MR : setting subActive = false only causes, this + // particular delivery attempt to end. This is called from + // flushSubscription and processQueue both of which attempt + // delivery a number of times. Won't a bytes limited + // subscriber with not enough credit for the next message + // create a lot of new QELs? How about a browser that calls + // this method LONG.MAX_LONG times! + subActive = false; + node.addStateChangeListener(new QueueEntryListener(sub, node)); + } + } + else + { + // this subscription is not interested in this node so we can skip over it + QueueEntry newNode = _entries.next(node); + if (newNode != null) + { + sub.setLastSeenEntry(node, newNode); } } - } atTail = (_entries.next(node) == null) && !advanced; } @@ -1409,6 +1448,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + + if (_logger.isDebugEnabled()) + { + _logger.debug(sub + ": nextNode: " + (node == null ? "null" : node.debugIdentity())); + } + return node; } @@ -1423,6 +1468,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asynchronousRunner.compareAndSet(runner, null); + // For every message enqueue/requeue the we fire deliveryAsync() which + // increases _stateChangeCount. If _sCC changes whilst we are in our loop + // (detected by setting previousStateChangeCount to stateChangeCount in the loop body) + // then we will continue to run for a maximum of iterations. + // So whilst delivery/rejection is going on a processQueue thread will be running while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner)) { // we want to have one extra loop after every subscription has reached the point where it cannot move @@ -1442,20 +1492,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener //iterate over the subscribers and try to advance their pointer while (subscriptionIter.advance()) { - boolean closeConsumer = false; Subscription sub = subscriptionIter.getNode().getSubscription(); sub.getSendLock(); try { - if (sub != null) - { - - QueueEntry node = moveSubscriptionToNextNode(sub); - if (node != null) - { - done = attemptDelivery(sub); - } - } + done = attemptDelivery(sub); if (done) { if (extraLoops == 0) @@ -1492,11 +1533,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // therefore we should schedule this runner again (unless someone beats us to it :-) ). if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner)) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Rescheduling runner:" + runner); + } _asyncDelivery.execute(runner); } } - @Override public void checkMessageStatus() throws AMQException { -- cgit v1.2.1 From 1b3fa553929bc0532f47f60d488327b9070c8fa4 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 30 Sep 2009 15:58:16 +0000 Subject: QPID-2118 : Corrected 010Exclude for runtime selector exception. Tidied up SelectorTest so that it uses more of QTC functionality and stops creating random queue names. The init() methods could be totally removed with a bit more work. Updated test() to be testOnMessage() to better identify what test was supposed to be using onMessage() previously they all were! JMSMessageID test should now pass again on CPP profile. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820321 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 9894efed20..4b9fc9ca55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1338,7 +1338,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener * Looks up the next node for the subscription and attempts to deliver it. * * @param sub - * @return + * @return true if we have completed all possible deliveries for this sub. * @throws AMQException */ private boolean attemptDelivery(Subscription sub) throws AMQException @@ -1349,7 +1349,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (subActive) { QueueEntry node = moveSubscriptionToNextNode(sub); - _logger.debug(sub + ": attempt delivery: " + node.debugIdentity()); + if (_logger.isDebugEnabled()) + { + _logger.debug(sub + ": attempting Delivery: " + node.debugIdentity()); + } if (!(node.isAcquired() || node.isDeleted())) { if (sub.hasInterest(node)) -- cgit v1.2.1 From c62dbd2ed611515bf232b52455c785b1c87861f1 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 1 Oct 2009 18:09:10 +0000 Subject: QPID-942 : Add Simplistic Producer Flow Control to the java Broker / java 0-8/0-9 client git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@820739 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 55 +++++++++-- .../server/configuration/QueueConfiguration.java | 10 ++ .../server/configuration/ServerConfiguration.java | 13 ++- .../configuration/VirtualHostConfiguration.java | 11 +++ .../logging/messages/LogMessages_en_US.properties | 6 +- .../org/apache/qpid/server/queue/AMQQueue.java | 13 +++ .../apache/qpid/server/queue/AMQQueueFactory.java | 106 +++++++++++++++++++++ .../apache/qpid/server/queue/QueueEntryImpl.java | 6 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 92 +++++++++++++++++- .../qpid/server/txn/LocalTransactionalContext.java | 1 + .../qpid/server/txn/NonTransactionalContext.java | 2 + 11 files changed, 296 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 180f0a992c..ea48bd7cc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -27,13 +27,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.*; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; @@ -42,12 +41,8 @@ import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.UnauthorizedAccessException; +import org.apache.qpid.server.protocol.AMQMinaProtocolSession; +import org.apache.qpid.server.queue.*; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; @@ -59,6 +54,7 @@ import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogMessage; import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.logging.actors.AMQPChannelActor; @@ -119,6 +115,11 @@ public class AMQChannel private final AMQProtocolSession _session; private boolean _closing; + private final ConcurrentMap _blockingQueues = new ConcurrentHashMap(); + + private final AtomicBoolean _blocking = new AtomicBoolean(false); + + private LogActor _actor; private LogSubject _logSubject; @@ -798,6 +799,7 @@ public class AMQChannel _actor.message(_logSubject, ChannelMessages.CHN_1002("Started")); } + // This section takes two different approaches to perform to perform // the same function. Ensuring that the Subscription has taken note // of the change in Channel State @@ -978,4 +980,37 @@ public class AMQChannel { return _actor; } + + public void block(AMQQueue queue) + { + if(_blockingQueues.putIfAbsent(queue, Boolean.TRUE) == null) + { + + if(_blocking.compareAndSet(false,true)) + { + _actor.message(_logSubject, ChannelMessages.CHN_1005(queue.getName().toString())); + flow(false); + } + } + } + + public void unblock(AMQQueue queue) + { + if(_blockingQueues.remove(queue)) + { + if(_blocking.compareAndSet(true,false)) + { + _actor.message(_logSubject, ChannelMessages.CHN_1006()); + + flow(true); + } + } + } + + private void flow(boolean flow) + { + MethodRegistry methodRegistry = _session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow); + _session.writeFrame(responseBody.generateFrame(_channelId)); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 74bb7ee969..5c73e353de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -108,4 +108,14 @@ public class QueueConfiguration return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); } + public long getCapacity() + { + return _config.getLong("capacity", _vHostConfig.getCapacity()); + } + + public long getFlowResumeCapacity() + { + return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index ed9d8acc08..01befbbfe8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -103,6 +103,8 @@ public class ServerConfiguration implements SignalHandler envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth"); envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize"); envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap"); + envVarMap.put("QPID_QUEUECAPACITY", "capacity"); + envVarMap.put("QPID_FLOWRESUMECAPACITY", "flowResumeCapacity"); envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer"); envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer"); envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay"); @@ -289,7 +291,6 @@ public class ServerConfiguration implements SignalHandler return conf; } - @Override public void handle(Signal arg0) { try @@ -507,6 +508,16 @@ public class ServerConfiguration implements SignalHandler return getConfig().getLong("minimumAlertRepeatGap", 0); } + public long getCapacity() + { + return getConfig().getLong("capacity", 0L); + } + + public long getFlowResumeCapacity() + { + return getConfig().getLong("flowResumeCapacity", getCapacity()); + } + public int getProcessors() { return getConfig().getInt("connector.processors", 4); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 0273a13262..6c72025ec2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -166,4 +166,15 @@ public class VirtualHostConfiguration return _config.getLong("queues.minimumAlertRepeatGap", 0); } + + public long getCapacity() + { + return _config.getLong("queues.capacity", 0l); + } + + public long getFlowResumeCapacity() + { + return _config.getLong("queues.flowResumeCapacity", getCapacity()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 5ced7cc0b9..9169a1a651 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -249,12 +249,16 @@ CHN-1003 = Close # 0 - bytes allowed in prefetch # 1 - number of messagse. CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +CHN-1005 = Flow Control Enforced (Queue {0}) +CHN-1006 = Flow Control Removed #Queue # 0 - owner # 1 - priority QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted +QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} +QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} #Exchange # 0 - type @@ -269,4 +273,4 @@ BND-1002 = Deleted #Subscription SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close -SUB-1003 = State : {0} \ No newline at end of file +SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 2a692344d0..184504717e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -160,6 +160,17 @@ public interface AMQQueue extends Managable, Comparable void setMinimumAlertRepeatGap(long value); + long getCapacity(); + + void setCapacity(long capacity); + + + long getFlowResumeCapacity(); + + void setFlowResumeCapacity(long flowResumeCapacity); + + + void deleteMessageFromTop(StoreContext storeContext) throws AMQException; long clearQueue(StoreContext storeContext) throws AMQException; @@ -180,6 +191,8 @@ public interface AMQQueue extends Managable, Comparable void stop(); + void checkCapacity(AMQChannel channel); + /** * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription * already exists. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 7509350e65..267ccf43ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -26,11 +26,105 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Map; +import java.util.HashMap; + public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + private abstract static class QueueProperty + { + + private final AMQShortString _argumentName; + + + public QueueProperty(String argumentName) + { + _argumentName = new AMQShortString(argumentName); + } + + public AMQShortString getArgumentName() + { + return _argumentName; + } + + + public abstract void setPropertyValue(AMQQueue queue, Object value); + + } + + private abstract static class QueueLongProperty extends QueueProperty + { + + public QueueLongProperty(String argumentName) + { + super(argumentName); + } + + public void setPropertyValue(AMQQueue queue, Object value) + { + if(value instanceof Number) + { + setPropertyValue(queue, ((Number)value).longValue()); + } + + } + + abstract void setPropertyValue(AMQQueue queue, long value); + + + } + + private static final QueueProperty[] DECLAREABLE_PROPERTIES = { + new QueueLongProperty("x-qpid-maximum-message-age") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setMaximumMessageAge(value); + } + }, + new QueueLongProperty("x-qpid-maximum-message-size") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setMaximumMessageSize(value); + } + }, + new QueueLongProperty("x-qpid-maximum-message-count") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setMaximumMessageCount(value); + } + }, + new QueueLongProperty("x-qpid-minimum-alert-repeat-gap") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setMinimumAlertRepeatGap(value); + } + }, + new QueueLongProperty("x-qpid-capacity") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setCapacity(value); + } + }, + new QueueLongProperty("x-qpid-flow-resume-capacity") + { + public void setPropertyValue(AMQQueue queue, long value) + { + queue.setFlowResumeCapacity(value); + } + } + + }; + + + public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, AMQShortString owner, @@ -53,6 +147,18 @@ public class AMQQueueFactory //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString())); + + if(arguments != null) + { + for(QueueProperty p : DECLAREABLE_PROPERTIES) + { + if(arguments.containsKey(p.getArgumentName())) + { + p.setPropertyValue(q, arguments.get(p.getArgumentName())); + } + } + } + return q; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 01b249b847..3b58f05f93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -42,8 +42,7 @@ public class QueueEntryImpl implements QueueEntry private final SimpleQueueEntryList _queueEntryList; - private AMQMessage _message; - + private final AMQMessage _message; private Set _rejectedBy = null; @@ -191,7 +190,7 @@ public class QueueEntryImpl implements QueueEntry public boolean immediateAndNotDelivered() { - return _message.immediateAndNotDelivered(); + return getMessage().immediateAndNotDelivered(); } public void setRedelivered(boolean b) @@ -393,4 +392,5 @@ public class QueueEntryImpl implements QueueEntry { return _queueEntryList; } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 4b9fc9ca55..8b6c15c0c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,11 +1,10 @@ package org.apache.qpid.server.queue; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -35,6 +34,7 @@ import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.messages.QueueMessages; +import org.apache.qpid.server.AMQChannel; /* * @@ -96,6 +96,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final Executor _asyncDelivery; private final AtomicLong _totalMessagesReceived = new AtomicLong(); + private final ConcurrentMap _blockedChannels = new ConcurrentHashMap(); + /** max allowed size(KB) of a single message */ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); @@ -122,6 +124,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private LogSubject _logSubject; private LogActor _logActor; + + private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); + private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException { @@ -629,6 +635,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new FailedDequeueException(_name.toString(), e); } + checkCapacity(); + } private void decrementQueueSize(final QueueEntry entry) @@ -1173,6 +1181,58 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + public void checkCapacity(AMQChannel channel) + { + if(_capacity != 0l) + { + if(_atomicQueueSize.get() > _capacity) + { + //Overfull log message + _logActor.message(_logSubject, QueueMessages.QUE_1003(_atomicQueueSize.get(), _capacity)); + + if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null) + { + channel.block(this); + } + + if(_atomicQueueSize.get() <= _flowResumeCapacity) + { + + //Underfull log message + _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + + channel.unblock(this); + _blockedChannels.remove(channel); + + } + + } + + + + } + } + + private void checkCapacity() + { + if(_capacity != 0L) + { + if(_atomicQueueSize.get() <= _flowResumeCapacity) + { + //Underfull log message + _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + + + for(AMQChannel c : _blockedChannels.keySet()) + { + c.unblock(this); + _blockedChannels.remove(c); + } + } + } + } + + public void deliverAsync() { Runner runner = new Runner(_stateChangeCount.incrementAndGet()); @@ -1544,6 +1604,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + public void checkMessageStatus() throws AMQException { @@ -1651,6 +1712,27 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + public long getCapacity() + { + return _capacity; + } + + public void setCapacity(long capacity) + { + _capacity = capacity; + } + + public long getFlowResumeCapacity() + { + return _flowResumeCapacity; + } + + public void setFlowResumeCapacity(long flowResumeCapacity) + { + _flowResumeCapacity = flowResumeCapacity; + } + + public Set getNotificationChecks() { return _notificationChecks; @@ -1720,6 +1802,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener setMaximumMessageSize(config.getMaximumMessageSize()); setMaximumMessageCount(config.getMaximumMessageCount()); setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); + _capacity = config.getCapacity(); + _flowResumeCapacity = config.getFlowResumeCapacity(); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index 3c71282c57..450852cef7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -97,6 +97,7 @@ public class LocalTransactionalContext implements TransactionalContext try { QueueEntry entry = _queue.enqueue(getStoreContext(),_message); + _queue.checkCapacity(_channel); if(entry.immediateAndNotDelivered()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java index 28af36e3db..10d6021d27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -91,6 +91,8 @@ public class NonTransactionalContext implements TransactionalContext public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException { QueueEntry entry = queue.enqueue(_storeContext, message); + queue.checkCapacity(_channel); + //following check implements the functionality //required by the 'immediate' flag: -- cgit v1.2.1 From 4a997d0ccf34f790cf9e55e6b2e22cc65b0428e1 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Wed, 7 Oct 2009 22:28:45 +0000 Subject: QPID-942 : Added tests for broker and client log messages produced when flow control invoked git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@822949 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 8b6c15c0c3..08c4e94d1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -127,6 +127,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); + private final AtomicBoolean _overfull = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) throws AMQException @@ -1187,6 +1188,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if(_atomicQueueSize.get() > _capacity) { + _overfull.set(true); //Overfull log message _logActor.message(_logSubject, QueueMessages.QUE_1003(_atomicQueueSize.get(), _capacity)); @@ -1217,10 +1219,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if(_capacity != 0L) { - if(_atomicQueueSize.get() <= _flowResumeCapacity) + if(_overfull.get() && _atomicQueueSize.get() <= _flowResumeCapacity) { - //Underfull log message - _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + if(_overfull.compareAndSet(true,false)) + {//Underfull log message + _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + } for(AMQChannel c : _blockedChannels.keySet()) -- cgit v1.2.1 From 7568fef734b03114883a9256a927d5f9151da0b1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 8 Oct 2009 08:17:33 +0000 Subject: QPID-1950 : Problem is that the thrown exception whilst an IOException does not signify that the socket has closed. So the broker had two open connections to send messages on. Change was to ensure that the previous Socket/IOSession has been closed before failover starts. Also added protected to ChannelOpenHandler to guard against out of order frames causing a NPE. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@823087 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/handler/BasicRejectMethodHandler.java | 2 +- .../java/org/apache/qpid/server/handler/ChannelOpenHandler.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index f3cab10ed7..fcf3fd4337 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -71,7 +71,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener Date: Fri, 9 Oct 2009 08:54:26 +0000 Subject: QPID-1872: check for existence of outer consume permissions map before proceeding to further checks, and if not present then deny immediately as it signifies a complete lack of consume rights in the ACL settigns for the user in question. Update SimpleACLTest to add a check for consumption with create but without consume right, and to allow each test to customise the ACL settings before QTC.setUp() starts the broker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@823464 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/security/access/PrincipalPermissions.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index f852514444..fb57ca9a59 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -494,6 +494,12 @@ public class PrincipalPermissions { AMQQueue queue = ((AMQQueue) parameters[0]); Map queuePermissions = (Map) _permissions.get(permission); + + if (queuePermissions == null) + { + //if the outer map is null, the user has no CONSUME rights at all + return AuthzResult.DENIED; + } List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); -- cgit v1.2.1 From 70164157c627ca78e09dea002fe9cae2bbd54e02 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Sun, 11 Oct 2009 19:50:21 +0000 Subject: Refactor a little, extract large inline case statements to individual methods. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@824128 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissions.java | 1008 ++++++++++---------- 1 file changed, 516 insertions(+), 492 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index fb57ca9a59..d2bbb795e9 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -20,16 +20,17 @@ */ package org.apache.qpid.server.security.access; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.QueueBindBody; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.exchange.Exchange; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; public class PrincipalPermissions { @@ -41,6 +42,7 @@ public class PrincipalPermissions private static final Object CREATE_QUEUES_KEY = new Object(); private static final Object CREATE_EXCHANGES_KEY = new Object(); + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); @@ -80,248 +82,257 @@ public class PrincipalPermissions { switch (permission) { - case ACCESS: - break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS - case BIND: - break; // All the details are currently included in the create setup. case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly - Map consumeRights = (Map) _permissions.get(permission); - - if (consumeRights == null) - { - consumeRights = new ConcurrentHashMap(); - _permissions.put(permission, consumeRights); - } - - //if we have parametsre - if (parameters.length > 0) - { - AMQShortString queueName = (AMQShortString) parameters[0]; - Boolean temporary = (Boolean) parameters[1]; - Boolean ownQueueOnly = (Boolean) parameters[2]; - - if (temporary) - { - consumeRights.put(CONSUME_TEMPORARY_KEY, true); - } - else - { - consumeRights.put(CONSUME_TEMPORARY_KEY, false); - } - - if (ownQueueOnly) - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); - } - else - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); - } - - - LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); - if (queues == null) - { - queues = new LinkedList(); - consumeRights.put(CONSUME_QUEUES_KEY, queues); - } - - if (queueName != null) - { - queues.add(queueName); - } - } - - + grantConsume(permission, parameters); break; case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName // , AMQShortString exchangeName , AMQShortString routingKey - - Map createRights = (Map) _permissions.get(permission); - - if (createRights == null) - { - createRights = new ConcurrentHashMap(); - _permissions.put(permission, createRights); - - } - - //The existence of the empty map mean permission to all. - if (parameters.length == 0) - { - return; - } - - Boolean temporary = (Boolean) parameters[0]; - - AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; - AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; - //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; - - // Get the queues map - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - if (create_queues == null) - { - create_queues = new ConcurrentHashMap(); - createRights.put(CREATE_QUEUES_KEY, create_queues); - } - - //Allow all temp queues to be created - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); - - //Create empty list of queues - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - if (create_queues_queues == null) - { - create_queues_queues = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); - } - - // We are granting CREATE rights to all temporary queues only - if (parameters.length == 1) - { - return; - } - - // if we have a queueName then we need to store any associated exchange / rk bindings - if (queueName != null) - { - Map queue = (Map) create_queues_queues.get(queueName); - if (queue == null) - { - queue = new ConcurrentHashMap(); - create_queues_queues.put(queueName, queue); - } - - if (exchangeName != null) - { - queue.put(exchangeName, routingKey); - } - - //If no exchange is specified then the presence of the queueName in the map says any exchange is ok - } - - // Store the exchange that we are being granted rights to. This will be used as part of binding - - //Lookup the list of exchanges - Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - if (create_queues_exchanges == null) - { - create_queues_exchanges = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); - } - - //if we have an exchange - if (exchangeName != null) - { - //Retrieve the list of permitted exchanges. - Map exchanges = (Map) create_queues_exchanges.get(exchangeName); - - if (exchanges == null) - { - exchanges = new ConcurrentHashMap(); - create_queues_exchanges.put(exchangeName, exchanges); - } - - //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY - exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); - - //Store the binding details of queue/rk for this exchange. - if (queueName != null) - { - //Retrieve the list of permitted routingKeys. - Map rKeys = (Map) exchanges.get(exchangeName); - - if (rKeys == null) - { - rKeys = new ConcurrentHashMap(); - exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); - } - - rKeys.put(queueName, routingKey); - } - } + grantCreateQueue(permission, parameters); break; case CREATEEXCHANGE: // Parameters AMQShortString exchangeName , AMQShortString Class - Map rights = (Map) _permissions.get(permission); - if (rights == null) - { - rights = new ConcurrentHashMap(); - _permissions.put(permission, rights); - } - - Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); - if (create_exchanges == null) - { - create_exchanges = new ConcurrentHashMap(); - rights.put(CREATE_EXCHANGES_KEY, create_exchanges); - } - - //Should perhaps error if parameters[0] is null; - AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; - AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); - - //Store the exchangeName / class mapping if the mapping is null - rights.put(name, className); - break; - case DELETE: + grantCreateExchange(permission, parameters); break; - case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - publishRights = new ConcurrentHashMap(); - _permissions.put(permission, publishRights); - } - - if (parameters == null || parameters.length == 0) - { - //If we have no parameters then allow publish to all destinations - // this is signified by having a null value for publish_exchanges - } - else - { - Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - if (publish_exchanges == null) - { - publish_exchanges = new ConcurrentHashMap(); - publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); - } - - - HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); - - // Check to see if we have a routing key - if (parameters.length == 2) - { - if (routingKeys == null) - { - routingKeys = new HashSet(); - } - //Add routing key to permitted publish destinations - routingKeys.add(parameters[1]); - } - - // Add the updated routingkey list or null if all values allowed - publish_exchanges.put(parameters[0], routingKeys); - } + grantPublish(permission, parameters); break; + /* The other cases just fall through to no-op */ + case DELETE: + case ACCESS: // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS + case BIND: // All the details are currently included in the create setup. case PURGE: - break; case UNBIND: break; } } + private void grantPublish(Permission permission, Object... parameters) { + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + publishRights = new ConcurrentHashMap(); + _permissions.put(permission, publishRights); + } + + if (parameters == null || parameters.length == 0) + { + //If we have no parameters then allow publish to all destinations + // this is signified by having a null value for publish_exchanges + } + else + { + Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + if (publish_exchanges == null) + { + publish_exchanges = new ConcurrentHashMap(); + publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); + } + + + HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); + + // Check to see if we have a routing key + if (parameters.length == 2) + { + if (routingKeys == null) + { + routingKeys = new HashSet(); + } + //Add routing key to permitted publish destinations + routingKeys.add(parameters[1]); + } + + // Add the updated routingkey list or null if all values allowed + publish_exchanges.put(parameters[0], routingKeys); + } + } + + private void grantCreateExchange(Permission permission, Object... parameters) { + Map rights = (Map) _permissions.get(permission); + if (rights == null) + { + rights = new ConcurrentHashMap(); + _permissions.put(permission, rights); + } + + Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); + if (create_exchanges == null) + { + create_exchanges = new ConcurrentHashMap(); + rights.put(CREATE_EXCHANGES_KEY, create_exchanges); + } + + //Should perhaps error if parameters[0] is null; + AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; + AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); + + //Store the exchangeName / class mapping if the mapping is null + rights.put(name, className); + } + + private void grantCreateQueue(Permission permission, Object... parameters) { + Map createRights = (Map) _permissions.get(permission); + + if (createRights == null) + { + createRights = new ConcurrentHashMap(); + _permissions.put(permission, createRights); + + } + + //The existence of the empty map mean permission to all. + if (parameters.length == 0) + { + return; + } + + Boolean temporary = (Boolean) parameters[0]; + + AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; + + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } + + //Allow all temp queues to be created + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } + + // We are granting CREATE rights to all temporary queues only + if (parameters.length == 1) + { + return; + } + + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) + { + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); + } + + if (exchangeName != null) + { + queue.put(exchangeName, routingKey); + } + + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } + + // Store the exchange that we are being granted rights to. This will be used as part of binding + + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } + + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + + if (exchanges == null) + { + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); + } + + //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY + exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) + { + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); + + if (rKeys == null) + { + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); + } + + rKeys.put(queueName, routingKey); + } + } + } + + private void grantConsume(Permission permission, Object... parameters) { + Map consumeRights = (Map) _permissions.get(permission); + + if (consumeRights == null) + { + consumeRights = new ConcurrentHashMap(); + _permissions.put(permission, consumeRights); + } + + //if we have parametsre + if (parameters.length > 0) + { + AMQShortString queueName = (AMQShortString) parameters[0]; + Boolean temporary = (Boolean) parameters[1]; + Boolean ownQueueOnly = (Boolean) parameters[2]; + + if (temporary) + { + consumeRights.put(CONSUME_TEMPORARY_KEY, true); + } + else + { + consumeRights.put(CONSUME_TEMPORARY_KEY, false); + } + + if (ownQueueOnly) + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); + } + else + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); + } + + + LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); + if (queues == null) + { + queues = new LinkedList(); + consumeRights.put(CONSUME_QUEUES_KEY, queues); + } + + if (queueName != null) + { + queues.add(queueName); + } + } + } + /** * * @param permission the type of permission to check @@ -346,273 +357,286 @@ public class PrincipalPermissions return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it. // The existence of this user specific PP can be validated in the map SimpleXML maintains. case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey - - Exchange exchange = (Exchange) parameters[1]; - - AMQQueue bind_queueName = (AMQQueue) parameters[2]; - AMQShortString routingKey = (AMQShortString) parameters[3]; - - //Get all Create Rights for this user - Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); - - //Look up the Queue Creation Rights - Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues - Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); - - // Check and see if we have a queue white list to check - if (bind_create_queues_queues != null) - { - //There a white list for queues - Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); - - if (exchangeDetails == null) //Then all queue can be bound to all exchanges. - { - return AuthzResult.ALLOWED; - } - - // Check to see if we have a white list of routingkeys to check - Map rkeys = (Map) exchangeDetails.get(exchange.getName()); - - // if keys is null then any rkey is allowed on this exchange - if (rkeys == null) - { - // There is no routingkey white list - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = rkeys.keySet().iterator(); - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - if (rkey.endsWith("*")) - { - matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); - } - else - { - matched = routingKey.equals(rkey); - } - } - - - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - - } - else - { - //There a is no white list for queues - - // So can allow all queues to be bound - // but we should first check and see if we have a temp queue and validate that we are allowed - // to bind temp queues. - - //Check to see if we have a temporary queue - if (bind_queueName.isAutoDelete()) - { - // Check and see if we have an exchange white list. - Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - // If the exchange exists then we must check to see if temporary queues are allowed here - if (bind_exchanges != null) - { - // Check to see if the requested exchange is allowed. - Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); - - return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - //no white list so all allowed, drop through to return true below. - } - - // not a temporary queue and no white list so all allowed. - return AuthzResult.ALLOWED; - } - + return authoriseBind(parameters); case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name - - Map createRights = (Map) _permissions.get(permission); - - // If there are no create rights then deny request - if (createRights == null) - { - return AuthzResult.DENIED; - } - - //Look up the Queue Creation Rights - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues allowed to be created - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - - AMQShortString queueName = (AMQShortString) parameters[1]; - Boolean autoDelete = (Boolean) parameters[0]; - - if (autoDelete)// we have a temporary queue - { - return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - // If there is a white list then check - if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } - - } + return authoriseCreateQueue(permission, parameters); case CREATEEXCHANGE: - Map rights = (Map) _permissions.get(permission); - - AMQShortString exchangeName = (AMQShortString) parameters[0]; - - // If the exchange list is doesn't exist then all is allowed else - // check the valid exchanges - if (rights == null || rights.containsKey(exchangeName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } + return authoriseCreateExchange(permission, parameters); case CONSUME: // Parameters : AMQQueue - - if (parameters.length == 1 && parameters[0] instanceof AMQQueue) - { - AMQQueue queue = ((AMQQueue) parameters[0]); - Map queuePermissions = (Map) _permissions.get(permission); - - if (queuePermissions == null) - { - //if the outer map is null, the user has no CONSUME rights at all - return AuthzResult.DENIED; - } - - List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); - - Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); - Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); - - // If user is allowed to publish to temporary queues and this is a temp queue then allow it. - if (temporayQueues) - { - if (queue.isAutoDelete()) - // This will allow consumption from any temporary queue including ones not owned by this user. - // Of course the exclusivity will not be broken. - { - // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } - - // if queues are white listed then ensure it is ok - if (queues != null) - { - // if no queues are listed then ALL are ok othereise it must be specified. - if (ownQueuesOnly) - { - if (queue.getOwner().equals(_user)) - { - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } - - // If we are - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - - // Can't authenticate without the right parameters - return AuthzResult.DENIED; - case DELETE: - break; - + return authoriseConsume(permission, parameters); case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - return AuthzResult.DENIED; - } - - Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - // Having no exchanges listed gives full publish rights to all exchanges - if (exchanges == null) - { - return AuthzResult.ALLOWED; - } - // Otherwise exchange must be listed in the white list - - // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) - { - return AuthzResult.DENIED; - } - else - { - - // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); - - // Having no routingKeys in the map then all are allowed. - if (routingKeys == null) - { - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = routingKeys.iterator(); - - - AMQShortString publishRKey = (AMQShortString)parameters[1]; - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - - if (rkey.endsWith("*")) - { - matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); - } - else - { - matched = publishRKey.equals(rkey); - } - } - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } + return authorisePublish(permission, parameters); + /* Fall through */ + case DELETE: case PURGE: - break; case UNBIND: - break; - + default: + return AuthzResult.DENIED; } - return AuthzResult.DENIED; } + + private AuthzResult authoriseConsume(Permission permission, Object... parameters) { + if (parameters.length == 1 && parameters[0] instanceof AMQQueue) + { + AMQQueue queue = ((AMQQueue) parameters[0]); + Map queuePermissions = (Map) _permissions.get(permission); + + if (queuePermissions == null) + { + //if the outer map is null, the user has no CONSUME rights at all + return AuthzResult.DENIED; + } + + List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); + + Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); + Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); + + // If user is allowed to publish to temporary queues and this is a temp queue then allow it. + if (temporayQueues) + { + if (queue.isAutoDelete()) + // This will allow consumption from any temporary queue including ones not owned by this user. + // Of course the exclusivity will not be broken. + { + // if not limited to ownQueuesOnly then ok else check queue Owner. + return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + return AuthzResult.DENIED; + } + } + + // if queues are white listed then ensure it is ok + if (queues != null) + { + // if no queues are listed then ALL are ok othereise it must be specified. + if (ownQueuesOnly) + { + if (queue.getOwner().equals(_user)) + { + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + return AuthzResult.DENIED; + } + } + + // If we are + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + + // Can't authenticate without the right parameters + return AuthzResult.DENIED; + } + + private AuthzResult authorisePublish(Permission permission, Object... parameters) { + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + return AuthzResult.DENIED; + } + + Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + // Having no exchanges listed gives full publish rights to all exchanges + if (exchanges == null) + { + return AuthzResult.ALLOWED; + } + // Otherwise exchange must be listed in the white list + + // If the map doesn't have the exchange then it isn't allowed + if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) + { + return AuthzResult.DENIED; + } + else + { + + // Get valid routing keys + HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); + + // Having no routingKeys in the map then all are allowed. + if (routingKeys == null) + { + return AuthzResult.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = routingKeys.iterator(); + + + AMQShortString publishRKey = (AMQShortString)parameters[1]; + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + + if (rkey.endsWith("*")) + { + matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); + } + else + { + matched = publishRKey.equals(rkey); + } + } + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + } + + private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters) { + Map rights = (Map) _permissions.get(permission); + + AMQShortString exchangeName = (AMQShortString) parameters[0]; + + // If the exchange list is doesn't exist then all is allowed else + // check the valid exchanges + if (rights == null || rights.containsKey(exchangeName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } + } + + private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters) { + Map createRights = (Map) _permissions.get(permission); + + // If there are no create rights then deny request + if (createRights == null) + { + return AuthzResult.DENIED; + } + + //Look up the Queue Creation Rights + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues allowed to be created + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + + AMQShortString queueName = (AMQShortString) parameters[1]; + Boolean autoDelete = (Boolean) parameters[0]; + + if (autoDelete)// we have a temporary queue + { + return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + // If there is a white list then check + if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) + { + return AuthzResult.ALLOWED; + } + else + { + return AuthzResult.DENIED; + } + + } + } + + private AuthzResult authoriseBind(Object... parameters) { + Exchange exchange = (Exchange) parameters[1]; + + AMQQueue bind_queueName = (AMQQueue) parameters[2]; + AMQShortString routingKey = (AMQShortString) parameters[3]; + + //Get all Create Rights for this user + Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); + + //Look up the Queue Creation Rights + Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues + Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); + + // Check and see if we have a queue white list to check + if (bind_create_queues_queues != null) + { + //There a white list for queues + Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); + + if (exchangeDetails == null) //Then all queue can be bound to all exchanges. + { + return AuthzResult.ALLOWED; + } + + // Check to see if we have a white list of routingkeys to check + Map rkeys = (Map) exchangeDetails.get(exchange.getName()); + + // if keys is null then any rkey is allowed on this exchange + if (rkeys == null) + { + // There is no routingkey white list + return AuthzResult.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = rkeys.keySet().iterator(); + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + if (rkey.endsWith("*")) + { + matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); + } + else + { + matched = routingKey.equals(rkey); + } + } + + + return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + + + } + else + { + //There a is no white list for queues + + // So can allow all queues to be bound + // but we should first check and see if we have a temp queue and validate that we are allowed + // to bind temp queues. + + //Check to see if we have a temporary queue + if (bind_queueName.isAutoDelete()) + { + // Check and see if we have an exchange white list. + Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + // If the exchange exists then we must check to see if temporary queues are allowed here + if (bind_exchanges != null) + { + // Check to see if the requested exchange is allowed. + Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); + + return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + + //no white list so all allowed, drop through to return true below. + } + + // not a temporary queue and no white list so all allowed. + return AuthzResult.ALLOWED; + } + } } -- cgit v1.2.1 From 9904f496554fb9a36a8ba3b8088a78afc8d4e9e1 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Sun, 11 Oct 2009 19:51:53 +0000 Subject: Fix compiler compliance levels, not allowed @Override on interfaces in 1.5 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@824129 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/ConfigurationManagementMBean.java | 2 -- .../apache/qpid/server/exchange/DefaultExchangeFactory.java | 1 - .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 1 - .../qpid/server/security/access/plugins/BasicACLPlugin.java | 12 ------------ .../security/access/plugins/network/FirewallPlugin.java | 1 - .../auth/database/PropertiesPrincipalDatabaseManager.java | 1 - 6 files changed, 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java index 1541d3d892..9954719866 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -35,13 +35,11 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION); } - @Override public String getObjectInstanceName() { return ConfigurationManagement.TYPE; } - @Override public void reloadSecurityConfiguration() throws Exception { ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index c04b6c559c..620799a81f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -73,7 +73,6 @@ public class DefaultExchangeFactory implements ExchangeFactory return e; } - @Override public void initialise(VirtualHostConfiguration hostConfig) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 08c4e94d1e..d781dc4dea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1608,7 +1608,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public void checkMessageStatus() throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java index a6fae053c2..ca6b68dafa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -35,28 +35,24 @@ public abstract class BasicACLPlugin implements ACLPlugin // Returns true or false if the plugin should authorise or deny the request protected abstract AuthzResult getResult(); - @Override public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return getResult(); } - @Override public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) { return getResult(); } - @Override public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) { return getResult(); } - @Override public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) @@ -64,7 +60,6 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - @Override public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, @@ -73,7 +68,6 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - @Override public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) @@ -81,19 +75,16 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - @Override public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) { return getResult(); } - @Override public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) { return getResult(); } - @Override public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) @@ -101,20 +92,17 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - @Override public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) { return getResult(); } - @Override public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return getResult(); } - @Override public void setConfiguration(Configuration config) { // no-op diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 810be8ae22..5b3c3659c4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -226,7 +226,6 @@ public class FirewallPlugin extends AbstractACLPlugin } } - @Override public void setConfiguration(Configuration config) throws ConfigurationException { // Get default action diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java index 4efe381a8b..8658101cd8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -42,7 +42,6 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana return _databases; } - @Override public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException { //todo -- cgit v1.2.1 From c8f80076d67d2f156a85e4d0d86b5798b3f83a27 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 15 Oct 2009 01:06:23 +0000 Subject: Merge java-network-refactor branch git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@825362 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 1 - .../src/main/java/org/apache/qpid/server/Main.java | 199 ++-- .../server/configuration/ServerConfiguration.java | 56 +- .../qpid/server/connection/ConnectionRegistry.java | 9 +- .../server/connection/IConnectionRegistry.java | 1 - .../server/protocol/AMQMinaProtocolSession.java | 923 ----------------- .../server/protocol/AMQPFastProtocolHandler.java | 290 ------ .../qpid/server/protocol/AMQPProtocolProvider.java | 52 - .../qpid/server/protocol/AMQProtocolEngine.java | 1035 ++++++++++++++++++++ .../server/protocol/AMQProtocolEngineFactory.java | 29 + .../qpid/server/protocol/AMQProtocolSession.java | 17 + .../server/protocol/AMQProtocolSessionMBean.java | 42 +- .../qpid/server/registry/ApplicationRegistry.java | 2 +- .../access/plugins/network/FirewallPlugin.java | 23 +- .../apache/qpid/server/transport/QpidAcceptor.java | 12 +- .../qpid/server/virtualhost/VirtualHost.java | 8 + 16 files changed, 1243 insertions(+), 1456 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index ea48bd7cc3..644a33db01 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -41,7 +41,6 @@ import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.queue.*; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index f8deb95628..c45e794145 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -20,6 +20,13 @@ */ package org.apache.qpid.server; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Properties; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; @@ -30,16 +37,9 @@ import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.FixedSizeByteBufferAllocator; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; -import org.apache.mina.transport.socket.nio.SocketSessionConfig; -import org.apache.mina.util.NewThreadExecutor; import org.apache.qpid.AMQException; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.pool.ReadWriteThreadModel; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.information.management.ServerInformationMBean; @@ -48,19 +48,13 @@ import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; -import org.apache.qpid.server.protocol.AMQPProtocolProvider; +import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.transport.QpidAcceptor; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Properties; +import org.apache.qpid.ssl.SSLContextFactory; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.network.mina.MINANetworkDriver; /** * Main entry point for AMQPD. @@ -300,20 +294,6 @@ public class Main _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - ByteBuffer.setUseDirectBuffers(serverConfig.getEnableDirectBuffers()); - - // 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 (!serverConfig.getEnablePooledAllocator()) - { - ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator()); - } - - if (serverConfig.getUseBiasedWrites()) - { - System.setProperty("org.apache.qpid.use_write_biased_pool", "true"); - } - int port = serverConfig.getPort(); String portStr = commandLine.getOptionValue("p"); @@ -329,7 +309,54 @@ public class Main } } - bind(port, serverConfig); + String bindAddr = commandLine.getOptionValue("b"); + if (bindAddr == null) + { + bindAddr = serverConfig.getBind(); + } + InetAddress bindAddress = null; + if (bindAddr.equals("wildcard")) + { + bindAddress = new InetSocketAddress(port).getAddress(); + } + else + { + bindAddress = InetAddress.getByAddress(parseIP(bindAddr)); + } + + String keystorePath = serverConfig.getKeystorePath(); + String keystorePassword = serverConfig.getKeystorePassword(); + String certType = serverConfig.getCertType(); + SSLContextFactory sslFactory = null; + boolean isSsl = false; + + if (!serverConfig.getSSLOnly()) + { + NetworkDriver driver = new MINANetworkDriver(); + driver.bind(port, new InetAddress[]{bindAddress}, new AMQProtocolEngineFactory(), + serverConfig.getNetworkConfiguration(), null); + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + new QpidAcceptor(driver,"TCP")); + CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + } + + if (serverConfig.getEnableSSL()) + { + sslFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); + NetworkDriver driver = new MINANetworkDriver(); + driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress}, + new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory); + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + new QpidAcceptor(driver,"TCP")); + CurrentActor.get().message(BrokerMessages.BRK_1002("TCP/SSL", serverConfig.getSSLPort())); + } + + //fixme qpid.AMQP should be using qpidproperties to get value + _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + + " build: " + QpidProperties.getBuildVersion()); + + CurrentActor.get().message(BrokerMessages.BRK_1004()); + } finally { @@ -358,114 +385,6 @@ public class Main } } - protected void bind(int port, ServerConfiguration config) throws BindException - { - String bindAddr = commandLine.getOptionValue("b"); - if (bindAddr == null) - { - bindAddr = config.getBind(); - } - - try - { - IoAcceptor acceptor; - - if (ApplicationRegistry.getInstance().getConfiguration().getQpidNIO()) - { - _logger.warn("Using Qpid Multithreaded IO Processing"); - acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(config.getProcessors(), new NewThreadExecutor()); - } - else - { - _logger.warn("Using Mina IO Processing"); - acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(config.getProcessors(), new NewThreadExecutor()); - } - - SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); - SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); - - sc.setReceiveBufferSize(config.getReceiveBufferSize()); - sc.setSendBufferSize(config.getWriteBufferSize()); - sc.setTcpNoDelay(config.getTcpNoDelay()); - - // if we do not use the executor pool threading model we get the default leader follower - // implementation provided by MINA - if (config.getEnableExecutorPool()) - { - sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); - } - - if (!config.getEnableSSL() || !config.getSSLOnly()) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - InetSocketAddress bindAddress; - if (bindAddr.equals("wildcard")) - { - bindAddress = new InetSocketAddress(port); - } - else - { - bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); - } - - bind(new QpidAcceptor(acceptor,"TCP"), bindAddress, handler, sconfig); - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); - } - - if (config.getEnableSSL()) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - try - { - - bind(new QpidAcceptor(acceptor, "TCP/SSL"), new InetSocketAddress(config.getSSLPort()), handler, sconfig); - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid.AMQP listening on SSL port " + config.getSSLPort()); - - } - catch (IOException e) - { - _brokerLogger.error("Unable to listen on SSL port: " + e, e); - } - } - - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - - CurrentActor.get().message(BrokerMessages.BRK_1004()); - - } - catch (Exception e) - { - _logger.error("Unable to bind service to registry: " + e, e); - //fixme this need tidying up - throw new BindException(e.getMessage()); - } - } - - /** - * Ensure that any bound Acceptors are recorded in the registry so they can be closed later. - * - * @param acceptor - * @param bindAddress - * @param handler - * @param sconfig - * - * @throws IOException from the acceptor.bind command - */ - private void bind(QpidAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException - { - acceptor.getIoAcceptor().bind(bindAddress, handler, sconfig); - - CurrentActor.get().message(BrokerMessages.BRK_1002(acceptor.toString(), bindAddress.getPort())); - - ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor); - } - public static void main(String[] args) { //if the -Dlog4j.configuration property has not been set, enable the init override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 01befbbfe8..641b44bb18 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -38,6 +38,7 @@ import org.apache.qpid.server.configuration.management.ConfigurationManagementMB import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.transport.NetworkDriverConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -570,7 +571,7 @@ public class ServerConfiguration implements SignalHandler public boolean getSSLOnly() { - return getConfig().getBoolean("connector.ssl.sslOnly", true); + return getConfig().getBoolean("connector.ssl.sslOnly", false); } public int getSSLPort() @@ -619,4 +620,57 @@ public class ServerConfiguration implements SignalHandler getConfig().getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } + + public NetworkDriverConfiguration getNetworkConfiguration() + { + return new NetworkDriverConfiguration() + { + + public Integer getTrafficClass() + { + return null; + } + + public Boolean getTcpNoDelay() + { + // Can't call parent getTcpNoDelay since it just calls this one + return getConfig().getBoolean("connector.tcpNoDelay", true); + } + + public Integer getSoTimeout() + { + return null; + } + + public Integer getSoLinger() + { + return null; + } + + public Integer getSendBufferSize() + { + return getBufferWriteLimit(); + } + + public Boolean getReuseAddress() + { + return null; + } + + public Integer getReceiveBufferSize() + { + return getBufferReadLimit(); + } + + public Boolean getOOBInline() + { + return null; + } + + public Boolean getKeepAlive() + { + return null; + } + }; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java index d287595e2d..7b50a2e3ad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.connection; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; @@ -45,6 +44,14 @@ public class ConnectionRegistry implements IConnectionRegistry { } + + public void expireClosedChannels() + { + for (AMQProtocolSession connection : _registry) + { + connection.closeIfLingeringClosedChannels(); + } + } /** Close all of the currently open connections. */ public void close() throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java index d64fde1c20..002269bbaa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.connection; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java deleted file mode 100644 index 7bc4365152..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ /dev/null @@ -1,923 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.CloseFuture; -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoServiceConfig; -import org.apache.mina.common.IoSession; -import org.apache.mina.transport.vmpipe.VmPipeAddress; -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.codec.AMQDecoder; -import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodDispatcher; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.protocol.AMQMethodEvent; -import org.apache.qpid.protocol.AMQMethodListener; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; -import org.apache.qpid.server.logging.actors.AMQPConnectionActor; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.messages.ConnectionMessages; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; -import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.transport.Sender; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicLong; - -public class AMQMinaProtocolSession implements AMQProtocolSession, Managable -{ - private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); - - private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); - - private static final AtomicLong idGenerator = new AtomicLong(0); - - // to save boxing the channelId and looking up in a map... cache in an array the low numbered - // channels. This value must be of the form 2^x - 1. - private static final int CHANNEL_CACHE_SIZE = 0xff; - - private final IoSession _minaProtocolSession; - - private AMQShortString _contextKey; - - private AMQShortString _clientVersion = null; - - private VirtualHost _virtualHost; - - private final Map _channelMap = new HashMap(); - - private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; - - private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); - - private final AMQStateManager _stateManager; - - private AMQCodecFactory _codecFactory; - - private AMQProtocolSessionMBean _managedObject; - - private SaslServer _saslServer; - - private Object _lastReceived; - - private Object _lastSent; - - protected boolean _closed; - // maximum number of channels this session should have - private long _maxNoOfChannels = 1000; - - /* AMQP Version for this session */ - private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); - - private FieldTable _clientProperties; - private final List _taskList = new CopyOnWriteArrayList(); - - private List _closingChannelsList = new CopyOnWriteArrayList(); - private ProtocolOutputConverter _protocolOutputConverter; - private Principal _authorizedID; - private MethodDispatcher _dispatcher; - private ProtocolSessionIdentifier _sessionIdentifier; - - private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L; - private org.apache.mina.common.WriteFuture _lastWriteFuture; - - // Create a simple ID that increments for ever new Session - private final long _sessionID = idGenerator.getAndIncrement(); - - private AMQPConnectionActor _actor; - private LogSubject _logSubject; - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory) - throws AMQException - { - _stateManager = new AMQStateManager(virtualHostRegistry, this); - _minaProtocolSession = session; - session.setAttachment(this); - - _codecFactory = codecFactory; - - _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); - - _actor.message(ConnectionMessages.CON_1001(null, null, false, false)); - - try - { - IoServiceConfig config = session.getServiceConfig(); - ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel(); - threadModel.getAsynchronousReadFilter().createNewJobForSession(session); - threadModel.getAsynchronousWriteFilter().createNewJobForSession(session); - } - catch (RuntimeException e) - { - e.printStackTrace(); - throw e; - - } - } - - private AMQProtocolSessionMBean createMBean() throws AMQException - { - try - { - return new AMQProtocolSessionMBean(this); - } - catch (JMException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed ", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); - } - } - - public IoSession getIOSession() - { - return _minaProtocolSession; - } - - public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) - { - return (AMQProtocolSession) minaProtocolSession.getAttachment(); - } - - public long getSessionID() - { - return _sessionID; - } - - public LogActor getLogActor() - { - return _actor; - } - - public void dataBlockReceived(AMQDataBlock message) throws Exception - { - _lastReceived = message; - if (message instanceof ProtocolInitiation) - { - protocolInitiationReceived((ProtocolInitiation) message); - - } - else if (message instanceof AMQFrame) - { - AMQFrame frame = (AMQFrame) message; - frameReceived(frame); - - } - else - { - throw new UnknnownMessageTypeException(message); - } - } - - private void frameReceived(AMQFrame frame) throws AMQException - { - int channelId = frame.getChannel(); - AMQBody body = frame.getBodyFrame(); - - //Look up the Channel's Actor and set that as the current actor - // If that is not available then we can use the ConnectionActor - // that is associated with this AMQMPSession. - LogActor channelActor = null; - if (_channelMap.get(channelId) != null) - { - channelActor = _channelMap.get(channelId).getLogActor(); - } - CurrentActor.set(channelActor == null ? _actor : channelActor); - - try - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Frame Received: " + frame); - } - - // Check that this channel is not closing - if (channelAwaitingClosure(channelId)) - { - if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); - } - } - else - { - if (_logger.isInfoEnabled()) - { - _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame); - } - - closeProtocolSession(); - return; - } - } - - try - { - body.handle(channelId, this); - } - catch (AMQException e) - { - closeChannel(channelId); - throw e; - } - } - finally - { - CurrentActor.remove(); - } - } - - private void protocolInitiationReceived(ProtocolInitiation pi) - { - // this ensures the codec never checks for a PI message again - ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); - try - { - // Log incomming protocol negotiation request - _actor.message(ConnectionMessages.CON_1001(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); - - ProtocolVersion pv = pi.checkVersion(); // Fails if not correct - - // This sets the protocol version (and hence framing classes) for this session. - setProtocolVersion(pv); - - String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); - - String locales = "en_US"; - - AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), - (short) getProtocolMinorVersion(), - null, - mechanisms.getBytes(), - locales.getBytes()); - _minaProtocolSession.write(responseBody.generateFrame(0)); - - } - catch (AMQException e) - { - _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion()); - - _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - // TODO: Close connection (but how to wait until message is sent?) - // ritchiem 2006-12-04 will this not do? - // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()])); - // future.join(); - // close connection - - } - } - - public void methodFrameReceived(int channelId, AMQMethodBody methodBody) - { - - final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); - - try - { - try - { - - boolean wasAnyoneInterested = _stateManager.methodReceived(evt); - - if (!_frameListeners.isEmpty()) - { - for (AMQMethodListener listener : _frameListeners) - { - wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; - } - } - - if (!wasAnyoneInterested) - { - throw new AMQNoMethodHandlerException(evt); - } - } - catch (AMQChannelException e) - { - if (getChannel(channelId) != null) - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing channel due to: " + e.getMessage()); - } - - writeFrame(e.getCloseFrame(channelId)); - closeChannel(channelId); - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - AMQConnectionException ce = - evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, - AMQConstant.CHANNEL_ERROR.getName().toString()); - - closeConnection(channelId, ce, false); - } - } - catch (AMQConnectionException e) - { - closeConnection(channelId, e, false); - } - } - catch (Exception e) - { - - for (AMQMethodListener listener : _frameListeners) - { - listener.error(e); - } - - _logger.error("Unexpected exception while processing frame. Closing connection.", e); - - closeProtocolSession(); - } - } - - public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException - { - - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentHeader(body); - - } - - public void contentBodyReceived(int channelId, ContentBody body) throws AMQException - { - AMQChannel channel = getAndAssertChannel(channelId); - - channel.publishContentBody(body); - } - - public void heartbeatBodyReceived(int channelId, HeartbeatBody body) - { - // NO - OP - } - - /** - * Convenience method that writes a frame to the protocol session. Equivalent to calling - * getProtocolSession().write(). - * - * @param frame the frame to write - */ - public void writeFrame(AMQDataBlock frame) - { - _lastSent = frame; - - _lastWriteFuture = _minaProtocolSession.write(frame); - } - - public AMQShortString getContextKey() - { - return _contextKey; - } - - public void setContextKey(AMQShortString contextKey) - { - _contextKey = contextKey; - } - - public List getChannels() - { - return new ArrayList(_channelMap.values()); - } - - public AMQChannel getAndAssertChannel(int channelId) throws AMQException - { - AMQChannel channel = getChannel(channelId); - if (channel == null) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); - } - - return channel; - } - - public AMQChannel getChannel(int channelId) throws AMQException - { - final AMQChannel channel = - ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); - if ((channel == null) || channel.isClosing()) - { - return null; - } - else - { - return channel; - } - } - - public boolean channelAwaitingClosure(int channelId) - { - return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId); - } - - public void addChannel(AMQChannel channel) throws AMQException - { - if (_closed) - { - throw new AMQException("Session is closed"); - } - - final int channelId = channel.getChannelId(); - - if (_closingChannelsList.contains(channelId)) - { - throw new AMQException("Session is marked awaiting channel close"); - } - - if (_channelMap.size() == _maxNoOfChannels) - { - String errorMessage = - toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels - + "); can't create channel"; - _logger.error(errorMessage); - throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); - } - else - { - _channelMap.put(channel.getChannelId(), channel); - } - - if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) - { - _cachedChannels[channelId] = channel; - } - - checkForNotification(); - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (channelsCount >= _maxNoOfChannels) - { - _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); - } - } - - public Long getMaximumNumberOfChannels() - { - return _maxNoOfChannels; - } - - public void setMaximumNumberOfChannels(Long value) - { - _maxNoOfChannels = value; - } - - public void commitTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.commit(); - } - } - - public void rollbackTransactions(AMQChannel channel) throws AMQException - { - if ((channel != null) && channel.isTransactional()) - { - channel.rollback(); - } - } - - /** - * Close a specific channel. This will remove any resources used by the channel, including:

      • 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 = getChannel(channelId); - if (channel == null) - { - throw new IllegalArgumentException("Unknown channel id"); - } - else - { - try - { - channel.close(); - markChannelAwaitingCloseOk(channelId); - } - finally - { - removeChannel(channelId); - } - } - } - - public void closeChannelOk(int channelId) - { - // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler. - // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory. - // We do it from the Close Handler as we are sending the OK back to the client. - // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException - // will send a close-ok.. Where we should call removeChannel. - // However, due to the poor exception handling on the client. The client-user will be notified of the - // InvalidArgument and if they then decide to close the session/connection then the there will be time - // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. - //removeChannel(channelId); - _closingChannelsList.remove(new Integer(channelId)); - } - - private void markChannelAwaitingCloseOk(int channelId) - { - _closingChannelsList.add(channelId); - } - - /** - * In our current implementation this is used by the clustering code. - * - * @param channelId The channel to remove - */ - public void removeChannel(int channelId) - { - _channelMap.remove(channelId); - if ((channelId & CHANNEL_CACHE_SIZE) == channelId) - { - _cachedChannels[channelId] = null; - } - } - - /** - * Initialise heartbeats on the session. - * - * @param delay delay in seconds (not ms) - */ - public void initHeartbeats(int delay) - { - if (delay > 0) - { - _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); - _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, (int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay)); - } - } - - /** - * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. - * - * @throws AMQException if an error occurs while closing any channel - */ - private void closeAllChannels() throws AMQException - { - for (AMQChannel channel : _channelMap.values()) - { - channel.close(); - } - - _channelMap.clear(); - for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) - { - _cachedChannels[i] = null; - } - } - - /** This must be called when the session is _closed in order to free up any resources managed by the session. */ - public void closeSession() throws AMQException - { - if (!_closed) - { - if (_virtualHost != null) - { - _virtualHost.getConnectionRegistry().deregisterConnection(this); - } - - closeAllChannels(); - if (_managedObject != null) - { - _managedObject.unregister(); - } - - for (Task task : _taskList) - { - task.doTask(this); - } - - _closed = true; - - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); - } - } - - public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException - { - if (_logger.isInfoEnabled()) - { - _logger.info("Closing connection due to: " + e.getMessage()); - } - - markChannelAwaitingCloseOk(channelId); - closeSession(); - _stateManager.changeState(AMQState.CONNECTION_CLOSING); - writeFrame(e.getCloseFrame(channelId)); - - if (closeProtocolSession) - { - closeProtocolSession(); - } - } - - public void closeProtocolSession() - { - closeProtocolSession(true); - } - - public void closeProtocolSession(boolean waitLast) - { - if (waitLast && (_lastWriteFuture != null)) - { - _logger.debug("Waiting for last write to join."); - _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); - } - - _logger.debug("REALLY Closing protocol session:" + _minaProtocolSession); - final CloseFuture future = _minaProtocolSession.close(); - future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT); - - try - { - _stateManager.changeState(AMQState.CONNECTION_CLOSED); - } - catch (AMQException e) - { - _logger.info(e.getMessage()); - } - } - - public String toString() - { - return _minaProtocolSession.getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")"); - } - - public String dump() - { - return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; - } - - /** @return an object that can be used to identity */ - public Object getKey() - { - return _minaProtocolSession.getRemoteAddress(); - } - - /** - * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may - * be bound to multiple addresses this could vary depending on the acceptor this session was created from. - * - * @return a String FQDN - */ - public String getLocalFQDN() - { - SocketAddress address = _minaProtocolSession.getLocalAddress(); - // we use the vmpipe address in some tests hence the need for this rather ugly test. The host - // information is used by SASL primary. - if (address instanceof InetSocketAddress) - { - return ((InetSocketAddress) address).getHostName(); - } - else if (address instanceof VmPipeAddress) - { - return "vmpipe:" + ((VmPipeAddress) address).getPort(); - } - else - { - throw new IllegalArgumentException("Unsupported socket address class: " + address); - } - } - - public SaslServer getSaslServer() - { - return _saslServer; - } - - public void setSaslServer(SaslServer saslServer) - { - _saslServer = saslServer; - } - - public FieldTable getClientProperties() - { - return _clientProperties; - } - - public void setClientProperties(FieldTable clientProperties) - { - _clientProperties = clientProperties; - if (_clientProperties != null) - { - if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) - { - String clientID = _clientProperties.getString(CLIENT_PROPERTIES_INSTANCE); - setContextKey(new AMQShortString(clientID)); - - // Log the Opening of the connection for this client - _actor.message(ConnectionMessages.CON_1001(clientID, _protocolVersion.toString(), true, true)); - } - - if (_clientProperties.getString(ClientProperties.version.toString()) != null) - { - _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); - } - } - _sessionIdentifier = new ProtocolSessionIdentifier(this); - } - - private void setProtocolVersion(ProtocolVersion pv) - { - _protocolVersion = pv; - - _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); - _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion); - } - - public byte getProtocolMajorVersion() - { - return _protocolVersion.getMajorVersion(); - } - - public ProtocolVersion getProtocolVersion() - { - return _protocolVersion; - } - - public byte getProtocolMinorVersion() - { - return _protocolVersion.getMinorVersion(); - } - - public boolean isProtocolVersion(byte major, byte minor) - { - return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); - } - - public MethodRegistry getRegistry() - { - return getMethodRegistry(); - } - - public Object getClientIdentifier() - { - return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null; - } - - public VirtualHost getVirtualHost() - { - return _virtualHost; - } - - public void setVirtualHost(VirtualHost virtualHost) throws AMQException - { - _virtualHost = virtualHost; - - _actor.virtualHostSelected(this); - _logSubject = new ConnectionLogSubject(this); - - _virtualHost.getConnectionRegistry().registerConnection(this); - - _managedObject = createMBean(); - _managedObject.register(); - } - - public void addSessionCloseTask(Task task) - { - _taskList.add(task); - } - - public void removeSessionCloseTask(Task task) - { - _taskList.remove(task); - } - - public ProtocolOutputConverter getProtocolOutputConverter() - { - return _protocolOutputConverter; - } - - public void setAuthorizedID(Principal authorizedID) - { - _authorizedID = authorizedID; - - // Let the actor know that this connection is now Authorized - _actor.connectionAuthorized(this); - } - - public Principal getAuthorizedID() - { - return _authorizedID; - } - - public SocketAddress getRemoteAddress() - { - return _minaProtocolSession.getRemoteAddress(); - } - - public MethodRegistry getMethodRegistry() - { - return MethodRegistry.getMethodRegistry(getProtocolVersion()); - } - - public MethodDispatcher getMethodDispatcher() - { - return _dispatcher; - } - - public ProtocolSessionIdentifier getSessionIdentifier() - { - return _sessionIdentifier; - } - - public String getClientVersion() - { - return (_clientVersion == null) ? null : _clientVersion.toString(); - } - - public void setSender(Sender sender) - { - // No-op, interface munging between this and AMQProtocolSession - } - - public void init() - { - // No-op, interface munging between this and AMQProtocolSession - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java deleted file mode 100644 index 16b85e67b3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoFilterChain; -import org.apache.mina.common.IoHandlerAdapter; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.ReadThrottleFilterBuilder; -import org.apache.mina.filter.SSLFilter; -import org.apache.mina.filter.WriteBufferLimitFilterBuilder; -import org.apache.mina.filter.codec.QpidProtocolCodecFilter; -import org.apache.mina.filter.executor.ExecutorFilter; -import org.apache.mina.util.SessionUtil; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQProtocolHeaderException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.ssl.SSLContextFactory; - -/** - * The protocol handler handles "protocol events" for all connections. The state - * associated with an individual connection is accessed through the protocol session. - * - * We delegate all frame (message) processing to the AMQProtocolSession which wraps - * the state for the connection. - */ -public class AMQPFastProtocolHandler extends IoHandlerAdapter -{ - private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); - - private final IApplicationRegistry _applicationRegistry; - - private final int BUFFER_READ_LIMIT_SIZE; - private final int BUFFER_WRITE_LIMIT_SIZE; - - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) - { - this(ApplicationRegistry.getInstance(applicationRegistryInstance)); - } - - public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry) - { - _applicationRegistry = applicationRegistry; - - // Read the configuration from the application registry - BUFFER_READ_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferReadLimit(); - BUFFER_WRITE_LIMIT_SIZE = _applicationRegistry.getConfiguration().getBufferWriteLimit(); - - _logger.debug("AMQPFastProtocolHandler created"); - } - - protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) - { - this(handler._applicationRegistry); - } - - public void sessionCreated(IoSession protocolSession) throws Exception - { - SessionUtil.initialize(protocolSession); - final AMQCodecFactory codecFactory = new AMQCodecFactory(true); - - createSession(protocolSession, _applicationRegistry, codecFactory); - _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress()); - - final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory); - final ServerConfiguration config = _applicationRegistry.getConfiguration(); - - String keystorePath = config.getKeystorePath(); - String keystorePassword = config.getKeystorePassword(); - String certType = config.getCertType(); - SSLContextFactory sslContextFactory = null; - boolean isSsl = false; - if (config.getEnableSSL() && isSSLClient(config, protocolSession)) - { - sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); - isSsl = true; - } - if (config.getEnableExecutorPool()) - { - if (isSsl) - { - protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); - } - else - { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); - if (isSsl) - { - protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter", - new SSLFilter(sslContextFactory.buildServerContext())); - } - } - - if (ApplicationRegistry.getInstance().getConfiguration().getProtectIOEnabled()) - { - try - { -// //Add IO Protection Filters - IoFilterChain chain = protocolSession.getFilterChain(); - - - protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter()); - - ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); - readfilter.setMaximumConnectionBufferSize(BUFFER_READ_LIMIT_SIZE); - readfilter.attach(chain); - - WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); - writefilter.setMaximumConnectionBufferSize(BUFFER_WRITE_LIMIT_SIZE); - writefilter.attach(chain); - - protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder"); - _logger.info("Using IO Read/Write Filter Protection"); - } - catch (Exception e) - { - _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage()); - } - } - } - - /** Separated into its own, protected, method to allow easier reuse */ - protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException - { - new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec); - } - - public void sessionOpened(IoSession protocolSession) throws Exception - { - _logger.info("Session opened for:" + protocolSession.getRemoteAddress()); - } - - public void sessionClosed(IoSession protocolSession) throws Exception - { - _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress()); - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - //fixme -- this can be null - if (amqProtocolSession != null) - { - try - { - CurrentActor.set(amqProtocolSession.getLogActor()); - amqProtocolSession.closeSession(); - } - catch (AMQException e) - { - _logger.error("Caught AMQException whilst closingSession:" + e); - } - finally - { - CurrentActor.remove(); - } - } - } - - public void sessionIdle(IoSession session, IdleStatus status) throws Exception - { - _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress()); - if (IdleStatus.WRITER_IDLE.equals(status)) - { - //write heartbeat frame: - session.write(HeartbeatBody.FRAME); - } - else if (IdleStatus.READER_IDLE.equals(status)) - { - //failover: - throw new IOException("Timed out while waiting for heartbeat from peer."); - } - - } - - public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception - { - AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - if (throwable instanceof AMQProtocolHeaderException) - { - - protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); - - protocolSession.close(); - - _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable); - } - else if (throwable instanceof IOException) - { - _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable); - } - else - { - _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); - - - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(session.getProtocolVersion()); - ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); - - protocolSession.write(closeBody.generateFrame(0)); - - protocolSession.close(); - } - } - - /** - * Invoked when a message is received on a particular protocol session. Note that a - * protocol session is directly tied to a particular physical connection. - * - * @param protocolSession the protocol session that received the message - * @param message the message itself (i.e. a decoded frame) - * - * @throws Exception if the message cannot be processed - */ - public void messageReceived(IoSession protocolSession, Object message) throws Exception - { - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - - if (message instanceof AMQDataBlock) - { - amqProtocolSession.dataBlockReceived((AMQDataBlock) message); - - } - else if (message instanceof ByteBuffer) - { - throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); - } - else - { - throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); - } - } - - /** - * Called after a message has been sent out on a particular protocol session - * - * @param protocolSession the protocol session (i.e. connection) on which this - * message was sent - * @param object the message (frame) that was encoded and sent - * - * @throws Exception if we want to indicate an error - */ - public void messageSent(IoSession protocolSession, Object object) throws Exception - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Message sent: " + object); - } - } - - protected boolean isSSLClient(ServerConfiguration connectionConfig, - IoSession protocolSession) - { - InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress(); - return addr.getPort() == connectionConfig.getSSLPort(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java deleted file mode 100644 index 07c153bfe8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; - -/** - * The protocol provide's role is to encapsulate the initialisation of the protocol handler. - * - * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events - * such as connection closing or a frame being received. It can either do this directly - * or pass off to the protocol session in the cases where state information is required to - * deal with the event. - * - */ -public class AMQPProtocolProvider -{ - /** - * Handler for protocol events - */ - private AMQPFastProtocolHandler _handler; - - public AMQPProtocolProvider() - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - _handler = new AMQPFastProtocolHandler(registry); - } - - public AMQPFastProtocolHandler getHandler() - { - return _handler; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java new file mode 100644 index 0000000000..3bcd102858 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -0,0 +1,1035 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicLong; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; +import org.apache.mina.transport.vmpipe.VmPipeAddress; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.codec.AMQDecoder; +import org.apache.qpid.common.ClientProperties; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodDispatcher; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.pool.Job; +import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQMethodListener; +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.AMQPConnectionActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ConnectionMessages; +import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Sender; + +public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession +{ + private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); + + private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString(); + + private static final AtomicLong idGenerator = new AtomicLong(0); + + // to save boxing the channelId and looking up in a map... cache in an array the low numbered + // channels. This value must be of the form 2^x - 1. + private static final int CHANNEL_CACHE_SIZE = 0xff; + + private AMQShortString _contextKey; + + private AMQShortString _clientVersion = null; + + private VirtualHost _virtualHost; + + private final Map _channelMap = new HashMap(); + + private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1]; + + private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); + + private final AMQStateManager _stateManager; + + private AMQCodecFactory _codecFactory; + + private AMQProtocolSessionMBean _managedObject; + + private SaslServer _saslServer; + + private Object _lastReceived; + + private Object _lastSent; + + protected boolean _closed; + // maximum number of channels this session should have + private long _maxNoOfChannels = 1000; + + /* AMQP Version for this session */ + private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion(); + + private FieldTable _clientProperties; + private final List _taskList = new CopyOnWriteArrayList(); + + private Map _closingChannelsList = new ConcurrentHashMap(); + private ProtocolOutputConverter _protocolOutputConverter; + private Principal _authorizedID; + private MethodDispatcher _dispatcher; + private ProtocolSessionIdentifier _sessionIdentifier; + + // Create a simple ID that increments for ever new Session + private final long _sessionID = idGenerator.getAndIncrement(); + + private AMQPConnectionActor _actor; + private LogSubject _logSubject; + + private NetworkDriver _networkDriver; + + private long _lastIoTime; + + private long _writtenBytes; + private long _readBytes; + + private Job _readJob; + private Job _writeJob; + + private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + public AMQProtocolEngine(VirtualHostRegistry virtualHostRegistry, NetworkDriver driver) + { + _stateManager = new AMQStateManager(virtualHostRegistry, this); + _networkDriver = driver; + + _codecFactory = new AMQCodecFactory(true, this); + _poolReference.acquireExecutorService(); + _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true); + _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false); + + _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); + _actor.message(ConnectionMessages.CON_1001(null, null, false, false)); + + } + + private AMQProtocolSessionMBean createMBean() throws AMQException + { + try + { + return new AMQProtocolSessionMBean(this); + } + catch (JMException ex) + { + _logger.error("AMQProtocolSession MBean creation has failed ", ex); + throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); + } + } + + public long getSessionID() + { + return _sessionID; + } + + public LogActor getLogActor() + { + return _actor; + } + + @Override + public void received(final ByteBuffer msg) + { + _lastIoTime = System.currentTimeMillis(); + try + { + final ArrayList dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg); + Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable() + { + @Override + public void run() + { + // Decode buffer + + for (AMQDataBlock dataBlock : dataBlocks) + { + try + { + dataBlockReceived(dataBlock); + } + catch (Exception e) + { + _logger.error("Unexpected exception when processing datablock", e); + closeProtocolSession(); + } + } + } + }); + } + catch (Exception e) + { + _logger.error("Unexpected exception when processing datablock", e); + closeProtocolSession(); + } + } + + public void dataBlockReceived(AMQDataBlock message) throws Exception + { + _lastReceived = message; + if (message instanceof ProtocolInitiation) + { + protocolInitiationReceived((ProtocolInitiation) message); + + } + else if (message instanceof AMQFrame) + { + AMQFrame frame = (AMQFrame) message; + frameReceived(frame); + + } + else + { + throw new UnknnownMessageTypeException(message); + } + } + + private void frameReceived(AMQFrame frame) throws AMQException + { + int channelId = frame.getChannel(); + AMQBody body = frame.getBodyFrame(); + + //Look up the Channel's Actor and set that as the current actor + // If that is not available then we can use the ConnectionActor + // that is associated with this AMQMPSession. + LogActor channelActor = null; + if (_channelMap.get(channelId) != null) + { + channelActor = _channelMap.get(channelId).getLogActor(); + } + CurrentActor.set(channelActor == null ? _actor : channelActor); + + try + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Frame Received: " + frame); + } + + // Check that this channel is not closing + if (channelAwaitingClosure(channelId)) + { + if ((frame.getBodyFrame() instanceof ChannelCloseOkBody)) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok"); + } + } + else + { + // The channel has been told to close, we don't process any more frames until + // it's closed. + return; + } + } + + try + { + body.handle(channelId, this); + } + catch (AMQException e) + { + closeChannel(channelId); + throw e; + } + } + finally + { + CurrentActor.remove(); + } + } + + private void protocolInitiationReceived(ProtocolInitiation pi) + { + // this ensures the codec never checks for a PI message again + ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false); + try + { + // Log incomming protocol negotiation request + _actor.message(ConnectionMessages.CON_1001(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); + + ProtocolVersion pv = pi.checkVersion(); // Fails if not correct + + // This sets the protocol version (and hence framing classes) for this session. + setProtocolVersion(pv); + + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + + String locales = "en_US"; + + AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), + (short) getProtocolMinorVersion(), + null, + mechanisms.getBytes(), + locales.getBytes()); + _networkDriver.send(responseBody.generateFrame(0).toNioByteBuffer()); + + } + catch (AMQException e) + { + _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion()); + + _networkDriver.send(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()).toNioByteBuffer()); + } + } + + public void methodFrameReceived(int channelId, AMQMethodBody methodBody) + { + + final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); + + try + { + try + { + + boolean wasAnyoneInterested = _stateManager.methodReceived(evt); + + if (!_frameListeners.isEmpty()) + { + for (AMQMethodListener listener : _frameListeners) + { + wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested; + } + } + + if (!wasAnyoneInterested) + { + throw new AMQNoMethodHandlerException(evt); + } + } + catch (AMQChannelException e) + { + if (getChannel(channelId) != null) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing channel due to: " + e.getMessage()); + } + + writeFrame(e.getCloseFrame(channelId)); + closeChannel(channelId); + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage()); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + AMQConnectionException ce = + evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, + AMQConstant.CHANNEL_ERROR.getName().toString()); + + closeConnection(channelId, ce, false); + } + } + catch (AMQConnectionException e) + { + closeConnection(channelId, e, false); + } + } + catch (Exception e) + { + + for (AMQMethodListener listener : _frameListeners) + { + listener.error(e); + } + + _logger.error("Unexpected exception while processing frame. Closing connection.", e); + + closeProtocolSession(); + } + } + + public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException + { + + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentHeader(body); + + } + + public void contentBodyReceived(int channelId, ContentBody body) throws AMQException + { + AMQChannel channel = getAndAssertChannel(channelId); + + channel.publishContentBody(body); + } + + public void heartbeatBodyReceived(int channelId, HeartbeatBody body) + { + // NO - OP + } + + /** + * Convenience method that writes a frame to the protocol session. Equivalent to calling + * getProtocolSession().write(). + * + * @param frame the frame to write + */ + public void writeFrame(AMQDataBlock frame) + { + _lastSent = frame; + final ByteBuffer buf = frame.toNioByteBuffer(); + _lastIoTime = System.currentTimeMillis(); + _writtenBytes += buf.remaining(); + Job.fireAsynchEvent(_poolReference.getPool(), _writeJob, new Runnable() + { + @Override + public void run() + { + _networkDriver.send(buf); + } + }); + } + + public AMQShortString getContextKey() + { + return _contextKey; + } + + public void setContextKey(AMQShortString contextKey) + { + _contextKey = contextKey; + } + + public List getChannels() + { + return new ArrayList(_channelMap.values()); + } + + public AMQChannel getAndAssertChannel(int channelId) throws AMQException + { + AMQChannel channel = getChannel(channelId); + if (channel == null) + { + throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId); + } + + return channel; + } + + public AMQChannel getChannel(int channelId) throws AMQException + { + final AMQChannel channel = + ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId); + if ((channel == null) || channel.isClosing()) + { + return null; + } + else + { + return channel; + } + } + + public boolean channelAwaitingClosure(int channelId) + { + return !_closingChannelsList.isEmpty() && _closingChannelsList.containsKey(channelId); + } + + public void addChannel(AMQChannel channel) throws AMQException + { + if (_closed) + { + throw new AMQException("Session is closed"); + } + + final int channelId = channel.getChannelId(); + + if (_closingChannelsList.containsKey(channelId)) + { + throw new AMQException("Session is marked awaiting channel close"); + } + + if (_channelMap.size() == _maxNoOfChannels) + { + String errorMessage = + toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels + + "); can't create channel"; + _logger.error(errorMessage); + throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage); + } + else + { + _channelMap.put(channel.getChannelId(), channel); + } + + if (((channelId & CHANNEL_CACHE_SIZE) == channelId)) + { + _cachedChannels[channelId] = channel; + } + + checkForNotification(); + } + + private void checkForNotification() + { + int channelsCount = _channelMap.size(); + if (channelsCount >= _maxNoOfChannels) + { + _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); + } + } + + public Long getMaximumNumberOfChannels() + { + return _maxNoOfChannels; + } + + public void setMaximumNumberOfChannels(Long value) + { + _maxNoOfChannels = value; + } + + public void commitTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.commit(); + } + } + + public void rollbackTransactions(AMQChannel channel) throws AMQException + { + if ((channel != null) && channel.isTransactional()) + { + channel.rollback(); + } + } + + /** + * Close a specific channel. This will remove any resources used by the channel, including:
      • 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 = getChannel(channelId); + if (channel == null) + { + throw new IllegalArgumentException("Unknown channel id"); + } + else + { + try + { + channel.close(); + markChannelAwaitingCloseOk(channelId); + } + finally + { + removeChannel(channelId); + } + } + } + + public void closeChannelOk(int channelId) + { + // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler. + // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory. + // We do it from the Close Handler as we are sending the OK back to the client. + // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException + // will send a close-ok.. Where we should call removeChannel. + // However, due to the poor exception handling on the client. The client-user will be notified of the + // InvalidArgument and if they then decide to close the session/connection then the there will be time + // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. + //removeChannel(channelId); + _closingChannelsList.remove(new Integer(channelId)); + } + + private void markChannelAwaitingCloseOk(int channelId) + { + _closingChannelsList.put(channelId, System.currentTimeMillis()); + } + + /** + * In our current implementation this is used by the clustering code. + * + * @param channelId The channel to remove + */ + public void removeChannel(int channelId) + { + _channelMap.remove(channelId); + if ((channelId & CHANNEL_CACHE_SIZE) == channelId) + { + _cachedChannels[channelId] = null; + } + } + + /** + * Initialise heartbeats on the session. + * + * @param delay delay in seconds (not ms) + */ + public void initHeartbeats(int delay) + { + if (delay > 0) + { + _networkDriver.setMaxWriteIdle(delay); + _networkDriver.setMaxReadIdle((int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay)); + } + } + + /** + * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel. + * + * @throws AMQException if an error occurs while closing any channel + */ + private void closeAllChannels() throws AMQException + { + for (AMQChannel channel : _channelMap.values()) + { + channel.close(); + } + + _channelMap.clear(); + for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++) + { + _cachedChannels[i] = null; + } + } + + /** This must be called when the session is _closed in order to free up any resources managed by the session. */ + public void closeSession() throws AMQException + { + if (CurrentActor.get() == null) + { + CurrentActor.set(_actor); + } + if (!_closed) + { + if (_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + } + + for (Task task : _taskList) + { + task.doTask(this); + } + + _closed = true; + _poolReference.releaseExecutorService(); + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); + } + } + + public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException + { + if (_logger.isInfoEnabled()) + { + _logger.info("Closing connection due to: " + e.getMessage()); + } + + markChannelAwaitingCloseOk(channelId); + closeSession(); + _stateManager.changeState(AMQState.CONNECTION_CLOSING); + writeFrame(e.getCloseFrame(channelId)); + + if (closeProtocolSession) + { + closeProtocolSession(); + } + } + + public void closeProtocolSession() + { + _networkDriver.close(); + try + { + _stateManager.changeState(AMQState.CONNECTION_CLOSED); + } + catch (AMQException e) + { + _logger.info(e.getMessage()); + } + } + + public String toString() + { + return getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")"); + } + + public String dump() + { + return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; + } + + /** @return an object that can be used to identity */ + public Object getKey() + { + return getRemoteAddress(); + } + + /** + * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may + * be bound to multiple addresses this could vary depending on the acceptor this session was created from. + * + * @return a String FQDN + */ + public String getLocalFQDN() + { + SocketAddress address = _networkDriver.getLocalAddress(); + // we use the vmpipe address in some tests hence the need for this rather ugly test. The host + // information is used by SASL primary. + if (address instanceof InetSocketAddress) + { + return ((InetSocketAddress) address).getHostName(); + } + else if (address instanceof VmPipeAddress) + { + return "vmpipe:" + ((VmPipeAddress) address).getPort(); + } + else + { + throw new IllegalArgumentException("Unsupported socket address class: " + address); + } + } + + public SaslServer getSaslServer() + { + return _saslServer; + } + + public void setSaslServer(SaslServer saslServer) + { + _saslServer = saslServer; + } + + public FieldTable getClientProperties() + { + return _clientProperties; + } + + public void setClientProperties(FieldTable clientProperties) + { + _clientProperties = clientProperties; + if (_clientProperties != null) + { + if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null) + { + String clientID = _clientProperties.getString(CLIENT_PROPERTIES_INSTANCE); + setContextKey(new AMQShortString(clientID)); + + // Log the Opening of the connection for this client + _actor.message(ConnectionMessages.CON_1001(clientID, _protocolVersion.toString(), true, true)); + } + + if (_clientProperties.getString(ClientProperties.version.toString()) != null) + { + _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString())); + } + } + _sessionIdentifier = new ProtocolSessionIdentifier(this); + } + + private void setProtocolVersion(ProtocolVersion pv) + { + _protocolVersion = pv; + + _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this); + _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion); + } + + public byte getProtocolMajorVersion() + { + return _protocolVersion.getMajorVersion(); + } + + public ProtocolVersion getProtocolVersion() + { + return _protocolVersion; + } + + public byte getProtocolMinorVersion() + { + return _protocolVersion.getMinorVersion(); + } + + public boolean isProtocolVersion(byte major, byte minor) + { + return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor); + } + + public MethodRegistry getRegistry() + { + return getMethodRegistry(); + } + + public Object getClientIdentifier() + { + return (_networkDriver != null) ? _networkDriver.getRemoteAddress() : null; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) throws AMQException + { + _virtualHost = virtualHost; + + _actor.virtualHostSelected(this); + _logSubject = new ConnectionLogSubject(this); + + _virtualHost.getConnectionRegistry().registerConnection(this); + + _managedObject = createMBean(); + _managedObject.register(); + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + public ProtocolOutputConverter getProtocolOutputConverter() + { + return _protocolOutputConverter; + } + + public void setAuthorizedID(Principal authorizedID) + { + _authorizedID = authorizedID; + + // Let the actor know that this connection is now Authorized + _actor.connectionAuthorized(this); + } + + public Principal getAuthorizedID() + { + return _authorizedID; + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public MethodRegistry getMethodRegistry() + { + return MethodRegistry.getMethodRegistry(getProtocolVersion()); + } + + public MethodDispatcher getMethodDispatcher() + { + return _dispatcher; + } + + @Override + public void closed() + { + try + { + closeSession(); + } + catch (AMQException e) + { + _logger.error("Could not close protocol engine", e); + } + } + + @Override + public void readerIdle() + { + // Nothing + } + + @Override + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + } + + @Override + public void writerIdle() + { + _networkDriver.send(HeartbeatBody.FRAME.toNioByteBuffer()); + } + + @Override + public void exception(Throwable throwable) + { + if (throwable instanceof AMQProtocolHeaderException) + { + + writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); + _networkDriver.close(); + + _logger.error("Error in protocol initiation " + this + ":" + getRemoteAddress() + " :" + throwable.getMessage(), throwable); + } + else if (throwable instanceof IOException) + { + _logger.error("IOException caught in" + this + ", session closed implictly: " + throwable); + } + else + { + _logger.error("Exception caught in" + this + ", closing session explictly: " + throwable, throwable); + + + MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(getProtocolVersion()); + ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); + + writeFrame(closeBody.generateFrame(0)); + + _networkDriver.close(); + } + } + + @Override + public void init() + { + // Do nothing + } + + @Override + public void setSender(Sender sender) + { + // Do nothing + } + + @Override + public long getReadBytes() + { + return _readBytes; + } + + public long getWrittenBytes() + { + return _writtenBytes; + } + + public long getLastIoTime() + { + return _lastIoTime; + } + + public ProtocolSessionIdentifier getSessionIdentifier() + { + return _sessionIdentifier; + } + + public String getClientVersion() + { + return (_clientVersion == null) ? null : _clientVersion.toString(); + } + + @Override + public void closeIfLingeringClosedChannels() + { + for (Entryid : _closingChannelsList.entrySet()) + { + if (id.getValue() + 30000 > System.currentTimeMillis()) + { + // We have a channel that we closed 30 seconds ago. Client's dead, kill the connection + _logger.error("Closing connection as channel was closed more than 30 seconds ago and no ChannelCloseOk has been processed"); + closeProtocolSession(); + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java new file mode 100644 index 0000000000..ff0c007a60 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java @@ -0,0 +1,29 @@ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.transport.NetworkDriver; + +public class AMQProtocolEngineFactory implements ProtocolEngineFactory +{ + private VirtualHostRegistry _vhosts; + + public AMQProtocolEngineFactory() + { + this(1); + } + + public AMQProtocolEngineFactory(Integer port) + { + _vhosts = ApplicationRegistry.getInstance(port).getVirtualHostRegistry(); + } + + + public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) + { + return new AMQProtocolEngine(_vhosts, networkDriver); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index fff406bb3d..b16ed01c79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; import java.security.Principal; +import java.util.List; public interface AMQProtocolSession extends AMQVersionAwareProtocolSession @@ -210,5 +211,21 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public MethodDispatcher getMethodDispatcher(); public ProtocolSessionIdentifier getSessionIdentifier(); + + String getClientVersion(); + + long getLastIoTime(); + + long getWrittenBytes(); + + Long getMaximumNumberOfChannels(); + + void setMaximumNumberOfChannels(Long value); + + void commitTransactions(AMQChannel channel) throws AMQException; + + List getChannels(); + + void closeIfLingeringClosedChannels(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 81dbeeded2..8497c95e26 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -79,7 +79,7 @@ import org.apache.qpid.server.management.ManagedObject; @MBeanDescription("Management Bean for an AMQ Broker Connection") public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection { - private AMQMinaProtocolSession _session = null; + private AMQProtocolSession _protocolSession = null; private String _name = null; // openmbean data types for representing the channel attributes @@ -92,10 +92,10 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed new AMQShortString("Broker Management Console has closed the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException + public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException { super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); - _session = session; + _protocolSession = amqProtocolSession; String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; _name = jmxEncode(new StringBuffer(remote), 0).toString(); @@ -128,52 +128,52 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public String getClientId() { - return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); + return (_protocolSession.getContextKey() == null) ? null : _protocolSession.getContextKey().toString(); } public String getAuthorizedId() { - return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; + return (_protocolSession.getAuthorizedID() != null ) ? _protocolSession.getAuthorizedID().getName() : null; } public String getVersion() { - return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); + return (_protocolSession.getClientVersion() == null) ? null : _protocolSession.getClientVersion().toString(); } public Date getLastIoTime() { - return new Date(_session.getIOSession().getLastIoTime()); + return new Date(_protocolSession.getLastIoTime()); } public String getRemoteAddress() { - return _session.getIOSession().getRemoteAddress().toString(); + return _protocolSession.getRemoteAddress().toString(); } public ManagedObject getParentObject() { - return _session.getVirtualHost().getManagedObject(); + return _protocolSession.getVirtualHost().getManagedObject(); } public Long getWrittenBytes() { - return _session.getIOSession().getWrittenBytes(); + return _protocolSession.getWrittenBytes(); } public Long getReadBytes() { - return _session.getIOSession().getReadBytes(); + return _protocolSession.getWrittenBytes(); } public Long getMaximumNumberOfChannels() { - return _session.getMaximumNumberOfChannels(); + return _protocolSession.getMaximumNumberOfChannels(); } public void setMaximumNumberOfChannels(Long value) { - _session.setMaximumNumberOfChannels(value); + _protocolSession.setMaximumNumberOfChannels(value); } public String getObjectInstanceName() @@ -192,13 +192,13 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { - AMQChannel channel = _session.getChannel(channelId); + AMQChannel channel = _protocolSession.getChannel(channelId); if (channel == null) { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } - _session.commitTransactions(channel); + _protocolSession.commitTransactions(channel); } catch (AMQException ex) { @@ -221,13 +221,13 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try { - AMQChannel channel = _session.getChannel(channelId); + AMQChannel channel = _protocolSession.getChannel(channelId); if (channel == null) { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } - _session.rollbackTransactions(channel); + _protocolSession.commitTransactions(channel); } catch (AMQException ex) { @@ -248,7 +248,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public TabularData channels() throws OpenDataException { TabularDataSupport channelsList = new TabularDataSupport(_channelsType); - List list = _session.getChannels(); + List list = _protocolSession.getChannels(); for (AMQChannel channel : list) { @@ -274,7 +274,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public void closeConnection() throws JMException { - MethodRegistry methodRegistry = _session.getMethodRegistry(); + MethodRegistry methodRegistry = _protocolSession.getMethodRegistry(); ConnectionCloseBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), // replyCode @@ -301,12 +301,12 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed try { - _session.writeFrame(responseBody.generateFrame(0)); + _protocolSession.writeFrame(responseBody.generateFrame(0)); try { - _session.closeSession(); + _protocolSession.closeSession(); } catch (AMQException ex) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 7511b5c818..1affdd6590 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -258,7 +258,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry for (InetSocketAddress bindAddress : _acceptors.keySet()) { QpidAcceptor acceptor = _acceptors.get(bindAddress); - acceptor.getIoAcceptor().unbind(bindAddress); + acceptor.getNetworkDriver().close(); CurrentActor.get().message(BrokerMessages.BRK_1003(acceptor.toString(), bindAddress.getPort())); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 5b3c3659c4..7450322130 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -23,7 +23,6 @@ package org.apache.qpid.server.security.access.plugins.network; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; @@ -32,7 +31,6 @@ import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.protocol.AMQMinaProtocolSession; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; @@ -180,13 +178,13 @@ public class FirewallPlugin extends AbstractACLPlugin @Override public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) { - if (!(session instanceof AMQMinaProtocolSession)) + SocketAddress sockAddr = session.getRemoteAddress(); + if (!(sockAddr instanceof InetSocketAddress)) { - return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which - // mean MINA right now + return AuthzResult.ABSTAIN; // We only deal with tcp sessions } - InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session); + InetAddress addr = ((InetSocketAddress) sockAddr).getAddress(); if (addr == null) { @@ -213,19 +211,6 @@ public class FirewallPlugin extends AbstractACLPlugin } - private InetAddress getInetAdressFromMinaSession(AMQMinaProtocolSession session) - { - SocketAddress remote = session.getIOSession().getRemoteAddress(); - if (remote instanceof InetSocketAddress) - { - return ((InetSocketAddress) remote).getAddress(); - } - else - { - return null; - } - } - public void setConfiguration(Configuration config) throws ConfigurationException { // Get default action diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java index 61cc7cdeb6..3ca22b60c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java @@ -20,21 +20,21 @@ */ package org.apache.qpid.server.transport; -import org.apache.mina.common.IoAcceptor; +import org.apache.qpid.transport.NetworkDriver; public class QpidAcceptor { - IoAcceptor _acceptor; + NetworkDriver _driver; String _protocol; - public QpidAcceptor(IoAcceptor acceptor, String protocol) + public QpidAcceptor(NetworkDriver driver, String protocol) { - _acceptor = acceptor; + _driver = driver; _protocol = protocol; } - public IoAcceptor getIoAcceptor() + public NetworkDriver getNetworkDriver() { - return _acceptor; + return _driver; } public String toString() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9ab3592628..3b776a62b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -279,6 +279,14 @@ public class VirtualHost implements Accessable _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), period / 2, period); + + class ForceChannelClosuresTask extends TimerTask + { + public void run() + { + _connectionRegistry.expireClosedChannels(); + } + } } } -- cgit v1.2.1 From b236bf545c35139d43b127531a3ae9ecda889b28 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 15 Oct 2009 10:08:56 +0000 Subject: QPID-1304: implement the ACCESS section of SimpleXML ACL. Enables virtualhost level access control, giving the defined users full access to all artifacts in the vhost git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@825453 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissions.java | 66 ++++++++++++++++++---- .../server/security/access/plugins/SimpleXML.java | 21 +++++++ 2 files changed, 75 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index d2bbb795e9..3e065f9a9b 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -53,6 +53,7 @@ public class PrincipalPermissions private static final int PUBLISH_EXCHANGES_KEY = 0; private Map _permissions; + private boolean _fullVHostAccess = false; private String _user; @@ -82,6 +83,9 @@ public class PrincipalPermissions { switch (permission) { + case ACCESS:// Parameters : None + grantAccess(permission); + break; case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly grantConsume(permission, parameters); break; @@ -98,7 +102,6 @@ public class PrincipalPermissions break; /* The other cases just fall through to no-op */ case DELETE: - case ACCESS: // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS case BIND: // All the details are currently included in the create setup. case PURGE: case UNBIND: @@ -107,6 +110,11 @@ public class PrincipalPermissions } + private void grantAccess(Permission permission) + { + _fullVHostAccess = true; + } + private void grantPublish(Permission permission, Object... parameters) { Map publishRights = (Map) _permissions.get(permission); @@ -353,9 +361,8 @@ public class PrincipalPermissions switch (permission) { - case ACCESS: - return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it. - // The existence of this user specific PP can be validated in the map SimpleXML maintains. + case ACCESS://No Parameters + return AuthzResult.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey return authoriseBind(parameters); case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name @@ -376,7 +383,14 @@ public class PrincipalPermissions } - private AuthzResult authoriseConsume(Permission permission, Object... parameters) { + private AuthzResult authoriseConsume(Permission permission, Object... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + if (parameters.length == 1 && parameters[0] instanceof AMQQueue) { AMQQueue queue = ((AMQQueue) parameters[0]); @@ -434,8 +448,15 @@ public class PrincipalPermissions return AuthzResult.DENIED; } - private AuthzResult authorisePublish(Permission permission, Object... parameters) { - Map publishRights = (Map) _permissions.get(permission); + private AuthzResult authorisePublish(Permission permission, Object... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + + Map publishRights = (Map) _permissions.get(permission); if (publishRights == null) { @@ -494,7 +515,14 @@ public class PrincipalPermissions } } - private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters) { + private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + Map rights = (Map) _permissions.get(permission); AMQShortString exchangeName = (AMQShortString) parameters[0]; @@ -511,8 +539,15 @@ public class PrincipalPermissions } } - private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters) { - Map createRights = (Map) _permissions.get(permission); + private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + + Map createRights = (Map) _permissions.get(permission); // If there are no create rights then deny request if (createRights == null) @@ -549,8 +584,15 @@ public class PrincipalPermissions } } - private AuthzResult authoriseBind(Object... parameters) { - Exchange exchange = (Exchange) parameters[1]; + private AuthzResult authoriseBind(Object... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + + Exchange exchange = (Exchange) parameters[1]; AMQQueue bind_queueName = (AMQQueue) parameters[2]; AMQShortString routingKey = (AMQShortString) parameters[3]; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 2cc0c530de..d0514224f1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -85,8 +85,29 @@ public class SimpleXML implements ACLPlugin processConsume(config); processCreate(config); + + processAccess(config); } + private void processAccess(Configuration config) + { + Configuration accessConfig = config.subset("access_control_list.access"); + + if(accessConfig.isEmpty()) + { + //there is no access configuration to process + return; + } + + // Process users that have full access permission + String[] users = accessConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.ACCESS, user); + } + } + /** * Publish format takes Exchange + Routing Key Pairs * -- cgit v1.2.1 From 9617dce00b2cabbaf5b5ada6da53fc4193dfe17f Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 16 Oct 2009 08:20:20 +0000 Subject: QPID-1304: add vhost access check for missed corner cases, allowing for users granted vhost access and otherwise abstaining. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@825805 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/security/access/PrincipalPermissions.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 3e065f9a9b..6fe4696d20 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -378,7 +378,16 @@ public class PrincipalPermissions case PURGE: case UNBIND: default: - return AuthzResult.DENIED; + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return AuthzResult.ALLOWED; + } + else + { + //SimpleXML ACL does not implement these permissions and should abstain + return AuthzResult.ABSTAIN; + } } } -- cgit v1.2.1 From aed0bb719788394c2b5db5b1da354e6134da5d31 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 19 Oct 2009 11:11:30 +0000 Subject: Remove Java 1.6 @Overrides on interface implmentations git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@826639 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/protocol/AMQProtocolEngine.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 3bcd102858..a6fcadad0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -201,7 +201,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _actor; } - @Override public void received(final ByteBuffer msg) { _lastIoTime = System.currentTimeMillis(); @@ -210,7 +209,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol final ArrayList dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg); Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable() { - @Override public void run() { // Decode buffer @@ -457,7 +455,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _writtenBytes += buf.remaining(); Job.fireAsynchEvent(_poolReference.getPool(), _writeJob, new Runnable() { - @Override public void run() { _networkDriver.send(buf); @@ -679,6 +676,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol /** 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 { + // REMOVE THIS SHOULD NOT BE HERE. if (CurrentActor.get() == null) { CurrentActor.set(_actor); @@ -694,6 +692,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol if (_managedObject != null) { _managedObject.unregister(); + // Ensure we only do this once. + _managedObject = null; } for (Task task : _taskList) @@ -920,7 +920,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _dispatcher; } - @Override public void closed() { try @@ -933,25 +932,21 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } - @Override public void readerIdle() { // Nothing } - @Override public void setNetworkDriver(NetworkDriver driver) { _networkDriver = driver; } - @Override public void writerIdle() { _networkDriver.send(HeartbeatBody.FRAME.toNioByteBuffer()); } - @Override public void exception(Throwable throwable) { if (throwable instanceof AMQProtocolHeaderException) @@ -980,19 +975,16 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } - @Override public void init() { // Do nothing } - @Override public void setSender(Sender sender) { // Do nothing } - @Override public long getReadBytes() { return _readBytes; @@ -1018,7 +1010,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return (_clientVersion == null) ? null : _clientVersion.toString(); } - @Override public void closeIfLingeringClosedChannels() { for (Entryid : _closingChannelsList.entrySet()) -- cgit v1.2.1 From ca1f20721eec0b9d6805a9d26b7bf805b52a294d Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Tue, 20 Oct 2009 11:46:29 +0000 Subject: QPID-1301 Fixes for issues with temporary queue permissions, including promotion of temporary element out from individual queue elements. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@827041 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissions.java | 409 ++++++++++----------- .../server/security/access/plugins/SimpleXML.java | 50 ++- 2 files changed, 238 insertions(+), 221 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 6fe4696d20..6d35d7ae48 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -47,7 +47,6 @@ public class PrincipalPermissions private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); - private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object(); private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); private static final int PUBLISH_EXCHANGES_KEY = 0; @@ -181,165 +180,168 @@ public class PrincipalPermissions rights.put(name, className); } - private void grantCreateQueue(Permission permission, Object... parameters) { - Map createRights = (Map) _permissions.get(permission); - - if (createRights == null) - { - createRights = new ConcurrentHashMap(); - _permissions.put(permission, createRights); - - } - - //The existence of the empty map mean permission to all. - if (parameters.length == 0) - { - return; - } - - Boolean temporary = (Boolean) parameters[0]; - - AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; - AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; - //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; - - // Get the queues map - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - if (create_queues == null) - { - create_queues = new ConcurrentHashMap(); - createRights.put(CREATE_QUEUES_KEY, create_queues); - } - - //Allow all temp queues to be created - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); - - //Create empty list of queues - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - if (create_queues_queues == null) - { - create_queues_queues = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); - } - - // We are granting CREATE rights to all temporary queues only - if (parameters.length == 1) - { - return; - } + private void grantCreateQueue(Permission permission, Object... parameters) + { + Map createRights = (Map) _permissions.get(permission); - // if we have a queueName then we need to store any associated exchange / rk bindings - if (queueName != null) - { - Map queue = (Map) create_queues_queues.get(queueName); - if (queue == null) - { - queue = new ConcurrentHashMap(); - create_queues_queues.put(queueName, queue); - } + if (createRights == null) + { + createRights = new ConcurrentHashMap(); + _permissions.put(permission, createRights); + } - if (exchangeName != null) - { - queue.put(exchangeName, routingKey); - } + //The existence of the empty map mean permission to all. + if (parameters.length == 0) + { + return; + } - //If no exchange is specified then the presence of the queueName in the map says any exchange is ok - } + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - // Store the exchange that we are being granted rights to. This will be used as part of binding + //Initialiase the queue permissions if not already done + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + //initialise temp queue permission to false and overwrite below if true + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, false); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } - //Lookup the list of exchanges - Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - if (create_queues_exchanges == null) - { - create_queues_exchanges = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); - } + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } - //if we have an exchange - if (exchangeName != null) - { - //Retrieve the list of permitted exchanges. - Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + // If we are initialising and granting CREATE rights to all temporary queues, then that's all we do + Boolean temporary = false; + if (parameters.length == 1) + { + temporary = (Boolean) parameters[0]; + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + return; + } - if (exchanges == null) - { - exchanges = new ConcurrentHashMap(); - create_queues_exchanges.put(exchangeName, exchanges); - } + //From here we can be permissioning a variety of things, with varying parameters + AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) + { + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); + } + + if (exchangeName != null) + { + queue.put(exchangeName, routingKey); + } + + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } - //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY - exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary); + // Store the exchange that we are being granted rights to. This will be used as part of binding - //Store the binding details of queue/rk for this exchange. - if (queueName != null) - { - //Retrieve the list of permitted routingKeys. - Map rKeys = (Map) exchanges.get(exchangeName); + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - if (rKeys == null) - { - rKeys = new ConcurrentHashMap(); - exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); - } + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } - rKeys.put(queueName, routingKey); - } - } - } + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + + if (exchanges == null) + { + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); + } + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) + { + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); + + if (rKeys == null) + { + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); + } - private void grantConsume(Permission permission, Object... parameters) { - Map consumeRights = (Map) _permissions.get(permission); + rKeys.put(queueName, routingKey); + } + } + } - if (consumeRights == null) - { - consumeRights = new ConcurrentHashMap(); - _permissions.put(permission, consumeRights); - } + /** + * Grant consume permissions + */ + private void grantConsume(Permission permission, Object... parameters) + { + Map consumeRights = (Map) _permissions.get(permission); - //if we have parametsre - if (parameters.length > 0) - { - AMQShortString queueName = (AMQShortString) parameters[0]; - Boolean temporary = (Boolean) parameters[1]; - Boolean ownQueueOnly = (Boolean) parameters[2]; + if (consumeRights == null) + { + consumeRights = new ConcurrentHashMap(); + _permissions.put(permission, consumeRights); - if (temporary) - { - consumeRights.put(CONSUME_TEMPORARY_KEY, true); - } - else - { - consumeRights.put(CONSUME_TEMPORARY_KEY, false); - } + //initialise own and temporary rights to false to be overwritten below if set + consumeRights.put(CONSUME_TEMPORARY_KEY, false); + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); + } - if (ownQueueOnly) - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); - } - else - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); - } + //if we only have one param then we're permissioning temporary queues and topics + if (parameters.length == 1) + { + Boolean temporary = (Boolean) parameters[0]; - LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); - if (queues == null) - { - queues = new LinkedList(); - consumeRights.put(CONSUME_QUEUES_KEY, queues); - } + if (temporary) + { + consumeRights.put(CONSUME_TEMPORARY_KEY, true); + } + } - if (queueName != null) - { - queues.add(queueName); - } - } - } + //if we have 2 parameters - should be a contract for this, but for now we'll handle it as is + if (parameters.length == 2) + { + AMQShortString queueName = (AMQShortString) parameters[0]; + Boolean ownQueueOnly = (Boolean) parameters[1]; + + if (ownQueueOnly) + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); + } + + LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); + if (queues == null) + { + queues = new LinkedList(); + consumeRights.put(CONSUME_QUEUES_KEY, queues); + } + + if (queueName != null) + { + queues.add(queueName); + } + } + } /** * @@ -399,62 +401,63 @@ public class PrincipalPermissions //user has been granted full access to the vhost return AuthzResult.ALLOWED; } - - if (parameters.length == 1 && parameters[0] instanceof AMQQueue) - { - AMQQueue queue = ((AMQQueue) parameters[0]); - Map queuePermissions = (Map) _permissions.get(permission); - - if (queuePermissions == null) - { - //if the outer map is null, the user has no CONSUME rights at all - return AuthzResult.DENIED; - } - List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); + if (parameters.length == 1 && parameters[0] instanceof AMQQueue) + { + AMQQueue queue = ((AMQQueue) parameters[0]); + Map queuePermissions = (Map) _permissions.get(permission); - Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); - Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); + if (queuePermissions == null) + { + //we have a problem - we've never granted this type of permission ..... + return AuthzResult.DENIED; + } - // If user is allowed to publish to temporary queues and this is a temp queue then allow it. - if (temporayQueues) - { - if (queue.isAutoDelete()) - // This will allow consumption from any temporary queue including ones not owned by this user. - // Of course the exclusivity will not be broken. - { - // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } + List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); - // if queues are white listed then ensure it is ok - if (queues != null) - { - // if no queues are listed then ALL are ok othereise it must be specified. - if (ownQueuesOnly) - { - if (queue.getOwner().equals(_user)) - { - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } + Boolean temporaryQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); + Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); - // If we are - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - // Can't authenticate without the right parameters - return AuthzResult.DENIED; + // If user is allowed to consume from temporary queues and this is a temp queue then allow it. + if (temporaryQueues && queue.isAutoDelete()) + { + // This will allow consumption from any temporary queue including ones not owned by this user. + // Of course the exclusivity will not be broken. + { + // if not limited to ownQueuesOnly then ok else check queue Owner. + return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + //if this is a temporary queue and the user does not have permissions for temporary queues then deny + else if (!temporaryQueues && queue.isAutoDelete()) + { + return AuthzResult.DENIED; + } + + // if queues are white listed then ensure it is ok + if (queues != null) + { + // if no queues are listed then ALL are ok othereise it must be specified. + if (ownQueuesOnly) + { + if (queue.getOwner().equals(_user)) + { + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + else + { + return AuthzResult.DENIED; + } + } + + // If we are + return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + } + } + + // Can't authenticate without the right parameters + return AuthzResult.DENIED; } private AuthzResult authorisePublish(Permission permission, Object... parameters) @@ -662,31 +665,7 @@ public class PrincipalPermissions } else { - //There a is no white list for queues - - // So can allow all queues to be bound - // but we should first check and see if we have a temp queue and validate that we are allowed - // to bind temp queues. - - //Check to see if we have a temporary queue - if (bind_queueName.isAutoDelete()) - { - // Check and see if we have an exchange white list. - Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - // If the exchange exists then we must check to see if temporary queues are allowed here - if (bind_exchanges != null) - { - // Check to see if the requested exchange is allowed. - Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName()); - - return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - //no white list so all allowed, drop through to return true below. - } - - // not a temporary queue and no white list so all allowed. + //no white list so all allowed. return AuthzResult.ALLOWED; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index d0514224f1..e299ce99c4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -187,8 +187,26 @@ public class SimpleXML implements ACLPlugin private void processConsume(Configuration config) { + boolean temporary = false; + Configuration tempConfig = null; Configuration consumeConfig = config.subset("access_control_list.consume"); + tempConfig = consumeConfig.subset("queues.temporary(0)"); + if (tempConfig != null) + { + temporary = true; + } + + //Permission all users who have rights to temp queues and topics + if (tempConfig != null && !tempConfig.isEmpty()) + { + String[] tempUsers = tempConfig.getStringArray("users.user"); + for (String user : tempUsers) + { + grant(Permission.CONSUME, user, temporary); + } + } + // Process queue limited users int queueCount = 0; Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); @@ -198,14 +216,14 @@ public class SimpleXML implements ACLPlugin // Get queue Name AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); // if there is no name then there may be a temporary element - boolean temporary = queueConfig.containsKey("temporary"); + boolean ownQueues = queueConfig.containsKey("own_queues"); // Process permissions for this queue String[] users = queueConfig.getStringArray("users.user"); for (String user : users) { - grant(Permission.CONSUME, user, queueName, temporary, ownQueues); + grant(Permission.CONSUME, user, queueName, ownQueues); } // See if we have another config @@ -218,14 +236,33 @@ public class SimpleXML implements ACLPlugin for (String user : users) { + //NOTE: this call does not appear to do anything inside the grant section for consume grant(Permission.CONSUME, user); } } private void processCreate(Configuration config) { + boolean temporary = false; + Configuration tempConfig = null; + Configuration createConfig = config.subset("access_control_list.create"); + tempConfig = createConfig.subset("queues.temporary(0)"); + if (tempConfig != null) + { + temporary = true; + } + + //Permission all users who have rights to temp queues and topics + if (tempConfig != null && !tempConfig.isEmpty()) + { + String[] tempUsers = tempConfig.getStringArray("users.user"); + for (String user : tempUsers) + { + grant(Permission.CREATEQUEUE, user, temporary); + } + } // Process create permissions for queue creation int queueCount = 0; Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); @@ -235,9 +272,6 @@ public class SimpleXML implements ACLPlugin // Get queue Name AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); - // if there is no name then there may be a temporary element - boolean temporary = queueConfig.containsKey("temporary"); - int exchangeCount = 0; Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); @@ -246,12 +280,15 @@ public class SimpleXML implements ACLPlugin AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); - + // Process permissions for this queue String[] users = exchangeConfig.getStringArray("users.user"); for (String user : users) { + //This is broken as the user name is not stored grant(Permission.CREATEEXCHANGE, user, exchange); + + //This call could be cleaned up as temporary is now being set earlier (above) grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); } @@ -287,6 +324,7 @@ public class SimpleXML implements ACLPlugin String[] users = exchangeConfig.getStringArray("users.user"); for (String user : users) { + //And this is broken too grant(Permission.CREATEEXCHANGE, user, exchange, clazz); } -- cgit v1.2.1 From bc832b23f5484422ef373d09f6ad74971c2cd497 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 20 Oct 2009 14:45:05 +0000 Subject: QPID-2040: remove use of FileUtils.copyCheckedEx for security reasons, generate new file in same filesystem as existing file to avoid copying between filesystems git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@827584 13f79535-47bb-0310-9956-ffa450edef68 --- .../PlainPasswordFilePrincipalDatabase.java | 46 ++++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 6ec7cea4c0..8665e579ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -26,7 +26,6 @@ import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; -import org.apache.qpid.util.FileUtils; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -41,6 +40,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -395,7 +395,15 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase BufferedReader reader = null; PrintStream writer = null; - File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + + Random r = new Random(); + File tmp; + do + { + tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + tmp.deleteOnExit(); try @@ -479,30 +487,26 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase old.delete(); } - try - { - if(!_passwordFile.renameTo(old)) - { - FileUtils.copyCheckedEx(_passwordFile, old); - } - } - catch (IOException e) + if(!_passwordFile.renameTo(old)) { - _logger.error("Could not backup the existing password file: " +e); - throw new IOException("Could not backup the existing password file: " + e); + //unable to rename the existing file to the backup name + _logger.error("Could not backup the existing password file"); + throw new IOException("Could not backup the existing password file"); } - - try + + if(!tmp.renameTo(_passwordFile)) { - if(!tmp.renameTo(_passwordFile)) + //failed to rename the new file to the required filename + + if(!old.renameTo(_passwordFile)) { - FileUtils.copyCheckedEx(tmp, _passwordFile); + //unable to return the backup to required filename + _logger.error("Could not rename the new password file into place, and unable to restore original file"); + throw new IOException("Could not rename the new password file into place, and unable to restore original file"); } - } - catch (IOException e) - { - _logger.error("Could not copy the new password file into place: " +e); - throw new IOException("Could not copy the new password file into place: " + e); + + _logger.error("Could not rename the new password file into place"); + throw new IOException("Could not rename the new password file into place"); } } -- cgit v1.2.1 From 405c85cad7208112d907c614faf2ff7c548e1db7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 20 Oct 2009 14:45:36 +0000 Subject: QPID-2041: remove use of FileUtils.copyCheckedEx for security reasons, generate new file in same filesystem as existing file to avoid copying between filesystems git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@827587 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 45 ++++++++++++---------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index cd4eb0bec7..581eeabbc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -40,6 +40,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -428,7 +429,15 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase BufferedReader reader = null; PrintStream writer = null; - File tmp = File.createTempFile(_passwordFile.getName(), ".tmp"); + + Random r = new Random(); + File tmp; + do + { + tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + tmp.deleteOnExit(); try @@ -528,30 +537,26 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase old.delete(); } - try - { - if(!_passwordFile.renameTo(old)) - { - FileUtils.copyCheckedEx(_passwordFile, old); - } - } - catch (IOException e) + if(!_passwordFile.renameTo(old)) { - _logger.error("Could not backup the existing password file: " +e); - throw new IOException("Could not backup the existing password file: " + e); + //unable to rename the existing file to the backup name + _logger.error("Could not backup the existing password file"); + throw new IOException("Could not backup the existing password file"); } - - try + + if(!tmp.renameTo(_passwordFile)) { - if(!tmp.renameTo(_passwordFile)) + //failed to rename the new file to the required filename + + if(!old.renameTo(_passwordFile)) { - FileUtils.copyCheckedEx(tmp, _passwordFile); + //unable to return the backup to required filename + _logger.error("Could not rename the new password file into place, and unable to restore original file"); + throw new IOException("Could not rename the new password file into place, and unable to restore original file"); } - } - catch (IOException e) - { - _logger.error("Could not copy the new password file into place: " +e); - throw new IOException("Could not copy the new password file into place: " + e); + + _logger.error("Could not rename the new password file into place"); + throw new IOException("Could not rename the new password file into place"); } } finally -- cgit v1.2.1 From e3a5192ce683341b0c7b21565726b8639778b7f7 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 20 Oct 2009 14:46:05 +0000 Subject: QPID-2042: remove use of FileUtils.copyCheckedEx for security reasons, generate new file in same filesystem as existing file to avoid copying between filesystems git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@827589 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/management/AMQUserManagementMBean.java | 44 ++++++++++++---------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index b6d2c3ab67..69abac7bd6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -51,6 +51,7 @@ import java.io.FileOutputStream; import java.util.Properties; import java.util.List; import java.util.Enumeration; +import java.util.Random; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import java.security.Principal; @@ -439,7 +440,14 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.lock(); // Create temporary file - File tmp = File.createTempFile(_accessFile.getName(), ".tmp"); + Random r = new Random(); + File tmp; + do + { + tmp = new File(_accessFile.getPath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + tmp.deleteOnExit(); FileOutputStream output = new FileOutputStream(tmp); @@ -453,30 +461,26 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana old.delete(); } - try + if(!_accessFile.renameTo(old)) { - if(!_accessFile.renameTo(old)) - { - FileUtils.copyCheckedEx(_accessFile, old); - } + //unable to rename the existing file to the backup name + _logger.error("Could not backup the existing management rights file"); + throw new IOException("Could not backup the existing management rights file"); } - catch (IOException e) - { - _logger.warn("Could not backup the existing management rights file: " +e); - throw new IOException("Could not backup the existing management rights file: " +e); - } - - try + + if(!tmp.renameTo(_accessFile)) { - if(!tmp.renameTo(_accessFile)) + //failed to rename the new file to the required filename + + if(!old.renameTo(_accessFile)) { - FileUtils.copyCheckedEx(tmp, _accessFile); + //unable to return the backup to required filename + _logger.error("Could not rename the new management rights file into place, and unable to restore original file"); + throw new IOException("Could not rename the new management rights file into place, and unable to restore original file"); } - } - catch (IOException e) - { - _logger.warn("Could not copy the new management rights file into place: " +e); - throw new IOException("Could not copy the new management rights file into place" +e); + + _logger.error("Could not rename the new management rights file into place"); + throw new IOException("Could not rename the new management rights file into place"); } } finally -- cgit v1.2.1 From cc12b352d19e7f51eba772300535b2751484b1fb Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 20 Oct 2009 14:46:35 +0000 Subject: QPID-2055: remove use of FileUtils.copyCheckedEx for security reasons, generate new file in same filesystem as existing file to avoid copying between filesystems git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@827591 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/management/LoggingManagementMBean.java | 51 +++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 3c47cdd094..c36eeb5016 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -29,6 +29,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; @@ -365,10 +366,17 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM DOMSource source = new DOMSource(doc); File tmp; + Random r = new Random(); + do + { + tmp = new File(log4jConfigFile.getPath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + + tmp.deleteOnExit(); + try { - tmp = File.createTempFile("LogManMBeanTemp", ".tmp"); - tmp.deleteOnExit(); StreamResult result = new StreamResult(tmp); transformer.transform(source, result); } @@ -377,11 +385,6 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM _logger.warn("Could not transform the XML into new file: " +e); throw new IOException("Could not transform the XML into new file: " +e); } - catch (IOException e) - { - _logger.warn("Could not create the new log4j XML file: " +e); - throw new IOException("Could not create the new log4j XML file: " +e); - } // Swap temp file in to replace existing configuration file. File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); @@ -390,30 +393,26 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM old.delete(); } - try + if(!log4jConfigFile.renameTo(old)) { - if(!log4jConfigFile.renameTo(old)) - { - FileUtils.copyCheckedEx(log4jConfigFile, old); - } + //unable to rename the existing file to the backup name + _logger.error("Could not backup the existing log4j XML file"); + throw new IOException("Could not backup the existing log4j XML file"); } - catch (IOException e) - { - _logger.warn("Could not backup the existing log4j XML file: " +e); - throw new IOException("Could not backup the existing log4j XML file: " +e); - } - - try + + if(!tmp.renameTo(log4jConfigFile)) { - if(!tmp.renameTo(log4jConfigFile)) + //failed to rename the new file to the required filename + + if(!old.renameTo(log4jConfigFile)) { - FileUtils.copyCheckedEx(tmp, log4jConfigFile); + //unable to return the backup to required filename + _logger.error("Could not rename the new log4j configuration file into place, and unable to restore original file"); + throw new IOException("Could not rename the new log4j configuration file into place, and unable to restore original file"); } - } - catch (IOException e) - { - _logger.warn("Could not copy the new configuration into place: " +e); - throw new IOException("Could not copy the new configuration into place: " +e); + + _logger.error("Could not rename the new log4j configuration file into place"); + throw new IOException("Could not rename the new log4j configuration file into place"); } return true; -- cgit v1.2.1 From 62bf473eb34ba29e5770b21e7241c194db12b83d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 22 Oct 2009 16:14:45 +0000 Subject: QPID-2001 : Added A NullRootMessageLogger to drop logging, Currently only used by external tools. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@828768 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/NullRootMessageLogger.java | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java new file mode 100644 index 0000000000..6cd29b95fb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.ConfigurationException; + +public class NullRootMessageLogger extends RootMessageLoggerImpl +{ + + public NullRootMessageLogger() throws ConfigurationException + { + super(new ServerConfiguration(new PropertiesConfiguration()), new NullMessageLogger()); + } + + @Override + public boolean isMessageEnabled(LogActor actor, LogSubject subject) + { + return false; + } + + @Override + public boolean isMessageEnabled(LogActor actor) + { + return false; + } + + public static class NullMessageLogger implements RawMessageLogger + { + public void rawMessage(String message) + { + // drop message + } + + public void rawMessage(String message, Throwable throwable) + { + // drop message + } + } + +} -- cgit v1.2.1 From afcf8099695253651c73910a243fb29aa520b008 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 25 Oct 2009 22:58:57 +0000 Subject: Merged from java-broker-0-10 branch git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@829675 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 43 +- .../java/org/apache/qpid/server/AMQChannel.java | 672 +++++++---- .../qpid/server/ConsumerTagNotUniqueException.java | 25 - .../qpid/server/ExtractResendAndRequeue.java | 55 +- .../src/main/java/org/apache/qpid/server/Main.java | 201 +++- .../qpid/server/RequiredDeliveryException.java | 79 -- .../java/org/apache/qpid/server/ack/TxAck.java | 148 --- .../qpid/server/ack/UnacknowledgedMessageMap.java | 11 +- .../server/ack/UnacknowledgedMessageMapImpl.java | 67 +- .../server/configuration/ServerConfiguration.java | 47 +- .../qpid/server/exchange/AbstractExchange.java | 91 +- .../server/exchange/DefaultExchangeFactory.java | 16 +- .../server/exchange/DefaultExchangeRegistry.java | 42 +- .../qpid/server/exchange/DirectExchange.java | 37 +- .../org/apache/qpid/server/exchange/Exchange.java | 29 +- .../qpid/server/exchange/ExchangeFactory.java | 2 + .../qpid/server/exchange/ExchangeInitialiser.java | 47 + .../qpid/server/exchange/ExchangeReferrer.java | 26 + .../qpid/server/exchange/ExchangeRegistry.java | 4 + .../qpid/server/exchange/FanoutExchange.java | 31 +- .../qpid/server/exchange/HeadersBinding.java | 58 +- .../qpid/server/exchange/HeadersExchange.java | 65 +- .../org/apache/qpid/server/exchange/Index.java | 15 + .../apache/qpid/server/exchange/MessageRouter.java | 5 +- .../qpid/server/exchange/NoRouteException.java | 49 - .../apache/qpid/server/exchange/TopicExchange.java | 75 +- .../qpid/server/filter/ArithmeticExpression.java | 4 +- .../qpid/server/filter/BinaryExpression.java | 16 +- .../qpid/server/filter/BooleanExpression.java | 7 +- .../qpid/server/filter/ComparisonExpression.java | 28 +- .../qpid/server/filter/ConstantExpression.java | 10 +- .../org/apache/qpid/server/filter/Expression.java | 6 +- .../apache/qpid/server/filter/FilterManager.java | 14 +- .../qpid/server/filter/JMSSelectorFilter.java | 6 +- .../apache/qpid/server/filter/LogicExpression.java | 24 +- .../apache/qpid/server/filter/MessageFilter.java | 10 +- .../qpid/server/filter/PropertyExpression.java | 117 +- .../qpid/server/filter/SimpleFilterManager.java | 27 +- .../apache/qpid/server/filter/UnaryExpression.java | 44 +- .../apache/qpid/server/filter/XPathExpression.java | 7 +- .../qpid/server/filter/XQueryExpression.java | 9 +- .../qpid/server/filter/XalanXPathEvaluator.java | 20 +- .../server/flow/AbstractFlowCreditManager.java | 17 +- .../qpid/server/flow/BytesOnlyCreditManager.java | 24 +- .../qpid/server/flow/CreditCreditManager.java | 188 +++ .../apache/qpid/server/flow/FlowCreditManager.java | 12 +- .../qpid/server/flow/FlowCreditManager_0_10.java | 28 + .../qpid/server/flow/LimitlessCreditManager.java | 16 +- .../server/flow/MessageAndBytesCreditManager.java | 25 +- .../qpid/server/flow/MessageOnlyCreditManager.java | 20 +- .../qpid/server/flow/Pre0_10CreditManager.java | 16 +- .../qpid/server/flow/WindowCreditManager.java | 213 ++++ .../server/handler/BasicConsumeMethodHandler.java | 40 +- .../qpid/server/handler/BasicGetMethodHandler.java | 15 +- .../server/handler/BasicRejectMethodHandler.java | 6 +- .../handler/ConnectionOpenMethodHandler.java | 3 +- .../handler/ConnectionTuneOkMethodHandler.java | 1 + .../server/handler/ExchangeDeclareHandler.java | 14 +- .../qpid/server/handler/QueueDeclareHandler.java | 38 +- .../qpid/server/handler/QueueDeleteHandler.java | 3 +- .../qpid/server/handler/QueuePurgeHandler.java | 3 +- .../qpid/server/handler/TxCommitHandler.java | 4 +- .../qpid/server/handler/TxRollbackHandler.java | 25 +- .../server/logging/actors/AMQPChannelActor.java | 2 +- .../server/logging/actors/AMQPConnectionActor.java | 4 +- .../qpid/server/logging/actors/CurrentActor.java | 12 +- .../server/logging/messages/LogMessages.properties | 33 +- .../logging/messages/LogMessages_en_US.properties | 198 +--- .../server/logging/subjects/ChannelLogSubject.java | 2 +- .../logging/subjects/ConnectionLogSubject.java | 2 +- .../server/management/DefaultManagedObject.java | 19 +- .../management/JMXManagedObjectRegistry.java | 14 +- .../qpid/server/management/ManagedObject.java | 7 +- .../org/apache/qpid/server/message/AMQMessage.java | 329 ++++++ .../qpid/server/message/AMQMessageHeader.java | 51 + .../qpid/server/message/AMQMessageReference.java | 44 + .../server/message/ContentHeaderBodyAdapter.java | 114 ++ .../qpid/server/message/EnqueableMessage.java | 27 + .../apache/qpid/server/message/InboundMessage.java | 37 + .../qpid/server/message/MessageContentSource.java | 31 + .../qpid/server/message/MessageMetaData.java | 309 +++++ .../qpid/server/message/MessageMetaData_0_10.java | 242 ++++ .../qpid/server/message/MessageReference.java | 57 + .../qpid/server/message/MessageTransferHeader.java | 112 ++ .../server/message/MessageTransferMessage.java | 146 +++ .../apache/qpid/server/message/ServerMessage.java | 47 + .../server/message/TransferMessageReference.java | 39 + .../server/output/HeaderPropertiesConverter.java | 124 ++ .../server/output/ProtocolOutputConverter.java | 11 +- .../amqp0_8/ProtocolOutputConverterImpl.java | 237 ++-- .../amqp0_9/ProtocolOutputConverterImpl.java | 278 +++-- .../qpid/server/protocol/AMQProtocolEngine.java | 147 ++- .../qpid/server/protocol/AMQProtocolSession.java | 21 +- .../server/protocol/AMQProtocolSessionMBean.java | 4 +- .../qpid/server/protocol/ExchangeInitialiser.java | 51 - .../protocol/MultiVersionProtocolEngine.java | 366 ++++++ .../MultiVersionProtocolEngineFactory.java | 75 ++ .../protocol/ProtocolEngineFactory_0_10.java | 46 + .../qpid/server/protocol/ProtocolEngine_0_10.java | 84 ++ .../org/apache/qpid/server/queue/AMQMessage.java | 502 -------- .../apache/qpid/server/queue/AMQMessageHandle.java | 79 -- .../apache/qpid/server/queue/AMQPriorityQueue.java | 36 +- .../org/apache/qpid/server/queue/AMQQueue.java | 63 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 37 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 159 ++- .../qpid/server/queue/DefaultQueueRegistry.java | 13 +- .../org/apache/qpid/server/queue/Filterable.java | 7 +- .../qpid/server/queue/InMemoryMessageHandle.java | 157 --- .../qpid/server/queue/InboundMessageAdapter.java | 71 ++ .../apache/qpid/server/queue/IncomingMessage.java | 283 +++-- .../qpid/server/queue/MessageHandleFactory.java | 46 - .../apache/qpid/server/queue/MessageMetaData.java | 92 -- .../qpid/server/queue/NoConsumersException.java | 47 - .../qpid/server/queue/NotificationCheck.java | 22 +- .../qpid/server/queue/PriorityQueueList.java | 23 +- .../org/apache/qpid/server/queue/QueueContext.java | 49 + .../org/apache/qpid/server/queue/QueueEntry.java | 51 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 230 +++- .../apache/qpid/server/queue/QueueEntryList.java | 4 +- .../apache/qpid/server/queue/QueueRegistry.java | 9 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 902 ++++++++------- .../qpid/server/queue/SimpleQueueEntryList.java | 69 +- .../apache/qpid/server/queue/SubFlushRunner.java | 68 ++ .../qpid/server/queue/TransientMessageData.java | 127 --- .../server/queue/UnauthorizedAccessException.java | 45 - .../server/queue/WeakReferenceMessageHandle.java | 219 ---- .../ConfigurationFileApplicationRegistry.java | 14 +- .../qpid/server/security/PrincipalHolder.java | 29 + .../qpid/server/security/access/ACLManager.java | 45 +- .../qpid/server/security/access/ACLPlugin.java | 30 +- .../security/access/PrincipalPermissions.java | 5 +- .../security/access/plugins/AbstractACLPlugin.java | 26 +- .../security/access/plugins/BasicACLPlugin.java | 31 +- .../server/security/access/plugins/DenyAll.java | 2 +- .../server/security/access/plugins/SimpleXML.java | 56 +- .../access/plugins/network/FirewallPlugin.java | 26 +- .../ConfigurationFilePrincipalDatabaseManager.java | 9 +- .../qpid/server/store/AbstractMessageStore.java | 4 +- .../server/store/ConfigurationRecoveryHandler.java | 57 + .../qpid/server/store/DerbyMessageStore.java | 1069 +++++++++--------- .../server/store/DurableConfigurationStore.java | 116 ++ .../qpid/server/store/MemoryMessageStore.java | 162 ++- .../qpid/server/store/MessageMetaDataType.java | 41 + .../org/apache/qpid/server/store/MessageStore.java | 251 +--- .../server/store/MessageStoreRecoveryHandler.java | 33 + .../qpid/server/store/StorableMessageMetaData.java | 36 + .../org/apache/qpid/server/store/StoreContext.java | 2 + .../qpid/server/store/StoredMemoryMessage.java | 80 ++ .../apache/qpid/server/store/StoredMessage.java | 38 + .../apache/qpid/server/store/TransactionLog.java | 92 ++ .../store/TransactionLogRecoveryHandler.java | 33 + .../qpid/server/store/TransactionLogResource.java | 26 + .../ExplicitAcceptDispositionChangeListener.java | 93 ++ .../ImplicitAcceptDispositionChangeListener.java | 86 ++ .../MessageAcceptCompletionListener.java | 57 + .../qpid/server/subscription/Subscription.java | 23 +- .../qpid/server/subscription/SubscriptionImpl.java | 196 ++-- .../server/subscription/Subscription_0_10.java | 658 +++++++++++ .../qpid/server/transport/ServerConnection.java | 64 ++ .../server/transport/ServerConnectionDelegate.java | 120 ++ .../qpid/server/transport/ServerSession.java | 398 +++++++ .../server/transport/ServerSessionDelegate.java | 1193 ++++++++++++++++++++ .../qpid/server/txn/AutoCommitTransaction.java | 170 +++ .../apache/qpid/server/txn/LocalTransaction.java | 243 ++++ .../qpid/server/txn/LocalTransactionalContext.java | 294 ----- .../qpid/server/txn/NonTransactionalContext.java | 215 ---- .../apache/qpid/server/txn/ServerTransaction.java | 60 + .../qpid/server/txn/StoreMessageOperation.java | 58 - .../qpid/server/txn/TransactionalContext.java | 179 --- .../java/org/apache/qpid/server/txn/TxnBuffer.java | 109 -- .../java/org/apache/qpid/server/txn/TxnOp.java | 55 - .../server/util/ConcurrentLinkedQueueNoSize.java | 38 - .../qpid/server/virtualhost/VirtualHost.java | 644 +---------- .../VirtualHostConfigRecoveryHandler.java | 340 ++++++ .../qpid/server/virtualhost/VirtualHostImpl.java | 608 ++++++++++ .../server/virtualhost/VirtualHostRegistry.java | 3 +- .../qpid/tools/messagestore/commands/Copy.java | 10 +- .../qpid/tools/messagestore/commands/Dump.java | 31 +- .../qpid/tools/messagestore/commands/List.java | 4 +- .../qpid/tools/messagestore/commands/Move.java | 20 +- .../qpid/tools/messagestore/commands/Purge.java | 2 +- .../qpid/tools/messagestore/commands/Show.java | 43 +- 182 files changed, 11527 insertions(+), 6532 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java mode change 100644 => 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 5cfa8066e5..08b3c08215 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -63,8 +63,9 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.AMQQueueMBean; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -78,12 +79,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; + private final DurableConfigurationStore _durableConfig; - private final VirtualHost.VirtualHostMBean _virtualHostMBean; + private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean; @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException + public AMQBrokerManagerMBean(VirtualHostImpl.VirtualHostMBean virtualHostMBean) throws JMException { super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); @@ -92,7 +93,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr _queueRegistry = virtualHost.getQueueRegistry(); _exchangeRegistry = virtualHost.getExchangeRegistry(); - _messageStore = virtualHost.getMessageStore(); + _durableConfig = virtualHost.getDurableConfigurationStore(); _exchangeFactory = virtualHost.getExchangeFactory(); } @@ -113,10 +114,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { exchangeTypes.add(ex.getName().toString()); } - + return exchangeTypes.toArray(new String[0]); } - + /** * Returns a list containing the names of the attributes available for the Queue mbeans. * @since Qpid JMX API 1.3 @@ -129,12 +130,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { attributeList.add(attr); } - + Collections.sort(attributeList); return attributeList; } - + /** * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost. * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-". @@ -147,22 +148,22 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { return new ArrayList>(); } - + List> queueAttributesList = new ArrayList>(_queueRegistry.getQueues().size()); - + int attributesLength = attributes.length; - + for(AMQQueue queue : _queueRegistry.getQueues()) { AMQQueueMBean mbean = (AMQQueueMBean) queue.getManagedObject(); - + if(mbean == null) { continue; } - + List attributeValues = new ArrayList(attributesLength); - + for(int i=0; i < attributesLength; i++) { try @@ -174,13 +175,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr attributeValues.add(new String("-")); } } - + queueAttributesList.add(attributeValues); } - + return queueAttributesList; } - + /** * Creates new exchange and registers it with the registry. * @@ -277,7 +278,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr null); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue); + _durableConfig.createQueue(queue); } _queueRegistry.registerQueue(queue); @@ -319,7 +320,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr queue.delete(); if (queue.isDurable()) { - _messageStore.removeQueue(queue); + _durableConfig.removeQueue(queue); } } catch (AMQException ex) @@ -330,7 +331,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } finally { - CurrentActor.remove(); + CurrentActor.remove(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 644a33db01..262bb2f226 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,24 +20,20 @@ */ package org.apache.qpid.server; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.*; import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -47,23 +43,30 @@ import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; import org.apache.qpid.server.subscription.RecordDeliveryMethod; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.txn.*; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogMessage; import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.logging.actors.AMQPChannelActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.output.ProtocolOutputConverter; public class AMQChannel { public static final int DEFAULT_PREFETCH = 5000; - private static final Logger _log = Logger.getLogger(AMQChannel.class); + private static final Logger _logger = Logger.getLogger(AMQChannel.class); + + private static final boolean MSG_AUTH = + ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); + private final int _channelId; @@ -96,19 +99,12 @@ public class AMQChannel private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - private final AtomicBoolean _suspended = new AtomicBoolean(false); + // Set of messages being acknoweledged in the current transaction + private SortedSet _acknowledgedMessages = new TreeSet(); - private TransactionalContext _txnContext; - - /** - * A context used by the message store enabling it to track context for a given channel even across thread - * boundaries - */ - private final StoreContext _storeContext; - - private final List _returnMessages = new LinkedList(); + private final AtomicBoolean _suspended = new AtomicBoolean(false); - private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + private ServerTransaction _transaction; // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; @@ -121,6 +117,12 @@ public class AMQChannel private LogActor _actor; private LogSubject _logSubject; + private volatile boolean _rollingBack; + + private static final Runnable NULL_TASK = new Runnable() { public void run() {} }; + private List _resendList = new ArrayList(); + private static final + AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible."); public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -130,22 +132,19 @@ public class AMQChannel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); - - _actor.message(ChannelMessages.CHN_1001()); - - _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); + _actor.message(ChannelMessages.CHN_1001()); _messageStore = messageStore; // by default the session is non-transactional - _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + _transaction = new AutoCommitTransaction(_messageStore); } /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { - _txnContext = new LocalTransactionalContext(this); + _transaction = new LocalTransaction(_messageStore); } public boolean isTransactional() @@ -153,7 +152,7 @@ public class AMQChannel // this does not look great but there should only be one "non-transactional" // transactional context, while there could be several transactional ones in // theory - return !(_txnContext instanceof NonTransactionalContext); + return !(_transaction instanceof AutoCommitTransaction); } public int getChannelId() @@ -164,8 +163,7 @@ public class AMQChannel public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException { - _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session); - _currentMessage.setMessageStore(_messageStore); + _currentMessage = new IncomingMessage(info); _currentMessage.setExchange(e); } @@ -178,18 +176,35 @@ public class AMQChannel } else { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug("Content header received on channel " + _channelId); + _logger.debug("Content header received on channel " + _channelId); } _currentMessage.setContentHeaderBody(contentHeaderBody); _currentMessage.setExpiration(); + + MessageMetaData mmd = _currentMessage.headersReceived(); + final StoredMessage handle = _messageStore.addMessage(mmd); + _currentMessage.setStoredMessage(handle); + routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + + _transaction.addPostCommitAction(new ServerTransaction.Action() + { + + public void postCommit() + { + } + + public void onRollback() + { + handle.remove(); + } + }); deliverCurrentMessageIfComplete(); @@ -204,21 +219,36 @@ public class AMQChannel { try { - _currentMessage.deliverToQueues(); - } - catch (NoRouteException e) - { - _returnMessages.add(e); - } - catch(UnauthorizedAccessException ex) - { - _returnMessages.add(ex); + + final ArrayList destinationQueues = _currentMessage.getDestinationQueues(); + + if(!checkMessageUserId(_currentMessage.getContentHeader())) + { + _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage)); + } + else + { + if(destinationQueues == null || _currentMessage.getDestinationQueues().isEmpty()) + { + if (_currentMessage.isMandatory() || _currentMessage.isImmediate()) + { + _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage)); + } + else + { + _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage)); + } + + } + else + { + _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues)); + + } + } } finally { - // callback to allow the context to do any post message processing - // primary use is to allow message return processing in the non-tx case - _txnContext.messageProcessed(_session); _currentMessage = null; } } @@ -232,9 +262,9 @@ public class AMQChannel throw new AMQException("Received content body without previously receiving a JmsPublishBody"); } - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug(debugIdentity() + "Content body received on channel " + _channelId); + _logger.debug(debugIdentity() + "Content body received on channel " + _channelId); } try @@ -242,9 +272,10 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received - _currentMessage.addContentBodyFrame( - _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody)); + final ContentChunk contentChunk = + _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(contentBody); + + _currentMessage.addContentBodyFrame(contentChunk); deliverCurrentMessageIfComplete(); } @@ -259,15 +290,7 @@ public class AMQChannel protected void routeCurrentMessage() throws AMQException { - try - { - _currentMessage.route(); - } - catch (NoRouteException e) - { - //_currentMessage.incrementReference(); - _returnMessages.add(e); - } + _currentMessage.route(); } public long getNextDeliveryTag() @@ -280,6 +303,12 @@ public class AMQChannel return ++_consumerTag; } + + public Subscription getSubscription(AMQShortString subscription) + { + return _tag2SubscriptionMap.get(subscription); + } + /** * Subscribe to a queue. We register all subscriptions in the channel so that if the channel is closed we can clean * up all subscriptions, even if the client does not explicitly unsubscribe from all queues. @@ -293,11 +322,10 @@ public class AMQChannel * @param exclusive Flag requesting exclusive access to the queue * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests * - * @throws ConsumerTagNotUniqueException if the tag is not unique * @throws AMQException if something goes wrong */ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (tag == null) { @@ -306,7 +334,7 @@ public class AMQChannel if (_tag2SubscriptionMap.containsKey(tag)) { - throw new ConsumerTagNotUniqueException(); + throw new AMQException("Consumer already exists with same tag: " + tag); } Subscription subscription = @@ -344,12 +372,12 @@ public class AMQChannel Subscription sub = _tag2SubscriptionMap.remove(consumerTag); if (sub != null) { - try + try { sub.getSendLock(); sub.getQueue().unregisterSubscription(sub); } - finally + finally { sub.releaseSendLock(); } @@ -357,7 +385,7 @@ public class AMQChannel } else { - _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); + _logger.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); } return false; } @@ -369,18 +397,20 @@ public class AMQChannel */ public void close() throws AMQException { - _txnContext.rollback(); + setClosing(true); + unsubscribeAllConsumers(); + _transaction.rollback(); + try { requeue(); } catch (AMQException e) { - _log.error("Caught AMQException whilst attempting to reque:" + e); + _logger.error("Caught AMQException whilst attempting to reque:" + e); } - setClosing(true); } private void setClosing(boolean closing) @@ -392,23 +422,23 @@ public class AMQChannel private void unsubscribeAllConsumers() throws AMQException { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { if (!_tag2SubscriptionMap.isEmpty()) { - _log.info("Unsubscribing all consumers on channel " + toString()); + _logger.info("Unsubscribing all consumers on channel " + toString()); } else { - _log.info("No consumers to unsubscribe on channel " + toString()); + _logger.info("No consumers to unsubscribe on channel " + toString()); } } for (Map.Entry me : _tag2SubscriptionMap.entrySet()) { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); + _logger.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); } Subscription sub = me.getValue(); @@ -422,7 +452,7 @@ public class AMQChannel { sub.releaseSendLock(); } - + } _tag2SubscriptionMap.clear(); @@ -438,17 +468,17 @@ public class AMQChannel */ public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription) { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { if (entry.getQueue() == null) { - _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity()); + _logger.debug("Adding unacked message with a null queue:" + entry); } else { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + _logger.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + ") with a queue(" + entry.getQueue() + ") for " + subscription); } } @@ -476,27 +506,13 @@ public class AMQChannel // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext = null; - if (!messagesToBeDelivered.isEmpty()) { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + _logger.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); } - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } } for (QueueEntry unacked : messagesToBeDelivered) @@ -504,18 +520,15 @@ public class AMQChannel if (!unacked.isQueueDeleted()) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(); // Ensure message is released for redelivery unacked.release(); - // Deliver Message - deliveryContext.requeue(unacked); - } else { - unacked.discard(_storeContext); + unacked.discard(); } } @@ -535,48 +548,27 @@ public class AMQChannel if (unacked != null) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(); // Ensure message is released for redelivery if (!unacked.isQueueDeleted()) - { - unacked.release(); - } - - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) { - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - - } - else - { - deliveryContext = _txnContext; - } + // Ensure message is released for redelivery + unacked.release(); - if (!unacked.isQueueDeleted()) - { - // Redeliver the messages to the front of the queue - deliveryContext.requeue(unacked); - // Deliver increments the message count but we have already deliverted this once so don't increment it again - // this was because deliver did an increment changed this. } else { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + _logger.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - unacked.discard(_storeContext); + unacked.discard(); } } else { - _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _logger.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); } @@ -597,28 +589,31 @@ public class AMQChannel final Map msgToRequeue = new LinkedHashMap(); final Map msgToResend = new LinkedHashMap(); - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); + _logger.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); } // Process the Unacked-Map. // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. - _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, requeue, _storeContext)); + _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, + msgToRequeue, + msgToResend, + requeue, + _messageStore)); // Process Messages to Resend - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { if (!msgToResend.isEmpty()) { - _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); + _logger.debug("Preparing (" + msgToResend.size() + ") message to resend."); } else { - _log.debug("No message to resend."); + _logger.debug("No message to resend."); } } @@ -629,7 +624,7 @@ public class AMQChannel - AMQMessage msg = message.getMessage(); + ServerMessage msg = message.getMessage(); AMQQueue queue = message.getQueue(); // Our Java Client will always suspend the channel when resending! @@ -638,7 +633,7 @@ public class AMQChannel // i.e. The channel hasn't been server side suspended. // if (isSuspended()) // { - // _log.info("Channel is suspended so requeuing"); + // _logger.info("Channel is suspended so requeuing"); // //move this message to requeue // msgToRequeue.add(message); // } @@ -648,14 +643,14 @@ public class AMQChannel // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. - msg.setRedelivered(true); + message.setRedelivered(); Subscription sub = message.getDeliveredSubscription(); if (sub != null) { - - if(!queue.resend(message, sub)) + + if(!queue.resend(message,sub)) { msgToRequeue.put(deliveryTag, message); } @@ -663,9 +658,9 @@ public class AMQChannel else { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + _logger.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + ")to prevent loss"); } // move this message to requeue @@ -674,91 +669,28 @@ public class AMQChannel } // for all messages // } else !isSuspend - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { if (!msgToRequeue.isEmpty()) { - _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); + _logger.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); } } - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } - // Process Messages to Requeue at the front of the queue for (Map.Entry entry : msgToRequeue.entrySet()) { QueueEntry message = entry.getValue(); long deliveryTag = entry.getKey(); - - message.release(); - message.setRedelivered(true); + _unacknowledgedMessageMap.remove(deliveryTag); - deliveryContext.requeue(message); + message.setRedelivered(); + message.release(); - _unacknowledgedMessageMap.remove(deliveryTag); } } - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to - * remove the queue reference and also decrement any message reference counts, without actually removing the item - * since we may get an ack for a delivery tag that was generated from the deleted queue. - * - * @param queue the queue that has been deleted - * - */ - /* public void queueDeleted(final AMQQueue queue) - { - try - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) - { - if (message.getQueue() == queue) - { - try - { - message.discard(_storeContext); - message.setQueueDeleted(true); - - } - catch (AMQException e) - { - _log.error( - "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); - throw new RuntimeException(e); - } - } - - return false; - } - - public void visitComplete() - { - } - }); - } - catch (AMQException e) - { - _log.error("Unexpected Error while handling deletion of queue", e); - throw new RuntimeException(e); - } - } -*/ /** * Acknowledge one or more messages. * @@ -770,7 +702,17 @@ public class AMQChannel */ public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); + Collection ackedMessages = getAckedMessages(deliveryTag, multiple); + _transaction.dequeue(ackedMessages, new MessageAcknowledgeAction(ackedMessages)); + } + + private Collection getAckedMessages(long deliveryTag, boolean multiple) + { + + Map ackedMessageMap = new LinkedHashMap(); + _unacknowledgedMessageMap.collect(deliveryTag, multiple, ackedMessageMap); + _unacknowledgedMessageMap.remove(ackedMessageMap); + return ackedMessageMap.values(); } /** @@ -854,7 +796,7 @@ public class AMQChannel public boolean isSuspended() { - return _suspended.get(); + return _suspended.get() || _closing || _session.isClosing(); } public void commit() throws AMQException @@ -864,57 +806,87 @@ public class AMQChannel throw new AMQException("Fatal error: commit called on non-transactional channel"); } - _txnContext.commit(); + _transaction.commit(); + } public void rollback() throws AMQException { - _txnContext.rollback(); + rollback(NULL_TASK); } - public String toString() + public void rollback(Runnable postRollbackTask) throws AMQException { - return "["+_session.toString()+":"+_channelId+"]"; - } + if (!isTransactional()) + { + throw new AMQException("Fatal error: commit called on non-transactional channel"); + } - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } + // stop all subscriptions + _rollingBack = true; + boolean requiresSuspend = _suspended.compareAndSet(false,true); - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } + // ensure all subscriptions have seen the change to the channel state + for(Subscription sub : _tag2SubscriptionMap.values()) + { + sub.getSendLock(); + sub.releaseSendLock(); + } - public StoreContext getStoreContext() - { - return _storeContext; - } + try + { + _transaction.rollback(); + } + finally + { + _rollingBack = false; + } - public void processReturns() throws AMQException - { - if (!_returnMessages.isEmpty()) + postRollbackTask.run(); + + for(QueueEntry entry : _resendList) { - for (RequiredDeliveryException bouncedMessage : _returnMessages) + Subscription sub = entry.getDeliveredSubscription(); + if(sub == null || sub.isClosed()) { - AMQMessage message = bouncedMessage.getAMQMessage(); - _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); + entry.release(); + } + else + { + sub.getQueue().resend(entry, sub); + } + } + _resendList.clear(); - message.decrementReference(_storeContext); + if(requiresSuspend) + { + _suspended.set(false); + for(Subscription sub : _tag2SubscriptionMap.values()) + { + sub.getQueue().deliverAsync(sub); } - _returnMessages.clear(); } + + } + public String toString() + { + return "["+_session.toString()+":"+_channelId+"]"; + } - public TransactionalContext getTransactionalContext() + public void setDefaultQueue(AMQQueue queue) { - return _txnContext; + _defaultQueue = queue; } + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public boolean isClosing() { return _closing; @@ -936,11 +908,6 @@ public class AMQChannel _creditManager.setCreditLimits(prefetchSize, prefetchCount); } - public List getReturnMessages() - { - return _returnMessages; - } - public MessageStore getMessageStore() { return _messageStore; @@ -952,8 +919,10 @@ public class AMQChannel public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException { - getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag()); + getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), + deliveryTag, sub.getConsumerTag()); } + }; public ClientDeliveryMethod getClientDeliveryMethod() @@ -975,6 +944,213 @@ public class AMQChannel return _recordDeliveryMethod; } + + private AMQMessage createAMQMessage(IncomingMessage incomingMessage) + throws AMQException + { + + AMQMessage message = new AMQMessage(incomingMessage.getStoredMessage()); + + message.setExpiration(incomingMessage.getExpiration()); + message.setClientIdentifier(_session); + return message; + } + + private boolean checkMessageUserId(ContentHeaderBody header) + { + AMQShortString userID = + header.properties instanceof BasicContentHeaderProperties + ? ((BasicContentHeaderProperties) header.properties).getUserId() + : null; + + return (!MSG_AUTH || _session.getPrincipal().getName().equals(userID == null? "" : userID.toString())); + + } + + private class MessageDeliveryAction implements ServerTransaction.Action + { + private IncomingMessage _incommingMessage; + private ArrayList _destinationQueues; + + public MessageDeliveryAction(IncomingMessage currentMessage, + ArrayList destinationQueues) + { + _incommingMessage = currentMessage; + _destinationQueues = destinationQueues; + } + + public void postCommit() + { + try + { + final boolean immediate = _incommingMessage.isImmediate(); + + final AMQMessage amqMessage = createAMQMessage(_incommingMessage); + MessageReference ref = amqMessage.newReference(); + + for(AMQQueue queue : _destinationQueues) + { + + QueueEntry entry = queue.enqueue(amqMessage); + queue.checkCapacity(AMQChannel.this); + + + if(immediate && !entry.getDeliveredToConsumer() && entry.acquire()) + { + + + ServerTransaction txn = new LocalTransaction(_messageStore); + Collection entries = new ArrayList(1); + entries.add(entry); + final AMQMessage message = (AMQMessage) entry.getMessage(); + txn.dequeue(queue, entry.getMessage(), + new MessageAcknowledgeAction(entries) + { + @Override + public void postCommit() + { + try + { + final + ProtocolOutputConverter outputConverter = + _session.getProtocolOutputConverter(); + + outputConverter.writeReturn(message.getMessagePublishInfo(), + message.getContentHeaderBody(), + message, + _channelId, + AMQConstant.NO_CONSUMERS.getCode(), + IMMEDIATE_DELIVERY_REPLY_TEXT); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + super.postCommit(); + } + } + ); + txn.commit(); + + + + + } + + } + ref.release(); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + + + + + } + + public void onRollback() + { + // Maybe keep track of entries that were created and then delete them here in case of failure + // to in memory enqueue + } + } + + private class MessageAcknowledgeAction implements ServerTransaction.Action + { + private final Collection _ackedMessages; + + + public MessageAcknowledgeAction(Collection ackedMessages) + { + _ackedMessages = ackedMessages; + } + + public void postCommit() + { + try + { + for(QueueEntry entry : _ackedMessages) + { + entry.discard(); + } + } + finally + { + _acknowledgedMessages.clear(); + } + + } + + public void onRollback() + { + // explicit rollbacks resend the message after the rollback-ok is sent + if(_rollingBack) + { + _resendList.addAll(_ackedMessages); + } + else + { + try + { + for(QueueEntry entry : _ackedMessages) + { + entry.release(); + } + } + finally + { + _acknowledgedMessages.clear(); + } + } + + } + } + + private class WriteReturnAction implements ServerTransaction.Action + { + private final AMQConstant _errorCode; + private final IncomingMessage _message; + private final String _description; + + public WriteReturnAction(AMQConstant errorCode, + String description, + IncomingMessage message) + { + _errorCode = errorCode; + _message = message; + _description = description; + } + + public void postCommit() + { + try + { + _session.getProtocolOutputConverter().writeReturn(_message.getMessagePublishInfo(), + _message.getContentHeader(), + _message, + _channelId, + _errorCode.getCode(), + new AMQShortString(_description)); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + + public void onRollback() + { + //To change body of implemented methods use File | Settings | File Templates. + } + } + + public LogActor getLogActor() { return _actor; @@ -993,7 +1169,7 @@ public class AMQChannel } } - public void unblock(AMQQueue queue) + public void unblock(AMQQueue queue) { if(_blockingQueues.remove(queue)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java deleted file mode 100644 index 9a98af5689..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -public class ConsumerTagNotUniqueException extends Exception -{ -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 29494c4118..9da02e0600 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -21,11 +21,11 @@ package org.apache.qpid.server; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; @@ -35,30 +35,29 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor { private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class); - private Map _msgToRequeue; - private Map _msgToResend; - private boolean _requeueIfUnabletoResend; - private StoreContext _storeContext; - private UnacknowledgedMessageMap _unacknowledgedMessageMap; + private final Map _msgToRequeue; + private final Map _msgToResend; + private final boolean _requeueIfUnabletoResend; + private final UnacknowledgedMessageMap _unacknowledgedMessageMap; + private final TransactionLog _transactionLog; - public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, + public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, Map msgToRequeue, Map msgToResend, boolean requeueIfUnabletoResend, - StoreContext storeContext) + TransactionLog txnLog) { _unacknowledgedMessageMap = unacknowledgedMessageMap; _msgToRequeue = msgToRequeue; _msgToResend = msgToResend; _requeueIfUnabletoResend = requeueIfUnabletoResend; - _storeContext = storeContext; + _transactionLog = txnLog; } public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException { - AMQMessage msg = message.getMessage(); - msg.setRedelivered(true); + message.setRedelivered(); final Subscription subscription = message.getDeliveredSubscription(); if (subscription != null) { @@ -85,13 +84,14 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor } else { - message.discard(_storeContext); + + dequeueEntry(message); _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); } } else { - message.discard(_storeContext); + dequeueEntry(message); _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } } @@ -100,6 +100,31 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor return false; } + + private void dequeueEntry(final QueueEntry node) + { + ServerTransaction txn = new AutoCommitTransaction(_transactionLog); + dequeueEntry(node, txn); + } + + private void dequeueEntry(final QueueEntry node, ServerTransaction txn) + { + txn.dequeue(node.getQueue(), node.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + node.discard(); + } + + public void onRollback() + { + + } + }); + } + public void visitComplete() { _unacknowledgedMessageMap.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index c45e794145..0a2bd6e8b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -26,6 +26,11 @@ import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Properties; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.Collection; +import java.util.Arrays; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -37,7 +42,8 @@ import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; -import org.apache.qpid.AMQException; +import org.apache.qpid.transport.network.ConnectionBinding; +import org.apache.qpid.transport.*; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -49,12 +55,16 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ServerConnection; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.ssl.SSLContextFactory; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.network.mina.MINANetworkDriver; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; /** * Main entry point for AMQPD. @@ -73,6 +83,7 @@ public class Main private static final int IPV4_ADDRESS_LENGTH = 4; private static final char IPV4_LITERAL_SEPARATOR = '.'; + private static final Collection ALL_VERSIONS = Arrays.asList(VERSION.values()); protected static class InitException extends Exception { @@ -123,6 +134,24 @@ public class Main OptionBuilder.withArgName("port").hasArg() .withDescription("listen on the specified port. Overrides any value in the config file") .withLongOpt("port").create("p"); + + Option exclude0_10 = + OptionBuilder.withArgName("exclude-0-10").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-10 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-10").create(); + + Option exclude0_9 = + OptionBuilder.withArgName("exclude-0-9").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-9 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-9").create(); + + + Option exclude0_8 = + OptionBuilder.withArgName("exclude-0-8").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-8 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-8").create(); + + Option mport = OptionBuilder.withArgName("mport").hasArg() .withDescription("listen on the specified management port. Overrides any value in the config file") @@ -149,6 +178,9 @@ public class Main options.addOption(logconfig); options.addOption(logwatchconfig); options.addOption(port); + options.addOption(exclude0_10); + options.addOption(exclude0_9); + options.addOption(exclude0_8); options.addOption(mport); options.addOption(bind); } @@ -239,7 +271,7 @@ public class Main String logConfig = commandLine.getOptionValue("l"); String logWatchConfig = commandLine.getOptionValue("w", "0"); - + int logWatchTime = 0; try { @@ -250,7 +282,7 @@ public class Main System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + "a non-negative integer. Using default of zero (no watching configured"); } - + File logConfigFile; if (logConfig != null) { @@ -276,9 +308,12 @@ public class Main BrokerMessages.reload(); // AR.initialise() sets its own actor so we now need to set the actor - // for the remainder of the startup + // for the remainder of the startup CurrentActor.set(new BrokerActor(config.getRootMessageLogger())); - try{ + CurrentActor.setDefault(new BrokerActor(config.getRootMessageLogger())); + + try + { configureLoggingManagementMBean(logConfigFile, logWatchTime); ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); @@ -294,20 +329,35 @@ public class Main _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - int port = serverConfig.getPort(); - String portStr = commandLine.getOptionValue("p"); - if (portStr != null) + + String[] portStr = commandLine.getOptionValues("p"); + + Set ports = new HashSet(); + Set exclude_0_10 = new HashSet(); + Set exclude_0_9 = new HashSet(); + Set exclude_0_8 = new HashSet(); + + if(portStr == null || portStr.length == 0) { - try - { - port = Integer.parseInt(portStr); - } - catch (NumberFormatException e) - { - throw new InitException("Invalid port: " + portStr, e); - } + + parsePortList(ports, serverConfig.getPorts()); + parsePortList(exclude_0_10, serverConfig.getPortExclude010()); + parsePortList(exclude_0_9, serverConfig.getPortExclude09()); + parsePortList(exclude_0_8, serverConfig.getPortExclude08()); + } + else + { + parsePortArray(ports, portStr); + parsePortArray(exclude_0_10, commandLine.getOptionValues("exclude-0-10")); + parsePortArray(exclude_0_9, commandLine.getOptionValues("exclude-0-9")); + parsePortArray(exclude_0_8, commandLine.getOptionValues("exclude-0-8")); + + } + + + String bindAddr = commandLine.getOptionValue("b"); if (bindAddr == null) @@ -315,42 +365,75 @@ public class Main bindAddr = serverConfig.getBind(); } InetAddress bindAddress = null; + + + if (bindAddr.equals("wildcard")) { - bindAddress = new InetSocketAddress(port).getAddress(); + bindAddress = new InetSocketAddress(0).getAddress(); } else { bindAddress = InetAddress.getByAddress(parseIP(bindAddr)); } + String hostName = bindAddress.getCanonicalHostName(); + + String keystorePath = serverConfig.getKeystorePath(); String keystorePassword = serverConfig.getKeystorePassword(); String certType = serverConfig.getCertType(); SSLContextFactory sslFactory = null; - boolean isSsl = false; - + if (!serverConfig.getSSLOnly()) { - NetworkDriver driver = new MINANetworkDriver(); - driver.bind(port, new InetAddress[]{bindAddress}, new AMQProtocolEngineFactory(), - serverConfig.getNetworkConfiguration(), null); - ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), - new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + + for(int port : ports) + { + + NetworkDriver driver = new MINANetworkDriver(); + + Set supported = new HashSet(ALL_VERSIONS); + + if(exclude_0_10.contains(port)) + { + supported.remove(VERSION.v0_10); + } + if(exclude_0_9.contains(port)) + { + supported.remove(VERSION.v0_9); + } + if(exclude_0_8.contains(port)) + { + supported.remove(VERSION.v0_8); + } + + MultiVersionProtocolEngineFactory protocolEngineFactory = + new MultiVersionProtocolEngineFactory(hostName, supported); + + + + driver.bind(port, new InetAddress[]{bindAddress}, protocolEngineFactory, + serverConfig.getNetworkConfiguration(), null); + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + new QpidAcceptor(driver,"TCP")); + CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + + } + } - + if (serverConfig.getEnableSSL()) { sslFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); NetworkDriver driver = new MINANetworkDriver(); - driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress}, + driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress}, new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory); - ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, serverConfig.getSSLPort()), new QpidAcceptor(driver,"TCP")); CurrentActor.get().message(BrokerMessages.BRK_1002("TCP/SSL", serverConfig.getSSLPort())); } - + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); @@ -363,6 +446,47 @@ public class Main // Startup is complete so remove the AR initialised Startup actor CurrentActor.remove(); } + + + + } + + private void parsePortArray(Set ports, String[] portStr) + throws InitException + { + if(portStr != null) + { + for(int i = 0; i < portStr.length; i++) + { + try + { + ports.add(Integer.parseInt(portStr[i])); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + portStr[i], e); + } + } + } + } + + private void parsePortList(Set output, List input) + throws InitException + { + if(input != null) + { + for(Object port : input) + { + try + { + output.add(Integer.parseInt(String.valueOf(port))); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + port, e); + } + } + } } /** @@ -394,11 +518,11 @@ public class Main { System.setProperty("log4j.defaultInitOverride", "true"); } - + //now that the override status is know, we can instantiate the Loggers _logger = Logger.getLogger(Main.class); _brokerLogger = Logger.getLogger("Qpid.Broker"); - + new Main(args); } @@ -434,7 +558,7 @@ public class Main { if (logConfigFile.exists() && logConfigFile.canRead()) { - CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { @@ -466,7 +590,7 @@ public class Main { System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); System.err.println("Using the fallback internal log4j.properties configuration"); - + InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties"); if(propsFile == null) { @@ -484,14 +608,7 @@ public class Main private void configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception { LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); - - try - { - blm.register(); - } - catch (AMQException e) - { - throw new InitException("Unable to initialise the Logging Management MBean: ", e); - } + + blm.register(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java deleted file mode 100644 index 3f1947d65a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the - * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. - * - *

      The failed message is associated with this error condition, by taking a reference to it. This enables the - * correct compensating action to be taken against the message, for example, bouncing it back to the sender. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      Associate the failed message with the error condition. {@link AMQMessage} - *
      - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private AMQMessage _amqMessage; - - public RequiredDeliveryException(String message, AMQMessage payload) - { - super(message); - - setMessage(payload); - } - - - public RequiredDeliveryException(String message) - { - super(message); - } - - public void setMessage(final AMQMessage payload) - { - - // Increment the reference as this message is in the routing phase - // and so will have the ref decremented as routing fails. - // we need to keep this message around so we can return it in the - // handler. So increment here. - _amqMessage = payload.takeReference(); - - } - - public AMQMessage getAMQMessage() - { - return _amqMessage; - } - - public AMQConstant getErrorCode() - { - return getReplyCode(); - } - - public abstract AMQConstant getReplyCode(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java deleted file mode 100644 index db3a05eb52..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TxnOp; -import org.apache.qpid.server.queue.QueueEntry; - -/** - * A TxnOp implementation for handling accumulated acks - */ -public class TxAck implements TxnOp -{ - private final UnacknowledgedMessageMap _map; - private final Map _unacked = new HashMap(); - private List _individual; - private long _deliveryTag; - private boolean _multiple; - - public TxAck(UnacknowledgedMessageMap map) - { - _map = map; - } - - public void update(long deliveryTag, boolean multiple) - { - _unacked.clear(); - if (!multiple) - { - if(_individual == null) - { - _individual = new ArrayList(); - } - //have acked a single message that is not part of - //the previously acked region so record - //individually - _individual.add(deliveryTag);//_multiple && !multiple - } - else if (deliveryTag > _deliveryTag) - { - //have simply moved the last acked message on a - //bit - _deliveryTag = deliveryTag; - _multiple = true; - } - } - - public void consolidate() - { - if(_unacked.isEmpty()) - { - //lookup all the unacked messages that have been acked in this transaction - if (_multiple) - { - //get all the unacked messages for the accumulated - //multiple acks - _map.collect(_deliveryTag, true, _unacked); - } - if(_individual != null) - { - //get any unacked messages for individual acks outside the - //range covered by multiple acks - for (long tag : _individual) - { - if(_deliveryTag < tag) - { - _map.collect(tag, false, _unacked); - } - } - } - } - } - - public boolean checkPersistent() throws AMQException - { - consolidate(); - //if any of the messages in unacked are persistent the txn - //buffer must be marked as persistent: - for (QueueEntry msg : _unacked.values()) - { - if (msg.getMessage().isPersistent()) - { - return true; - } - } - return false; - } - - public void prepare(StoreContext storeContext) throws AMQException - { - //make persistent changes, i.e. dequeue and decrementReference - for (QueueEntry msg : _unacked.values()) - { - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(storeContext); - - } - } - - public void undoPrepare() - { - //decrementReference is annoyingly untransactional (due to - //in memory counter) so if we failed in prepare for full - //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for (QueueEntry msg : _unacked.values()) - { - msg.getMessage().takeReference(); - } - } - - public void commit(StoreContext storeContext) - { - //remove the unacked messages from the channels map - _map.remove(_unacked); - } - - public void rollback(StoreContext storeContext) - { - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index c80a96f967..3bad73d86d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -21,14 +21,12 @@ package org.apache.qpid.server.ack; import java.util.Collection; -import java.util.List; import java.util.Set; import java.util.Map; import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; + public interface UnacknowledgedMessageMap { @@ -50,18 +48,12 @@ public interface UnacknowledgedMessageMap void collect(long deliveryTag, boolean multiple, Map msgs); - boolean contains(long deliveryTag) throws AMQException; - void remove(Map msgs); QueueEntry remove(long deliveryTag); - public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException; - Collection cancelAllMessages(); - void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; - int size(); void clear(); @@ -75,7 +67,6 @@ public interface UnacknowledgedMessageMap */ Set getDeliveryTags(); - public long getUnacknowledgeBytes(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index c567387662..d920d97c1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -20,20 +20,13 @@ */ package org.apache.qpid.server.ack; -import org.apache.qpid.server.store.StoreContext; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.txn.TransactionalContext; public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { @@ -61,19 +54,15 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } else { - msgs.put(deliveryTag, get(deliveryTag)); + final QueueEntry entry = get(deliveryTag); + if(entry != null) + { + msgs.put(deliveryTag, entry); + } } } - public boolean contains(long deliveryTag) throws AMQException - { - synchronized (_lock) - { - return _map.containsKey(deliveryTag); - } - } - public void remove(Map msgs) { synchronized (_lock) @@ -135,15 +124,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) - throws AMQException - { - synchronized (_lock) - { - txnContext.acknowledgeMessage(deliveryTag, _lastDeliveryTag, multiple, this); - } - } - public int size() { synchronized (_lock) @@ -161,39 +141,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException - - { - synchronized (_lock) - { - Iterator> 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()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - unacked.getValue().discard(storeContext); - - it.remove(); - - _unackedSize -= unacked.getValue().getMessage().getSize(); - - - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - } - public QueueEntry get(long key) { synchronized (_lock) @@ -225,8 +172,4 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public long getUnacknowledgeBytes() - { - return _unackedSize; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 641b44bb18..7bf28c7560 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -14,8 +14,8 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. - * + * under the License. + * */ package org.apache.qpid.server.configuration; @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Locale; +import java.util.Collections; import java.util.Map.Entry; import org.apache.commons.configuration.CompositeConfiguration; @@ -124,7 +125,7 @@ public class ServerConfiguration implements SignalHandler } catch (IllegalArgumentException e) { - // We're on something that doesn't handle SIGHUP, how sad, Windows. + // We're on something that doesn't handle SIGHUP, how sad, Windows. } } @@ -221,7 +222,7 @@ public class ServerConfiguration implements SignalHandler String localeString = getConfig().getString(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant - // If the configuration does not have a defined locale use the JVM default + // If the configuration does not have a defined locale use the JVM default if (localeString == null) { return Locale.getDefault(); @@ -524,11 +525,27 @@ public class ServerConfiguration implements SignalHandler return getConfig().getInt("connector.processors", 4); } - public int getPort() + public List getPorts() + { + return getConfig().getList("connector.port", Collections.singletonList(DEFAULT_PORT)); + } + + public List getPortExclude010() + { + return getConfig().getList("connector.non010port", Collections.EMPTY_LIST); + } + + public List getPortExclude09() + { + return getConfig().getList("connector.non09port", Collections.EMPTY_LIST); + } + + public List getPortExclude08() { - return getConfig().getInt("connector.port", DEFAULT_PORT); + return getConfig().getList("connector.non08port", Collections.EMPTY_LIST); } + public String getBind() { return getConfig().getString("connector.bind", "wildcard"); @@ -625,48 +642,48 @@ public class ServerConfiguration implements SignalHandler { return new NetworkDriverConfiguration() { - + public Integer getTrafficClass() { return null; } - + public Boolean getTcpNoDelay() { // Can't call parent getTcpNoDelay since it just calls this one return getConfig().getBoolean("connector.tcpNoDelay", true); } - + public Integer getSoTimeout() { return null; } - + public Integer getSoLinger() { return null; } - + public Integer getSendBufferSize() { return getBufferWriteLimit(); } - + public Boolean getReuseAddress() { return null; } - + public Integer getReceiveBufferSize() { return getBufferReadLimit(); } - + public Boolean getOOBInline() { return null; } - + public Boolean getKeepAlive() { return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index bb70ce556b..7983c62443 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; +import javax.management.JMException; import javax.management.openmbean.OpenType; import javax.management.openmbean.CompositeType; import javax.management.openmbean.TabularType; @@ -39,18 +40,23 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ExchangeMessages; import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; import org.apache.qpid.server.logging.LogSubject; +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; - + private Exchange _alternateExchange; protected boolean _durable; protected String _exchangeType; @@ -67,6 +73,7 @@ public abstract class AbstractExchange implements Exchange, Managable //The logSubject for ths exchange private LogSubject _logSubject; + private Map _referrers = new ConcurrentHashMap(); /** * Abstract MBean class. This has some of the methods implemented from @@ -80,14 +87,14 @@ public abstract class AbstractExchange implements Exchange, Managable protected CompositeType _bindingDataType; protected TabularType _bindinglistDataType; protected TabularDataSupport _bindingList; - + public ExchangeMBean() throws NotCompliantMBeanException { super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); } protected void init() throws OpenDataException - { + { _bindingItemTypes = new OpenType[2]; _bindingItemTypes[0] = SimpleType.STRING; _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); @@ -156,23 +163,33 @@ public abstract class AbstractExchange implements Exchange, Managable * called during initialisation (template method pattern). * @return the MBean */ - protected abstract ExchangeMBean createMBean() throws AMQException; + protected abstract ExchangeMBean createMBean() throws JMException; - public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException { _virtualHost = host; _name = name; _durable = durable; _autoDelete = autoDelete; _ticket = ticket; - _exchangeMbean = createMBean(); - _exchangeMbean.register(); + try + { + _exchangeMbean = createMBean(); + _exchangeMbean.register(); + } + catch (JMException e) + { + getLogger().error(e); + } _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation CurrentActor.get().message(ExchangeMessages.EXH_1001(String.valueOf(getType()), String.valueOf(name), durable)); } + public abstract Logger getLogger(); + public boolean isDurable() { return _durable; @@ -194,9 +211,13 @@ public abstract class AbstractExchange implements Exchange, Managable { _exchangeMbean.unregister(); } + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_1002()); - } + } public String toString() { @@ -217,4 +238,54 @@ public abstract class AbstractExchange implements Exchange, Managable { return getVirtualHost().getQueueRegistry(); } + + public boolean isBound(String bindingKey, Map arguments, AMQQueue queue) + { + return isBound(new AMQShortString(bindingKey), queue); + } + + + public boolean isBound(String bindingKey, AMQQueue queue) + { + return isBound(new AMQShortString(bindingKey), queue); + } + + public boolean isBound(String bindingKey) + { + return isBound(new AMQShortString(bindingKey)); + } + + public Exchange getAlternateExchange() + { + return _alternateExchange; + } + + public void setAlternateExchange(Exchange exchange) + { + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + if(exchange != null) + { + exchange.addReference(this); + } + _alternateExchange = exchange; + + } + + public void removeReference(ExchangeReferrer exchange) + { + _referrers.remove(exchange); + } + + public void addReference(ExchangeReferrer exchange) + { + _referrers.put(exchange, Boolean.TRUE); + } + + public boolean hasReferrers() + { + return !_referrers.isEmpty(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 620799a81f..6b0cf89b95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -59,6 +59,20 @@ public class DefaultExchangeFactory implements ExchangeFactory return _exchangeClassMap.values(); } + public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) + throws AMQException + { + ExchangeType exchType = _exchangeClassMap.get(new AMQShortString(type)); + if (exchType == null) + { + + throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); + } + Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete); + return e; + + } + public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException @@ -92,7 +106,7 @@ public class DefaultExchangeFactory implements ExchangeFactory return; } Class exchangeTypeClass = exchangeType.getClass(); - ExchangeType type = exchangeTypeClass.newInstance(); + ExchangeType type = exchangeTypeClass.newInstance(); registerExchangeType(type); } catch (ClassCastException classCastEx) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 0ab8208d88..2a8a87be7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,10 +23,9 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.exchange.ExchangeInitialiser; import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Collection; @@ -41,6 +40,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry * Maps from exchange name to exchange instance */ private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); + private ConcurrentMap _exchangeMapStr = new ConcurrentHashMap(); private Exchange _defaultExchange; private VirtualHost _host; @@ -57,17 +57,20 @@ public class DefaultExchangeRegistry implements ExchangeRegistry new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); } - public MessageStore getMessageStore() + + + public DurableConfigurationStore getDurableConfigurationStore() { - return _host.getMessageStore(); + return _host.getDurableConfigurationStore(); } public void registerExchange(Exchange exchange) throws AMQException { _exchangeMap.put(exchange.getName(), exchange); + _exchangeMapStr.put(exchange.getName().toString(), exchange); if (exchange.isDurable()) { - getMessageStore().createExchange(exchange); + getDurableConfigurationStore().createExchange(exchange); } } @@ -90,11 +93,12 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); + _exchangeMapStr.remove(name.toString()); if (e != null) { if (e.isDurable()) { - getMessageStore().removeExchange(e); + getDurableConfigurationStore().removeExchange(e); } e.close(); } @@ -104,6 +108,11 @@ public class DefaultExchangeRegistry implements ExchangeRegistry } } + public void unregisterExchange(String name, boolean inUse) throws AMQException + { + unregisterExchange(new AMQShortString(name), inUse); + } + public Exchange getExchange(AMQShortString name) { if ((name == null) || name.length() == 0) @@ -117,6 +126,19 @@ public class DefaultExchangeRegistry implements ExchangeRegistry } + public Exchange getExchange(String name) + { + if ((name == null) || name.length() == 0) + { + return getDefaultExchange(); + } + else + { + return _exchangeMapStr.get(name); + } + } + + /** * Routes content through exchanges, delivering it to 1 or more queues. * @param payload @@ -134,6 +156,6 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { throw new AMQException("Exchange '" + exchange + "' does not exist"); } - exch.route(payload); + payload.enqueue(exch.route(payload)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 3567cdff85..4788f96d6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -40,9 +40,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -149,17 +149,14 @@ public class DirectExchange extends AbstractExchange }// End of MBean class - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new DirectExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } + return new DirectExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } public AMQShortString getType() @@ -167,7 +164,17 @@ public class DirectExchange extends AbstractExchange return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; } + public void registerQueue(String routingKey, AMQQueue queue, Map args) throws AMQException + { + registerQueue(new AMQShortString(routingKey), queue); + } + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + registerQueue(routingKey, queue); + } + + private void registerQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException { assert queue != null; assert routingKey != null; @@ -199,10 +206,11 @@ public class DirectExchange extends AbstractExchange } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList route(InboundMessage payload) { - final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); + final String routingKey = payload.getRoutingKey(); + final ArrayList queues = (routingKey == null) ? null : _index.get(routingKey); @@ -211,7 +219,8 @@ public class DirectExchange extends AbstractExchange _logger.debug("Publishing message to queue " + queues); } - payload.enqueue(queues); + return queues; + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 06209c5458..4bbdeaef1c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -24,20 +24,21 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; -import java.util.List; -import java.util.Map; +import javax.management.JMException; +import java.util.ArrayList; -public interface Exchange +public interface Exchange extends ExchangeReferrer { AMQShortString getName(); AMQShortString getType(); - void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException, JMException; boolean isDurable(); @@ -52,9 +53,11 @@ public interface Exchange void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - void route(IncomingMessage message) throws AMQException; + ArrayList route(InboundMessage message); /** @@ -93,6 +96,18 @@ public interface Exchange */ boolean hasBindings(); - + boolean isBound(String bindingKey, AMQQueue queue); + + boolean isBound(String bindingKey); + + Exchange getAlternateExchange(); + + void setAlternateExchange(Exchange exchange); + + void removeReference(ExchangeReferrer exchange); + + void addReference(ExchangeReferrer exchange); + + boolean hasReferrers(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index 2f76d41228..b91bf559f1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -38,4 +38,6 @@ public interface ExchangeFactory void initialise(VirtualHostConfiguration hostConfig); Collection> getRegisteredTypes(); + + Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java new file mode 100644 index 0000000000..59fe94ddc0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; + +public class ExchangeInitialiser +{ + public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ + for (ExchangeType type : factory.getRegisteredTypes()) + { + define (registry, factory, type.getDefaultExchangeName(), type.getName()); + } + + define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); + } + + private void define(ExchangeRegistry r, ExchangeFactory f, + AMQShortString name, AMQShortString type) throws AMQException + { + if(r.getExchange(name)== null) + { + r.registerExchange(f.createExchange(name, type, true, false, 0)); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java new file mode 100755 index 0000000000..e41d63d97d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.exchange; + +public interface ExchangeReferrer +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index fe3b19e74e..e34ef29d9b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -48,4 +48,8 @@ public interface ExchangeRegistry extends MessageRouter Collection getExchangeNames(); void initialise() throws AMQException; + + Exchange getExchange(String exchangeName); + + void unregisterExchange(String exchange, boolean ifUnused) throws ExchangeInUseException, AMQException;; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 7fa438587c..00f8ebd856 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -28,9 +28,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -62,7 +62,7 @@ public class FanoutExchange extends AbstractExchange private final class FanoutExchangeMBean extends ExchangeMBean { private static final String BINDING_KEY_SUBSTITUTE = "*"; - + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") public FanoutExchangeMBean() throws JMException { @@ -75,7 +75,7 @@ public class FanoutExchange extends AbstractExchange { _bindingList = new TabularDataSupport(_bindinglistDataType); - + if(_queues.isEmpty()) { return _bindingList; @@ -88,7 +88,7 @@ public class FanoutExchange extends AbstractExchange String queueName = queue.getName().toString(); queueNames.add(queueName); } - + Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingData); @@ -121,17 +121,14 @@ public class FanoutExchange extends AbstractExchange } // End of MBean class - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new FanoutExchange.FanoutExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } + return new FanoutExchange.FanoutExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } public static final ExchangeType TYPE = new ExchangeType() @@ -199,16 +196,16 @@ public class FanoutExchange extends AbstractExchange } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList route(InboundMessage payload) { - + if (_logger.isDebugEnabled()) { _logger.debug("Publishing message to queue " + _queues); } - payload.enqueue(new ArrayList(_queues)); + return new ArrayList(_queues); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index 2b7df4361a..35c4a8f9b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.message.AMQMessageHeader; /** * Defines binding and matching based on a set of headers. @@ -87,7 +88,7 @@ class HeadersBinding * Creates a binding for a set of mappings. Those mappings whose value is * null or the empty string are assumed only to be required headers, with * no constraint on the value. Those with a non-null value are assumed to - * define a required match of value. + * define a required match of value. * @param mappings the defined mappings this binding should use */ @@ -139,7 +140,7 @@ class HeadersBinding * @return true if the headers define any required keys and match any required * values */ - public boolean matches(FieldTable headers) + public boolean matches(AMQMessageHeader headers) { if(headers == null) { @@ -151,13 +152,13 @@ class HeadersBinding } } - private boolean and(FieldTable headers) + private boolean and(AMQMessageHeader headers) { - if(headers.keys().containsAll(required)) + if(headers.containsHeaders(required)) { for(Map.Entry e : matches.entrySet()) { - if(!e.getValue().equals(headers.getObject(e.getKey()))) + if(!e.getValue().equals(headers.getHeader(e.getKey()))) { return false; } @@ -171,17 +172,50 @@ class HeadersBinding } - private boolean or(final FieldTable headers) + private boolean or(final AMQMessageHeader headers) { - if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) + if(required.isEmpty()) { - return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) - || (required.isEmpty() && matches.isEmpty()); + return matches.isEmpty() || passesMatchesOr(headers); } else { - return true; + if(!passesRequiredOr(headers)) + { + return !matches.isEmpty() && passesMatchesOr(headers); + } + else + { + return true; + } + + } + } + + private boolean passesMatchesOr(AMQMessageHeader headers) + { + for(Map.Entry entry : matches.entrySet()) + { + if(headers.containsHeader(entry.getKey()) + && ((entry.getValue() == null && headers.getHeader(entry.getKey()) == null) + || (entry.getValue().equals(headers.getHeader(entry.getKey()))))) + { + return true; + } + } + return false; + } + + private boolean passesRequiredOr(AMQMessageHeader headers) + { + for(String name : required) + { + if(headers.containsHeader(name)) + { + return true; + } } + return false; } private void processSpecial(String key, Object value) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index c5f5cd05e1..5677cc4510 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -31,9 +31,10 @@ import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; import javax.management.JMException; import javax.management.openmbean.ArrayType; @@ -50,8 +51,8 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ConcurrentHashMap; /** * An exchange that binds queues based on a set of required headers and header values @@ -82,6 +83,7 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public class HeadersExchange extends AbstractExchange { + private static final Logger _logger = Logger.getLogger(HeadersExchange.class); public static final ExchangeType TYPE = new ExchangeType() @@ -101,6 +103,7 @@ public class HeadersExchange extends AbstractExchange boolean autoDelete) throws AMQException { HeadersExchange exch = new HeadersExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); return exch; } @@ -114,6 +117,7 @@ public class HeadersExchange extends AbstractExchange private final List _bindings = new CopyOnWriteArrayList(); + private Map _bindingByKey = new ConcurrentHashMap(); /** * HeadersExchangeMBean class implements the management interface for the @@ -208,7 +212,7 @@ public class HeadersExchange extends AbstractExchange { throw new JMException("Format for headers binding should be \"=,=\" "); } - + if(keyAndValue.length ==1) { //no value was given, only a key. Use an empty value @@ -221,7 +225,7 @@ public class HeadersExchange extends AbstractExchange } } - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); + _bindings.add(new Registration(new HeadersBinding(bindingMap), queue, new AMQShortString(binding))); } } // End of MBean class @@ -234,44 +238,48 @@ public class HeadersExchange extends AbstractExchange public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); - _bindings.add(new Registration(new HeadersBinding(args), queue)); + + Registration registration = new Registration(new HeadersBinding(args), queue, routingKey); + _bindings.add(registration); + } public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - if(!_bindings.remove(new Registration(new HeadersBinding(args), queue))) + + if(!_bindings.remove(new Registration(args == null ? null : new HeadersBinding(args), queue, routingKey))) { throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with headers args " + args); + + " with headers args " + args); } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList route(InboundMessage payload) { - FieldTable headers = getHeaders(payload.getContentHeaderBody()); + AMQMessageHeader header = payload.getMessageHeader(); if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); + _logger.debug("Exchange " + getName() + ": routing message with headers " + header); } boolean routed = false; ArrayList queues = new ArrayList(); for (Registration e : _bindings) { - if (e.binding.matches(headers)) + if (e.binding.matches(header)) { if (_logger.isDebugEnabled()) { _logger.debug("Exchange " + getName() + ": delivering message with headers " + - headers + " to " + e.queue.getName()); + header + " to " + e.queue.getName()); } queues.add(e.queue); routed = true; } } - payload.enqueue(queues); + return queues; } public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) @@ -314,17 +322,9 @@ public class HeadersExchange extends AbstractExchange return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); } - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new HeadersExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); - } + return new HeadersExchangeMBean(); } public Map> getBindings() @@ -332,25 +332,38 @@ public class HeadersExchange extends AbstractExchange return null; } + public Logger getLogger() + { + return _logger; + } + + private static class Registration { private final HeadersBinding binding; private final AMQQueue queue; + private final AMQShortString routingKey; - Registration(HeadersBinding binding, AMQQueue queue) + Registration(HeadersBinding binding, AMQQueue queue, AMQShortString routingKey) { this.binding = binding; this.queue = queue; + this.routingKey = routingKey; } public int hashCode() { - return queue.hashCode(); + int queueHash = queue.hashCode(); + int routingHash = routingKey == null ? 0 : routingKey.hashCode(); + return queueHash + routingHash; } public boolean equals(Object o) { - return o instanceof Registration && ((Registration) o).queue.equals(queue); + return o instanceof Registration + && ((Registration) o).queue.equals(queue) + && (routingKey == null ? ((Registration)o).routingKey == null + : routingKey.equals(((Registration)o).routingKey)); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index ec83161029..90d04c814a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -39,6 +39,9 @@ class Index { private ConcurrentMap> _index = new ConcurrentHashMap>(); + private ConcurrentMap> _stringIndex + = new ConcurrentHashMap>(); + synchronized boolean add(AMQShortString key, AMQQueue queue) { @@ -51,8 +54,10 @@ class Index { queues = new ArrayList(queues); } + //next call is atomic, so there is no race to create the list _index.put(key, queues); + _stringIndex.put(key.toString(), queues); if(queues.contains(queue)) { @@ -64,6 +69,8 @@ class Index } } + + synchronized boolean remove(AMQShortString key, AMQQueue queue) { ArrayList queues = _index.get(key); @@ -76,10 +83,12 @@ class Index if (queues.size() == 0) { _index.remove(key); + _stringIndex.remove(key.toString()); } else { _index.put(key, queues); + _stringIndex.put(key.toString(), queues); } } return removed; @@ -92,6 +101,12 @@ class Index return _index.get(key); } + ArrayList get(String key) + { + return _stringIndex.get(key); + } + + Map> getBindingsMap() { return new HashMap>(_index); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java index db9beb6da7..025a8014aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.IncomingMessage; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java deleted file mode 100644 index d18ad7ab14..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.IncomingMessage; - -/** - * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message - * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report - * this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoRouteException extends RequiredDeliveryException -{ - public NoRouteException(String msg, AMQMessage amqMessage) - { - super(msg, amqMessage); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_ROUTE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 31db1148c6..d5ca5a8a81 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -30,13 +30,13 @@ import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortStringTokenizer; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.topic.TopicParser; import org.apache.qpid.server.exchange.topic.TopicMatcherResult; import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.filter.JMSSelectorFilter; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -111,7 +111,7 @@ public class TopicExchange extends AbstractExchange private final Map _bindings = new HashMap(); - private final Map>> _selectorCache = new WeakHashMap>>(); + private final Map> _selectorCache = new WeakHashMap>(); public static class Binding { @@ -162,7 +162,7 @@ public class TopicExchange extends AbstractExchange private final class TopicExchangeResult implements TopicMatcherResult { private final Map _unfilteredQueues = new ConcurrentHashMap(); - private final ConcurrentHashMap,Integer>> _filteredQueues = new ConcurrentHashMap, Integer>>(); + private final ConcurrentHashMap> _filteredQueues = new ConcurrentHashMap>(); public void addUnfilteredQueue(AMQQueue queue) { @@ -192,12 +192,12 @@ public class TopicExchange extends AbstractExchange } - public void addFilteredQueue(AMQQueue queue, MessageFilter filter) + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) { - Map,Integer> filters = _filteredQueues.get(queue); + Map filters = _filteredQueues.get(queue); if(filters == null) { - filters = new ConcurrentHashMap,Integer>(); + filters = new ConcurrentHashMap(); _filteredQueues.put(queue, filters); } Integer instances = filters.get(filter); @@ -212,9 +212,9 @@ public class TopicExchange extends AbstractExchange } - public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) { - Map,Integer> filters = _filteredQueues.get(queue); + Map filters = _filteredQueues.get(queue); if(filters != null) { Integer instances = filters.get(filter); @@ -228,7 +228,7 @@ public class TopicExchange extends AbstractExchange _filteredQueues.remove(queue); } } - else + else { filters.put(filter, instances - 1); } @@ -239,11 +239,11 @@ public class TopicExchange extends AbstractExchange } public void replaceQueueFilter(AMQQueue queue, - MessageFilter oldFilter, - MessageFilter newFilter) + MessageFilter oldFilter, + MessageFilter newFilter) { - Map,Integer> filters = _filteredQueues.get(queue); - Map,Integer> newFilters = new ConcurrentHashMap,Integer>(filters); + Map filters = _filteredQueues.get(queue); + Map newFilters = new ConcurrentHashMap(filters); Integer oldFilterInstances = filters.get(oldFilter); if(oldFilterInstances == 1) { @@ -265,7 +265,7 @@ public class TopicExchange extends AbstractExchange _filteredQueues.put(queue,newFilters); } - public Collection processMessage(IncomingMessage msg, Collection queues) + public Collection processMessage(InboundMessage msg, Collection queues) { if(queues == null) { @@ -286,11 +286,11 @@ public class TopicExchange extends AbstractExchange queues.addAll(_unfilteredQueues.keySet()); if(!_filteredQueues.isEmpty()) { - for(Map.Entry, Integer>> entry : _filteredQueues.entrySet()) + for(Map.Entry> entry : _filteredQueues.entrySet()) { if(!queues.contains(entry.getKey())) { - for(MessageFilter filter : entry.getValue().keySet()) + for(MessageFilter filter : entry.getValue().keySet()) { if(filter.matches(msg)) { @@ -443,10 +443,10 @@ public class TopicExchange extends AbstractExchange { result.addUnfilteredQueue(queue); } - _parser.addBinding(routingKey, result); + _parser.addBinding(routingKey, result); _topicExchangeResults.put(routingKey,result); } - else + else { if(argumentsContainSelector(args)) { @@ -463,18 +463,18 @@ public class TopicExchange extends AbstractExchange } - private JMSSelectorFilter createSelectorFilter(final FieldTable args) + private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQException { final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - WeakReference> selectorRef = _selectorCache.get(selectorString); + WeakReference selectorRef = _selectorCache.get(selectorString); JMSSelectorFilter selector = null; if(selectorRef == null || (selector = selectorRef.get())==null) { - selector = new JMSSelectorFilter(selectorString); - _selectorCache.put(selectorString, new WeakReference>(selector)); + selector = new JMSSelectorFilter(selectorString); + _selectorCache.put(selectorString, new WeakReference(selector)); } return selector; } @@ -490,7 +490,7 @@ public class TopicExchange extends AbstractExchange { routingKey = AMQShortString.EMPTY_STRING; } - + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); List subscriptionList = new ArrayList(); @@ -535,10 +535,12 @@ public class TopicExchange extends AbstractExchange return normalizedString; } - public void route(IncomingMessage payload) throws AMQException + public ArrayList route(InboundMessage payload) { - final AMQShortString routingKey = payload.getRoutingKey(); + final AMQShortString routingKey = payload.getRoutingKey() == null + ? AMQShortString.EMPTY_STRING + : new AMQShortString(payload.getRoutingKey()); // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues @@ -550,7 +552,7 @@ public class TopicExchange extends AbstractExchange _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); } - payload.enqueue(queues); + return queues; } @@ -572,7 +574,7 @@ public class TopicExchange extends AbstractExchange { return false; } - + } } @@ -640,20 +642,17 @@ public class TopicExchange extends AbstractExchange } - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new TopicExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); - } + return new TopicExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } - private Collection getMatchedQueues(IncomingMessage message, AMQShortString routingKey) + private Collection getMatchedQueues(InboundMessage message, AMQShortString routingKey) { Collection results = _parser.parse(routingKey); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index a964bce306..2ead9e57af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -26,7 +26,7 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class ArithmeticExpression extends BinaryExpression +public abstract class ArithmeticExpression extends BinaryExpression { protected static final int INTEGER = 1; @@ -248,7 +248,7 @@ public abstract class ArithmeticExpression extends BinaryEx } } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object lvalue = left.evaluate(message); if (lvalue == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java index 7308de80d6..024257bea9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -23,23 +23,23 @@ package org.apache.qpid.server.filter; /** * An expression which performs an operation on two expression values. */ -public abstract class BinaryExpression implements Expression +public abstract class BinaryExpression implements Expression { - protected Expression left; - protected Expression right; + protected Expression left; + protected Expression right; - public BinaryExpression(Expression left, Expression right) + public BinaryExpression(Expression left, Expression right) { this.left = left; this.right = right; } - public Expression getLeft() + public Expression getLeft() { return left; } - public Expression getRight() + public Expression getRight() { return right; } @@ -90,7 +90,7 @@ public abstract class BinaryExpression implements Expressio /** * @param expression */ - public void setRight(Expression expression) + public void setRight(Expression expression) { right = expression; } @@ -98,7 +98,7 @@ public abstract class BinaryExpression implements Expressio /** * @param expression */ - public void setLeft(Expression expression) + public void setLeft(Expression expression) { left = expression; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index 9beb9798d0..06e8664470 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -20,22 +20,19 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A BooleanExpression is an expression that always * produces a Boolean result. */ -public interface BooleanExpression extends Expression +public interface BooleanExpression extends Expression { /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws E */ - public boolean matches(Filterable message) throws E; + public boolean matches(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 921005c462..f0650cb642 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -27,22 +27,20 @@ import java.util.HashSet; import java.util.List; import java.util.regex.Pattern; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) { return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); } - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) { return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); } @@ -73,7 +71,7 @@ public abstract class ComparisonExpression extends BinaryEx REGEXP_CONTROL_CHARS.add(new Character('!')); } - static class LikeExpression extends UnaryExpression implements BooleanExpression + static class LikeExpression extends UnaryExpression implements BooleanExpression { Pattern likePattern; @@ -81,7 +79,7 @@ public abstract class ComparisonExpression extends BinaryEx /** * @param right */ - public LikeExpression(Expression right, String like, int escape) + public LikeExpression(Expression right, String like, int escape) { super(right); @@ -138,7 +136,7 @@ public abstract class ComparisonExpression extends BinaryEx /** * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) */ - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object rv = this.getRight().evaluate(message); @@ -158,7 +156,7 @@ public abstract class ComparisonExpression extends BinaryEx return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; } - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -236,7 +234,7 @@ public abstract class ComparisonExpression extends BinaryEx return doCreateEqual(left, right); } - private static BooleanExpression doCreateEqual(Expression left, Expression right) + private static BooleanExpression doCreateEqual(Expression left, Expression right) { return new EqualExpression(left, right); } @@ -388,7 +386,7 @@ public abstract class ComparisonExpression extends BinaryEx super(left, right); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Comparable lv = (Comparable) left.evaluate(message); if (lv == null) @@ -550,21 +548,21 @@ public abstract class ComparisonExpression extends BinaryEx protected abstract boolean asBoolean(int answer); - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } - private static class EqualExpression extends ComparisonExpression + private static class EqualExpression extends ComparisonExpression { - public EqualExpression(final Expression left, final Expression right) + public EqualExpression(final Expression left, final Expression right) { super(left, right); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object lv = left.evaluate(message); Object rv = right.evaluate(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 3ed2286f2e..15cb770216 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -25,24 +25,22 @@ package org.apache.qpid.server.filter; import java.math.BigDecimal; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * Represents a constant expression */ -public class ConstantExpression implements Expression +public class ConstantExpression implements Expression { - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression { public BooleanConstantExpression(Object value) { super(value); } - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -121,7 +119,7 @@ public class ConstantExpression implements Expression this.value = value; } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { return value; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index f2ebe41d26..97e9915271 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -20,19 +20,17 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * Represents an expression */ -public interface Expression +public interface Expression { /** * @return the value of this expression */ - public Object evaluate(Filterable message) throws E; + public Object evaluate(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java index dd3c126ee5..b5e282038b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -14,26 +14,24 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.filter; // // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; -import org.apache.qpid.AMQException; -public interface FilterManager +public interface FilterManager { - void add(MessageFilter filter); + void add(MessageFilter filter); - void remove(MessageFilter filter); + void remove(MessageFilter filter); - boolean allAllow(Filterable msg); + boolean allAllow(Filterable msg); boolean hasFilters(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 4adf5eb9ee..dacd047fea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -26,12 +26,12 @@ import org.apache.qpid.server.filter.jms.selector.SelectorParser; import org.apache.qpid.server.queue.Filterable; -public class JMSSelectorFilter implements MessageFilter +public class JMSSelectorFilter implements MessageFilter { private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); private String _selector; - private BooleanExpression _matcher; + private BooleanExpression _matcher; public JMSSelectorFilter(String selector) throws AMQException { @@ -39,7 +39,7 @@ public class JMSSelectorFilter implements MessageFilter _matcher = new SelectorParser().parse(selector); } - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { boolean match = _matcher.matches(message); if(_logger.isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index 094363ed9a..fdba184da4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -20,22 +20,20 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { return new OrExpression(lvalue, rvalue); } - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { return new AndExpression(lvalue, rvalue); } @@ -49,23 +47,23 @@ public abstract class LogicExpression extends BinaryExpress super(left, right); } - public abstract Object evaluate(Filterable message) throws E; + public abstract Object evaluate(Filterable message); - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } - private static class OrExpression extends LogicExpression + private static class OrExpression extends LogicExpression { - public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) { super(lvalue, rvalue); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Boolean lv = (Boolean) left.evaluate(message); @@ -86,14 +84,14 @@ public abstract class LogicExpression extends BinaryExpress } } - private static class AndExpression extends LogicExpression + private static class AndExpression extends LogicExpression { - public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) + public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) { super(lvalue, rvalue); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Boolean lv = (Boolean) left.evaluate(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index 58fc55f8e6..f5416af09a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -14,17 +14,15 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.filter; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; -public interface MessageFilter +public interface MessageFilter { - boolean matches(Filterable message) throws E; + boolean matches(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 946274f936..11fdeae2b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -27,7 +27,6 @@ import java.util.HashMap; import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.server.queue.Filterable; @@ -35,7 +34,7 @@ import org.apache.qpid.server.queue.Filterable; /** * Represents a property expression */ -public class PropertyExpression implements Expression +public class PropertyExpression implements Expression { // Constants - defined the same as JMS private static final int NON_PERSISTENT = 1; @@ -44,12 +43,12 @@ public class PropertyExpression implements Expression private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - private static final HashMap> JMS_PROPERTY_EXPRESSIONS = new HashMap>(); + private static final HashMap JMS_PROPERTY_EXPRESSIONS = new HashMap(); { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() { - public Object evaluate(Filterable message) + public Object evaluate(Filterable message) { //TODO return null; @@ -73,9 +72,9 @@ public class PropertyExpression implements Expression JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { return message.isRedelivered(); } @@ -83,7 +82,7 @@ public class PropertyExpression implements Expression } private final String name; - private final Expression jmsPropertyExpression; + private final Expression jmsPropertyExpression; public boolean outerTest() { @@ -96,10 +95,10 @@ public class PropertyExpression implements Expression - jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); + jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { if (jmsPropertyExpression != null) @@ -108,17 +107,7 @@ public class PropertyExpression implements Expression } else { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking up property:" + name); - _logger.debug("Properties are:" + _properties.getHeaders().keySet()); - } - - return _properties.getHeaders().getObject(name); + return message.getMessageHeader().getHeader(name); } } @@ -158,39 +147,30 @@ public class PropertyExpression implements Expression } - private static class ReplyToExpression implements Expression + private static class ReplyToExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - - return (replyTo == null) ? null : replyTo.toString(); - + String replyTo = message.getMessageHeader().getReplyTo(); + return replyTo; } } - private static class TypeExpression implements Expression + private static class TypeExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - return (type == null) ? null : type.toString(); + String type = message.getMessageHeader().getType(); + return type; } } - private static class DeliveryModeExpression implements Expression + private static class DeliveryModeExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; if (_logger.isDebugEnabled()) @@ -202,68 +182,53 @@ public class PropertyExpression implements Expression } } - private static class PriorityExpression implements Expression + private static class PriorityExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return (int) _properties.getPriority(); + byte priority = message.getMessageHeader().getPriority(); + return (int) priority; } } - private static class MessageIDExpression implements Expression + private static class MessageIDExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); + String messageId = message.getMessageHeader().getMessageId(); - return (messageId == null) ? null : messageId; + return messageId; } } - private static class TimestampExpression implements Expression + private static class TimestampExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getTimestamp(); + long timestamp = message.getMessageHeader().getTimestamp(); + return timestamp; } } - private static class CorrelationIdExpression implements Expression + private static class CorrelationIdExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - return (correlationId == null) ? null : correlationId.toString(); + String correlationId = message.getMessageHeader().getCorrelationId(); + + return correlationId; } } - private static class ExpirationExpression implements Expression + private static class ExpirationExpression implements Expression { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getExpiration(); + long expiration = message.getMessageHeader().getExpiration(); + return expiration; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index b037f57787..c563569cb4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -26,46 +26,37 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.Filterable; -public class SimpleFilterManager implements FilterManager +public class SimpleFilterManager implements FilterManager { private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - private final ConcurrentLinkedQueue> _filters; + private final ConcurrentLinkedQueue _filters; private String _toString = ""; public SimpleFilterManager() { _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue>(); + _filters = new ConcurrentLinkedQueue(); } - public void add(MessageFilter filter) + public void add(MessageFilter filter) { _filters.add(filter); updateStringValue(); } - public void remove(MessageFilter filter) + public void remove(MessageFilter filter) { _filters.remove(filter); updateStringValue(); } - public boolean allAllow(Filterable msg) + public boolean allAllow(Filterable msg) { - for (MessageFilter filter : _filters) + for (MessageFilter filter : _filters) { - try + if (!filter.matches(msg)) { - if (!filter.matches(msg)) - { - return false; - } - } - catch (AMQException e) - { - //fixme - e.printStackTrace(); return false; } } @@ -87,7 +78,7 @@ public class SimpleFilterManager implements FilterManager private void updateStringValue() { StringBuilder toString = new StringBuilder(); - for (MessageFilter filter : _filters) + for (MessageFilter filter : _filters) { toString.append(filter.toString()); toString.append(","); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 799a38af5a..9e03ecd8bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -35,18 +35,18 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class UnaryExpression implements Expression +public abstract class UnaryExpression implements Expression { private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression right; + protected Expression right; - public static Expression createNegate(Expression left) + public static Expression createNegate(Expression left) { return new NegativeExpression(left); } - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { // Use a HashSet if there are many elements. @@ -69,14 +69,14 @@ public abstract class UnaryExpression implements Expression return new InExpression(right, inList, not); } - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { - public BooleanUnaryExpression(Expression left) + public BooleanUnaryExpression(Expression left) { super(left); } - public boolean matches(Filterable message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -85,7 +85,7 @@ public abstract class UnaryExpression implements Expression } ; - public static BooleanExpression createNOT(BooleanExpression left) + public static BooleanExpression createNOT(BooleanExpression left) { return new NotExpression(left); } @@ -100,7 +100,7 @@ public abstract class UnaryExpression implements Expression return new XQueryExpression(xpath); } - public static BooleanExpression createBooleanCast(Expression left) + public static BooleanExpression createBooleanCast(Expression left) { return new BooleanCastExpression(left); } @@ -151,7 +151,7 @@ public abstract class UnaryExpression implements Expression this.right = left; } - public Expression getRight() + public Expression getRight() { return right; } @@ -204,14 +204,14 @@ public abstract class UnaryExpression implements Expression */ public abstract String getExpressionSymbol(); - private static class NegativeExpression extends UnaryExpression + private static class NegativeExpression extends UnaryExpression { - public NegativeExpression(final Expression left) + public NegativeExpression(final Expression left) { super(left); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); if (rvalue == null) @@ -233,19 +233,19 @@ public abstract class UnaryExpression implements Expression } } - private static class InExpression extends BooleanUnaryExpression + private static class InExpression extends BooleanUnaryExpression { private final Collection _inList; private final boolean _not; - public InExpression(final PropertyExpression right, final Collection inList, final boolean not) + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) { super(right); _inList = inList; _not = not; } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); @@ -309,14 +309,14 @@ public abstract class UnaryExpression implements Expression } } - private static class NotExpression extends BooleanUnaryExpression + private static class NotExpression extends BooleanUnaryExpression { - public NotExpression(final BooleanExpression left) + public NotExpression(final BooleanExpression left) { super(left); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Boolean lvalue = (Boolean) right.evaluate(message); if (lvalue == null) @@ -333,14 +333,14 @@ public abstract class UnaryExpression implements Expression } } - private static class BooleanCastExpression extends BooleanUnaryExpression + private static class BooleanCastExpression extends BooleanUnaryExpression { - public BooleanCastExpression(final Expression left) + public BooleanCastExpression(final Expression left) { super(left); } - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); if (rvalue == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index 1311178fb1..aa35cb5a76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import java.lang.reflect.Constructor; @@ -71,7 +70,7 @@ public final class XPathExpression implements BooleanExpression { private final XPathEvaluator evaluator; static public interface XPathEvaluator { - public boolean evaluate(Filterable message) throws AMQException; + public boolean evaluate(Filterable message); } XPathExpression(String xpath) { @@ -93,7 +92,7 @@ public final class XPathExpression implements BooleanExpression { } } - public Object evaluate(Filterable message) throws AMQException { + public Object evaluate(Filterable message) { // try { //FIXME this is flow to disk work // if( message.isDropped() ) @@ -118,7 +117,7 @@ public final class XPathExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(Filterable message) throws AMQException + public boolean matches(Filterable message) { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index c13f81cd08..ae22f17413 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -18,7 +18,6 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; // @@ -36,23 +35,23 @@ public final class XQueryExpression implements BooleanExpression { this.xpath = xpath; } - public Object evaluate(Filterable message) throws AMQException { + public Object evaluate(Filterable message) { return Boolean.FALSE; } public String toString() { return "XQUERY "+ConstantExpression.encodeString(xpath); } - + /** * @param message * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(Filterable message) throws AMQException + public boolean matches(Filterable message) { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + return object!=null && object==Boolean.TRUE; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index cc67776682..f83eb63ac5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -27,8 +27,6 @@ import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import org.apache.xpath.CachedXPathAPI; import org.w3c.dom.Document; @@ -36,14 +34,14 @@ import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { - + private final String xpath; public XalanXPathEvaluator(String xpath) { this.xpath = xpath; } - - public boolean evaluate(Filterable m) throws AMQException + + public boolean evaluate(Filterable m) { // TODO - we would have to check the content type and then evaluate the content // here... is this really a feature we wish to implement? - RobG @@ -65,18 +63,18 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(byte[] data) { try { - + InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder dbuilder = factory.newDocumentBuilder(); Document doc = dbuilder.parse(inputSource); - + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); return iterator.nextNode()!=null; - + } catch (Throwable e) { return false; } @@ -85,12 +83,12 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(String text) { try { InputSource inputSource = new InputSource(new StringReader(text)); - + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder dbuilder = factory.newDocumentBuilder(); Document doc = dbuilder.parse(inputSource); - + // We should associated the cachedXPathAPI object with the message being evaluated // since that should speedup subsequent xpath expressions. CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java index 895db7b15b..cfe5aedd61 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java @@ -31,19 +31,28 @@ public abstract class AbstractFlowCreditManager implements FlowCreditManager public final void addStateListener(FlowCreditManagerListener listener) { - _listeners.add(listener); + synchronized(_listeners) + { + _listeners.add(listener); + } } public final boolean removeListener(FlowCreditManagerListener listener) { - return _listeners.remove(listener); + synchronized(_listeners) + { + return _listeners.remove(listener); + } } private void notifyListeners(final boolean suspended) { - for(FlowCreditManagerListener listener : _listeners) + synchronized(_listeners) { - listener.creditStateChanged(!suspended); + for(FlowCreditManagerListener listener : _listeners) + { + listener.creditStateChanged(!suspended); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java index 96a1071135..c5f2d1e808 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -1,11 +1,8 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Set; -import java.util.HashSet; /* * @@ -36,7 +33,17 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager _bytesCredit = new AtomicLong(initialCredit); } - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return -1L; + } + + public long getBytesCredit() + { + return _bytesCredit.get(); + } + + public void restoreCredit(long messageCredit, long bytesCredit) { _bytesCredit.addAndGet(bytesCredit); setSuspended(false); @@ -52,7 +59,7 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager return _bytesCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { final long msgSize = msg.getSize(); if(hasCredit()) @@ -74,4 +81,9 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager } } + + public void setBytesCredit(long bytesCredit) + { + _bytesCredit.set( bytesCredit ); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java new file mode 100644 index 0000000000..b47f986155 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.message.ServerMessage; + +public class CreditCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10 +{ + private volatile long _bytesCredit; + private volatile long _messageCredit; + + + public CreditCreditManager() + { + this(0L, 0L); + } + + public CreditCreditManager(long bytesCredit, long messageCredit) + { + _bytesCredit = bytesCredit; + _messageCredit = messageCredit; + setSuspended(!hasCredit()); + + } + + + public synchronized void setCreditLimits(final long bytesCredit, final long messageCredit) + { + _bytesCredit = bytesCredit; + _messageCredit = messageCredit; + + setSuspended(!hasCredit()); + + } + + + public long getMessageCredit() + { + return _messageCredit == -1L + ? Long.MAX_VALUE + : _messageCredit; + } + + public long getBytesCredit() + { + return _bytesCredit == -1L + ? Long.MAX_VALUE + : _bytesCredit; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) + { + /*_bytesCredit = 0l; + _messageCredit = 0l; + setSuspended(true);*/ + } + + + public synchronized void addCredit(final long messageCredit, final long bytesCredit) + { + boolean notifyIncrease = true; + if(_messageCredit >= 0L && messageCredit > 0L) + { + notifyIncrease = _messageCredit != 0L; + _messageCredit += messageCredit; + } + + + + if(_bytesCredit >= 0L && bytesCredit > 0L) + { + notifyIncrease = notifyIncrease && bytesCredit>0; + _bytesCredit += bytesCredit; + + + + if(notifyIncrease) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + public void clearCredit() + { + _bytesCredit = 0l; + _messageCredit = 0l; + setSuspended(true); + } + + + public synchronized boolean hasCredit() + { + // Note !=, if credit is < 0 that indicates infinite credit + return (_bytesCredit != 0L && _messageCredit != 0L); + } + + public synchronized boolean useCreditForMessage(final ServerMessage msg) + { + if(_messageCredit >= 0L) + { + if(_messageCredit > 0) + { + if(_bytesCredit < 0L) + { + _messageCredit--; + + return true; + } + else if(msg.getSize() <= _bytesCredit) + { + _messageCredit--; + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + } + else if(_bytesCredit >= 0L) + { + if(msg.getSize() <= _bytesCredit) + { + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + + } + else + { + return true; + } + + } + + public synchronized void stop() + { + if(_bytesCredit > 0) + { + _bytesCredit = 0; + } + if(_messageCredit > 0) + { + _messageCredit = 0; + } + + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java index a249a6e63a..bec51d361d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,6 +24,9 @@ import org.apache.qpid.server.queue.AMQMessage; */ public interface FlowCreditManager { + long getMessageCredit(); + + long getBytesCredit(); public static interface FlowCreditManagerListener { @@ -34,11 +37,10 @@ public interface FlowCreditManager boolean removeListener(FlowCreditManagerListener listener); - public void addCredit(long messageCredit, long bytesCredit); - - public void removeAllCredit(); + public void restoreCredit(long messageCredit, long bytesCredit); public boolean hasCredit(); - public boolean useCreditForMessage(AMQMessage msg); + public boolean useCreditForMessage(ServerMessage msg); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java new file mode 100755 index 0000000000..48c336c0b1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java @@ -0,0 +1,28 @@ +package org.apache.qpid.server.flow; + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +public interface FlowCreditManager_0_10 extends FlowCreditManager +{ + public void addCredit(long count, long bytes); + + void clearCredit(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java index d63431c3eb..901b71fd1f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,7 +24,17 @@ import org.apache.qpid.server.queue.AMQMessage; */ public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager { - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return -1L; + } + + public long getBytesCredit() + { + return -1L; + } + + public void restoreCredit(long messageCredit, long bytesCredit) { } @@ -37,7 +47,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements return true; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java index 9c377481de..19a9ac1d23 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -1,8 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; - -import java.util.concurrent.atomic.AtomicLong; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -29,14 +27,24 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl private long _messageCredit; private long _bytesCredit; - MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) + public MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) { _messageCredit = messageCredit; _bytesCredit = bytesCredit; } - public synchronized void addCredit(long messageCredit, long bytesCredit) + public synchronized long getMessageCredit() { + return _messageCredit; + } + + public synchronized long getBytesCredit() + { + return _bytesCredit; + } + + public synchronized void restoreCredit(long messageCredit, long bytesCredit) + { _messageCredit += messageCredit; _bytesCredit += bytesCredit; setSuspended(hasCredit()); @@ -54,7 +62,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl return (_messageCredit > 0L) && ( _bytesCredit > 0L ); } - public synchronized boolean useCreditForMessage(AMQMessage msg) + public synchronized boolean useCreditForMessage(ServerMessage msg) { if(_messageCredit == 0L) { @@ -76,4 +84,9 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl } } + + public synchronized void setBytesCredit(long bytesCredit) + { + _bytesCredit = bytesCredit; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java index c1b3a09006..a386f66b11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; import java.util.concurrent.atomic.AtomicLong; @@ -33,10 +33,21 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen _messageCredit = new AtomicLong(initialCredit); } - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return _messageCredit.get(); + } + + public long getBytesCredit() + { + return -1L; + } + + public void restoreCredit(long messageCredit, long bytesCredit) { - setSuspended(false); _messageCredit.addAndGet(messageCredit); + setSuspended(false); + } public void removeAllCredit() @@ -50,7 +61,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen return _messageCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { if(hasCredit()) { @@ -73,4 +84,5 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java index be0300f2c1..026804439c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager { @@ -81,7 +81,17 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F } - public synchronized void addCredit(final long messageCredit, final long bytesCredit) + public long getMessageCredit() + { + return _messageCredit; + } + + public long getBytesCredit() + { + return _bytesCredit; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) { final long messageCreditLimit = _messageCreditLimit; boolean notifyIncrease = true; @@ -123,7 +133,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F && (_messageCreditLimit == 0L || _messageCredit > 0); } - public synchronized boolean useCreditForMessage(final AMQMessage msg) + public synchronized boolean useCreditForMessage(final ServerMessage msg) { if(_messageCreditLimit != 0L) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java new file mode 100644 index 0000000000..10f578551a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java @@ -0,0 +1,213 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.message.ServerMessage; + +public class WindowCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10 +{ + private volatile long _bytesCreditLimit; + private volatile long _messageCreditLimit; + + private volatile long _bytesUsed; + private volatile long _messageUsed; + + public WindowCreditManager() + { + this(0L, 0L); + } + + public WindowCreditManager(long bytesCreditLimit, long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + setSuspended(!hasCredit()); + + } + + + public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + + setSuspended(!hasCredit()); + + } + + + public long getMessageCredit() + { + return _messageCreditLimit == -1L + ? Long.MAX_VALUE + : _messageUsed < _messageCreditLimit ? _messageCreditLimit - _messageUsed : 0L; + } + + public long getBytesCredit() + { + return _bytesCreditLimit == -1L + ? Long.MAX_VALUE + : _bytesUsed < _bytesCreditLimit ? _bytesCreditLimit - _bytesUsed : 0L; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) + { + boolean notifyIncrease = true; + if(_messageCreditLimit > 0L) + { + notifyIncrease = (_messageUsed != _messageCreditLimit); + _messageUsed -= messageCredit; + + //TODO log warning + if(_messageUsed < 0L) + { + _messageUsed = 0; + } + } + + + + if(_bytesCreditLimit > 0L) + { + notifyIncrease = notifyIncrease && bytesCredit>0; + _bytesUsed -= bytesCredit; + + //TODO log warning + if(_bytesUsed < 0L) + { + _bytesUsed = 0; + } + + if(notifyIncrease) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + + + public synchronized boolean hasCredit() + { + return (_bytesCreditLimit < 0L || _bytesCreditLimit > _bytesUsed) + && (_messageCreditLimit < 0L || _messageCreditLimit > _messageUsed); + } + + public synchronized boolean useCreditForMessage(final ServerMessage msg) + { + if(_messageCreditLimit >= 0L) + { + if(_messageUsed < _messageCreditLimit) + { + if(_bytesCreditLimit < 0L) + { + _messageUsed++; + + return true; + } + else if(_bytesUsed + msg.getSize() <= _bytesCreditLimit) + { + _messageUsed++; + _bytesUsed += msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + } + else if(_bytesCreditLimit >= 0L) + { + if(_bytesUsed + msg.getSize() <= _bytesCreditLimit) + { + _bytesUsed += msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + + } + else + { + return true; + } + + } + + public void stop() + { + if(_bytesCreditLimit > 0) + { + _bytesCreditLimit = 0; + } + if(_messageCreditLimit > 0) + { + _messageCreditLimit = 0; + } + + } + + public synchronized void addCredit(long count, long bytes) + { + if(bytes > 0) + { + _bytesCreditLimit += bytes; + } + else if(bytes == -1) + { + _bytesCreditLimit = -1; + } + + + if(count > 0) + { + _messageCreditLimit += count; + } + else if(count == -1) + { + _messageCreditLimit = -1; + } + } + + public void clearCredit() + { + _bytesCreditLimit = 0l; + _messageCreditLimit = 0l; + setSuspended(true); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 08610f24cd..859a3477e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -25,7 +25,6 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.Permission; @@ -116,17 +115,31 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener @@ -60,11 +60,11 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -106,7 +105,7 @@ public class QueuePurgeHandler implements StateAwareMethodListener { throw body.getChannelNotFoundException(channelId); } - channel.commit(); MethodRegistry methodRegistry = session.getMethodRegistry(); AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); session.writeFrame(responseBody.generateFrame(channelId)); - - channel.processReturns(); + } catch (AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 5f402f3fda..4643dee0a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -44,9 +44,9 @@ public class TxRollbackHandler implements StateAwareMethodListener @@ -105,7 +110,12 @@ public class CurrentActor } catch (EmptyStackException ese) { - return null; + return _defaultActor; } } + + public static void setDefault(LogActor defaultActor) + { + _defaultActor = defaultActor; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index eafcb43cc0..1a2cb7251c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -61,13 +61,32 @@ MST-1001 = Created : {0} # 0 - path MST-1002 = Store location : {0} MST-1003 = Closed +MST-1004 = Recovery Start +MST-1005 = Recovered {0,number} messages +MST-1006 = Recovery Complete + +#ConfigStore +# 0 - name +CFG-1001 = Created : {0} +# 0 - path +CFG-1002 = Store location : {0} +CFG-1003 = Closed +CFG-1004 = Recovery Start +CFG-1005 = Recovery Complete + +#TransactionLog +# 0 - name +TXN-1001 = Created : {0} +# 0 - path +TXN-1002 = Store location : {0} +TXN-1003 = Closed # 0 - queue name -MST-1004 = Recovery Start[ : {0}] +TXN-1004 = Recovery Start[ : {0}] # 0 - count # 1 - queue count -MST-1005 = Recovered {0,number} messages for queue {1} +TXN-1005 = Recovered {0,number} messages for queue {1} # 0 - queue name -MST-1006 = Recovery Complete[ : {0}] +TXN-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id @@ -83,12 +102,18 @@ CHN-1003 = Close # 0 - bytes allowed in prefetch # 1 - number of messagse. CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +# 0 - queue causing flow control +CHN-1005 = Flow Control Enforced (Queue {0}) +CHN-1006 = Flow Control Removed #Queue # 0 - owner # 1 - priority QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted +QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} +QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} + #Exchange # 0 - type @@ -104,4 +129,4 @@ BND-1002 = Deleted SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close # 0 - The current subscription state -SUB-1003 = State : {0} \ No newline at end of file +SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 9169a1a651..1a2cb7251c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -16,173 +16,7 @@ # specific language governing permissions and limitations # under the License. # -# LogMessages used within the Java Broker as originally defined on the wiki: -# -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded through a ResourceBundle named LogMessages. the en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is requried then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat peforms its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addtion of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexepcted. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formating. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the first and final stage of processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# paramters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important is it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java -# Currently the following classes are created and are populated with the -# messages that bear their 3-digit type identifier: -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# BRK-1003 = Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage BRK_1003(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain paramters -# however nesting of options is not permitted. Identification is performed on -# first matchings so give the message: -# Msg = Log Message [option1] [option2] -# Two options will be identifed and enabled to select text 'option1 and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# The final processing that is done in the generation is the conversion of the -# property name. As a '-' is an illegal character in the method name it is -# converted to '_' This processing gives the final method signature as follows: -# Message._(,) -# +# Default File used for all non-defined locales. #Broker # 0 - Version # 1 = Build @@ -227,13 +61,32 @@ MST-1001 = Created : {0} # 0 - path MST-1002 = Store location : {0} MST-1003 = Closed +MST-1004 = Recovery Start +MST-1005 = Recovered {0,number} messages +MST-1006 = Recovery Complete + +#ConfigStore +# 0 - name +CFG-1001 = Created : {0} +# 0 - path +CFG-1002 = Store location : {0} +CFG-1003 = Closed +CFG-1004 = Recovery Start +CFG-1005 = Recovery Complete + +#TransactionLog +# 0 - name +TXN-1001 = Created : {0} +# 0 - path +TXN-1002 = Store location : {0} +TXN-1003 = Closed # 0 - queue name -MST-1004 = Recovery Start[ : {0}] +TXN-1004 = Recovery Start[ : {0}] # 0 - count # 1 - queue count -MST-1005 = Recovered {0,number} messages for queue {1} +TXN-1005 = Recovered {0,number} messages for queue {1} # 0 - queue name -MST-1006 = Recovery Complete[ : {0}] +TXN-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id @@ -247,8 +100,9 @@ CHN-1001 = Create CHN-1002 = Flow {0} CHN-1003 = Close # 0 - bytes allowed in prefetch -# 1 - number of messagse. +# 1 - number of messagse. CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +# 0 - queue causing flow control CHN-1005 = Flow Control Enforced (Queue {0}) CHN-1006 = Flow Control Removed @@ -260,6 +114,7 @@ QUE-1002 = Deleted QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} + #Exchange # 0 - type # 1 - name @@ -273,4 +128,5 @@ BND-1002 = Deleted #Subscription SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close +# 0 - The current subscription state SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index 1b22de6d01..03afd0b772 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -46,7 +46,7 @@ public class ChannelLogSubject extends AbstractLogSubject // Provide the value for the 4th replacement. setLogStringWithFormat(CHANNEL_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName(), channel.getChannelId()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index e07dbcda23..65d65a24d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -41,7 +41,7 @@ public class ConnectionLogSubject extends AbstractLogSubject public ConnectionLogSubject(AMQProtocolSession session) { setLogStringWithFormat(CONNECTION_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 67aee90ba4..d72b8f24ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -65,16 +65,9 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana return null; } - public void register() throws AMQException + public void register() throws JMException { - try - { - getManagedObjectRegistry().registerObject(this); - } - catch (JMException e) - { - throw new AMQException("Error registering managed object " + this + ": " + e, e); - } + getManagedObjectRegistry().registerObject(this); } protected ManagedObjectRegistry getManagedObjectRegistry() @@ -98,7 +91,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana { return getObjectInstanceName() + "[" + getType() + "]"; } - + /** * Created the ObjectName as per the JMX Specs @@ -140,7 +133,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(","); objectName.append("version=").append(_version); - + return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index aea9ab43ea..92657d7f3c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -54,6 +54,7 @@ import java.lang.reflect.Proxy; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.UnknownHostException; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; @@ -236,8 +237,17 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. */ - final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); - final String hostname = InetAddress.getLocalHost().getHostName(); + final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); + String localHost; + try + { + localHost = InetAddress.getLocalHost().getHostName(); + } + catch(UnknownHostException ex) + { + localHost="127.0.0.1"; + } + final String hostname = localHost; final JMXServiceURL externalUrl = new JMXServiceURL( "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java index 42ea8921a4..de14785fb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,6 +22,7 @@ package org.apache.qpid.server.management; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import javax.management.JMException; import org.apache.qpid.AMQException; @@ -45,7 +46,7 @@ public interface ManagedObject ManagedObject getParentObject(); - void register() throws AMQException; + void register() throws AMQException, JMException; void unregister() throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java new file mode 100644 index 0000000000..b8a36aba58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java @@ -0,0 +1,329 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.queue.AMQQueue; + + +import java.util.concurrent.atomic.AtomicInteger; +import java.nio.ByteBuffer; + +/** + * A deliverable message. + */ +public class AMQMessage implements ServerMessage +{ + /** Used for debugging purposes. */ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + private final AtomicInteger _referenceCount = new AtomicInteger(0); + + /** Flag to indicate that this message requires 'immediate' delivery. */ + + private static final byte IMMEDIATE = 0x01; + + /** + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. + */ + + private static final byte DELIVERED_TO_CONSUMER = 0x02; + + private byte _flags = 0; + + private long _expiration; + + private final long _size; + + private Object _sessionIdentifier; + private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); + + private final StoredMessage _handle; + + + public AMQMessage(StoredMessage handle) + { + _handle = handle; + final MessageMetaData metaData = handle.getMetaData(); + _size = metaData.getContentSize(); + final MessagePublishInfo messagePublishInfo = metaData.getMessagePublishInfo(); + + if(messagePublishInfo.isImmediate()) + { + _flags |= IMMEDIATE; + } + } + + + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; + } + + public void setExpiration(final long expiration) + { + + _expiration = expiration; + + } + + public boolean isReferenced() + { + return _referenceCount.get() > 0; + } + + public MessageMetaData getMessageMetaData() + { + return _handle.getMetaData(); + } + + public ContentHeaderBody getContentHeaderBody() throws AMQException + { + return getMessageMetaData().getContentHeaderBody(); + } + + + + public Long getMessageId() + { + return _handle.getMessageNumber(); + } + + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. + */ + public AMQMessage takeReference() + { + incrementReference(); // _referenceCount.incrementAndGet(); + + return this; + } + + public boolean incrementReference() + { + return incrementReference(1); + } + + /* Threadsafe. Increment the reference count on the message. */ + public boolean incrementReference(int count) + { + + if(_referenceCount.addAndGet(count) <= 0) + { + _referenceCount.addAndGet(-count); + return false; + } + else + { + return true; + } + + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * + * @throws org.apache.qpid.server.queue.MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + public void decrementReference() + { + int count = _referenceCount.decrementAndGet(); + + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (count == 0) + { + // set the reference count way below 0 so that we can detect that the message has been deleted + // this is to guard against the message being spontaneously recreated (from the mgmt console) + // by copying from other queues at the same time as it is being removed. + _referenceCount.set(Integer.MIN_VALUE/2); + + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + if (_handle != null) + { + _handle.remove(); + + } + } + else + { + if (count < 0) + { + throw new RuntimeException("Reference count for message id " + debugIdentity() + + " has gone below 0."); + } + } + } + + + /** + * Called selectors to determin if the message has already been sent + * + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return (_flags & DELIVERED_TO_CONSUMER) != 0; + } + + public String getRoutingKey() + { + // TODO + return null; + } + + public AMQMessageHeader getMessageHeader() + { + return getMessageMetaData().getMessageHeader(); + } + + public boolean isPersistent() + { + return getMessageMetaData().isPersistent(); + } + + /** + * Called to enforce the 'immediate' flag. + * + * @returns true if the message is marked for immediate delivery but has not been marked as delivered + * to a consumer + */ + public boolean immediateAndNotDelivered() + { + + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; + + } + + public MessagePublishInfo getMessagePublishInfo() throws AMQException + { + return getMessageMetaData().getMessagePublishInfo(); + } + + public long getArrivalTime() + { + return getMessageMetaData().getArrivalTime(); + } + + /** + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @param queue The queue to check the expiration against. (Currently not used) + * + * @return true if the message has expire + * + * @throws AMQException + */ + public boolean expired(AMQQueue queue) throws AMQException + { + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > _expiration); + } + + return false; + } + + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + */ + public void setDeliveredToConsumer() + { + _flags |= DELIVERED_TO_CONSUMER; + } + + public long getSize() + { + return _size; + + } + + public boolean isImmediate() + { + return (_flags & IMMEDIATE) == IMMEDIATE; + } + + public long getExpiration() + { + return _expiration; + } + + public MessageReference newReference() + { + return new AMQMessageReference(this); + } + + public Long getMessageNumber() + { + return getMessageId(); + } + + + public Object getPublisherIdentifier() + { + //todo store sessionIdentifier/client id with message in store + //Currently the _sessionIdentifier will be null if the message has been + // restored from a message Store + + return _sessionIdentifier; + + } + + public void setClientIdentifier(final Object sessionIdentifier) + { + _sessionIdentifier = sessionIdentifier; + } + + + public String toString() + { + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; + + return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; + } + + public int getContent(ByteBuffer buf, int offset) + { + return _handle.getContent(offset, buf); + } + + public StoredMessage getStoredMessage() + { + return _handle; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java new file mode 100644 index 0000000000..6c9311c3de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.util.Set; + +public interface AMQMessageHeader +{ + String getCorrelationId(); + + long getExpiration(); + + String getMessageId(); + + String getMimeType(); + + String getEncoding(); + + byte getPriority(); + + long getTimestamp(); + + String getType(); + + String getReplyTo(); + + Object getHeader(String name); + + boolean containsHeaders(Set names); + + boolean containsHeader(String name); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java new file mode 100644 index 0000000000..940caaefe4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.queue.MessageCleanupException; + +public class AMQMessageReference extends MessageReference +{ + + + public AMQMessageReference(AMQMessage message) + { + super(message); + } + + protected void onReference(AMQMessage message) + { + message.incrementReference(); + } + + protected void onRelease(AMQMessage message) + { + message.decrementReference(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java new file mode 100644 index 0000000000..4a1f8dd191 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -0,0 +1,114 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; + +import java.util.Set; + +public class ContentHeaderBodyAdapter implements AMQMessageHeader +{ + private final ContentHeaderBody _contentHeaderBody; + + public ContentHeaderBodyAdapter(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + private BasicContentHeaderProperties getProperties() + { + return (BasicContentHeaderProperties) _contentHeaderBody.properties; + } + + public String getCorrelationId() + { + return getProperties().getCorrelationIdAsString(); + } + + public long getExpiration() + { + return getProperties().getExpiration(); + } + + public String getMessageId() + { + return getProperties().getMessageIdAsString(); + } + + public String getMimeType() + { + return getProperties().getContentTypeAsString(); + } + + public String getEncoding() + { + return getProperties().getEncodingAsString(); + } + + public byte getPriority() + { + return getProperties().getPriority(); + } + + public long getTimestamp() + { + return getProperties().getTimestamp(); + } + + public String getType() + { + return getProperties().getTypeAsString(); + } + + public String getReplyTo() + { + return getProperties().getReplyToAsString(); + } + + public Object getHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.get(name); + } + + public boolean containsHeaders(Set names) + { + FieldTable ft = getProperties().getHeaders(); + for(String name : names) + { + if(!ft.containsKey(name)) + { + return false; + } + } + return true; + } + + public boolean containsHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.containsKey(name); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java new file mode 100755 index 0000000000..c32f80fc5b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java @@ -0,0 +1,27 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.message; + +public interface EnqueableMessage +{ + Long getMessageNumber(); + boolean isPersistent(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java new file mode 100644 index 0000000000..1b3fdb1870 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + + +import org.apache.qpid.server.queue.Filterable; + +public interface InboundMessage extends Filterable +{ + String getRoutingKey(); + + AMQMessageHeader getMessageHeader(); + + boolean isPersistent(); + + boolean isRedelivered(); + + long getSize(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java new file mode 100755 index 0000000000..08a09c4a85 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java @@ -0,0 +1,31 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.message; + +import java.nio.ByteBuffer; + +public interface MessageContentSource +{ + public int getContent(ByteBuffer buf, int offset); + + long getSize(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java new file mode 100644 index 0000000000..b34a8fc470 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -0,0 +1,309 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.EncodingUtils; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.MessageMetaDataType; +import org.apache.qpid.AMQException; + +import java.nio.ByteBuffer; +import java.util.Set; + +/** + * Encapsulates a publish body and a content header. In the context of the message store these are treated as a + * single unit. + */ +public class MessageMetaData implements StorableMessageMetaData +{ + private MessagePublishInfo _messagePublishInfo; + + private ContentHeaderBody _contentHeaderBody; + + private int _contentChunkCount; + + private long _arrivalTime; + private static final byte MANDATORY_FLAG = 1; + private static final byte IMMEDIATE_FLAG = 2; + public static final MessageMetaDataType.Factory FACTORY = new MetaDataFactory(); + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); + } + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) + { + _contentHeaderBody = contentHeaderBody; + _messagePublishInfo = publishBody; + _contentChunkCount = contentChunkCount; + _arrivalTime = arrivalTime; + } + + public int getContentChunkCount() + { + return _contentChunkCount; + } + + public void setContentChunkCount(int contentChunkCount) + { + _contentChunkCount = contentChunkCount; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void setArrivalTime(long arrivalTime) + { + _arrivalTime = arrivalTime; + } + + public MessageMetaDataType getType() + { + return MessageMetaDataType.META_DATA_0_8; + } + + public int getStorableSize() + { + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); + int size = _contentHeaderBody.getSize(); + size += 4; + size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getExchange()); + size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getRoutingKey()); + size += 1; // flags for immediate/mandatory + size += EncodingUtils.encodedLongLength(); + + return size; + } + + public int writeToBuffer(int offset, ByteBuffer dest) + { + ByteBuffer src = ByteBuffer.allocate((int)getStorableSize()); + + org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(src); + EncodingUtils.writeInteger(minaSrc, _contentHeaderBody.getSize()); + _contentHeaderBody.writePayload(minaSrc); + EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getExchange()); + EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getRoutingKey()); + byte flags = 0; + if(_messagePublishInfo.isMandatory()) + { + flags |= MANDATORY_FLAG; + } + if(_messagePublishInfo.isImmediate()) + { + flags |= IMMEDIATE_FLAG; + } + EncodingUtils.writeByte(minaSrc, flags); + EncodingUtils.writeLong(minaSrc,_arrivalTime); + src.position(minaSrc.position()); + src.flip(); + src.position(offset); + src = src.slice(); + if(dest.remaining() < src.limit()) + { + src.limit(dest.remaining()); + } + dest.put(src); + + + return src.limit(); + } + + public int getContentSize() + { + return (int) _contentHeaderBody.bodySize; + } + + public boolean isPersistent() + { + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); + return properties.getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; + } + + private static class MetaDataFactory implements MessageMetaDataType.Factory + { + + + public MessageMetaData createMetaData(ByteBuffer buf) + { + try + { + org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(buf); + int size = EncodingUtils.readInteger(minaSrc); + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(minaSrc, size); + final AMQShortString exchange = EncodingUtils.readAMQShortString(minaSrc); + final AMQShortString routingKey = EncodingUtils.readAMQShortString(minaSrc); + + final byte flags = EncodingUtils.readByte(minaSrc); + long arrivalTime = EncodingUtils.readLong(minaSrc); + + MessagePublishInfo publishBody = + new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public void setExchange(AMQShortString exchange) + { + } + + public boolean isImmediate() + { + return (flags & IMMEDIATE_FLAG) != 0; + } + + public boolean isMandatory() + { + return (flags & MANDATORY_FLAG) != 0; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + }; + return new MessageMetaData(publishBody, chb, 0, arrivalTime); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + }; + + public AMQMessageHeader getMessageHeader() + { + return new MessageHeaderAdapter(); + } + + private final class MessageHeaderAdapter implements AMQMessageHeader + { + private BasicContentHeaderProperties getProperties() + { + return (BasicContentHeaderProperties) getContentHeaderBody().properties; + } + + public String getCorrelationId() + { + return getProperties().getCorrelationIdAsString(); + } + + public long getExpiration() + { + return getProperties().getExpiration(); + } + + public String getMessageId() + { + return getProperties().getMessageIdAsString(); + } + + public String getMimeType() + { + return getProperties().getContentTypeAsString(); + } + + public String getEncoding() + { + return getProperties().getEncodingAsString(); + } + + public byte getPriority() + { + return getProperties().getPriority(); + } + + public long getTimestamp() + { + return getProperties().getTimestamp(); + } + + public String getType() + { + return getProperties().getTypeAsString(); + } + + public String getReplyTo() + { + return getProperties().getReplyToAsString(); + } + + public Object getHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.get(name); + } + + public boolean containsHeaders(Set names) + { + FieldTable ft = getProperties().getHeaders(); + for(String name : names) + { + if(!ft.containsKey(name)) + { + return false; + } + } + return true; + } + + public boolean containsHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.containsKey(name); + } + + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java new file mode 100755 index 0000000000..5a5e2fe5b4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java @@ -0,0 +1,242 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.message; + +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.MessageMetaDataType; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageDeliveryMode; +import org.apache.qpid.transport.Struct; +import org.apache.qpid.transport.codec.BBEncoder; +import org.apache.qpid.transport.codec.BBDecoder; + +import java.nio.ByteBuffer; +import java.lang.ref.WeakReference; + +public class MessageMetaData_0_10 implements StorableMessageMetaData +{ + private Header _header; + private DeliveryProperties _deliveryProps; + private MessageProperties _messageProps; + private MessageTransferHeader _messageHeader; + private long _arrivalTime; + private int _bodySize; + private volatile WeakReference _body; + + private static final int ENCODER_SIZE = 1 << 16; + + public static final MessageMetaDataType.Factory FACTORY = new MetaDataFactory(); + + private volatile ByteBuffer _encoded; + + + public MessageMetaData_0_10(MessageTransfer xfr) + { + this(xfr.getHeader(), xfr.getBodySize(), xfr.getBody(), System.currentTimeMillis()); + } + + private MessageMetaData_0_10(Header header, int bodySize, long arrivalTime) + { + this(header, bodySize, null, arrivalTime); + } + + private MessageMetaData_0_10(Header header, int bodySize, ByteBuffer xfrBody, long arrivalTime) + { + _header = header; + if(_header != null) + { + _deliveryProps = _header.get(DeliveryProperties.class); + _messageProps = _header.get(MessageProperties.class); + } + else + { + _deliveryProps = null; + _messageProps = null; + } + _messageHeader = new MessageTransferHeader(_deliveryProps, _messageProps); + _arrivalTime = arrivalTime; + _bodySize = bodySize; + + + + if(xfrBody == null) + { + _body = null; + } + else + { + ByteBuffer body = ByteBuffer.allocate(_bodySize); + body.put(xfrBody); + body.flip(); + _body = new WeakReference(body); + } + + + } + + + + public MessageMetaDataType getType() + { + return MessageMetaDataType.META_DATA_0_10; + } + + public int getStorableSize() + { + ByteBuffer buf = _encoded; + + if(buf == null) + { + buf = encodeAsBuffer(); + _encoded = buf; + } + + //TODO -- need to add stuff + return buf.limit(); + } + + private ByteBuffer encodeAsBuffer() + { + BBEncoder encoder = new BBEncoder(ENCODER_SIZE); + + encoder.writeInt64(_arrivalTime); + encoder.writeInt32(_bodySize); + Struct[] headers = _header == null ? new Struct[0] : _header.getStructs(); + encoder.writeInt32(headers.length); + + + for(Struct header : headers) + { + encoder.writeStruct32(header); + + } + + ByteBuffer buf = encoder.buffer(); + return buf; + } + + public int writeToBuffer(int offsetInMetaData, ByteBuffer dest) + { + ByteBuffer buf = _encoded; + + if(buf == null) + { + buf = encodeAsBuffer(); + _encoded = buf; + } + + buf = buf.duplicate(); + + buf.position(offsetInMetaData); + + if(dest.remaining() < buf.limit()) + { + buf.limit(dest.remaining()); + } + dest.put(buf); + return buf.limit(); + } + + public int getContentSize() + { + return _bodySize; + } + + public boolean isPersistent() + { + return _deliveryProps == null ? false : _deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT; + } + + public String getRoutingKey() + { + return _deliveryProps == null ? null : _deliveryProps.getRoutingKey(); + } + + public AMQMessageHeader getMessageHeader() + { + return _messageHeader; + } + + public long getSize() + { + + return _bodySize; + } + + public boolean isImmediate() + { + return _deliveryProps != null && _deliveryProps.getImmediate(); + } + + public long getExpiration() + { + return _deliveryProps == null ? 0L : _deliveryProps.getExpiration(); + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public Header getHeader() + { + return _header; + } + + public ByteBuffer getBody() + { + ByteBuffer body = _body == null ? null : _body.get(); + return body; + } + + public void setBody(ByteBuffer body) + { + _body = new WeakReference(body); + } + + private static class MetaDataFactory implements MessageMetaDataType.Factory + { + public MessageMetaData_0_10 createMetaData(ByteBuffer buf) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(buf); + + long arrivalTime = decoder.readInt64(); + int bodySize = decoder.readInt32(); + int headerCount = decoder.readInt32(); + + Struct[] headers = new Struct[headerCount]; + + for(int i = 0 ; i < headerCount; i++) + { + headers[i] = decoder.readStruct32(); + } + + Header header = new Header(headers); + + return new MessageMetaData_0_10(header, bodySize, arrivalTime); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java new file mode 100644 index 0000000000..055403ff08 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public abstract class MessageReference +{ + + private static final AtomicReferenceFieldUpdater _messageUpdater = + AtomicReferenceFieldUpdater.newUpdater(MessageReference.class, ServerMessage.class,"_message"); + + private volatile M _message; + + public MessageReference(M message) + { + _message = message; + onReference(message); + } + + abstract protected void onReference(M message); + + abstract protected void onRelease(M message); + + public M getMessage() + { + return _message; + } + + public void release() + { + M message = (M) _messageUpdater.getAndSet(this,null); + if(message != null) + { + onRelease(message); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java new file mode 100644 index 0000000000..1a75d7ca65 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.MessageDeliveryPriority; + +import java.util.Set; +import java.util.Map; + +class MessageTransferHeader implements AMQMessageHeader +{ + + + public static final String JMS_TYPE = "x-jms-type"; + + private final DeliveryProperties _deliveryProps; + private final MessageProperties _messageProps; + + public MessageTransferHeader(DeliveryProperties deliveryProps, MessageProperties messageProps) + { + _deliveryProps = deliveryProps; + _messageProps = messageProps; + } + + public String getCorrelationId() + { + return _messageProps == null ? null : new String(_messageProps.getCorrelationId()); + } + + public long getExpiration() + { + return _deliveryProps == null ? null : _deliveryProps.getExpiration(); + } + + public String getMessageId() + { + return _messageProps == null ? null : String.valueOf(_messageProps.getMessageId()); + } + + public String getMimeType() + { + return _messageProps == null ? null : _messageProps.getContentType(); + } + + public String getEncoding() + { + return _messageProps == null ? null : _messageProps.getContentEncoding(); + } + + public byte getPriority() + { + MessageDeliveryPriority priority = _deliveryProps == null + ? MessageDeliveryPriority.MEDIUM + : _deliveryProps.getPriority(); + return (byte) priority.getValue(); + } + + public long getTimestamp() + { + return _deliveryProps == null ? 0L : _deliveryProps.getTimestamp(); + } + + public String getType() + { + Object type = getHeader(JMS_TYPE); + return type instanceof String ? (String) type : null; + } + + public String getReplyTo() + { + return _messageProps == null ? null : _messageProps.getReplyTo().toString(); + } + + public Object getHeader(String name) + { + Map appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders == null ? null : appHeaders.get(name); + } + + public boolean containsHeaders(Set names) + { + Map appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders != null && appHeaders.keySet().containsAll(names); + + } + + public boolean containsHeader(String name) + { + Map appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders != null && appHeaders.containsKey(name); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java new file mode 100644 index 0000000000..e866ad5078 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -0,0 +1,146 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.store.StoredMessage; + +import java.util.concurrent.atomic.AtomicLong; +import java.nio.ByteBuffer; +import java.lang.ref.WeakReference; + + +public class MessageTransferMessage implements InboundMessage, ServerMessage +{ + + + private StoredMessage _storeMessage; + + + private WeakReference _sessionRef; + + + public MessageTransferMessage(StoredMessage storeMessage, WeakReference sessionRef) + { + + _storeMessage = storeMessage; + _sessionRef = sessionRef; + + } + + private MessageMetaData_0_10 getMetaData() + { + return _storeMessage.getMetaData(); + } + + public String getRoutingKey() + { + return getMetaData().getRoutingKey(); + + } + + public AMQMessageHeader getMessageHeader() + { + return getMetaData().getMessageHeader(); + } + + public boolean isPersistent() + { + return getMetaData().isPersistent(); + } + + + public boolean isRedelivered() + { + // The *Message* is never redelivered, only queue entries are... this is here so that filters + // can run against the message on entry to an exchange + return false; + } + + public long getSize() + { + + return getMetaData().getSize(); + } + + public boolean isImmediate() + { + return getMetaData().isImmediate(); + } + + public long getExpiration() + { + return getMetaData().getExpiration(); + } + + public MessageReference newReference() + { + return new TransferMessageReference(this); + } + + public Long getMessageNumber() + { + return _storeMessage.getMessageNumber(); + } + + public long getArrivalTime() + { + return getMetaData().getArrivalTime(); + } + + public int getContent(ByteBuffer buf, int offset) + { + return _storeMessage.getContent(offset, buf); + } + + public Header getHeader() + { + return getMetaData().getHeader(); + } + + public ByteBuffer getBody() + { + ByteBuffer body = getMetaData().getBody(); + if(body == null) + { + final int size = (int) getSize(); + int pos = 0; + body = ByteBuffer.allocate(size); + + while(pos < size) + { + pos += getContent(body, pos); + } + + body.flip(); + + getMetaData().setBody(body.duplicate()); + } + return body; + } + + public Session getSession() + { + return _sessionRef == null ? null : _sessionRef.get(); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java new file mode 100644 index 0000000000..1ac538c15b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.nio.ByteBuffer; + +public interface ServerMessage extends EnqueableMessage, MessageContentSource +{ + String getRoutingKey(); + + AMQMessageHeader getMessageHeader(); + + boolean isPersistent(); + + long getSize(); + + boolean isImmediate(); + + long getExpiration(); + + MessageReference newReference(); + + Long getMessageNumber(); + + long getArrivalTime(); + + public int getContent(ByteBuffer buf, int offset); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java new file mode 100644 index 0000000000..ed189c49c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +public class TransferMessageReference extends MessageReference +{ + public TransferMessageReference(MessageTransferMessage message) + { + super(message); + } + + protected void onReference(MessageTransferMessage message) + { + + } + + protected void onRelease(MessageTransferMessage message) + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java new file mode 100755 index 0000000000..aded3f3d2a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java @@ -0,0 +1,124 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.MessageDeliveryMode; +import org.apache.qpid.AMQPInvalidClassException; + +import java.util.Map; + +public class HeaderPropertiesConverter +{ + + public static BasicContentHeaderProperties convert(MessageTransferMessage messageTransferMessage) + { + BasicContentHeaderProperties props = new BasicContentHeaderProperties(); + + Header header = messageTransferMessage.getHeader(); + DeliveryProperties deliveryProps = header.get(DeliveryProperties.class); + MessageProperties messageProps = header.get(MessageProperties.class); + + if(deliveryProps != null) + { + if(deliveryProps.hasDeliveryMode()) + { + props.setDeliveryMode((byte)(deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT ? BasicContentHeaderProperties.PERSISTENT : BasicContentHeaderProperties.NON_PERSISTENT)); + } + if(deliveryProps.hasExpiration()) + { + props.setExpiration(deliveryProps.getExpiration()); + } + if(deliveryProps.hasPriority()) + { + props.setPriority((byte)deliveryProps.getPriority().getValue()); + } + if(deliveryProps.hasTimestamp()) + { + props.setTimestamp(deliveryProps.getTimestamp()); + } + } + if(messageProps != null) + { + if(messageProps.hasAppId()) + { + props.setAppId(new AMQShortString(messageProps.getAppId())); + } + if(messageProps.hasContentType()) + { + props.setContentType(messageProps.getContentType()); + } + if(messageProps.hasCorrelationId()) + { + props.setCorrelationId(new AMQShortString(messageProps.getCorrelationId())); + } + if(messageProps.hasContentEncoding()) + { + props.setEncoding(messageProps.getContentEncoding()); + } + if(messageProps.hasMessageId()) + { + props.setMessageId(messageProps.getMessageId().toString()); + } + + // TODO Reply-to + + if(messageProps.hasUserId()) + { + props.setUserId(new AMQShortString(messageProps.getUserId())); + } + + if(messageProps.hasApplicationHeaders()) + { + Map appHeaders = messageProps.getApplicationHeaders(); + FieldTable ft = new FieldTable(); + for(Map.Entry entry : appHeaders.entrySet()) + { + try + { + ft.put(new AMQShortString(entry.getKey()), entry.getValue()); + } + catch(AMQPInvalidClassException e) + { + // TODO + // log here, but ignore - just can;t convert + } + } + props.setHeaders(ft); + + } + } + + + + + + + + return props; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java index e01c5aabbf..5300bad613 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -26,10 +26,13 @@ */ package org.apache.qpid.server.output; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.message.MessageContentSource; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.AMQException; public interface ProtocolOutputConverter @@ -41,16 +44,16 @@ public interface ProtocolOutputConverter ProtocolOutputConverter newInstance(AMQProtocolSession session); } - void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException; - void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException; + void writeGetOk(QueueEntry message, int channelId, long deliveryTag, int queueSize) throws AMQException; byte getProtocolMinorVersion(); byte getProtocolMajorVersion(); - void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource msgContent, int channelId, int replyCode, AMQShortString replyText) throws AMQException; void writeFrame(AMQDataBlock block); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index 2b55d294b5..2cebec373e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -27,28 +27,34 @@ package org.apache.qpid.server.output.amqp0_8; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.HeaderPropertiesConverter; +import org.apache.qpid.server.message.MessageContentSource; +import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl; import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.AMQException; +import org.apache.qpid.transport.DeliveryProperties; -import org.apache.mina.common.ByteBuffer; - -import java.util.Iterator; +import java.nio.ByteBuffer; public class ProtocolOutputConverterImpl implements ProtocolOutputConverter { + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + + private static final ProtocolVersionMethodConverter PROTOCOL_CONVERTER = + METHOD_REGISTRY.getProtocolVersionMethodConverter(); public static Factory getInstanceFactory() { return new Factory() { - + public ProtocolOutputConverter newInstance(AMQProtocolSession session) { return new ProtocolOutputConverterImpl(session); @@ -69,71 +75,47 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return _protocolSession; } - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { - AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - - - final int bodyCount = messageHandle.getBodyCount(storeContext); + AMQDataBlock deliver = createEncodedDeliverFrame(entry, channelId, deliveryTag, consumerTag); + writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver); + } - if(bodyCount == 0) + private ContentHeaderBody getContentHeaderBody(QueueEntry entry) + throws AMQException + { + if(entry.getMessage() instanceof AMQMessage) { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - - writeFrame(compositeBlock); + return ((AMQMessage)entry.getMessage()).getContentHeaderBody(); } else { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); - } - - + final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message); + ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID); + chb.bodySize = message.getSize(); + return chb; } - - } - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException { + AMQDataBlock deliver = createEncodedGetOkFrame(entry, channelId, deliveryTag, queueSize); + writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver); + } - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); + private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody chb, int channelId, AMQDataBlock deliver) + throws AMQException + { - AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, chb); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - final int bodyCount = messageHandle.getBodyCount(storeContext); - if(bodyCount == 0) + final int bodySize = (int) message.getSize(); + if(bodySize == 0) { SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, contentHeader); @@ -141,66 +123,97 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter } else { + int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead(); + final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize; + ByteBuffer buf = ByteBuffer.allocate(capacity); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); + int writtenSize = 0; - AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)); + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)); AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); writeFrame(compositeBlock); - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) + while(writtenSize < bodySize) { - cb = messageHandle.getContentChunk(storeContext, i); - writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb))); + buf = java.nio.ByteBuffer.allocate(capacity); + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf))); } - } - - } - private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + private AMQDataBlock createEncodedDeliverFrame(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); BasicDeliverBody deliverBody = - methodRegistry.createBasicDeliverBody(consumerTag, + METHOD_REGISTRY.createBasicDeliverBody(consumerTag, deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey()); + isRedelivered, + exchangeName, + routingKey); + AMQFrame deliverFrame = deliverBody.generateFrame(channelId); return deliverFrame; } - private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + private AMQDataBlock createEncodedGetOkFrame(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); BasicGetOkBody getOkBody = - methodRegistry.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + isRedelivered, + exchangeName, + routingKey, queueSize); AMQFrame getOkFrame = getOkBody.generateFrame(channelId); @@ -217,54 +230,31 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return getProtocolSession().getProtocolMajorVersion(); } - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + private AMQDataBlock createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, int channelId, int replyCode, AMQShortString replyText) throws AMQException { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); BasicReturnBody basicReturnBody = - methodRegistry.createBasicReturnBody(replyCode, + METHOD_REGISTRY.createBasicReturnBody(replyCode, replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); return returnFrame; } - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + public void writeReturn(MessagePublishInfo messagePublishInfo, + ContentHeaderBody header, + MessageContentSource content, + int channelId, + int replyCode, + AMQShortString replyText) throws AMQException { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - message.getContentHeaderBody()); - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); + AMQDataBlock returnFrame = createEncodedReturnFrame(messagePublishInfo, channelId, replyCode, replyText); - writeFrame(compositeBlock); - } + writeMessageDelivery(content, header, channelId, returnFrame); - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } } @@ -276,8 +266,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) { - MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); - BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag); + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); writeFrame(basicCancelOkBody.generateFrame(channelId)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index 65184fe744..319b5cc7bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -1,46 +1,48 @@ package org.apache.qpid.server.output.amqp0_9; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ -import org.apache.mina.common.ByteBuffer; -import java.util.Iterator; +import org.apache.mina.common.ByteBuffer; import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.HeaderPropertiesConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.MessageContentSource; +import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.amqp_0_9.BasicGetBodyImpl; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.apache.qpid.AMQException; +import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; public class ProtocolOutputConverterImpl implements ProtocolOutputConverter { private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); - private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); + private static final ProtocolVersionMethodConverter + PROTOCOL_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter(); public static Factory getInstanceFactory() @@ -68,20 +70,46 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return _protocolSession; } - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { - AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag); - final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody(); + AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag); + writeMessageDelivery(entry, channelId, deliverBody); + } - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); + private ContentHeaderBody getContentHeaderBody(QueueEntry entry) + throws AMQException + { + if(entry.getMessage() instanceof AMQMessage) + { + return ((AMQMessage)entry.getMessage()).getContentHeaderBody(); + } + else + { + final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message); + ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID); + chb.bodySize = message.getSize(); + return chb; + } + } - final int bodyCount = messageHandle.getBodyCount(storeContext); + private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody) + throws AMQException + { + writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody); + } + + private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody) + throws AMQException + { - if(bodyCount == 0) + + int bodySize = (int) message.getSize(); + + if(bodySize == 0) { SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody); @@ -90,101 +118,75 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter } else { + int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead(); + + + final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize; + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(capacity); + int writtenSize = 0; - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); - AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb); + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + AMQBody firstContentBody = PROTOCOL_CONVERTER.convertToBody(buf); - CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + CompositeAMQBodyBlock + compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); writeFrame(compositeBlock); - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) + while(writtenSize < bodySize) { - cb = messageHandle.getContentChunk(storeContext, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - + buf = java.nio.ByteBuffer.allocate(capacity); + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf))); + } } - } private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) { - + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, contentHeaderBody); return contentHeader; } - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException { + AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize); + writeMessageDelivery(entry, channelId, deliver); + } - final AMQMessageHandle messageHandle = message.getMessageHandle(); - final StoreContext storeContext = message.getStoreContext(); - - AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize); + private AMQBody createEncodedDeliverBody(QueueEntry entry, + final long deliveryTag, + final AMQShortString consumerTag) + throws AMQException + { - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); + final AMQShortString exchangeName; + final AMQShortString routingKey; - final int bodyCount = messageHandle.getBodyCount(storeContext); - if(bodyCount == 0) + if(entry.getMessage() instanceof AMQMessage) { - SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver, - contentHeader); - writeFrame(compositeBlock); + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); } else { - - - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - ContentChunk cb = messageHandle.getContentChunk(storeContext, 0); - - AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)); - AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - - // - // Now start writing out the other content bodies - // - for(int i = 1; i < bodyCount; i++) - { - cb = messageHandle.getContentChunk(storeContext, i); - writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb))); - } - - + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); } - - } - - - private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag) - throws AMQException - { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); - - - final boolean isRedelivered = messageHandle.isRedelivered(); - final AMQShortString exchangeName = pb.getExchange(); - final AMQShortString routingKey = pb.getRoutingKey(); + final boolean isRedelivered = entry.isRedelivered(); final AMQBody returnBlock = new AMQBody() { @@ -237,22 +239,37 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return returnBlock; } - private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize) + private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize) throws AMQException { - final MessagePublishInfo pb = message.getMessagePublishInfo(); - final AMQMessageHandle messageHandle = message.getMessageHandle(); + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + final boolean isRedelivered = entry.isRedelivered(); BasicGetOkBody getOkBody = METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, - messageHandle.isRedelivered(), - pb.getExchange(), - pb.getRoutingKey(), + isRedelivered, + exchangeName, + routingKey, queueSize); - AMQFrame getOkFrame = getOkBody.generateFrame(channelId); - return getOkFrame; + return getOkBody; } public byte getProtocolMinorVersion() @@ -265,53 +282,28 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return getProtocolSession().getProtocolMajorVersion(); } - private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException + private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, + int replyCode, + AMQShortString replyText) throws AMQException { BasicReturnBody basicReturnBody = METHOD_REGISTRY.createBasicReturnBody(replyCode, replyText, - message.getMessagePublishInfo().getExchange(), - message.getMessagePublishInfo().getRoutingKey()); - AMQFrame returnFrame = basicReturnBody.generateFrame(channelId); + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); - return returnFrame; + + return basicReturnBody; } - public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) + public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText) throws AMQException { - AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText); - - AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody()); - - Iterator bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks); - writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader}); - writeFrame(compositeBlock); - } + AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText); - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - writeFrame(bodyFrameIterator.next()); - } + writeMessageDelivery(message, header, channelId, returnFrame); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index a6fcadad0f..04b3e75f8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -34,6 +34,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicMarkableReference; +import java.util.concurrent.atomic.AtomicBoolean; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -83,8 +85,8 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; @@ -124,7 +126,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Object _lastSent; - protected boolean _closed; + protected volatile boolean _closed; // maximum number of channels this session should have private long _maxNoOfChannels = 1000; @@ -139,7 +141,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Principal _authorizedID; private MethodDispatcher _dispatcher; private ProtocolSessionIdentifier _sessionIdentifier; - + // Create a simple ID that increments for ever new Session private final long _sessionID = idGenerator.getAndIncrement(); @@ -152,11 +154,13 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private long _writtenBytes; private long _readBytes; - + private Job _readJob; private Job _writeJob; private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); + private long _maxFrameSize; + private final AtomicBoolean _closing = new AtomicBoolean(false); public ManagedObject getManagedObject() { @@ -167,7 +171,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _stateManager = new AMQStateManager(virtualHostRegistry, this); _networkDriver = driver; - + _codecFactory = new AMQCodecFactory(true, this); _poolReference.acquireExecutorService(); _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true); @@ -178,17 +182,9 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } - private AMQProtocolSessionMBean createMBean() throws AMQException + private AMQProtocolSessionMBean createMBean() throws JMException { - try - { - return new AMQProtocolSessionMBean(this); - } - catch (JMException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed ", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); - } + return new AMQProtocolSessionMBean(this); } public long getSessionID() @@ -201,6 +197,21 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _actor; } + public void setMaxFrameSize(long frameMax) + { + _maxFrameSize = frameMax; + } + + public long getMaxFrameSize() + { + return _maxFrameSize; + } + + public boolean isClosing() + { + return _closing.get(); + } + public void received(final ByteBuffer msg) { _lastIoTime = System.currentTimeMillis(); @@ -290,7 +301,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol else { // The channel has been told to close, we don't process any more frames until - // it's closed. + // it's closed. return; } } @@ -545,7 +556,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private void checkForNotification() { int channelsCount = _channelMap.size(); - if (channelsCount >= _maxNoOfChannels) + if (_managedObject != null && channelsCount >= _maxNoOfChannels) { _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); } @@ -560,7 +571,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _maxNoOfChannels = value; } - + public void commitTransactions(AMQChannel channel) throws AMQException { if ((channel != null) && channel.isTransactional()) @@ -576,7 +587,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol channel.rollback(); } } - + /** * 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
      @@ -676,34 +687,58 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol /** 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 { - // REMOVE THIS SHOULD NOT BE HERE. - if (CurrentActor.get() == null) - { - CurrentActor.set(_actor); - } - if (!_closed) + if(_closing.compareAndSet(false,true)) { - if (_virtualHost != null) + // REMOVE THIS SHOULD NOT BE HERE. + if (CurrentActor.get() == null) { - _virtualHost.getConnectionRegistry().deregisterConnection(this); + CurrentActor.set(_actor); } - - closeAllChannels(); - if (_managedObject != null) + if (!_closed) { - _managedObject.unregister(); - // Ensure we only do this once. - _managedObject = null; - } + if (_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + // Ensure we only do this once. + _managedObject = null; + } - for (Task task : _taskList) + for (Task task : _taskList) + { + task.doTask(this); + } + + synchronized(this) + { + _closed = true; + notifyAll(); + } + _poolReference.releaseExecutorService(); + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); + } + } + else + { + synchronized(this) { - task.doTask(this); + while(!_closed) + { + try + { + wait(1000); + } + catch (InterruptedException e) + { + + } + } } - - _closed = true; - _poolReference.releaseExecutorService(); - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); } } @@ -778,7 +813,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol throw new IllegalArgumentException("Unsupported socket address class: " + address); } } - + public SaslServer getSaslServer() { return _saslServer; @@ -868,8 +903,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _virtualHost.getConnectionRegistry().registerConnection(this); - _managedObject = createMBean(); - _managedObject.register(); + try + { + _managedObject = createMBean(); + _managedObject.register(); + } + catch (JMException e) + { + _logger.error(e); + } } public void addSessionCloseTask(Task task) @@ -881,7 +923,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _taskList.remove(task); } - + public ProtocolOutputConverter getProtocolOutputConverter() { return _protocolOutputConverter; @@ -900,10 +942,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _authorizedID; } + public Principal getPrincipal() + { + return _authorizedID; + } + public SocketAddress getRemoteAddress() { return _networkDriver.getRemoteAddress(); - } + } public SocketAddress getLocalAddress() { @@ -939,7 +986,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void setNetworkDriver(NetworkDriver driver) { - _networkDriver = driver; + _networkDriver = driver; } public void writerIdle() @@ -968,7 +1015,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(getProtocolVersion()); ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); - + writeFrame(closeBody.generateFrame(0)); _networkDriver.close(); @@ -984,7 +1031,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { // Do nothing } - + public long getReadBytes() { return _readBytes; @@ -1004,7 +1051,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { return _sessionIdentifier; } - + public String getClientVersion() { return (_clientVersion == null) ? null : _clientVersion.toString(); @@ -1022,5 +1069,5 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } } - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index b16ed01c79..48dd16a98c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,7 +28,7 @@ import org.apache.qpid.framing.*; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -37,12 +37,18 @@ import java.security.Principal; import java.util.List; -public interface AMQProtocolSession extends AMQVersionAwareProtocolSession +public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, PrincipalHolder { long getSessionID(); LogActor getLogActor(); + void setMaxFrameSize(long frameMax); + + long getMaxFrameSize(); + + boolean isClosing(); + public static final class ProtocolSessionIdentifier { private final Object _sessionIdentifier; @@ -201,9 +207,6 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession void setAuthorizedID(Principal authorizedID); - /** @return a Principal that was used to authorized this session */ - Principal getAuthorizedID(); - public java.net.SocketAddress getRemoteAddress(); public MethodRegistry getMethodRegistry(); @@ -224,8 +227,10 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession void commitTransactions(AMQChannel channel) throws AMQException; + void rollbackTransactions(AMQChannel channel) throws AMQException; + List getChannels(); void closeIfLingeringClosedChannels(); - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 8497c95e26..67c1e51f6e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -133,7 +133,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public String getAuthorizedId() { - return (_protocolSession.getAuthorizedID() != null ) ? _protocolSession.getAuthorizedID().getName() : null; + return (_protocolSession.getPrincipal() != null ) ? _protocolSession.getPrincipal().getName() : null; } public String getVersion() @@ -227,7 +227,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } - _protocolSession.commitTransactions(channel); + _protocolSession.rollbackTransactions(channel); } catch (AMQException ex) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java deleted file mode 100644 index 2abcecb6de..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeType; - -public class ExchangeInitialiser -{ - public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ - for (ExchangeType type : factory.getRegisteredTypes()) - { - define (registry, factory, type.getDefaultExchangeName(), type.getName()); - } - - define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); - registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); - } - - private void define(ExchangeRegistry r, ExchangeFactory f, - AMQShortString name, AMQShortString type) throws AMQException - { - if(r.getExchange(name)== null) - { - r.registerExchange(f.createExchange(name, type, true, false, 0)); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java new file mode 100755 index 0000000000..78e21a8f14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -0,0 +1,366 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.log4j.Logger; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.Set; + +public class MultiVersionProtocolEngine implements ProtocolEngine +{ + private static final Logger _logger = Logger.getLogger(MultiVersionProtocolEngine.class); + + + + private NetworkDriver _networkDriver; + private Set _supported; + private String _fqdn; + private IApplicationRegistry _appRegistry; + + private volatile ProtocolEngine _delegate = new SelfDelegateProtocolEngine(); + + public MultiVersionProtocolEngine(IApplicationRegistry appRegistry, + String fqdn, + Set supported, NetworkDriver networkDriver) + { + _appRegistry = appRegistry; + _fqdn = fqdn; + _supported = supported; + _networkDriver = networkDriver; + } + + public void setNetworkDriver(NetworkDriver driver) + { + _delegate.setNetworkDriver(driver); + } + + public SocketAddress getRemoteAddress() + { + return _delegate.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _delegate.getLocalAddress(); + } + + public long getWrittenBytes() + { + return _delegate.getWrittenBytes(); + } + + public long getReadBytes() + { + return _delegate.getReadBytes(); + } + + public void closed() + { + _delegate.closed(); + } + + public void writerIdle() + { + _delegate.writerIdle(); + } + + public void readerIdle() + { + _delegate.readerIdle(); + } + + public void received(ByteBuffer msg) + { + _delegate.received(msg); + } + + public void exception(Throwable t) + { + _delegate.exception(t); + } + + private static final int MINIMUM_REQUIRED_HEADER_BYTES = 8; + + private static final byte[] AMQP_0_8_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 8, + (byte) 0 + }; + + private static final byte[] AMQP_0_9_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 9 + }; + +private static final byte[] AMQP_0_9_1_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 0, + (byte) 9, + (byte) 1 + }; + + + private static final byte[] AMQP_0_10_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 10 + }; + + private static interface DelegateCreator + { + VERSION getVersion(); + byte[] getHeaderIdentifier(); + ProtocolEngine getProtocolEngine(); + } + + private DelegateCreator creator_0_8 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_8; + } + + public byte[] getHeaderIdentifier() + { + return AMQP_0_8_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + private DelegateCreator creator_0_9 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_9; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_9_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + private DelegateCreator creator_0_9_1 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_9_1; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_9_1_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + + private DelegateCreator creator_0_10 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_10; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_10_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + final ConnectionDelegate connDelegate = + new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn); + + Connection conn = new ServerConnection(); + conn.setConnectionDelegate(connDelegate); + + return new ProtocolEngine_0_10( conn, _networkDriver); + } + }; + + private final DelegateCreator[] _creators = + new DelegateCreator[] { creator_0_8, creator_0_9, creator_0_9_1, creator_0_10 }; + + + private class SelfDelegateProtocolEngine implements ProtocolEngine + { + + private final ByteBuffer _header = ByteBuffer.allocate(MINIMUM_REQUIRED_HEADER_BYTES); + + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public long getWrittenBytes() + { + return 0; + } + + public long getReadBytes() + { + return 0; + } + + public void received(ByteBuffer msg) + { + ByteBuffer msgheader = msg.duplicate(); + if(_header.remaining() > msgheader.limit()) + { + msg.position(msg.limit()); + } + else + { + msgheader.limit(_header.remaining()); + msg.position(_header.remaining()); + } + + _header.put(msgheader); + + if(!_header.hasRemaining()) + { + _header.flip(); + byte[] headerBytes = new byte[MINIMUM_REQUIRED_HEADER_BYTES]; + _header.get(headerBytes); + + + ProtocolEngine newDelegate = null; + + for(int i = 0; newDelegate == null && i < _creators.length; i++) + { + + if(_supported.contains(_creators[i].getVersion())) + { + byte[] compareBytes = _creators[i].getHeaderIdentifier(); + boolean equal = true; + for(int j = 0; equal && j ALL_VERSIONS = new HashSet(Arrays.asList(VERSION.values())); + + private final IApplicationRegistry _appRegistry; + private final String _fqdn; + private final Set _supported; + + + public MultiVersionProtocolEngineFactory() + { + this(1, "localhost", ALL_VERSIONS); + } + + public MultiVersionProtocolEngineFactory(String fqdn, Set versions) + { + this(1, fqdn, versions); + } + + + public MultiVersionProtocolEngineFactory(String fqdn) + { + this(1, fqdn, ALL_VERSIONS); + } + + public MultiVersionProtocolEngineFactory(int instance, String fqdn, Set supportedVersions) + { + _appRegistry = ApplicationRegistry.getInstance(instance); + _fqdn = fqdn; + _supported = supportedVersions; + } + + + public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) + { + return new MultiVersionProtocolEngine(_appRegistry, _fqdn, _supported, networkDriver); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java new file mode 100755 index 0000000000..7c3adf8b7d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.protocol.ProtocolEngine_0_10; + +public class ProtocolEngineFactory_0_10 implements ProtocolEngineFactory +{ + private ConnectionDelegate _delegate; + + public ProtocolEngineFactory_0_10(ConnectionDelegate delegate) + { + _delegate = delegate; + } + + public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) + { + Connection conn = new ServerConnection(); + conn.setConnectionDelegate(_delegate); + return new ProtocolEngine_0_10(conn, networkDriver); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java new file mode 100755 index 0000000000..e3cd3acd98 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.network.InputHandler; +import org.apache.qpid.transport.network.Assembler; +import org.apache.qpid.transport.network.Disassembler; + +import java.net.SocketAddress; + +public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine +{ + public static final int MAX_FRAME_SIZE = 64 * 1024 - 1; + + private NetworkDriver _networkDriver; + private long _readBytes; + private long _writtenBytes; + private Connection _connection; + + public ProtocolEngine_0_10(Connection conn, NetworkDriver networkDriver) + { + super(new Assembler(conn)); + _connection = conn; + _networkDriver = networkDriver; + } + + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + Disassembler dis = new Disassembler(driver, MAX_FRAME_SIZE); + _connection.setSender(dis); + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public long getReadBytes() + { + return _readBytes; + } + + public long getWrittenBytes() + { + return _writtenBytes; + } + + public void writerIdle() + { + //Todo + } + + public void readerIdle() + { + //Todo + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java deleted file mode 100644 index b987dae16d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionalContext; - - -import java.util.Iterator; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A deliverable message. - */ -public class AMQMessage implements Filterable -{ - /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(AMQMessage.class); - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - private final AMQMessageHandle _messageHandle; - - /** Holds the transactional context in which this message is being processed. */ - private StoreContext _storeContext; - - /** Flag to indicate that this message requires 'immediate' delivery. */ - - private static final byte IMMEDIATE = 0x01; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - - private static final byte DELIVERED_TO_CONSUMER = 0x02; - - private byte _flags = 0; - - private long _expiration; - - private final long _size; - - private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; - private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - - - - /** - * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory - * therefore is memory-efficient. - */ - private class BodyFrameIterator implements Iterator - { - private int _channel; - - private int _index = -1; - private AMQProtocolSession _protocolSession; - - private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - _channel = channel; - _protocolSession = protocolSession; - } - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Unable to get body count: " + e, e); - - return false; - } - } - - public AMQDataBlock next() - { - try - { - - AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - ++_index)); - - return new AMQFrame(_channel, cb); - } - catch (AMQException e) - { - // have no choice but to throw a runtime exception - throw new RuntimeException("Error getting content body: " + e, e); - } - - } - - private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() - { - return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public void clearStoreContext() - { - _storeContext = new StoreContext(); - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - private class BodyContentIterator implements Iterator - { - - private int _index = -1; - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Error getting body count: " + e, e); - - return false; - } - } - - public ContentChunk next() - { - try - { - return _messageHandle.getContentChunk(getStoreContext(), ++_index); - } - catch (AMQException e) - { - throw new RuntimeException("Error getting content body: " + e, e); - } - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageId - * @param store - * @param factory - * - * @throws AMQException - */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws AMQException - { - _messageHandle = factory.createMessageHandle(messageId, store, true); - _storeContext = txnConext.getStoreContext(); - _size = _messageHandle.getBodySize(txnConext.getStoreContext()); - } - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageHandle - * - * @throws AMQException - */ - public AMQMessage( - AMQMessageHandle messageHandle, - StoreContext storeConext, - MessagePublishInfo info) - throws AMQException - { - _messageHandle = messageHandle; - _storeContext = storeConext; - - if(info.isImmediate()) - { - _flags |= IMMEDIATE; - } - _size = messageHandle.getBodySize(storeConext); - - } - - - protected AMQMessage(AMQMessage msg) throws AMQException - { - _messageHandle = msg._messageHandle; - _storeContext = msg._storeContext; - _flags = msg._flags; - _size = msg._size; - - } - - - public String debugIdentity() - { - return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; - } - - public void setExpiration(final long expiration) - { - - _expiration = expiration; - - } - - public boolean isReferenced() - { - return _referenceCount.get() > 0; - } - - public Iterator getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); - } - - public Iterator getContentBodyIterator() - { - return new BodyContentIterator(); - } - - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - return _messageHandle.getContentHeaderBody(getStoreContext()); - } - - - - public Long getMessageId() - { - return _messageHandle.getMessageId(); - } - - /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic - * operation. - */ - public AMQMessage takeReference() - { - incrementReference(); // _referenceCount.incrementAndGet(); - - return this; - } - - public boolean incrementReference() - { - return incrementReference(1); - } - - /* Threadsafe. Increment the reference count on the message. */ - public boolean incrementReference(int count) - { - if(_referenceCount.addAndGet(count) <= 1) - { - _referenceCount.addAndGet(-count); - return false; - } - else - { - return true; - } - - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @param storeContext - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException - { - - int count = _referenceCount.decrementAndGet(); - - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (count == 0) - { - // set the reference count way below 0 so that we can detect that the message has been deleted - // this is to guard against the message being spontaneously recreated (from the mgmt console) - // by copying from other queues at the same time as it is being removed. - _referenceCount.set(Integer.MIN_VALUE/2); - - try - { - // must check if the handle is null since there may be cases where we decide to throw away a message - // and the handle has not yet been constructed - if (_messageHandle != null) - { - _messageHandle.removeMessage(storeContext); - } - } - catch (AMQException e) - { - // to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException(getMessageId(), e); - } - } - else - { - if (count < 0) - { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() - + " has gone below 0."); - } - } - } - - - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - public boolean getDeliveredToConsumer() - { - return (_flags & DELIVERED_TO_CONSUMER) != 0; - } - - public boolean isPersistent() throws AMQException - { - return _messageHandle.isPersistent(); - } - - /** - * Called to enforce the 'immediate' flag. - * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer - */ - public boolean immediateAndNotDelivered() - { - - return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; - - } - - public MessagePublishInfo getMessagePublishInfo() throws AMQException - { - return _messageHandle.getMessagePublishInfo(getStoreContext()); - } - - public boolean isRedelivered() - { - return _messageHandle.isRedelivered(); - } - - public void setRedelivered(boolean redelivered) - { - _messageHandle.setRedelivered(redelivered); - } - - public long getArrivalTime() - { - return _messageHandle.getArrivalTime(); - } - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @param queue The queue to check the expiration against. (Currently not used) - * - * @return true if the message has expire - * - * @throws AMQException - */ - public boolean expired(AMQQueue queue) throws AMQException - { - - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } - - return false; - } - - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - */ - public void setDeliveredToConsumer() - { - _flags |= DELIVERED_TO_CONSUMER; - } - - - - public AMQMessageHandle getMessageHandle() - { - return _messageHandle; - } - - public long getSize() - { - return _size; - - } - - public Object getPublisherClientInstance() - { - //todo store sessionIdentifier/client id with message in store - //Currently the _sessionIdentifier will be null if the message has been - // restored from a message Store - if (_sessionIdentifier == null) - { - return null; - } - else - { - return _sessionIdentifier.getSessionInstance(); - } - } - - public Object getPublisherIdentifier() - { - //todo store sessionIdentifier/client id with message in store - //Currently the _sessionIdentifier will be null if the message has been - // restored from a message Store - if (_sessionIdentifier == null) - { - return null; - } - else - { - return _sessionIdentifier.getSessionIdentifier(); - } - } - - public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) - { - _sessionIdentifier = sessionIdentifier; - } - - - public String toString() - { - // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - // _taken + " by :" + _takenBySubcription; - - return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java deleted file mode 100644 index 0ddd4e4d92..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * A pluggable way of getting message data. Implementations can provide intelligent caching for example or - * even no caching at all to minimise the broker memory footprint. - */ -public interface AMQMessageHandle -{ - ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException; - - /** - * - * @return the messageId for the message associated with this handle - */ - Long getMessageId(); - - - /** - * @return the number of body frames associated with this message - */ - int getBodyCount(StoreContext context) throws AMQException; - - /** - * @return the size of the body - */ - long getBodySize(StoreContext context) throws AMQException; - - /** - * Get a particular content body - * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 - * @return a content body - * @throws IllegalArgumentException if the index is invalid - */ - ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException; - - void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - - MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; - - boolean isRedelivered(); - - void setRedelivered(boolean redelivered); - - boolean isPersistent(); - - void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException; - - void removeMessage(StoreContext storeContext) throws AMQException; - - long getArrivalTime(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index bb6ce65d42..51fbff76f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -24,7 +24,6 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.AMQException; public class AMQPriorityQueue extends SimpleAMQQueue { @@ -34,11 +33,19 @@ public class AMQPriorityQueue extends SimpleAMQQueue final boolean autoDelete, final VirtualHost virtualHost, int priorities) - throws AMQException { super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); } + public AMQPriorityQueue(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, int priorities) + { + this(new AMQShortString(queueName), durable, new AMQShortString(owner),autoDelete,virtualHost,priorities); + } + public int getPriorities() { return ((PriorityQueueList) _entries).getPriorities(); @@ -52,16 +59,25 @@ public class AMQPriorityQueue extends SimpleAMQQueue while(subIter.advance() && !entry.isAcquired()) { final Subscription subscription = subIter.getNode().getSubscription(); - QueueEntry subnode = subscription.getLastSeenEntry(); - while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()) + if(!subscription.isClosed()) { - if(subscription.setLastSeenEntry(subnode,entry)) - { - break; - } - else + QueueContext context = (QueueContext) subscription.getQueueContext(); + if(context != null) { - subnode = subscription.getLastSeenEntry(); + QueueEntry subnode = context._lastSeenEntry; + QueueEntry released = context._releasedEntry; + while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired() && (released == null || released.compareTo(entry) < 0)) + { + if(QueueContext._releasedUpdater.compareAndSet(context,released,entry)) + { + break; + } + else + { + subnode = context._lastSeenEntry; + released = context._releasedEntry; + } + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 184504717e..c9d20c53e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,34 +20,49 @@ */ package org.apache.qpid.server.queue; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import java.util.List; import java.util.Set; +import java.util.Map; -public interface AMQQueue extends Managable, Comparable +public interface AMQQueue extends Managable, Comparable, ExchangeReferrer, TransactionLogResource { + + public interface Context + { + QueueEntry getLastSeenEntry(); + } + AMQShortString getName(); + void setNoLocal(boolean b); + boolean isDurable(); boolean isAutoDelete(); AMQShortString getOwner(); + PrincipalHolder getPrincipalHolder(); + void setPrincipalHolder(PrincipalHolder principalHolder); + + void setExclusiveOwner(Object owner); + Object getExclusiveOwner(); VirtualHost getVirtualHost(); @@ -89,17 +104,19 @@ public interface AMQQueue extends Managable, Comparable int delete() throws AMQException; - QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; + QueueEntry enqueue(ServerMessage message) throws AMQException; + + void requeue(QueueEntry entry); - void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; + void requeue(QueueEntryImpl storeContext, Subscription subscription); - void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; + void dequeue(QueueEntry entry); boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - + void addQueueDeleteTask(final Task task); @@ -113,11 +130,11 @@ public interface AMQQueue extends Managable, Comparable List getMessagesOnTheQueue(int num, int offest); QueueEntry getMessageOnTheQueue(long messageId); - + /** * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. - * - * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. + * + * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. * Using 0 in the 'to' field will return an empty list regardless of the 'from' value. * @param fromPosition * @param toPosition @@ -127,11 +144,11 @@ public interface AMQQueue extends Managable, Comparable void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext); + ServerTransaction transaction); - void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext); + void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction transaction); - void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); + void removeMessagesFromQueue(long fromMessageId, long toMessageId); @@ -171,9 +188,9 @@ public interface AMQQueue extends Managable, Comparable - void deleteMessageFromTop(StoreContext storeContext) throws AMQException; + void deleteMessageFromTop(); - long clearQueue(StoreContext storeContext) throws AMQException; + long clearQueue(); /** * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. @@ -191,6 +208,14 @@ public interface AMQQueue extends Managable, Comparable void stop(); + boolean isExclusive(); + + Exchange getAlternateExchange(); + + void setAlternateExchange(Exchange exchange); + + Map getArguments(); + void checkCapacity(AMQChannel channel); /** @@ -242,6 +267,6 @@ public interface AMQQueue extends Managable, Comparable } void configure(QueueConfiguration config); - + ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 267ccf43ea..d4a5b3258b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -27,7 +27,6 @@ import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; -import java.util.HashMap; public class AMQQueueFactory @@ -130,7 +129,6 @@ public class AMQQueueFactory AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, final FieldTable arguments) - throws AMQException { final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; @@ -189,4 +187,39 @@ public class AMQQueueFactory q.configure(config); return q; } + + public static AMQQueue createAMQQueueImpl(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, Map arguments) + throws AMQException + { + int priorities = 1; + if(arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) + { + Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); + if(prioritiesObj instanceof Number) + { + priorities = ((Number)prioritiesObj).intValue(); + } + } + + + AMQQueue q = null; + if(priorities > 1) + { + q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities); + } + else + { + q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost); + } + + //Register the new queue + virtualHost.getQueueRegistry().registerQueue(q); + q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); + return q; + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index d340c9a91f..8e5310bc16 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -22,23 +22,21 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; - import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; import javax.management.JMException; -import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.OperationsException; @@ -72,12 +70,6 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); - /** - * Since the MBean is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - private StoreContext _storeContext = new StoreContext(); - private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method @@ -131,7 +123,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("Message Content", "AMQ Message Content", + _msgContentType = new CompositeType("Message Content", "AMQ Message Content", VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS, _msgContentAttributeTypes); @@ -141,9 +133,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered _msgAttributeTypes[4] = SimpleType.LONG; // For queue position - _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, + _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, VIEW_MSGS_TABULAR_UNIQUE_INDEX); } @@ -164,7 +156,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public String getOwner() { - return String.valueOf(_queue.getOwner()); + return String.valueOf(_queue.getPrincipalHolder() == null + ? null + : _queue.getPrincipalHolder().getPrincipal() == null + ? null + : _queue.getPrincipalHolder().getPrincipal().getName()); } public boolean isAutoDelete() @@ -246,7 +242,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que /** * Checks if there is any notification to be send to the listeners */ - public void checkForNotification(AMQMessage msg) throws AMQException + public void checkForNotification(ServerMessage msg) throws AMQException { final Set notificationChecks = _queue.getNotificationChecks(); @@ -296,32 +292,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public void deleteMessageFromTop() throws JMException { - try - { - _queue.deleteMessageFromTop(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } + _queue.deleteMessageFromTop(); } /** * Clears the queue of non-acquired messages - * + * * @return the number of messages deleted * @see AMQQueue#clearQueue */ public Long clearQueue() throws JMException { - try - { - return _queue.clearQueue(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } + return _queue.clearQueue(); } /** @@ -336,49 +318,41 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } - AMQMessage msg = entry.getMessage(); - // get message content - Iterator cBodies = msg.getContentBodyIterator(); + ServerMessage serverMsg = entry.getMessage(); + final int bodySize = (int) serverMsg.getSize(); + + List msgContent = new ArrayList(); - while (cBodies.hasNext()) - { - ContentChunk body = cBodies.next(); - if (body.getSize() != 0) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.getData().slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - } - try + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(bodySize); + int position = 0; + + while(position < bodySize) { - // Create header attributes list - CommonContentHeaderProperties headerProperties = - (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) + position += serverMsg.getContent(buf, position); + buf.flip(); + for(int i = 0; i < buf.limit(); i++) { - AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); - encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); + msgContent.add(buf.get(i)); } + buf.clear(); + } - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + AMQMessageHeader header = serverMsg.getMessageHeader(); - return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); - } - catch (AMQException e) + String mimeType = null, encoding = null; + if (header != null) { - JMException jme = new JMException("Error creating header attributes list: " + e); - jme.initCause(e); - throw jme; + mimeType = header.getMimeType(); + + encoding = header.getEncoding(); } + + + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + + return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); + } /** @@ -390,8 +364,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { return viewMessages((long)beginIndex,(long)endIndex); } - - + + /** * Returns the header contents of the messages stored in this queue in tabular form. * @param startPosition The queue position of the first message to be viewed @@ -404,7 +378,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); } - + if ((endPosition - startPosition) > Integer.MAX_VALUE) { throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size"); @@ -421,13 +395,22 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que for (int i = 0; i < size ; i++) { long position = startPosition + i; - AMQMessage msg = list.get(i).getMessage(); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); + final QueueEntry queueEntry = list.get(i); + ServerMessage serverMsg = queueEntry.getMessage(); + if(serverMsg instanceof AMQMessage) + { + AMQMessage msg = (AMQMessage) serverMsg; + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + String[] headerAttributes = getMessageHeaderProperties(headerBody); + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); + _messageList.put(messageData); + } + else + { + // TODO 0-10 Message + } } } catch (AMQException e) @@ -484,7 +467,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); + txn.commit(); } /** @@ -500,9 +485,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.removeMessagesFromQueue(fromMessageId, toMessageId, _storeContext); + _queue.removeMessagesFromQueue(fromMessageId, toMessageId); } - + /** * @see ManagedQueue#copyMessages * @param fromMessageId @@ -517,9 +502,15 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + + _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); + + txn.commit(); + + } - + /** * returns Notifications sent by this MBean. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index cbe9246f09..aea485e749 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -44,12 +44,12 @@ public class DefaultQueueRegistry implements QueueRegistry return _virtualHost; } - public void registerQueue(AMQQueue queue) throws AMQException + public void registerQueue(AMQQueue queue) { _queueMap.put(queue.getName(), queue); } - public void unregisterQueue(AMQShortString name) throws AMQException + public void unregisterQueue(AMQShortString name) { _queueMap.remove(name); } @@ -68,4 +68,9 @@ public class DefaultQueueRegistry implements QueueRegistry { return _queueMap.values(); } + + public AMQQueue getQueue(String queue) + { + return getQueue(new AMQShortString(queue)); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java index d38932bb61..eaa3992e98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java @@ -22,12 +22,13 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.AMQMessageHeader; -public interface Filterable +public interface Filterable { - ContentHeaderBody getContentHeaderBody() throws E; + AMQMessageHeader getMessageHeader(); - boolean isPersistent() throws E; + boolean isPersistent(); boolean isRedelivered(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java deleted file mode 100644 index 35ad5be4e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.Collections; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.StoreContext; - -/** - */ -public class InMemoryMessageHandle implements AMQMessageHandle -{ - - private ContentHeaderBody _contentHeaderBody; - - private MessagePublishInfo _messagePublishInfo; - - private List _contentBodies; - - private boolean _redelivered; - - private long _arrivalTime; - - private final Long _messageId; - - public InMemoryMessageHandle(final Long messageId) - { - _messageId = messageId; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - return _contentHeaderBody; - } - - public Long getMessageId() - { - return _messageId; - } - - public int getBodyCount(StoreContext context) - { - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - return _contentBodies.get(index); - } - - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) - throws AMQException - { - if(_contentBodies == null) - { - if(isLastContentBody) - { - _contentBodies = Collections.singletonList(contentBody); - } - else - { - _contentBodies = new ArrayList(); - _contentBodies.add(contentBody); - } - } - else - { - _contentBodies.add(contentBody); - } - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - return _messagePublishInfo; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent() - { - return false; - } - - /** - * This is called when all the content has been received. - * @param messagePublishInfo - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _messagePublishInfo = messagePublishInfo; - _contentHeaderBody = contentHeaderBody; - if(contentHeaderBody.bodySize == 0) - { - _contentBodies = Collections.EMPTY_LIST; - } - _arrivalTime = System.currentTimeMillis(); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - // NO OP - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java new file mode 100755 index 0000000000..77da08d8c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; + +class InboundMessageAdapter implements InboundMessage +{ + + private QueueEntry _entry; + + InboundMessageAdapter() + { + } + + InboundMessageAdapter(QueueEntry entry) + { + _entry = entry; + } + + public void setEntry(QueueEntry entry) + { + _entry = entry; + } + + + public String getRoutingKey() + { + return _entry.getMessage().getRoutingKey(); + } + + public AMQMessageHeader getMessageHeader() + { + return _entry.getMessageHeader(); + } + + public boolean isPersistent() + { + return _entry.isPersistent(); + } + + public boolean isRedelivered() + { + return _entry.isRedelivered(); + } + + public long getSize() + { + return _entry.getSize(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index d5e0b4d187..da4173d5d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -25,19 +25,22 @@ import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.MessageContentSource; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; +import java.nio.ByteBuffer; -public class IncomingMessage implements Filterable +public class IncomingMessage implements Filterable, InboundMessage, EnqueableMessage, MessageContentSource { /** Used for debugging purposes. */ @@ -48,12 +51,6 @@ public class IncomingMessage implements Filterable private final MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; - private AMQMessageHandle _messageHandle; - private final Long _messageId; - private final TransactionalContext _txnContext; - - private static final boolean MSG_AUTH = - ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); /** @@ -68,23 +65,27 @@ public class IncomingMessage implements Filterable */ private ArrayList _destinationQueues; - private AMQProtocolSession _publisher; - private MessageStore _messageStore; private long _expiration; - + private Exchange _exchange; - public IncomingMessage(final Long messageId, - final MessagePublishInfo info, - final TransactionalContext txnContext, - final AMQProtocolSession publisher) + private int _receivedChunkCount = 0; + private List _contentChunks = new ArrayList(); + + // we keep both the original meta data object and the store reference to it just in case the + // store would otherwise flow it to disk + + private MessageMetaData _messageMetaData; + + private StoredMessage _storedMessageHandle; + + + public IncomingMessage( + final MessagePublishInfo info + ) { - _messageId = messageId; _messagePublishInfo = info; - _txnContext = txnContext; - _publisher = publisher; - } public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException @@ -123,183 +124,94 @@ public class IncomingMessage implements Filterable } - public void routingComplete(final MessageStore store, - final MessageHandleFactory factory) throws AMQException + public MessageMetaData headersReceived() { - - final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(_messageId, store, persistent); - if (persistent) - { - _txnContext.beginTranIfNecessary(); - // enqueuing the messages ensure that if required the destinations are recorded to a - // persistent store - - if(_destinationQueues != null) - { - for (int i = 0; i < _destinationQueues.size(); i++) - { - store.enqueueMessage(_txnContext.getStoreContext(), - _destinationQueues.get(i), _messageId); - } - } - } + _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0); + return _messageMetaData; } - public AMQMessage deliverToQueues() - throws AMQException - { - - // we get a reference to the destination queues now so that we can clear the - // transient message data as quickly as possible - if (_logger.isDebugEnabled()) - { - _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); - } - - AMQMessage message = null; - - try - { - // first we allow the handle to know that the message has been fully received. This is useful if it is - // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), - _messagePublishInfo, getContentHeaderBody()); - - - - message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); - - message.setExpiration(_expiration); - message.setClientIdentifier(_publisher.getSessionIdentifier()); - - // 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()); - - AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; - - if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) - { - throw new UnauthorizedAccessException("Acccess Refused",message); - } - - if ((_destinationQueues == null) || _destinationQueues.size() == 0) - { - - if (isMandatory() || isImmediate()) - { - throw new NoRouteException("No Route for message", message); - - } - else - { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + message); - } - } - else - { - int offset; - final int queueCount = _destinationQueues.size(); - message.incrementReference(queueCount); - if(queueCount == 1) - { - offset = 0; - } - else - { - offset = ((int)(message.getMessageId().longValue())) % queueCount; - if(offset < 0) - { - offset = -offset; - } - } - for (int i = offset; i < queueCount; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); - } - for (int i = 0; i < offset; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); - } - } - - message.clearStoreContext(); - return message; - } - finally - { - // Remove refence for routing process . Reference count should now == delivered queue count - if(message != null) message.decrementReference(_txnContext.getStoreContext()); - } + public ArrayList getDestinationQueues() + { + return _destinationQueues; } - public void addContentBodyFrame(final ContentChunk contentChunk) + public int addContentBodyFrame(final ContentChunk contentChunk) throws AMQException { - + _storedMessageHandle.addContent((int)_bodyLengthReceived, contentChunk.getData().buf()); _bodyLengthReceived += contentChunk.getSize(); + _contentChunks.add(contentChunk); + - _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); + return _receivedChunkCount++; } public boolean allContentReceived() { - return (_bodyLengthReceived == getContentHeaderBody().bodySize); + return (_bodyLengthReceived == getContentHeader().bodySize); } - public AMQShortString getExchange() throws AMQException + public AMQShortString getExchange() { return _messagePublishInfo.getExchange(); } - public AMQShortString getRoutingKey() throws AMQException + public String getRoutingKey() { - return _messagePublishInfo.getRoutingKey(); + return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString(); } - public boolean isMandatory() throws AMQException + public String getBinding() + { + return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString(); + } + + + public boolean isMandatory() { return _messagePublishInfo.isMandatory(); } - public boolean isImmediate() throws AMQException + public boolean isImmediate() { return _messagePublishInfo.isImmediate(); } - public ContentHeaderBody getContentHeaderBody() + public ContentHeaderBody getContentHeader() { return _contentHeaderBody; } + public AMQMessageHeader getMessageHeader() + { + return _messageMetaData.getMessageHeader(); + } + public boolean isPersistent() { - return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == + return getContentHeader().properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) getContentHeader().properties).getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; } - + public boolean isRedelivered() { return false; } - public void setMessageStore(final MessageStore messageStore) + + public long getSize() { - _messageStore = messageStore; + return getContentHeader().bodySize; } - public Long getMessageId() + public Long getMessageNumber() { - return _messageId; + return _storedMessageHandle.getMessageNumber(); } public void setExchange(final Exchange e) @@ -307,13 +219,82 @@ public class IncomingMessage implements Filterable _exchange = e; } - public void route() throws AMQException + public void route() { - _exchange.route(this); + enqueue(_exchange.route(this)); + } public void enqueue(final ArrayList queues) { _destinationQueues = queues; } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public long getExpiration() + { + return _expiration; + } + + public int getReceivedChunkCount() + { + return _receivedChunkCount; + } + + + public int getBodyCount() throws AMQException + { + return _contentChunks.size(); + } + + public ContentChunk getContentChunk(int index) throws IllegalArgumentException, AMQException + { + return _contentChunks.get(index); + } + + + public int getContent(ByteBuffer buf, int offset) + { + int pos = 0; + int written = 0; + for(ContentChunk cb : _contentChunks) + { + ByteBuffer data = cb.getData().buf(); + if(offset+written >= pos && offset < pos + data.limit()) + { + ByteBuffer src = data.duplicate(); + src.position(offset+written - pos); + src = src.slice(); + + if(buf.remaining() < src.limit()) + { + src.limit(buf.remaining()); + } + int count = src.limit(); + buf.put(src); + written += count; + if(buf.remaining() == 0) + { + break; + } + } + pos+=data.limit(); + } + return written; + + } + + public void setStoredMessage(StoredMessage storedMessageHandle) + { + _storedMessageHandle = storedMessageHandle; + } + + public StoredMessage getStoredMessage() + { + return _storedMessageHandle; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java deleted file mode 100644 index 0b214ca336..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.store.MessageStore; - -/** - * Constructs a message handle based on the publish body, the content header and the queue to which the message - * has been routed. - * - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class MessageHandleFactory -{ - - public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) - { - // just hardcoded for now - if (persistent) - { - return new WeakReferenceMessageHandle(messageId, store); - } - else - { - return new InMemoryMessageHandle(messageId); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java deleted file mode 100644 index 6118a4c11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * Encapsulates a publish body and a content header. In the context of the message store these are treated as a - * single unit. - */ -public class MessageMetaData -{ - private MessagePublishInfo _messagePublishInfo; - - private ContentHeaderBody _contentHeaderBody; - - private int _contentChunkCount; - - private long _arrivalTime; - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) - { - this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); - } - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) - { - _contentHeaderBody = contentHeaderBody; - _messagePublishInfo = publishBody; - _contentChunkCount = contentChunkCount; - _arrivalTime = arrivalTime; - } - - public int getContentChunkCount() - { - return _contentChunkCount; - } - - public void setContentChunkCount(int contentChunkCount) - { - _contentChunkCount = contentChunkCount; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public void setArrivalTime(long arrivalTime) - { - _arrivalTime = arrivalTime; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java deleted file mode 100644 index d6fd1eec89..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate - * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is - * always used to report this condition. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represent failure to deliver a message that must be delivered. - *
      - */ -public class NoConsumersException extends RequiredDeliveryException -{ - public NoConsumersException(AMQMessage message) - { - super("Immediate delivery is not possible.", message); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_CONSUMERS; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 6f9efd3200..d1fb0f3fe6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -21,13 +21,14 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.ServerMessage; public enum NotificationCheck { MESSAGE_COUNT_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener) { int msgCount; final long maximumMessageCount = queue.getMaximumMessageCount(); @@ -41,26 +42,19 @@ public enum NotificationCheck }, MESSAGE_SIZE_ALERT(true) { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener) { final long maximumMessageSize = queue.getMaximumMessageSize(); if(maximumMessageSize != 0) { // Check for threshold message size long messageSize; - try - { - messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize; - } - catch (AMQException e) - { - messageSize = 0; - } + messageSize = (msg == null) ? 0 : msg.getSize(); if (messageSize >= maximumMessageSize) { - listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]"); + listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageNumber() + "]"); return true; } } @@ -70,7 +64,7 @@ public enum NotificationCheck }, QUEUE_DEPTH_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener) { // Check for threshold queue depth in bytes final long maximumQueueDepth = queue.getMaximumQueueDepth(); @@ -91,7 +85,7 @@ public enum NotificationCheck }, MESSAGE_AGE_ALERT { - boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener) + boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener) { final long maxMessageAge = queue.getMaximumMessageAge(); @@ -133,6 +127,6 @@ public enum NotificationCheck return _messageSpecific; } - abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener); + abstract boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java index fd46a8a5ff..0c6b84d2b6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.ServerMessage; public class PriorityQueueList implements QueueEntryList { @@ -52,26 +53,18 @@ public class PriorityQueueList implements QueueEntryList return _queue; } - public QueueEntry add(AMQMessage message) + public QueueEntry add(ServerMessage message) { - try + int index = message.getMessageHeader().getPriority() - _priorityOffset; + if(index >= _priorities) { - int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if(index >= _priorities) - { - index = _priorities-1; - } - else if(index < 0) - { - index = 0; - } - return _priorityLists[index].add(message); + index = _priorities-1; } - catch (AMQException e) + else if(index < 0) { - // TODO - fix AMQ Exception - throw new RuntimeException(e); + index = 0; } + return _priorityLists[index].add(message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java new file mode 100755 index 0000000000..825a85a89c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +final class QueueContext implements AMQQueue.Context +{ + volatile QueueEntry _lastSeenEntry; + volatile QueueEntry _releasedEntry; + + static final AtomicReferenceFieldUpdater + _lastSeenUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueContext.class, QueueEntry.class, "_lastSeenEntry"); + static final AtomicReferenceFieldUpdater + _releasedUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueContext.class, QueueEntry.class, "_releasedEntry"); + + public QueueContext(QueueEntry head) + { + _lastSeenEntry = head; + } + + public QueueEntry getLastSeenEntry() + { + return _lastSeenEntry; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 2657c459a9..a50e2b561d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -1,8 +1,8 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,18 +24,19 @@ import org.apache.qpid.server.subscription.Subscription; * under the License. * */ -public interface QueueEntry extends Comparable +public interface QueueEntry extends Comparable, Filterable { - public static enum State { AVAILABLE, ACQUIRED, EXPIRED, DEQUEUED, - DELETED + DELETED; + + } public static interface StateChangeListener @@ -121,6 +122,27 @@ public interface QueueEntry extends Comparable } } + public final class SubscriptionAssignedState extends EntryState + { + private final Subscription _subscription; + + public SubscriptionAssignedState(Subscription subscription) + { + _subscription = subscription; + } + + + public State getState() + { + return State.AVAILABLE; + } + + public Subscription getSubscription() + { + return _subscription; + } + } + final static EntryState AVAILABLE_STATE = new AvailableState(); final static EntryState DELETED_STATE = new DeletedState(); @@ -133,7 +155,7 @@ public interface QueueEntry extends Comparable AMQQueue getQueue(); - AMQMessage getMessage(); + ServerMessage getMessage(); long getSize(); @@ -150,16 +172,17 @@ public interface QueueEntry extends Comparable boolean isDeleted(); boolean acquiredBySubscription(); - - void setDeliveredToSubscription(); + boolean isAcquiredBy(Subscription subscription); void release(); + boolean releaseButRetain(); - String debugIdentity(); boolean immediateAndNotDelivered(); - void setRedelivered(boolean b); + void setRedelivered(); + + boolean isRedelivered(); Subscription getDeliveredSubscription(); @@ -169,13 +192,15 @@ public interface QueueEntry extends Comparable boolean isRejectedBy(Subscription subscription); - void requeue(StoreContext storeContext) throws AMQException; + void requeue(Subscription subscription); + + void dequeue(); - void dequeue(final StoreContext storeContext) throws FailedDequeueException; + void dispose(); - void dispose(final StoreContext storeContext) throws MessageCleanupException; + void discard(); - void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException; + void routeToAlternate(); boolean isQueueDeleted(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 3b58f05f93..5873e8f566 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -21,12 +21,16 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; import org.apache.log4j.Logger; -import java.util.Set; -import java.util.HashSet; +import java.util.*; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.CopyOnWriteArraySet; @@ -42,7 +46,7 @@ public class QueueEntryImpl implements QueueEntry private final SimpleQueueEntryList _queueEntryList; - private final AMQMessage _message; + private MessageReference _message; private Set _rejectedBy = null; @@ -75,6 +79,11 @@ public class QueueEntryImpl implements QueueEntry volatile QueueEntryImpl _next; + private static final int DELIVERED_TO_CONSUMER = 1; + private static final int REDELIVERED = 2; + + private volatile int _deliveryState; + QueueEntryImpl(SimpleQueueEntryList queueEntryList) { @@ -83,18 +92,19 @@ public class QueueEntryImpl implements QueueEntry } - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId) { _queueEntryList = queueEntryList; - _message = message; + + _message = message == null ? null : message.newReference(); _entryIdUpdater.set(this, entryId); } - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message) { _queueEntryList = queueEntryList; - _message = message; + _message = message == null ? null : message.newReference(); } protected void setEntryId(long entryId) @@ -112,24 +122,36 @@ public class QueueEntryImpl implements QueueEntry return _queueEntryList.getQueue(); } - public AMQMessage getMessage() + public ServerMessage getMessage() { - return _message; + return _message == null ? null : _message.getMessage(); } public long getSize() { - return getMessage().getSize(); + return getMessage() == null ? 0 : getMessage().getSize(); } public boolean getDeliveredToConsumer() { - return getMessage().getDeliveredToConsumer(); + return (_deliveryState & DELIVERED_TO_CONSUMER) != 0; } public boolean expired() throws AMQException { - return getMessage().expired(getQueue()); + ServerMessage message = getMessage(); + if(message != null) + { + long expiration = message.getExpiration(); + if (expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > expiration); + } + } + return false; + } public boolean isAcquired() @@ -145,6 +167,24 @@ public class QueueEntryImpl implements QueueEntry private boolean acquire(final EntryState state) { boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state); + + // deal with the case where the node has been assigned to a given subscription already + // including the case that the node is assigned to a closed subscription + if(!acquired) + { + if(state != NON_SUBSCRIPTION_ACQUIRED_STATE) + { + EntryState currentState = _state; + if(currentState.getState() == State.AVAILABLE + && ((currentState == AVAILABLE_STATE) + || (((SubscriptionAcquiredState)state).getSubscription() == + ((SubscriptionAssignedState)currentState).getSubscription()) + || ((SubscriptionAssignedState)currentState).getSubscription().isClosed() )) + { + acquired = _stateUpdater.compareAndSet(this,currentState, state); + } + } + } if(acquired && _stateChangeListeners != null) { notifyStateChange(State.AVAILABLE, State.ACQUIRED); @@ -155,7 +195,12 @@ public class QueueEntryImpl implements QueueEntry public boolean acquire(Subscription sub) { - return acquire(sub.getOwningState()); + final boolean acquired = acquire(sub.getOwningState()); + if(acquired) + { + _deliveryState |= DELIVERED_TO_CONSUMER; + } + return acquired; } public boolean acquiredBySubscription() @@ -164,38 +209,89 @@ public class QueueEntryImpl implements QueueEntry return (_state instanceof SubscriptionAcquiredState); } - public void setDeliveredToSubscription() + public boolean isAcquiredBy(Subscription subscription) { - getMessage().setDeliveredToConsumer(); + EntryState state = _state; + return state instanceof SubscriptionAcquiredState + && ((SubscriptionAcquiredState)state).getSubscription() == subscription; } public void release() { _stateUpdater.set(this,AVAILABLE_STATE); - } + if(!getQueue().isDeleted()) + { + getQueue().requeue(this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } - public String debugIdentity() - { - AMQMessage message = getMessage(); - if (message == null) + } + else if(acquire()) { - return "null"; + routeToAlternate(); } - else + + + } + + public boolean releaseButRetain() + { + EntryState state = _state; + + boolean stateUpdated = false; + + if(state instanceof SubscriptionAcquiredState) { - return message.debugIdentity(); + Subscription sub = ((SubscriptionAcquiredState) state).getSubscription(); + if(_stateUpdater.compareAndSet(this, state, sub.getAssignedState())) + { + System.err.println("Message released (and retained)" + getMessage().getMessageNumber()); + getQueue().requeue(this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } + stateUpdated = true; + } } + + return stateUpdated; + } + public boolean immediateAndNotDelivered() + { + return !getDeliveredToConsumer() && isImmediate(); + } + + private boolean isImmediate() + { + final ServerMessage message = getMessage(); + return message != null && message.isImmediate(); + } - public boolean immediateAndNotDelivered() + public void setRedelivered() { - return getMessage().immediateAndNotDelivered(); + _deliveryState |= REDELIVERED; } - public void setRedelivered(boolean b) + public AMQMessageHeader getMessageHeader() { - getMessage().setRedelivered(b); + final ServerMessage message = getMessage(); + return message == null ? null : message.getMessageHeader(); + } + + public boolean isPersistent() + { + final ServerMessage message = getMessage(); + return message != null && message.isPersistent(); + } + + public boolean isRedelivered() + { + return (_deliveryState & REDELIVERED) != 0; } public Subscription getDeliveredSubscription() @@ -230,12 +326,12 @@ public class QueueEntryImpl implements QueueEntry } else { - _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + _log.warn("Requesting rejection by null subscriber:" + this); } } public boolean isRejectedBy(Subscription subscription) - { + { if (_rejectedBy != null) // We have subscriptions that rejected this message { @@ -247,17 +343,16 @@ public class QueueEntryImpl implements QueueEntry } } - - public void requeue(final StoreContext storeContext) throws AMQException + public void requeue(Subscription subscription) { - getQueue().requeue(storeContext, this); + getQueue().requeue(this, subscription); if(_stateChangeListeners != null) { notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); } } - public void dequeue(final StoreContext storeContext) throws FailedDequeueException + public void dequeue() { EntryState state = _state; @@ -266,10 +361,10 @@ public class QueueEntryImpl implements QueueEntry if (state instanceof SubscriptionAcquiredState) { Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); - s.restoreCredit(this); + s.onDequeue(this); } - getQueue().dequeue(storeContext, this); + getQueue().dequeue(this); if(_stateChangeListeners != null) { notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); @@ -287,23 +382,74 @@ public class QueueEntryImpl implements QueueEntry } } - public void dispose(final StoreContext storeContext) throws MessageCleanupException + public void dispose() { if(delete()) { - getMessage().decrementReference(storeContext); + _message.release(); } } - public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + public void discard() { //if the queue is null then the message is waiting to be acked, but has been removed. if (getQueue() != null) { - dequeue(storeContext); + dequeue(); } - dispose(storeContext); + dispose(); + } + + public void routeToAlternate() + { + final AMQQueue currentQueue = getQueue(); + Exchange alternateExchange = currentQueue.getAlternateExchange(); + + if(alternateExchange != null) + { + final List rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); + final ServerMessage message = getMessage(); + if(rerouteQueues != null && rerouteQueues.size() != 0) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + + txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() { + public void postCommit() + { + try + { + for(AMQQueue queue : rerouteQueues) + { + QueueEntry entry = queue.enqueue(message); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + public void onRollback() + { + + } + }); + txn.dequeue(currentQueue,message, + new ServerTransaction.Action() + { + public void postCommit() + { + discard(); + } + + public void onRollback() + { + + } + }); + } + } } public boolean isQueueDeleted() @@ -379,7 +525,7 @@ public class QueueEntryImpl implements QueueEntry if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) { - _queueEntryList.advanceHead(); + _queueEntryList.advanceHead(); return true; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index 313e076f61..b4042ce02c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -20,11 +20,13 @@ */ package org.apache.qpid.server.queue; +import org.apache.qpid.server.message.ServerMessage; + public interface QueueEntryList { AMQQueue getQueue(); - QueueEntry add(AMQMessage message); + QueueEntry add(ServerMessage message); QueueEntry next(QueueEntry node); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index 1210f0e97c..a537e0c83f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -30,9 +30,9 @@ public interface QueueRegistry { VirtualHost getVirtualHost(); - void registerQueue(AMQQueue queue) throws AMQException; + void registerQueue(AMQQueue queue); - void unregisterQueue(AMQShortString name) throws AMQException; + void unregisterQueue(AMQShortString name); AMQQueue getQueue(AMQShortString name); @@ -40,4 +40,5 @@ public interface QueueRegistry Collection getQueues(); + AMQQueue getQueue(String queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d781dc4dea..77a6fb9328 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -3,12 +3,9 @@ package org.apache.qpid.server.queue; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import javax.management.JMException; @@ -21,13 +18,12 @@ import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.QueueActor; import org.apache.qpid.server.logging.subjects.QueueLogSubject; @@ -35,6 +31,9 @@ import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.messages.QueueMessages; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; /* * @@ -60,24 +59,40 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + private final VirtualHost _virtualHost; + private final AMQShortString _name; + private final String _resourceName; /** null means shared */ private final AMQShortString _owner; + private PrincipalHolder _prinicpalHolder; + + private Object _exclusiveOwner; + + private final boolean _durable; /** If true, this queue is deleted when the last subscriber is removed */ private final boolean _autoDelete; - private final VirtualHost _virtualHost; + private Exchange _alternateExchange; /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ private final ExchangeBindings _bindings = new ExchangeBindings(this); - private final AtomicBoolean _deleted = new AtomicBoolean(false); - private final List _deleteTaskList = new CopyOnWriteArrayList(); + protected final QueueEntryList _entries; + + protected final SubscriptionList _subscriptionList = new SubscriptionList(this); + + private final AtomicReference _lastSubscriptionNode = new AtomicReference(_subscriptionList.getHead()); + + private volatile Subscription _exclusiveSubscriber; + + private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); @@ -85,18 +100,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); - protected final SubscriptionList _subscriptionList = new SubscriptionList(this); - private final AtomicReference _lastSubscriptionNode = new AtomicReference(_subscriptionList.getHead()); - - private volatile Subscription _exclusiveSubscriber; + private final AtomicLong _totalMessagesReceived = new AtomicLong(); - protected final QueueEntryList _entries; - private final AMQQueueMBean _managedObject; - private final Executor _asyncDelivery; - private final AtomicLong _totalMessagesReceived = new AtomicLong(); - private final ConcurrentMap _blockedChannels = new ConcurrentHashMap(); /** max allowed size(KB) of a single message */ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); @@ -113,24 +120,38 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener /** the minimum interval between sending out consecutive alerts of the same type */ public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); - private static final int MAX_ASYNC_DELIVERIES = 10; + private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); + + private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); private final Set _notificationChecks = EnumSet.noneOf(NotificationCheck.class); + + static final int MAX_ASYNC_DELIVERIES = 10; + + private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); private AtomicReference _asynchronousRunner = new AtomicReference(null); + private final Executor _asyncDelivery; private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); + + private final ConcurrentMap _blockedChannels = new ConcurrentHashMap(); + + private final AtomicBoolean _deleted = new AtomicBoolean(false); + private final List _deleteTaskList = new CopyOnWriteArrayList(); + + private LogSubject _logSubject; private LogActor _logActor; + private AMQQueueMBean _managedObject; + private static final String SUB_FLUSH_RUNNER = "SUB_FLUSH_RUNNER"; + private boolean _nolocal; - private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); - private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); private final AtomicBoolean _overfull = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException { this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); } @@ -141,7 +162,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory) - throws AMQException { if (name == null) @@ -155,6 +175,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _name = name; + _resourceName = String.valueOf(name); _durable = durable; _owner = owner; _autoDelete = autoDelete; @@ -193,13 +214,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } catch (JMException e) { - throw new AMQException("AMQQueue MBean creation has failed ", e); + _logger.error("AMQQueue MBean creation has failed ", e); } resetNotifications(); } + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException + { + this(new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost); + } + public void resetNotifications() { // This ensure that the notification checks for the configured alerts are created. @@ -211,16 +238,54 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Getters and Setters + public void execute(ReadWriteRunnable runnable) + { + _asyncDelivery.execute(runnable); + } + public AMQShortString getName() { return _name; } + public void setNoLocal(boolean nolocal) + { + _nolocal = nolocal; + } + public boolean isDurable() { return _durable; } + public boolean isExclusive() + { + return _exclusiveOwner != null; + } + + public Exchange getAlternateExchange() + { + return _alternateExchange; + } + + public void setAlternateExchange(Exchange exchange) + { + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + if(exchange != null) + { + exchange.addReference(this); + } + _alternateExchange = exchange; + } + + public Map getArguments() + { + return null; + } + public boolean isAutoDelete() { return _autoDelete; @@ -231,6 +296,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _owner; } + public PrincipalHolder getPrincipalHolder() + { + return _prinicpalHolder; + } + + public void setPrincipalHolder(PrincipalHolder prinicpalHolder) + { + _prinicpalHolder = prinicpalHolder; + } + + public VirtualHost getVirtualHost() { return _virtualHost; @@ -238,13 +314,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ bind and unbind + public void bind(Exchange exchange, String bindingKey, Map arguments) throws AMQException + { + + FieldTable fieldTable = FieldTable.convertToFieldTable(arguments); + AMQShortString routingKey = new AMQShortString(bindingKey); + + exchange.registerQueue(routingKey, this, fieldTable); + + if (isDurable() && exchange.isDurable()) + { + + _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, fieldTable); + } + + _bindings.addBinding(routingKey, fieldTable, exchange); + } + + public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException { exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, arguments); } _bindings.addBinding(routingKey, arguments, exchange); @@ -255,7 +349,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + _virtualHost.getDurableConfigurationStore().unbindQueue(exchange, routingKey, this, arguments); } boolean removed = _bindings.remove(routingKey, arguments, exchange); @@ -295,11 +389,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _activeSubscriberCount.incrementAndGet(); subscription.setStateListener(this); - subscription.setLastSeenEntry(null, _entries.getHead()); + subscription.setQueueContext(new QueueContext(_entries.getHead())); if (!isDeleted()) { subscription.setQueue(this, exclusive); + if(_nolocal) + { + subscription.setNoLocal(_nolocal); + } _subscriptionList.add(subscription); if (isDeleted()) { @@ -329,17 +427,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener subscription.close(); // No longer can the queue have an exclusive consumer setExclusiveSubscriber(null); - - QueueEntry lastSeen; - - while ((lastSeen = subscription.getLastSeenEntry()) != null) - { - subscription.setLastSeenEntry(lastSeen, null); - } + subscription.setQueueContext(null); // auto-delete queues must be deleted if there are no remaining subscribers - if (_autoDelete && getConsumerCount() == 0) + if (_autoDelete && getConsumerCount() == 0 && !isExclusive()) { if (_logger.isInfoEnabled()) { @@ -358,7 +450,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Enqueue / Dequeue - public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException + public QueueEntry enqueue(ServerMessage message) throws AMQException { incrementQueueCount(); @@ -378,14 +470,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener entry = _entries.add(message); deliverToSubscription(exclusiveSub, entry); - - // where there is more than one producer there's a reasonable chance that even though there is - // no "queueing" we do not deliver because we get an interleving of _entries.add and - // deliverToSubscription between threads. Therefore have one more try. - if (!(entry.isAcquired() || entry.isDeleted())) - { - deliverToSubscription(exclusiveSub, entry); - } } finally { @@ -445,19 +529,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - if (entry.immediateAndNotDelivered()) - { - dequeue(storeContext, entry); - entry.dispose(storeContext); - } - else if (!(entry.isAcquired() || entry.isDeleted())) + + if (!(entry.isAcquired() || entry.isDeleted())) { checkSubscriptionsNotAheadOfDelivery(entry); deliverAsync(); } - _managedObject.checkForNotification(entry.getMessage()); + if(_managedObject != null) + { + _managedObject.checkForNotification(entry.getMessage()); + } return entry; } @@ -474,17 +557,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if (!sub.wouldSuspend(entry)) { - if (!sub.isBrowser() && !entry.acquire(sub)) + if (sub.acquires() && !entry.acquire(sub)) { // restore credit here that would have been taken away by wouldSuspend since we didn't manage // to acquire the entry for this subscription - sub.restoreCredit(entry); + sub.onDequeue(entry); } else { - deliverMessage(sub, entry); - } } } @@ -501,7 +582,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Simple Queues don't :-) } - private void incrementQueueSize(final AMQMessage message) + private void incrementQueueSize(final ServerMessage message) { getAtomicQueueSize().addAndGet(message.getSize()); } @@ -515,76 +596,48 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throws AMQException { _deliveredMessages.incrementAndGet(); - if (_logger.isDebugEnabled()) - { - _logger.debug(sub + ": deliverMessage: " + entry.debugIdentity()); - } sub.send(entry); + + setLastSeenEntry(sub,entry); } - private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) + private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) throws AMQException { + return sub.hasInterest(entry) && (getNextAvailableEntry(sub) == entry); + } - // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no - // interest in. - QueueEntry node = sub.getLastSeenEntry(); - while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node))) - { - - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - node = null; - break; - } - } + private void setLastSeenEntry(final Subscription sub, final QueueEntry entry) + { + QueueContext subContext = (QueueContext) sub.getQueueContext(); + QueueEntry releasedEntry = subContext._releasedEntry; - if (node == entry) + QueueContext._lastSeenUpdater.set(subContext, entry); + if(releasedEntry == entry) { - // If the first entry that subscription can process is the one we are trying to deliver to it, then we are - // good - return true; - } - else - { - // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing - // no-one else has updated it to something furhter on in the list - //TODO - check - //updateLastSeenEntry(sub, entry); - return false; + QueueContext._releasedUpdater.compareAndSet(subContext, releasedEntry, null); } - } - private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry) + private void updateSubRequeueEntry(final Subscription sub, final QueueEntry entry) { - QueueEntry node = sub.getLastSeenEntry(); - if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) + QueueContext subContext = (QueueContext) sub.getQueueContext(); + if(subContext != null) { - do + QueueEntry oldEntry; + + while((oldEntry = subContext._releasedEntry) == null || oldEntry.compareTo(entry) > 0) { - if (sub.setLastSeenEntry(node, entry)) - { - return; - } - else + if(QueueContext._releasedUpdater.compareAndSet(subContext, oldEntry, entry)) { - node = sub.getLastSeenEntry(); + break; } } - while (node != null && entry.compareTo(node) < 0); } - } - public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException + public void requeue(QueueEntry entry) { SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); @@ -594,9 +647,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener Subscription sub = subscriberIter.getNode().getSubscription(); // we don't make browsers send the same stuff twice - if (!sub.isBrowser()) + if (sub.seesRequeues()) { - updateLastSeenEntry(sub, entry); + updateSubRequeueEntry(sub, entry); } } @@ -604,36 +657,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + public void requeue(QueueEntryImpl entry, Subscription subscription) { - decrementQueueCount(); - decrementQueueSize(entry); - if (entry.acquiredBySubscription()) + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards + while (subscriberIter.advance()) { - _deliveredMessages.decrementAndGet(); - } + Subscription sub = subscriberIter.getNode().getSubscription(); - try - { - AMQMessage msg = entry.getMessage(); - if (msg.isPersistent()) + // we don't make browsers send the same stuff twice + if (sub.seesRequeues() && (!sub.acquires() && sub == subscription)) { - _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); + updateSubRequeueEntry(sub, entry); } - //entry.dispose(storeContext); - - } - catch (MessageCleanupException e) - { - // Message was dequeued, but could not then be deleted - // though it is no longer referenced. This should be very - // rare and can be detected and cleaned up on recovery or - // done through some form of manual intervention. - _logger.error(e, e); } - catch (AMQException e) + + deliverAsync(); + } + + public void dequeue(QueueEntry entry) + { + decrementQueueCount(); + decrementQueueSize(entry); + if (entry.acquiredBySubscription()) { - throw new FailedDequeueException(_name.toString(), e); + _deliveredMessages.decrementAndGet(); } checkCapacity(); @@ -811,7 +859,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessage().getMessageNumber(); return messageId >= fromMessageId && messageId <= toMessageId; } @@ -830,7 +878,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - _complete = entry.getMessage().getMessageId() == messageId; + _complete = entry.getMessage().getMessageNumber() == messageId; return _complete; } @@ -872,7 +920,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener List entries = getMessagesOnTheQueue(new QueueEntryFilter() { private long position = 0; - + public boolean accept(QueueEntry entry) { position++; @@ -884,25 +932,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return position >= toPosition; } }); - + return entries; } public void moveMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - StoreContext storeContext) + ServerTransaction txn) { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + List entries = getMessagesOnTheQueue(new QueueEntryFilter() { public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessage().getMessageNumber(); return (messageId >= fromMessageId) && (messageId <= toMessageId) && entry.acquire(); @@ -914,61 +962,48 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } }); - try + + + // Move the messages in on the message store. + for (final QueueEntry entry : entries) { - store.beginTran(storeContext); + final ServerMessage message = entry.getMessage(); + txn.enqueue(toQueue, message, + new ServerTransaction.Action() + { - // Move the messages in on the message store. - for (QueueEntry entry : entries) - { - AMQMessage message = entry.getMessage(); + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } - if (message.isPersistent() && toQueue.isDurable()) - { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); - } - // dequeue does not decrement the refence count - entry.dequeue(storeContext); - } + public void onRollback() + { + entry.release(); + } + }); + txn.dequeue(this, message, + new ServerTransaction.Action() + { - // Commit and flush the move transcations. - try - { - store.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - } - catch (AMQException e) - { - try - { - store.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + + } + }); - try - { - for (QueueEntry entry : entries) - { - toQueue.enqueue(storeContext, entry.getMessage()); - entry.delete(); - } - } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); } } @@ -976,27 +1011,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void copyMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - final StoreContext storeContext) + final ServerTransaction txn) { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); List entries = getMessagesOnTheQueue(new QueueEntryFilter() { public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); - if ((messageId >= fromMessageId) - && (messageId <= toMessageId)) - { - if (!entry.isDeleted()) - { - return entry.getMessage().incrementReference(); - } - } - - return false; + final long messageId = entry.getMessage().getMessageNumber(); + return ((messageId >= fromMessageId) + && (messageId <= toMessageId)); } public boolean filterComplete() @@ -1005,98 +1031,69 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } }); - try + + // Move the messages in on the message store. + for (QueueEntry entry : entries) { - store.beginTran(storeContext); + final ServerMessage message = entry.getMessage(); - // Move the messages in on the message store. - for (QueueEntry entry : entries) + if (message.isPersistent() && toQueue.isDurable()) { - AMQMessage message = entry.getMessage(); - if (message.isReferenced() && message.isPersistent() && toQueue.isDurable()) - { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); - } - } + txn.enqueue(toQueue, message, new ServerTransaction.Action() + { + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } - // Commit and flush the move transcations. - try - { - store.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - } - catch (AMQException e) - { - try - { - store.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } + public void onRollback() + { + + } + }); - try - { - for (QueueEntry entry : entries) - { - if (entry.getMessage().isReferenced()) - { - toQueue.enqueue(storeContext, entry.getMessage()); - } } } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } } - public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + public void removeMessagesFromQueue(long fromMessageId, long toMessageId) { - try + QueueEntryIterator queueListIterator = _entries.iterator(); + + while (queueListIterator.advance()) { - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntry node = queueListIterator.getNode(); - while (queueListIterator.advance()) + final ServerMessage message = node.getMessage(); + if(message != null) { - QueueEntry node = queueListIterator.getNode(); - - final long messageId = node.getMessage().getMessageId(); + final long messageId = message.getMessageNumber(); if ((messageId >= fromMessageId) && (messageId <= toMessageId) && !node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); } - } } - catch (AMQException e) - { - throw new RuntimeException(e); - } } // ------ Management functions - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + public void deleteMessageFromTop() { QueueEntryIterator queueListIterator = _entries.iterator(); boolean noDeletes = true; @@ -1106,33 +1103,62 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); noDeletes = false; } } } - public long clearQueue(StoreContext storeContext) throws AMQException + public long clearQueue() { QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node, txn); count++; } } + + txn.commit(); + return count; } + private void dequeueEntry(final QueueEntry node) + { + ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getTransactionLog()); + dequeueEntry(node, txn); + } + + private void dequeueEntry(final QueueEntry node, ServerTransaction txn) + { + txn.dequeue(this, node.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + node.discard(); + } + + public void onRollback() + { + + } + }); + } + public void addQueueDeleteTask(final Task task) { _deleteTaskList.add(task); @@ -1157,7 +1183,111 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); - _managedObject.unregister(); + List entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + return entry.acquire(); + } + + public boolean filterComplete() + { + return false; + } + }); + + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + + if(_alternateExchange != null) + { + + InboundMessageAdapter adapter = new InboundMessageAdapter(); + for(final QueueEntry entry : entries) + { + adapter.setEntry(entry); + final List rerouteQueues = _alternateExchange.route(adapter); + final ServerMessage message = entry.getMessage(); + if(rerouteQueues != null & rerouteQueues.size() != 0) + { + txn.enqueue(rerouteQueues, entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + try + { + for(AMQQueue queue : rerouteQueues) + { + QueueEntry entry = queue.enqueue(message); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void onRollback() + { + + } + }); + txn.dequeue(this, entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + } + }); + } + + } + + _alternateExchange.removeReference(this); + } + else + { + // TODO log discard + + for(final QueueEntry entry : entries) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + txn.dequeue(this, message, + new ServerTransaction.Action() + { + + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + } + }); + } + } + } + + txn.commit(); + + + if(_managedObject!=null) + { + _managedObject.unregister(); + } + for (Task task : _deleteTaskList) { task.doTask(this); @@ -1165,7 +1295,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.clear(); stop(); - + //Log Queue Deletion CurrentActor.get().message(_logSubject, QueueMessages.QUE_1002()); @@ -1249,7 +1379,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void deliverAsync(Subscription sub) { - _asyncDelivery.execute(new SubFlushRunner(sub)); + SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER); + if(flusher == null) + { + flusher = new SubFlushRunner(sub); + sub.set(SUB_FLUSH_RUNNER, flusher); + } + _asyncDelivery.execute(flusher); } @@ -1298,66 +1434,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - private class SubFlushRunner implements ReadWriteRunnable - { - private final Subscription _sub; - - public SubFlushRunner(Subscription sub) - { - _sub = sub; - } - - public void run() - { - - String originalName = Thread.currentThread().getName(); - try{ - Thread.currentThread().setName("SubFlushRunner-"+_sub); - - boolean complete = false; - try - { - CurrentActor.set(_sub.getLogActor()); - complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); - - } - catch (AMQException e) - { - _logger.error(e); - } - finally - { - CurrentActor.remove(); - } - if (!complete && !_sub.isSuspended()) - { - _asyncDelivery.execute(this); - } - } - finally - { - Thread.currentThread().setName(originalName); - } - - } - - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - } - public void flushSubscription(Subscription sub) throws AMQException { flushSubscription(sub, Long.MAX_VALUE); } - public boolean flushSubscription(Subscription sub, Long iterations) throws AMQException + public boolean flushSubscription(Subscription sub, long iterations) throws AMQException { boolean atTail = false; @@ -1371,8 +1453,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { unregisterSubscription(sub); - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + sub.confirmAutoClose(); + } else if (!atTail) { @@ -1408,41 +1490,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private boolean attemptDelivery(Subscription sub) throws AMQException { boolean atTail = false; - boolean advanced = false; + boolean subActive = sub.isActive() && !sub.isSuspended(); if (subActive) { - QueueEntry node = moveSubscriptionToNextNode(sub); - if (_logger.isDebugEnabled()) - { - _logger.debug(sub + ": attempting Delivery: " + node.debugIdentity()); - } - if (!(node.isAcquired() || node.isDeleted())) + + QueueEntry node = getNextAvailableEntry(sub); + + if (node != null && !(node.isAcquired() || node.isDeleted())) { if (sub.hasInterest(node)) { if (!sub.wouldSuspend(node)) { - if (!sub.isBrowser() && !node.acquire(sub)) + if (sub.acquires() && !node.acquire(sub)) { - sub.restoreCredit(node); + sub.onDequeue(node); } else { deliverMessage(sub, node); - - if (sub.isBrowser()) - { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - advanced = true; - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - - } } } @@ -1450,29 +1517,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { //QPID-1187 - Treat the subscription as suspended for this message // and wait for the message to be removed to continue delivery. - - // 2009-09-30 : MR : setting subActive = false only causes, this - // particular delivery attempt to end. This is called from - // flushSubscription and processQueue both of which attempt - // delivery a number of times. Won't a bytes limited - // subscriber with not enough credit for the next message - // create a lot of new QELs? How about a browser that calls - // this method LONG.MAX_LONG times! subActive = false; - node.addStateChangeListener(new QueueEntryListener(sub, node)); - } - } - else - { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); + node.addStateChangeListener(new QueueEntryListener(sub)); } } + } - atTail = (_entries.next(node) == null) && !advanced; + atTail = (node == null) || (_entries.next(node) == null); } return atTail || !subActive; } @@ -1484,46 +1535,58 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); Subscription sub = subNode.getSubscription(); - moveSubscriptionToNextNode(sub); + if(sub.acquires()) + { + getNextAvailableEntry(sub); + } + else + { + // TODO + } } } - private QueueEntry moveSubscriptionToNextNode(final Subscription sub) + private QueueEntry getNextAvailableEntry(final Subscription sub) throws AMQException { - QueueEntry node = sub.getLastSeenEntry(); - - while (node != null && (node.isAcquired() || node.isDeleted() || node.expired())) + QueueContext context = (QueueContext) sub.getQueueContext(); + if(context != null) { - if (!node.isAcquired() && !node.isDeleted() && node.expired()) + QueueEntry lastSeen = context._lastSeenEntry; + QueueEntry releasedNode = context._releasedEntry; + + QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen); + + boolean expired = false; + while (node != null && (node.isAcquired() || node.isDeleted() || (expired = node.expired()) || !sub.hasInterest(node))) { - if (node.acquire()) + if (expired) { - final StoreContext reapingStoreContext = new StoreContext(); - node.discard(reapingStoreContext); + expired = false; + if (node.acquire()) + { + dequeueEntry(node); + } } - } - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - break; - } - } + if(QueueContext._lastSeenUpdater.compareAndSet(context, lastSeen, node)) + { + QueueContext._releasedUpdater.compareAndSet(context, releasedNode, null); + } - if (_logger.isDebugEnabled()) + lastSeen = context._lastSeenEntry; + releasedNode = context._releasedEntry; + node = (releasedNode != null && lastSeen.compareTo(releasedNode)>0) ? releasedNode : _entries.next(lastSeen); + } + return node; + } + else { - _logger.debug(sub + ": nextNode: " + (node == null ? "null" : node.debugIdentity())); + return null; } - - return node; } + private void processQueue(Runnable runner) throws AMQException { long stateChangeCount; @@ -1563,7 +1626,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.getSendLock(); try { - done = attemptDelivery(sub); + if (sub != null) + { + done = attemptDelivery(sub); + } if (done) { if (extraLoops == 0) @@ -1573,8 +1639,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { unregisterSubscription(sub); - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + sub.confirmAutoClose(); } } else @@ -1611,8 +1676,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void checkMessageStatus() throws AMQException { - final StoreContext storeContext = new StoreContext(); - QueueEntryIterator queueListIterator = _entries.iterator(); while (queueListIterator.advance()) @@ -1620,11 +1683,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.expired() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); } else { - _managedObject.checkForNotification(node.getMessage()); + if(_managedObject!=null) + { + _managedObject.checkForNotification(node.getMessage()); + } } } @@ -1748,23 +1814,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final class QueueEntryListener implements QueueEntry.StateChangeListener { - private final QueueEntry _entry; + private final Subscription _sub; - public QueueEntryListener(final Subscription sub, final QueueEntry entry) + public QueueEntryListener(final Subscription sub) { - _entry = entry; _sub = sub; } public boolean equals(Object o) { - return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub; + return _sub == ((QueueEntryListener) o)._sub; } public int hashCode() { - return System.identityHashCode(_entry) ^ System.identityHashCode(_sub); + return System.identityHashCode(_sub); } public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState) @@ -1791,11 +1856,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for (int i = 0; i < num && !it.atTail(); i++) { it.advance(); - ids.add(it.getNode().getMessage().getMessageId()); + ids.add(it.getNode().getMessage().getMessageNumber()); } return ids; } + public Object getExclusiveOwner() + { + return _exclusiveOwner; + } + + public void setExclusiveOwner(Object exclusiveOwner) + { + _exclusiveOwner = exclusiveOwner; + } + + public void configure(QueueConfiguration config) { if (config != null) @@ -1809,4 +1885,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _flowResumeCapacity = config.getFlowResumeCapacity(); } } + + public String getResourceName() + { + return _resourceName; + } + + + @Override + public String toString() + { + return String.valueOf(getName()); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index a46c5ae2e8..d27a5ed234 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -1,6 +1,10 @@ package org.apache.qpid.server.queue; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.ServerMessage; + import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicLong; /* * @@ -24,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; */ public class SimpleQueueEntryList implements QueueEntryList { + private final QueueEntryImpl _head; private volatile QueueEntryImpl _tail; @@ -40,9 +45,7 @@ public class SimpleQueueEntryList implements QueueEntryList _nextUpdater = AtomicReferenceFieldUpdater.newUpdater (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); - - - + private AtomicLong _deletes = new AtomicLong(0L); public SimpleQueueEntryList(AMQQueue queue) @@ -52,21 +55,77 @@ public class SimpleQueueEntryList implements QueueEntryList _tail = _head; } + + void advanceHead() { + _deletes.incrementAndGet(); QueueEntryImpl head = _head.nextNode(); + boolean deleted = head.isDeleted(); while(head._next != null && head.isDeleted()) { + deleted = true; final QueueEntryImpl newhead = head.nextNode(); if(newhead != null) { - _nextUpdater.compareAndSet(_head,head, newhead); + if(_nextUpdater.compareAndSet(_head,head, newhead)) + { + _deletes.decrementAndGet(); + } } head = _head.nextNode(); } + + if(!deleted) + { + deleted = true; + } + + if(_deletes.get() > 1000L) + { + _deletes.set(0L); + scavenge(); + } } + void scavenge() + { + QueueEntryImpl root = _head; + QueueEntryImpl next = root.nextNode(); + + do + { + + + while(next._next != null && next.isDeleted()) + { + + final QueueEntryImpl newhead = next.nextNode(); + if(newhead != null) + { + _nextUpdater.compareAndSet(root,next, newhead); + } + next = root.nextNode(); + } + if(next._next != null) + { + if(!next.isDeleted()) + { + root = next; + next = root.nextNode(); + } + } + else + { + break; + } + + } while (next != null && next._next != null); + + } + + public AMQQueue getQueue() { @@ -74,7 +133,7 @@ public class SimpleQueueEntryList implements QueueEntryList } - public QueueEntry add(AMQMessage message) + public QueueEntry add(ServerMessage message) { QueueEntryImpl node = new QueueEntryImpl(this, message); for (;;) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java new file mode 100755 index 0000000000..547365f647 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java @@ -0,0 +1,68 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + + +class SubFlushRunner implements ReadWriteRunnable +{ + private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + + private final Subscription _sub; + private final String _name; + private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES; + + public SubFlushRunner(Subscription sub) + { + _sub = sub; + _name = "SubFlushRunner-"+_sub; + } + + public void run() + { + + + Thread.currentThread().setName(_name); + + boolean complete = false; + try + { + CurrentActor.set(_sub.getLogActor()); + complete = getQueue().flushSubscription(_sub, ITERATIONS); + + } + catch (AMQException e) + { + _logger.error(e); + } + finally + { + CurrentActor.remove(); + } + if (!complete && !_sub.isSuspended()) + { + getQueue().execute(this); + } + + + } + + private SimpleAMQQueue getQueue() + { + return (SimpleAMQQueue) _sub.getQueue(); + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java deleted file mode 100644 index b09283b11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * Contains data that is only used in AMQMessage transiently, e.g. while the content - * body fragments are arriving. - * - * Having this data stored in a separate class means that the AMQMessage class avoids - * the small overhead of numerous guaranteed-null references. - * - * @author Apache Software Foundation - */ -public class TransientMessageData -{ - /** - * Stored temporarily until the header has been received at which point it is used when - * constructing the handle - */ - private MessagePublishInfo _messagePublishInfo; - - /** - * Also stored temporarily. - */ - private ContentHeaderBody _contentHeaderBody; - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done - * by the message handle. - */ - private List _destinationQueues; - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public List getDestinationQueues() - { - return _destinationQueues == null ? (List) Collections.EMPTY_LIST : _destinationQueues; - } - - public void setDestinationQueues(List destinationQueues) - { - _destinationQueues = destinationQueues; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public long getBodyLengthReceived() - { - return _bodyLengthReceived; - } - - public void addBodyLength(int value) - { - _bodyLengthReceived += value; - } - - public boolean isAllContentReceived() throws AMQException - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public void addDestinationQueue(AMQQueue queue) - { - if(_destinationQueues == null) - { - _destinationQueues = new ArrayList(); - } - _destinationQueues.add(queue); - } - - public boolean isPersistent() - { - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == - BasicContentHeaderProperties.PERSISTENT; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java deleted file mode 100644 index 295cb266b9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * UnauthorizedAccessException is a {@link RequiredDeliveryException} that represents the failure case where a message - * is published with a user id different from the one used when creating the connection . - * The AMQP status code, 403, is always used to report this condition. - * - */ - -public class UnauthorizedAccessException extends RequiredDeliveryException -{ - public UnauthorizedAccessException(String msg, AMQMessage amqMessage) - { - super(msg, amqMessage); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.ACCESS_REFUSED; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java deleted file mode 100644 index 3ed8b0e55c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class WeakReferenceMessageHandle implements AMQMessageHandle -{ - private WeakReference _contentHeaderBody; - - private WeakReference _messagePublishInfo; - - private List> _contentBodies; - - private boolean _redelivered; - - private final MessageStore _messageStore; - - private final Long _messageId; - private long _arrivalTime; - - public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore) - { - _messageId = messageId; - _messageStore = messageStore; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); - if (chb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - chb = mmd.getContentHeaderBody(); - } - return chb; - } - - public Long getMessageId() - { - return _messageId; - } - - private MessageMetaData loadMessageMetaData(StoreContext context) - throws AMQException - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - populateFromMessageMetaData(mmd); - return mmd; - } - - private void populateFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); - _messagePublishInfo = new WeakReference(mmd.getMessagePublishInfo()); - } - - public int getBodyCount(StoreContext context) throws AMQException - { - if (_contentBodies == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - int chunkCount = mmd.getContentChunkCount(); - _contentBodies = new ArrayList>(chunkCount); - for (int i = 0; i < chunkCount; i++) - { - _contentBodies.add(new WeakReference(null)); - } - } - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - WeakReference wr = _contentBodies.get(index); - ContentChunk cb = wr.get(); - if (cb == null) - { - cb = _messageStore.getContentBodyChunk(context, _messageId, index); - _contentBodies.set(index, new WeakReference(cb)); - } - return cb; - } - - /** - * Content bodies are set before the publish and header frames - * - * @param storeContext - * @param contentChunk - * @param isLastContentBody - * @throws AMQException - */ - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - if (_contentBodies == null && isLastContentBody) - { - _contentBodies = new ArrayList>(1); - } - else - { - if (_contentBodies == null) - { - _contentBodies = new LinkedList>(); - } - } - _contentBodies.add(new WeakReference(contentChunk)); - _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, - contentChunk, isLastContentBody); - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); - if (bpb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - - bpb = mmd.getMessagePublishInfo(); - } - return bpb; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent() - { - return true; - } - - /** - * This is called when all the content has been received. - * - * @param publishBody - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - // if there are no content bodies the list will be null so we must - // create en empty list here - if (contentHeaderBody.bodySize == 0) - { - _contentBodies = new LinkedList>(); - } - - final long arrivalTime = System.currentTimeMillis(); - - - MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); - - _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); - - - populateFromMessageMetaData(mmd); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - _messageStore.removeMessage(storeContext, _messageId); - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 831f928832..8e8581b66f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -35,8 +35,8 @@ import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import java.io.File; @@ -51,15 +51,15 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise(int instanceID) throws Exception { - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); - + _registryName = String.valueOf(instanceID); // Set the Actor for current log messages CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); + CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); initialiseManagedObjectRegistry(); @@ -68,7 +68,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _pluginManager = new PluginManager(_configuration.getPluginDirectory()); _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); - + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); @@ -99,10 +99,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } private void initialiseVirtualHosts() throws Exception - { + { for (String name : _configuration.getVirtualHosts()) { - _virtualHostRegistry.registerVirtualHost(new VirtualHost(_configuration.getVirtualHostConfig(name))); + _virtualHostRegistry.registerVirtualHost(new VirtualHostImpl(_configuration.getVirtualHostConfig(name))); } getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java new file mode 100755 index 0000000000..7e93623cab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import java.security.Principal; + +public interface PrincipalHolder +{ + /** @return a Principal that was used to authorized this session */ + Principal getPrincipal(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index 6f7f66fad2..af0a1944cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -14,9 +14,9 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.security.access; @@ -32,14 +32,11 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.SecurityConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; public class ACLManager @@ -78,7 +75,7 @@ public class ACLManager { _hostPlugins = configurePlugins(hostConfig); } - + public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException { Configuration securityConfig = hostConfig.getConfiguration(); @@ -108,7 +105,7 @@ public class ACLManager } } return plugins; - } + } public static Logger getLogger() { @@ -131,18 +128,18 @@ public class ACLManager if (result == AuthzResult.DENIED) { // Something vetoed the access, we're done - return false; + return false; } else if (result == AuthzResult.ALLOWED) { - // Remove plugin from global check list since + // Remove plugin from global check list since // host allow overrides global allow remainingPlugins.remove(plugin.getKey()); } } - + for (ACLPlugin plugin : remainingPlugins.values()) - { + { result = checker.allowed(plugin); if (result == AuthzResult.DENIED) { @@ -152,7 +149,7 @@ public class ACLManager return true; } - public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue, + public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue, final AMQShortString routingKey) { return checkAllPlugins(new AccessCheck() @@ -167,7 +164,7 @@ public class ACLManager }); } - public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost) + public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost) { return checkAllPlugins(new AccessCheck() { @@ -181,7 +178,7 @@ public class ACLManager }); } - public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue) + public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -195,7 +192,7 @@ public class ACLManager }); } - public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck, + public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() @@ -210,7 +207,7 @@ public class ACLManager }); } - public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete, + public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete, final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, final boolean passive, final AMQShortString exchangeType) { @@ -227,7 +224,7 @@ public class ACLManager }); } - public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete, + public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete, final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, final AMQShortString queue) { @@ -243,7 +240,7 @@ public class ACLManager }); } - public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue) + public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -257,7 +254,7 @@ public class ACLManager }); } - public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange) + public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange) { return checkAllPlugins(new AccessCheck() { @@ -270,8 +267,8 @@ public class ACLManager }); } - - public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory, + + public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory, final AMQShortString routingKey, final Exchange e) { return checkAllPlugins(new AccessCheck() @@ -286,7 +283,7 @@ public class ACLManager }); } - public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue) + public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -300,7 +297,7 @@ public class ACLManager }); } - public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch, + public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch, final AMQShortString routingKey, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java index 032184ec39..cf8a3fede9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -24,9 +24,9 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.PrincipalHolder; public interface ACLPlugin { @@ -34,37 +34,37 @@ public interface ACLPlugin { ALLOWED, DENIED, - ABSTAIN + ABSTAIN } void setConfiguration(Configuration config) throws ConfigurationException; - // These return true if the plugin thinks the action should be allowed, and false if not. - - AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + // These return true if the plugin thinks the action should be allowed, and false if not. - AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + + AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue); - AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); + AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost); - AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); + AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue); - AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue); - AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue); + AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue); - AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange); + AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange); - AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e); - AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue); + AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue); - AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); + AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 6d35d7ae48..a299907e42 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -425,8 +425,9 @@ public class PrincipalPermissions // This will allow consumption from any temporary queue including ones not owned by this user. // Of course the exclusivity will not be broken. { + // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (!ownQueuesOnly || new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } //if this is a temporary queue and the user does not have permissions for temporary queues then deny @@ -441,7 +442,7 @@ public class PrincipalPermissions // if no queues are listed then ALL are ok othereise it must be specified. if (ownQueuesOnly) { - if (queue.getOwner().equals(_user)) + if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) { return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java index 682135bc25..f99f3a60f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java @@ -22,76 +22,76 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.PrincipalHolder; /** - * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. + * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. */ public abstract class AbstractACLPlugin implements ACLPlugin { private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) { // TODO Auto-generated method stub return null; } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { return DEFAULT_ANSWER; } - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { return DEFAULT_ANSWER; } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return DEFAULT_ANSWER; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java index ca6b68dafa..d0df354d78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -21,46 +21,45 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; public abstract class BasicACLPlugin implements ACLPlugin { - // Returns true or false if the plugin should authorise or deny the request + // Returns true or false if the plugin should authorise or deny the request protected abstract AuthzResult getResult(); - - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, + + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return getResult(); } - public AuthzResult authoriseConnect(AMQProtocolSession session, + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { return getResult(); } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { - return getResult(); + return getResult(); } - public AuthzResult authoriseConsume(AMQProtocolSession session, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) @@ -68,36 +67,36 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { return getResult(); } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { return getResult(); } - public AuthzResult authorisePublish(AMQProtocolSession session, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { return getResult(); } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return getResult(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 26a76c9af1..77d3c4bcdf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -54,7 +54,7 @@ public class DenyAll extends BasicACLPlugin if (ACLManager.getLogger().isInfoEnabled()) { ACLManager.getLogger().info( - "Denying user:" + session.getAuthorizedID()); + "Denying user:" + session.getPrincipal()); } throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "DenyAll Plugin"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index e299ce99c4..a5bdf662af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -22,24 +22,16 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.security.access.PrincipalPermissions; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; @@ -64,7 +56,7 @@ public class SimpleXML implements ACLPlugin return plugin; } }; - + private Map _users; private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); @@ -110,7 +102,7 @@ public class SimpleXML implements ACLPlugin /** * Publish format takes Exchange + Routing Key Pairs - * + * * @param config * XML Configuration */ @@ -349,9 +341,9 @@ public class SimpleXML implements ACLPlugin return "Simple"; } - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -362,9 +354,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -375,9 +367,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -388,16 +380,16 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return authoriseConsume(session, noAck, queue); } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -408,10 +400,10 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -422,9 +414,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -435,9 +427,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -448,10 +440,10 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -462,9 +454,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -475,9 +467,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 7450322130..17d80c63fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -31,10 +31,11 @@ import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.util.NetMatcher; @@ -57,7 +58,7 @@ public class FirewallPlugin extends AbstractACLPlugin return plugin; } }; - + public class FirewallRule { @@ -69,13 +70,13 @@ public class FirewallPlugin extends AbstractACLPlugin public FirewallRule(String access, List networks, List hostnames) { _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - + if (networks != null && networks.size() > 0) { String[] networkStrings = objListToStringArray(networks); _network = new NetMatcher(networkStrings); } - + if (hostnames != null && hostnames.size() > 0) { int i = 0; @@ -85,7 +86,7 @@ public class FirewallPlugin extends AbstractACLPlugin _hostnamePatterns[i++] = Pattern.compile(hostname); } } - + } private String[] objListToStringArray(List objList) @@ -147,7 +148,7 @@ public class FirewallPlugin extends AbstractACLPlugin thread.run(); long endTime = System.currentTimeMillis() + DNS_TIMEOUT; - + while (System.currentTimeMillis() < endTime && !done.get()) { try @@ -176,8 +177,15 @@ public class FirewallPlugin extends AbstractACLPlugin private FirewallRule[] _rules; @Override - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder principalHolder, VirtualHost virtualHost) { + if(!(principalHolder instanceof ProtocolEngine)) + { + return AuthzResult.ABSTAIN; // We only deal with tcp sessions + } + + ProtocolEngine session = (ProtocolEngine) principalHolder; + SocketAddress sockAddr = session.getRemoteAddress(); if (!(sockAddr instanceof InetSocketAddress)) { @@ -228,7 +236,7 @@ public class FirewallPlugin extends AbstractACLPlugin _default = AuthzResult.DENIED; } CompositeConfiguration finalConfig = new CompositeConfiguration(config); - + List subFiles = config.getList("xml[@fileName]"); for (Object subFile : subFiles) { @@ -236,7 +244,7 @@ public class FirewallPlugin extends AbstractACLPlugin } // all rules must have an access attribute - int numRules = finalConfig.getList("rule[@access]").size(); + int numRules = finalConfig.getList("rule[@access]").size(); _rules = new FirewallRule[numRules]; for (int i = 0; i < numRules; i++) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index e0d4c49af1..2619a69cfd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -215,14 +215,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab _logger.warn("Unable to load access file:" + jmxaccesssFile); } - try - { - _mbean.register(); - } - catch (AMQException e) - { - _logger.warn("Unable to register user management MBean"); - } + _mbean.register(); } catch (JMException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java index fd2d09b777..f8bc530aa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java @@ -31,12 +31,12 @@ public abstract class AbstractMessageStore implements MessageStore { protected LogSubject _logSubject; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception + public void configure(VirtualHost virtualHost) throws Exception { _logSubject = new MessageStoreLogSubject(virtualHost, this); CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); } - + public void close() throws Exception { CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java new file mode 100755 index 0000000000..c7606832d0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java @@ -0,0 +1,57 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; +import org.apache.qpid.framing.FieldTable; + +public interface ConfigurationRecoveryHandler +{ + QueueRecoveryHandler begin(MessageStore store); + + public static interface QueueRecoveryHandler + { + void queue(String queueName, String owner, FieldTable arguments); + ExchangeRecoveryHandler completeQueueRecovery(); + } + + public static interface ExchangeRecoveryHandler + { + void exchange(String exchangeName, String type, boolean autoDelete); + BindingRecoveryHandler completeExchangeRecovery(); + } + + public static interface BindingRecoveryHandler + { + void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf); + void completeBindingRecovery(); + } + + public static interface QueueEntryRecoveryHandler + { + void complete(); + + void queueEntry(String queueName, long messageId); + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index c014739324..ba5574d1fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -21,28 +21,18 @@ package org.apache.qpid.server.store; import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.commons.configuration.Configuration; + import java.io.ByteArrayInputStream; import java.io.File; @@ -56,15 +46,14 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; -public class DerbyMessageStore extends AbstractMessageStore +public class DerbyMessageStore implements MessageStore { private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); @@ -80,57 +69,66 @@ public class DerbyMessageStore extends AbstractMessageStore private static final String QUEUE_TABLE_NAME = "QPID_QUEUE"; private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS"; private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY"; - private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA"; + + private static final String META_DATA_TABLE_NAME = "QPID_META_DATA"; private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; private static final int DB_VERSION = 1; - private VirtualHost _virtualHost; private static Class DRIVER_CLASS; - private final AtomicLong _messageId = new AtomicLong(1); + private final AtomicLong _messageId = new AtomicLong(0); private AtomicBoolean _closed = new AtomicBoolean(false); private String _connectionURL; - Map _queueRecoveries = new TreeMap(); - + private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; + private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; - private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; - private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; - private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; private static final String SELECT_FROM_BINDINGS = - "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + "SELECT exchange_name, queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " ORDER BY exchange_name"; private static final String FIND_BINDING = "SELECT * FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ? "; - private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + + private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; - private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; - private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; - private static final String SELECT_FROM_MESSAGE_META_DATA = - "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME + " ORDER BY queue_name, message_id"; + + + private static final String CREATE_META_DATA_TABLE = "CREATE TABLE "+META_DATA_TABLE_NAME+" ( message_id bigint not null, meta_data blob, PRIMARY KEY ( message_id ) )"; + private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, offset int not null, last_byte int not null, content blob , PRIMARY KEY (message_id, offset) )"; + + private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, offset, last_byte, content ) values (?, ?, ?, ?)"; private static final String SELECT_FROM_MESSAGE_CONTENT = - "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; - private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; - private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; + "SELECT offset, content FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? AND last_byte > ? AND offset < ? ORDER BY message_id, offset"; + private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; + + private static final String INSERT_INTO_META_DATA = "INSERT INTO " + META_DATA_TABLE_NAME + "( message_id , meta_data ) values (?, ?)";; + private static final String SELECT_FROM_META_DATA = + "SELECT meta_data FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME; + + + private LogSubject _logSubject; + private boolean _configured; private enum State @@ -146,21 +144,82 @@ public class DerbyMessageStore extends AbstractMessageStore private State _state = State.INITIAL; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception { - super.configure(virtualHost,base,config); - stateTransition(State.INITIAL, State.CONFIGURING); + _logSubject = logSubject; + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); - initialiseDriver(); + if(!_configured) + { + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + // this recovers durable exchanges, queues, and bindings + recover(recoveryHandler); - _virtualHost = virtualHost; - _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + stateTransition(State.RECOVERING, State.STARTED); + + } + + + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception + { + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + + if(!_configured) + { + + _logSubject = logSubject; + + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + recoverMessages(recoveryHandler); + + } + + + + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception + { + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1001(this.getClass().getName())); + + if(!_configured) + { + + _logSubject = logSubject; + + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + recoverQueueEntries(recoveryHandler); + + } + + + + private void commonConfiguration(String name, Configuration storeConfiguration, LogSubject logSubject) + throws ClassNotFoundException, SQLException + { + initialiseDriver(); //Update to pick up QPID_WORK and use that as the default location not just derbyDB - final String databasePath = config.getStoreConfiguration().getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); + + final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) @@ -172,17 +231,9 @@ public class DerbyMessageStore extends AbstractMessageStore } } - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); - - createOrOpenDatabase(databasePath); - - // this recovers durable queues and persistent messages - - recover(); - - - stateTransition(State.RECOVERING, State.STARTED); + CurrentActor.get().message(logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); + createOrOpenDatabase(name, databasePath); } private static synchronized void initialiseDriver() throws ClassNotFoundException @@ -193,10 +244,10 @@ public class DerbyMessageStore extends AbstractMessageStore } } - private void createOrOpenDatabase(final String environmentPath) throws SQLException + private void createOrOpenDatabase(String name, final String environmentPath) throws SQLException { //fixme this the _vhost name should not be added here. - _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; + _connectionURL = "jdbc:derby:" + environmentPath + "/" + name + ";create=true"; Connection conn = newConnection(); @@ -205,7 +256,7 @@ public class DerbyMessageStore extends AbstractMessageStore createQueueTable(conn); createBindingsTable(conn); createQueueEntryTable(conn); - createMessageMetaDataTable(conn); + createMetaDataTable(conn); createMessageContentTable(conn); conn.close(); @@ -276,12 +327,12 @@ public class DerbyMessageStore extends AbstractMessageStore } - private void createMessageMetaDataTable(final Connection conn) throws SQLException + private void createMetaDataTable(final Connection conn) throws SQLException { - if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) + if(!tableExists(META_DATA_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); + stmt.execute(CREATE_META_DATA_TABLE); stmt.close(); } @@ -314,38 +365,22 @@ public class DerbyMessageStore extends AbstractMessageStore return exists; } - public void recover() throws AMQException + public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQException { stateTransition(State.CONFIGURING, State.RECOVERING); - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(null, false)); - - StoreContext context = new StoreContext(); try { - Map queues = loadQueues(); - - recoverExchanges(); - - try - { - - beginTran(context); + ConfigurationRecoveryHandler.QueueRecoveryHandler qrh = recoveryHandler.begin(this); + List queues = loadQueues(qrh); - deliverMessages(context, queues); - commitTran(context); + ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh = qrh.completeQueueRecovery(); + List exchanges = loadExchanges(erh); + ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery(); + recoverBindings(brh, exchanges); + brh.completeBindingRecovery(); - //Recovery Complete - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(null, false)); - } - finally - { - if(inTran(context)) - { - abortTran(context); - } - } } catch (SQLException e) @@ -357,53 +392,34 @@ public class DerbyMessageStore extends AbstractMessageStore } - private Map loadQueues() throws SQLException, AMQException + private List loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException, AMQException { Connection conn = newConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); - Map queueMap = new HashMap(); + List queues = new ArrayList(); + while(rs.next()) { String queueName = rs.getString(1); String owner = rs.getString(2); - AMQShortString queueNameShortString = new AMQShortString(queueName); + qrh.queue(queueName, owner, null); - AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + queues.add(queueName); - if (q == null) - { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, - null); - _virtualHost.getQueueRegistry().registerQueue(q); - } - - queueMap.put(queueNameShortString,q); - - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(String.valueOf(q.getName()), true)); - //Record that we have a queue for recovery - _queueRecoveries.put(new AMQShortString(queueName), 0); - - } - return queueMap; - } - private void recoverExchanges() throws AMQException, SQLException - { - for (Exchange exchange : loadExchanges()) - { - recoverExchange(exchange); } + return queues; } - private List loadExchanges() throws AMQException, SQLException + private List loadExchanges(ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh) throws AMQException, SQLException { - List exchanges = new ArrayList(); + List exchanges = new ArrayList(); Connection conn = null; try { @@ -413,21 +429,15 @@ public class DerbyMessageStore extends AbstractMessageStore Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); - Exchange exchange; while(rs.next()) { String exchangeName = rs.getString(1); String type = rs.getString(2); boolean autoDelete = rs.getShort(3) != 0; - AMQShortString exchangeNameSS = new AMQShortString(exchangeName); - exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS); - if (exchange == null) - { - exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0); - _virtualHost.getExchangeRegistry().registerExchange(exchange); - } - exchanges.add(exchange); + exchanges.add(exchangeName); + + erh.exchange(exchangeName, type, autoDelete); } return exchanges; @@ -443,11 +453,13 @@ public class DerbyMessageStore extends AbstractMessageStore } - private void recoverExchange(Exchange exchange) throws AMQException, SQLException + private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List exchanges) throws AMQException, SQLException { - _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "..."); - QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + + _logger.info("Recovering bindings..."); + + Connection conn = null; try @@ -455,41 +467,29 @@ public class DerbyMessageStore extends AbstractMessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString()); ResultSet rs = stmt.executeQuery(); while(rs.next()) { - String queueName = rs.getString(1); - String bindingKey = rs.getString(2); - Blob arguments = rs.getBlob(3); - + String exchangeName = rs.getString(1); + String queueName = rs.getString(2); + String bindingKey = rs.getString(3); + Blob arguments = rs.getBlob(4); + java.nio.ByteBuffer buf; - AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) + if(arguments != null && arguments.length() != 0) { - _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getName()); + byte[] argumentBytes = arguments.getBytes(1, (int) arguments.length()); + buf = java.nio.ByteBuffer.wrap(argumentBytes); } else { - _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName - + ", Routing Key: " + bindingKey + ", Arguments: " + arguments - + ")"); - - FieldTable argumentsFT = null; - if(arguments != null) - { - byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length()); - ByteBuffer buf = ByteBuffer.wrap(argumentBytes); - argumentsFT = new FieldTable(buf,arguments.length()); - } - - queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); - + buf = null; } + + brh.binding(exchangeName, queueName, bindingKey, buf); } } finally @@ -501,44 +501,48 @@ public class DerbyMessageStore extends AbstractMessageStore } } + + public void close() throws Exception { + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); _closed.getAndSet(true); - - super.close(); } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + public StoredMessage addMessage(StorableMessageMetaData metaData) { - - boolean localTx = getOrCreateTransaction(storeContext); - - Connection conn = getConnection(storeContext); - ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload(); - - - if (_logger.isDebugEnabled()) + if(metaData.isPersistent()) { - _logger.debug("Message Id: " + messageId + " Removing"); + return new StoredDerbyMessage(_messageId.incrementAndGet(), metaData); } + else + { + return new StoredMemoryMessage(_messageId.incrementAndGet(), metaData); + } + } - // first we need to look up the header to get the chunk count - MessageMetaData mmd = getMessageMetaData(storeContext, messageId); + public StoredMessage getMessage(long messageNumber) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeMessage(long messageId) + { + Connection conn = null; try { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); + + + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA); stmt.setLong(1,messageId); - wrapper.setRequiresCommit(); int results = stmt.executeUpdate(); if (results == 0) { - if (localTx) - { - abortTran(storeContext); - } - throw new AMQException("Message metadata not found for message id " + messageId); + + throw new RuntimeException("Message metadata not found for message id " + messageId); } stmt.close(); @@ -551,29 +555,27 @@ public class DerbyMessageStore extends AbstractMessageStore stmt.setLong(1,messageId); results = stmt.executeUpdate(); - if(results != mmd.getContentChunkCount()) - { - if (localTx) - { - abortTran(storeContext); - } - throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results); - } - if (localTx) - { - commitTran(storeContext); - } + conn.commit(); + conn.close(); } catch (SQLException e) { - if ((conn != null) && localTx) + if ((conn != null)) { - abortTran(storeContext); + try + { + conn.rollback(); + conn.close(); + } + catch (SQLException e1) + { + + } } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + throw new RuntimeException("Error removing Message with id " + messageId + " to database: " + e, e); } } @@ -802,8 +804,14 @@ public class DerbyMessageStore extends AbstractMessageStore { stmt = conn.prepareStatement(INSERT_INTO_QUEUE); + String owner = queue.getPrincipalHolder() == null + ? null + : queue.getPrincipalHolder().getPrincipal() == null + ? null + : queue.getPrincipalHolder().getPrincipal().getName(); + stmt.setString(1, queue.getName().toString()); - stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); + stmt.setString(2, owner); stmt.execute(); @@ -873,29 +881,26 @@ public class DerbyMessageStore extends AbstractMessageStore } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public Transaction newTransaction() { - AMQShortString name = queue.getName(); + return new DerbyTransaction(); + } + + public void enqueueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException + { + String name = queue.getResourceName(); + + Connection conn = connWrapper.getConnection(); - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); - stmt.setString(1,name.toString()); + stmt.setString(1,name); stmt.setLong(2,messageId); stmt.executeUpdate(); connWrapper.requiresCommit(); - if(localTx) - { - commitTran(context); - } - - - if (_logger.isDebugEnabled()) { _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); @@ -903,10 +908,6 @@ public class DerbyMessageStore extends AbstractMessageStore } catch (SQLException e) { - if(localTx) - { - abortTran(context); - } _logger.error("Failed to enqueue: " + e, e); throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name + " to database", e); @@ -914,18 +915,18 @@ public class DerbyMessageStore extends AbstractMessageStore } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void dequeueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException { - AMQShortString name = queue.getName(); + String name = queue.getResourceName(); + + + Connection conn = connWrapper.getConnection(); - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); - stmt.setString(1,name.toString()); + stmt.setString(1,name); stmt.setLong(2,messageId); int results = stmt.executeUpdate(); @@ -936,13 +937,6 @@ public class DerbyMessageStore extends AbstractMessageStore throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); } - if(localTx) - { - commitTran(context); - } - - - if (_logger.isDebugEnabled()) { _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]"); @@ -950,10 +944,6 @@ public class DerbyMessageStore extends AbstractMessageStore } catch (SQLException e) { - if(localTx) - { - abortTran(context); - } _logger.error("Failed to dequeue: " + e, e); throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name + " from database", e); @@ -987,51 +977,20 @@ public class DerbyMessageStore extends AbstractMessageStore } } - public void beginTran(StoreContext context) throws AMQException - { - if (context.getPayload() != null) - { - throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: " - + context.getPayload()); - } - else - { - try - { - Connection conn = newConnection(); - - context.setPayload(new ConnectionWrapper(conn)); - } - catch (SQLException e) - { - throw new AMQException("Error starting transaction: " + e, e); - } - } - } - - public void commitTran(StoreContext context) throws AMQException + public void commitTran(ConnectionWrapper connWrapper) throws AMQException { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - if (connWrapper == null) - { - throw new AMQException("Fatal internal error: transactional context is empty at commitTran"); - } try { Connection conn = connWrapper.getConnection(); - if(connWrapper.requiresCommit()) - { - conn.commit(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("commit tran completed"); - } + conn.commit(); + if (_logger.isDebugEnabled()) + { + _logger.debug("commit tran completed"); } + conn.close(); } catch (SQLException e) @@ -1040,14 +999,30 @@ public class DerbyMessageStore extends AbstractMessageStore } finally { - context.setPayload(null); + } } - public void abortTran(StoreContext context) throws AMQException + public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQException { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + commitTran(connWrapper); + return new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + } + }; + + } + + public void abortTran(ConnectionWrapper connWrapper) throws AMQException + { if (connWrapper == null) { throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); @@ -1072,272 +1047,261 @@ public class DerbyMessageStore extends AbstractMessageStore { throw new AMQException("Error aborting transaction: " + e, e); } - finally - { - context.setPayload(null); - } + } - public boolean inTran(StoreContext context) + public Long getNewMessageId() { - return context.getPayload() != null; + return _messageId.incrementAndGet(); } - public Long getNewMessageId() + + private void storeMetaData(Connection conn, long messageId, StorableMessageMetaData metaData) + throws SQLException { - return _messageId.getAndIncrement(); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_META_DATA); + stmt.setLong(1,messageId); + + final int bodySize = 1 + metaData.getStorableSize(); + byte[] underlying = new byte[bodySize]; + underlying[0] = (byte) metaData.getType().ordinal(); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(underlying); + buf.position(1); + buf = buf.slice(); + + metaData.writeToBuffer(0, buf); + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(2,bis,underlying.length); + stmt.executeUpdate(); + } - public void storeContentBodyChunk(StoreContext context, - Long messageId, - int index, - ContentChunk contentBody, - boolean lastContentBody) throws AMQException + + + + private void recoverMessages(MessageStoreRecoveryHandler recoveryHandler) throws SQLException { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + Connection conn = newConnection(); - try - { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - byte[] chunkData = new byte[contentBody.getSize()]; - contentBody.getData().duplicate().get(chunkData); - /* this would be the Java 6 way of doing things - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, chunkData); - stmt.setBlob(3, dataAsBlob); - */ - ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); - stmt.setBinaryStream(3, bis, chunkData.length); - stmt.executeUpdate(); - connWrapper.requiresCommit(); + MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin(); - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_ALL_FROM_META_DATA); + + long maxId = 0; + + while(rs.next()) { - if(localTx) + + long messageId = rs.getLong(1); + Blob dataAsBlob = rs.getBlob(2); + + if(messageId > maxId) { - abortTran(context); + maxId = messageId; } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); + StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false); + messageHandler.message(message); + + } + _messageId.set(maxId); + + messageHandler.completeMessageRecovery(); } - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd) - throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - try - { + private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws SQLException + { + Connection conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); - stmt.setLong(1,messageId); - stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); - stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); - stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0); - stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0); - - ContentHeaderBody headerBody = mmd.getContentHeaderBody(); - final int bodySize = headerBody.getSize(); - byte[] underlying = new byte[bodySize]; - ByteBuffer buf = ByteBuffer.wrap(underlying); - headerBody.writePayload(buf); -/* - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, underlying); - stmt.setBlob(6, dataAsBlob); -*/ - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(6,bis,underlying.length); + TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this); - stmt.setInt(7, mmd.getContentChunkCount()); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); - stmt.executeUpdate(); - connWrapper.requiresCommit(); - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) + while(rs.next()) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + String queueName = rs.getString(1); + long messageId = rs.getLong(2); + queueEntryHandler.queueEntry(queueName,messageId); } + + queueEntryHandler.completeQueueEntryRecovery(); + } - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + StorableMessageMetaData getMetaData(long messageId) throws SQLException { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - + Connection conn = newConnection(); try { - - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_META_DATA); stmt.setLong(1,messageId); ResultSet rs = stmt.executeQuery(); if(rs.next()) { - final AMQShortString exchange = new AMQShortString(rs.getString(1)); - final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); - final boolean mandatory = (rs.getShort(3) != (short)0); - final boolean immediate = (rs.getShort(4) != (short)0); - MessagePublishInfo info = new MessagePublishInfo() - { - public AMQShortString getExchange() - { - return exchange; - } + Blob dataAsBlob = rs.getBlob(1); - public void setExchange(AMQShortString exchange) - { + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); - } + return metaData; + } + else + { + throw new RuntimeException("Meta data not found for message with id " + messageId); + } - public boolean isImmediate() - { - return immediate; - } + } + finally + { + conn.close(); + } + } - public boolean isMandatory() - { - return mandatory; - } - public AMQShortString getRoutingKey() - { - return routingKey; - } - } ; + private void addContent(Connection conn, long messageId, int offset, ByteBuffer src) + { - Blob dataAsBlob = rs.getBlob(5); - byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); - ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); - ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length); + try + { + final boolean newConnection = conn == null; - if(localTx) - { - commitTran(context); - } + if(newConnection) + { + conn = newConnection(); + } - return new MessageMetaData(info, chb, rs.getInt(6)); + src = src.slice(); - } - else + byte[] chunkData = new byte[src.limit()]; + src.duplicate().get(chunkData); + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, offset); + stmt.setInt(3, offset+chunkData.length); + + + /* this would be the Java 6 way of doing things + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, chunkData); + stmt.setBlob(3, dataAsBlob); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); + stmt.setBinaryStream(4, bis, chunkData.length); + stmt.executeUpdate(); + + if(newConnection) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Metadata not found for message with id " + messageId); + conn.commit(); + conn.close(); } } catch (SQLException e) { - if(localTx) + if(conn != null) { - abortTran(context); + try + { + conn.close(); + } + catch (SQLException e1) + { + + } } - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); } } - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - - - try - { - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - ResultSet rs = stmt.executeQuery(); + public int getContent(long messageId, int offset, ByteBuffer dst) + { + Connection conn = null; - if(rs.next()) - { - Blob dataAsBlob = rs.getBlob(1); - final int size = (int) dataAsBlob.length(); - byte[] dataAsBytes = dataAsBlob.getBytes(1, size); - final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + try + { + conn = newConnection(); - ContentChunk cb = new ContentChunk() - { + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, offset); + stmt.setInt(3, offset+dst.remaining()); + ResultSet rs = stmt.executeQuery(); - public int getSize() - { - return size; - } + int written = 0; - public ByteBuffer getData() - { - return buf; - } + while(rs.next()) + { + int offsetInMessage = rs.getInt(1); + Blob dataAsBlob = rs.getBlob(2); - public void reduceToFit() - { + final int size = (int) dataAsBlob.length(); + byte[] dataAsBytes = dataAsBlob.getBytes(1, size); - } - }; + int posInArray = offset + written - offsetInMessage; + int count = size - posInArray; + if(count > dst.remaining()) + { + count = dst.remaining(); + } + dst.put(dataAsBytes,posInArray,count); + written+=count; - if(localTx) - { - commitTran(context); - } + if(dst.remaining() == 0) + { + break; + } + } - return cb; + conn.close(); + return written; - } - else - { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Message not found for message with id " + messageId); - } + } + catch (SQLException e) + { + if(conn != null) + { + try + { + conn.close(); } - catch (SQLException e) + catch (SQLException e1) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); } + } + + throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } @@ -1348,173 +1312,158 @@ public class DerbyMessageStore extends AbstractMessageStore return true; } - private void checkNotClosed() throws MessageStoreClosedException - { - if (_closed.get()) - { - throw new MessageStoreClosedException(); - } - } - - private static final class ProcessAction + private synchronized void stateTransition(State requiredState, State newState) throws AMQException { - private final AMQQueue _queue; - private final StoreContext _context; - private final AMQMessage _message; - - public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message) - { - _queue = queue; - _context = context; - _message = message; - } - - public void process() throws AMQException + if (_state != requiredState) { - _queue.enqueue(_context, _message); + throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + + "; currently in state: " + _state); } + _state = newState; } - private void deliverMessages(final StoreContext context, Map queues) - throws SQLException, AMQException + private class DerbyTransaction implements Transaction { - Map msgMap = new HashMap(); - List actions = new ArrayList(); + private final ConnectionWrapper _connWrapper; - final boolean inLocaltran = inTran(context); - Connection conn = null; - try + private DerbyTransaction() { - if(inLocaltran) + try { - conn = getConnection(context); + _connWrapper = new ConnectionWrapper(newConnection()); } - else + catch (SQLException e) { - conn = newConnection(); + throw new RuntimeException(e); } + } - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); - long maxId = 1; + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId); + } - TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId); - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + } - while (rs.next()) - { - AMQShortString queueName = new AMQShortString(rs.getString(1)); + public void commitTran() throws AMQException + { + DerbyMessageStore.this.commitTran(_connWrapper); + } - AMQQueue queue = queues.get(queueName); - if (queue == null) - { - queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); + public StoreFuture commitTranAsync() throws AMQException + { + return DerbyMessageStore.this.commitTranAsync(_connWrapper); + } - _virtualHost.getQueueRegistry().registerQueue(queue); - queues.put(queueName, queue); + public void abortTran() throws AMQException + { + DerbyMessageStore.this.abortTran(_connWrapper); + } + } - //Log Recovery Start - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1004(String.valueOf(queue.getName()), true)); - } + private class StoredDerbyMessage implements StoredMessage + { - long messageId = rs.getLong(2); - maxId = Math.max(maxId, messageId); - AMQMessage message = msgMap.get(messageId); + private final long _messageId; + private volatile WeakReference _metaDataRef; + private Connection _conn; - if(message != null) - { - message.incrementReference(); - } - else - { - message = new AMQMessage(messageId, this, messageHandleFactory, txnContext); - msgMap.put(messageId,message); - } + StoredDerbyMessage(long messageId, StorableMessageMetaData metaData) + { + this(messageId, metaData, true); + } - if (_logger.isDebugEnabled()) - { - _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); - } - Integer count = _queueRecoveries.get(queueName); - if (count == null) + StoredDerbyMessage(long messageId, + StorableMessageMetaData metaData, boolean persist) + { + try + { + _messageId = messageId; + + _metaDataRef = new WeakReference(metaData); + if(persist) { - count = 0; + _conn = newConnection(); + storeMetaData(_conn, messageId, metaData); } - - _queueRecoveries.put(queueName, ++count); - - actions.add(new ProcessAction(queue, context, message)); } - - for(ProcessAction action : actions) + catch (SQLException e) { - action.process(); + throw new RuntimeException(e); } - _messageId.set(maxId + 1); - } - catch (SQLException e) - { - _logger.error("Error: " + e, e); - throw e; } - finally + + public StorableMessageMetaData getMetaData() { - if (inLocaltran && conn != null) + StorableMessageMetaData metaData = _metaDataRef.get(); + if(metaData == null) { - conn.close(); + try + { + metaData = DerbyMessageStore.this.getMetaData(_messageId); + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + _metaDataRef = new WeakReference(metaData); } + + return metaData; } - if (_logger.isInfoEnabled()) + public long getMessageNumber() { - _logger.info("Recovered message counts: " + _queueRecoveries); + return _messageId; } - for(Map.Entry entry : _queueRecoveries.entrySet()) + public void addContent(int offsetInMessage, java.nio.ByteBuffer src) { - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1005(entry.getValue(), String.valueOf(entry.getKey()))); - - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(String.valueOf(entry.getKey()), true)); + DerbyMessageStore.this.addContent(_conn, _messageId, offsetInMessage, src); } - // Free the memory - _queueRecoveries = null; - - } - - private Connection getConnection(final StoreContext context) - { - return ((ConnectionWrapper)context.getPayload()).getConnection(); - } - - private boolean getOrCreateTransaction(StoreContext context) throws AMQException - { - - ConnectionWrapper tx = (ConnectionWrapper) context.getPayload(); - if (tx == null) + public int getContent(int offsetInMessage, java.nio.ByteBuffer dst) { - beginTran(context); - return true; + return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst); } - return false; - } - - private synchronized void stateTransition(State requiredState, State newState) throws AMQException - { - if (_state != requiredState) + public StoreFuture flushToStore() { - throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState - + "; currently in state: " + _state); + try + { + if(_conn != null) + { + _conn.commit(); + _conn.close(); + } + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + finally + { + _conn = null; + } + return IMMEDIATE_FUTURE; } - _state = newState; + public void remove() + { + flushToStore(); + DerbyMessageStore.this.removeMessage(_messageId); + } } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java new file mode 100755 index 0000000000..cfbacd28c8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -0,0 +1,116 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.commons.configuration.Configuration; + +public interface DurableConfigurationStore +{ + + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param name The name to be used by this storem + * @param recoveryHandler Handler to be called as the store recovers on start up + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception; + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createExchange(Exchange exchange) throws AMQException; + + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void removeExchange(Exchange exchange) throws AMQException; + + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @param arguments The additional arguments to the binding + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; + + /** + * Removes the specified queue from the persistent store. + * + * @param queue The queue to remove. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void removeQueue(AMQQueue queue) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 87ec66030d..f43177bfc1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -20,21 +20,20 @@ */ package org.apache.qpid.server.store; -import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.commons.configuration.Configuration; import java.util.ArrayList; import java.util.Collections; @@ -43,9 +42,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.nio.ByteBuffer; /** A simple message store that stores the messages in a threadsafe structure in memory. */ -public class MemoryMessageStore extends AbstractMessageStore +public class MemoryMessageStore implements MessageStore { private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -53,52 +53,74 @@ public class MemoryMessageStore extends AbstractMessageStore private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity"; - protected ConcurrentMap _metaDataMap; - - protected ConcurrentMap> _contentBodyMap; private final AtomicLong _messageId = new AtomicLong(1); private AtomicBoolean _closed = new AtomicBoolean(false); private LogSubject _logSubject; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + private static final Transaction IN_MEMORY_TRANSACTION = new Transaction() { - super.configure(virtualHost,base,config); + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + } - int hashtableCapacity = config.getStoreConfiguration().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 dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + } - public void close() throws Exception - { - _closed.getAndSet(true); - if (_metaDataMap != null) + public void commitTran() throws AMQException { - _metaDataMap.clear(); - _metaDataMap = null; } - if (_contentBodyMap != null) + + public StoreFuture commitTranAsync() throws AMQException + { + return IMMEDIATE_FUTURE; + } + + public void abortTran() throws AMQException { - _contentBodyMap.clear(); - _contentBodyMap = null; } - super.close(); + }; + + public void configureConfigStore(String name, ConfigurationRecoveryHandler handler, Configuration configuration, LogSubject logSubject) throws Exception + { + _logSubject = logSubject; + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); + + } - public void removeMessage(StoreContext context, Long messageId) throws AMQException + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception { - checkNotClosed(); - if (_log.isDebugEnabled()) + if(_logSubject == null) { - _log.debug("Removing message with id " + messageId); + _logSubject = logSubject; } - _metaDataMap.remove(messageId); - _contentBodyMap.remove(messageId); + int hashtableCapacity = config.getInt(name + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); + _log.info("Using capacity " + hashtableCapacity + " for hash tables"); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + } + + public void close() throws Exception + { + _closed.getAndSet(true); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + } + public StoredMessage addMessage(StorableMessageMetaData metaData) + { + final long id = _messageId.getAndIncrement(); + StoredMemoryMessage message = new StoredMemoryMessage(id, metaData); + + return message; + } + + public void createExchange(Exchange exchange) throws AMQException { @@ -135,35 +157,19 @@ public class MemoryMessageStore extends AbstractMessageStore // Not required to do anything } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception { - // Not required to do anything + //To change body of implemented methods use File | Settings | File Templates. } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public Transaction newTransaction() { - // Not required to do anything + return IN_MEMORY_TRANSACTION; } - public void beginTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void commitTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void abortTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public boolean inTran(StoreContext context) - { - return false; - } public List createQueues() throws AMQException { @@ -175,48 +181,6 @@ public class MemoryMessageStore extends AbstractMessageStore return _messageId.getAndIncrement(); } - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) - throws AMQException - { - checkNotClosed(); - List bodyList = _contentBodyMap.get(messageId); - - if (bodyList == null && lastContentBody) - { - _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); - } - else - { - if (bodyList == null) - { - bodyList = new ArrayList(); - _contentBodyMap.put(messageId, bodyList); - } - - bodyList.add(index, contentBody); - } - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) - throws AMQException - { - checkNotClosed(); - _metaDataMap.put(messageId, messageMetaData); - } - - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - checkNotClosed(); - return _metaDataMap.get(messageId); - } - - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - checkNotClosed(); - List bodyList = _contentBodyMap.get(messageId); - return bodyList.get(index); - } - public boolean isPersistent() { return false; @@ -229,4 +193,6 @@ public class MemoryMessageStore extends AbstractMessageStore throw new MessageStoreClosedException(); } } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java new file mode 100755 index 0000000000..428bb1e41b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageMetaData_0_10; + +import java.nio.ByteBuffer; + +public enum MessageMetaDataType +{ + META_DATA_0_8 { public Factory getFactory() { return MessageMetaData.FACTORY; } }, + META_DATA_0_10 { public Factory getFactory() { return MessageMetaData_0_10.FACTORY; } }; + + + public static interface Factory + { + M createMetaData(ByteBuffer buf); + } + + abstract public Factory getFactory(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 5a1b54b298..e2fca2f9c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -20,53 +20,43 @@ */ package org.apache.qpid.server.store; +import org.apache.qpid.server.logging.LogSubject; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - /** - * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues - * and exchanges in a transactional manner. - * - *

      All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which - * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single - * transaction. + * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages. * - *

      The storage and removal of queues and exchanges, are not carried out in a transactional context. - * - *

      - *
      CRC Card
      Responsibilities - *
      Accept transaction boundary demarcations: Begin, Commit, Abort. - *
      Store and remove queues. - *
      Store and remove exchanges. - *
      Store and remove messages. - *
      Bind and unbind queues to exchanges. - *
      Enqueue and dequeue messages to queues. - *
      Generate message identifiers. - *
      */ -public interface MessageStore +public interface MessageStore extends DurableConfigurationStore, TransactionLog { + StoreFuture IMMEDIATE_FUTURE = new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + + } + }; + + /** * Called after instantiation in order to configure the message store. A particular implementation can define * whatever parameters it wants. * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param hostConfig The apache commons configuration object. + * @param name The name to be used by this storem + * @param recoveryHandler Handler to be called as the store recovers on start up + * @param config The apache commons configuration object. * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception; + void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception; /** * Called to close and cleanup any resources used by the message store. @@ -75,203 +65,16 @@ public interface MessageStore */ void close() throws Exception; - /** - * Removes the specified message from the store in the given transactional store context. - * - * @param storeContext The transactional context to remove the message in. - * @param messageId Identifies the message to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - /** - * Makes the specified exchange persistent. - * - * @param exchange The exchange to persist. - * - * @throws AMQException If the operation fails for any reason. - */ - void createExchange(Exchange exchange) throws AMQException; - - /** - * Removes the specified persistent exchange. - * - * @param exchange The exchange to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeExchange(Exchange exchange) throws AMQException; - - /** - * Binds the specified queue to an exchange with a routing key. - * - * @param exchange The exchange to bind to. - * @param routingKey The routing key to bind by. - * @param queue The queue to bind. - * @param args Additional parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Unbinds the specified from an exchange under a particular routing key. - * - * @param exchange The exchange to unbind from. - * @param routingKey The routing key to unbind. - * @param queue The queue to unbind. - * @param args Additonal parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue) throws AMQException; + public StoredMessage addMessage(T metaData); - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @param arguments The additional arguments to the binding - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; - - /** - * Removes the specified queue from the persistent store. - * - * @param queue The queue to remove. - * @throws AMQException If the operation fails for any reason. - */ - void removeQueue(final AMQQueue queue) throws AMQException; - - /** - * Places a message onto a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to enqueue. - * @throws AMQException If the operation fails for any reason. - */ - void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to dequeue. - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Begins a transactional context. - * - * @param context The transactional context to begin. - * - * @throws AMQException If the operation fails for any reason. - */ - void beginTran(StoreContext context) throws AMQException; - - /** - * Commits all operations performed within a given transactional context. - * - * @param context The transactional context to commit all operations for. - * - * @throws AMQException If the operation fails for any reason. - */ - void commitTran(StoreContext context) throws AMQException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @param context The transactional context to abandon. - * - * @throws AMQException If the operation fails for any reason. - */ - void abortTran(StoreContext context) throws AMQException; - - /** - * Tests a transactional context to see if it has been begun but not yet committed or aborted. - * - * @param context The transactional context to test. - * - * @return true if the transactional context is live, false otherwise. - */ - boolean inTran(StoreContext context); - - /** - * Return a valid, currently unused message id. - * - * @return A fresh message id. - */ - Long getNewMessageId(); - - /** - * Stores a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param index The index of the data chunk. - * @param contentBody The content of the data chunk. - * @param lastContentBody Flag to indicate that this is the last such chunk for the message. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, - boolean lastContentBody) throws AMQException; - - /** - * Stores message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param messageMetaData The message meta data to store. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - - /** - * Retrieves message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the meta-data for. - * - * @return The message meta data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - - /** - * Retrieves a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the data chunk for. - * @param index The offset index of the data chunk within the message. - * - * @return A chunk of message data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; /** * Is this store capable of persisting the data - * + * * @return true if this store is capable of persisting data */ boolean isPersistent(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java new file mode 100755 index 0000000000..ba65b8e1ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface MessageStoreRecoveryHandler +{ + StoredMessageRecoveryHandler begin(); + + public static interface StoredMessageRecoveryHandler + { + void message(StoredMessage message); + + void completeMessageRecovery(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java new file mode 100755 index 0000000000..12d2a6a6c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public interface StorableMessageMetaData +{ + MessageMetaDataType getType(); + + int getStorableSize(); + + int writeToBuffer(int offsetInMetaData, ByteBuffer dest); + + int getContentSize(); + + boolean isPersistent(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index fdb56a1a55..88cc68bc71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -35,6 +35,7 @@ public class StoreContext private String _name; private Object _payload; + public StoreContext() { _name = "StoreContext"; @@ -68,4 +69,5 @@ public class StoreContext { return "<_name = " + _name + ", _payload = " + _payload + ">"; } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java new file mode 100755 index 0000000000..867fb4f9c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public class StoredMemoryMessage implements StoredMessage +{ + private final long _messageNumber; + private final ByteBuffer _content; + private final StorableMessageMetaData _metaData; + + StoredMemoryMessage(long messageNumber, StorableMessageMetaData metaData) + { + _messageNumber = messageNumber; + _metaData = metaData; + _content = ByteBuffer.allocate(metaData.getContentSize()); + + } + + public long getMessageNumber() + { + return _messageNumber; + } + + public void addContent(int offsetInMessage, ByteBuffer src) + { + src = src.duplicate(); + ByteBuffer dst = _content.duplicate(); + dst.position(offsetInMessage); + dst.put(src); + } + + public int getContent(int offset, ByteBuffer dst) + { + ByteBuffer src = _content.duplicate(); + src.position(offset); + src = src.slice(); + if(dst.remaining() < src.limit()) + { + src.limit(dst.remaining()); + } + dst.put(src); + return src.limit(); + } + + public TransactionLog.StoreFuture flushToStore() + { + return MessageStore.IMMEDIATE_FUTURE; + } + + + public StorableMessageMetaData getMetaData() + { + return _metaData; + } + + public void remove() + { + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java new file mode 100755 index 0000000000..0bc45c6718 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java @@ -0,0 +1,38 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public interface StoredMessage +{ + M getMetaData(); + + public long getMessageNumber(); + + void addContent(int offsetInMessage, ByteBuffer src); + + int getContent(int offsetInMessage, ByteBuffer dst); + + TransactionLog.StoreFuture flushToStore(); + + void remove(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java new file mode 100755 index 0000000000..e6a33e23d6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.AMQException; +import org.apache.commons.configuration.Configuration; + +public interface TransactionLog +{ + + public static interface Transaction + { + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param queue The queue to place the message on. + * @param messageId The message to enqueue. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param queue The queue to place the message on. + * @param messageId The message to dequeue. + * @throws org.apache.qpid.AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + + + /** + * Commits all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void commitTran() throws AMQException; + + /** + * Commits all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + StoreFuture commitTranAsync() throws AMQException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void abortTran() throws AMQException; + + + + } + + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception; + + Transaction newTransaction(); + + + + public static interface StoreFuture + { + boolean isComplete(); + + void waitForCompletion(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java new file mode 100755 index 0000000000..7781c52df3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface TransactionLogRecoveryHandler +{ + QueueEntryRecoveryHandler begin(TransactionLog log); + + public static interface QueueEntryRecoveryHandler + { + void queueEntry(String queuename, long messageId); + + void completeQueueEntryRecovery(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java new file mode 100755 index 0000000000..0d81dd151d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java @@ -0,0 +1,26 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface TransactionLogResource +{ + public String getResourceName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java new file mode 100755 index 0000000000..b49b12fb79 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java @@ -0,0 +1,93 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.log4j.Logger; + + +class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener +{ + private static final Logger _logger = Logger.getLogger(ExplicitAcceptDispositionChangeListener.class); + + + private final QueueEntry _entry; + private final Subscription_0_10 _sub; + + public ExplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10) + { + _entry = entry; + _sub = subscription_0_10; + } + + public void onAccept() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.getSession().acknowledge(subscription, _entry); + } + else + { + _logger.warn("MessageAccept received for message which has not been acquired (likely client error)"); + } + + } + + public void onRelease() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.release(_entry); + } + else + { + _logger.warn("MessageRelease received for message which has not been acquired (likely client error)"); + } + } + + public void onReject() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.reject(_entry); + } + else + { + _logger.warn("MessageReject received for message which has not been acquired (likely client error)"); + } + + } + + public boolean acquire() + { + return _entry.acquire(getSubscription()); + } + + + private Subscription_0_10 getSubscription() + { + return _sub; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java new file mode 100755 index 0000000000..b5bb2014b5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.log4j.Logger; + +class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener +{ + private static final Logger _logger = Logger.getLogger(ImplicitAcceptDispositionChangeListener.class); + + + private final QueueEntry _entry; + private Subscription_0_10 _sub; + + public ImplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10) + { + _entry = entry; + _sub = subscription_0_10; + } + + public void onAccept() + { + _logger.warn("MessageAccept received for message which is using NONE as the accept mode (likely client error)"); + } + + public void onRelease() + { + if(_entry.isAcquiredBy(_sub)) + { + getSubscription().release(_entry); + } + else + { + _logger.warn("MessageRelease received for message which has not been acquired (likely client error)"); + } + } + + public void onReject() + { + if(_entry.isAcquiredBy(_sub)) + { + getSubscription().reject(_entry); + } + else + { + _logger.warn("MessageReject received for message which has not been acquired (likely client error)"); + } + + } + + public boolean acquire() + { + boolean acquired = _entry.acquire(getSubscription()); + //TODO - why acknowledge here??? seems bizarre... + // getSubscription().getSession().acknowledge(getSubscription(), _entry); + return acquired; + + } + + public Subscription_0_10 getSubscription() + { + return _sub; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java new file mode 100755 index 0000000000..8a2a370236 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.transport.Method; + +public class MessageAcceptCompletionListener implements Method.CompletionListener +{ + private final Subscription_0_10 _sub; + private final QueueEntry _entry; + private final ServerSession _session; + private boolean _restoreCredit; + + public MessageAcceptCompletionListener(Subscription_0_10 sub, ServerSession session, QueueEntry entry, boolean restoreCredit) + { + super(); + _sub = sub; + _entry = entry; + _session = session; + _restoreCredit = restoreCredit; + } + + public void onComplete(Method method) + { + if(_restoreCredit) + { + _sub.restoreCredit(_entry); + } + if(_entry.isAcquiredBy(_sub)) + { + _session.acknowledge(_sub, _entry); + } + + _session.removeDispositionListener(method); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index c9042325bf..4db9c305b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -46,10 +46,12 @@ public interface Subscription AMQQueue getQueue(); QueueEntry.SubscriptionAcquiredState getOwningState(); + QueueEntry.SubscriptionAssignedState getAssignedState(); + void setQueue(AMQQueue queue, boolean exclusive); - AMQChannel getChannel(); + void setNoLocal(boolean noLocal); AMQShortString getConsumerTag(); @@ -63,23 +65,24 @@ public interface Subscription boolean isClosed(); - boolean isBrowser(); + boolean acquires(); - void close(); + boolean seesRequeues(); - boolean filtersMessages(); + void close(); void send(QueueEntry msg) throws AMQException; - void queueDeleted(AMQQueue queue); + void queueDeleted(AMQQueue queue); boolean wouldSuspend(QueueEntry msg); void getSendLock(); + void releaseSendLock(); - void resend(final QueueEntry entry) throws AMQException; + void onDequeue(final QueueEntry queueEntry); void restoreCredit(final QueueEntry queueEntry); @@ -87,13 +90,17 @@ public interface Subscription public State getState(); - QueueEntry getLastSeenEntry(); + AMQQueue.Context getQueueContext(); - boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); + void setQueueContext(AMQQueue.Context queueContext); boolean isActive(); + void confirmAutoClose(); + + public void set(String key, Object value); + public Object get(String key); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 2893e916cc..bb2e5ae918 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -25,6 +25,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -33,6 +35,8 @@ import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; @@ -45,7 +49,6 @@ import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; /** * Encapsulation of a supscription to a queue.

      Ties together the protocol session of a subscriber, the consumer tag @@ -65,11 +68,16 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final AtomicReference _state = new AtomicReference(State.ACTIVE); - private final AtomicReference _queueContext = new AtomicReference(null); + private AMQQueue.Context _queueContext; + private final ClientDeliveryMethod _deliveryMethod; private final RecordDeliveryMethod _recordMethod; - private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this); + + private final Map _properties = new ConcurrentHashMap(); + private final Lock _stateChangeLock; private static final AtomicLong idGenerator = new AtomicLong(0); @@ -78,6 +86,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private LogSubject _logSubject; private LogActor _logActor; + static final class BrowserSubscription extends SubscriptionImpl { public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, @@ -153,38 +162,28 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage @Override public void send(QueueEntry entry) throws AMQException { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - StoreContext storeContext = getChannel().getStoreContext(); - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - entry.dequeue(storeContext); + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + entry.dequeue(); - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); - sendToClient(entry, deliveryTag); + sendToClient(entry, deliveryTag); - } - entry.dispose(storeContext); } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? + entry.dispose(); + - entry.setDeliveredToSubscription(); - } } @Override @@ -225,39 +224,30 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public void send(QueueEntry entry) throws AMQException { - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); - recordMessageDelivery(entry, deliveryTag); - sendToClient(entry, deliveryTag); + recordMessageDelivery(entry, deliveryTag); + sendToClient(entry, deliveryTag); - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - entry.setDeliveredToSubscription(); } } + } @@ -268,7 +258,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final AMQShortString _consumerTag; - private final boolean _noLocal; + private boolean _noLocal; private final FlowCreditManager _creditManager; @@ -423,43 +413,35 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public boolean hasInterest(QueueEntry entry) { + + + + //check that the message hasn't been rejected if (entry.isRejectedBy(this)) { if (_logger.isDebugEnabled()) { - _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); + _logger.debug("Subscription:" + this + " rejected message:" + entry); } // return false; } if (_noLocal) { - //todo - client id should be recoreded so we don't have to handle + + AMQMessage message = (AMQMessage) entry.getMessage(); + + //todo - client id should be recorded so we don't have to handle // the case where this is null. - final Object publisherId = entry.getMessage().getPublisherClientInstance(); + final Object publisher = message.getPublisherIdentifier(); // We don't want local messages so check to see if message is one we sent - Object localInstance; + Object localInstance = getProtocolSession(); - if (publisherId != null && (getProtocolSession().getClientProperties() != null) && - (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + if(publisher.equals(localInstance)) { - if(publisherId.equals(localInstance)) - { - return false; - } - } - else - { - - localInstance = getProtocolSession().getClientIdentifier(); - - //todo - client id should be recoreded so we don't have to do the null check - if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) - { - return false; - } + return false; } @@ -468,7 +450,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if (_logger.isDebugEnabled()) { - _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity()); + _logger.debug("(" + this + ") checking filters for message (" + entry); } return checkFilters(entry); @@ -483,7 +465,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private boolean checkFilters(QueueEntry msg) { - return (_filters == null) || _filters.allAllow(msg.getMessage()); + return (_filters == null) || _filters.allAllow(msg); } public boolean isAutoClose() @@ -550,11 +532,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _stateChangeLock.unlock(); } - public void resend(final QueueEntry entry) throws AMQException - { - _queue.resend(entry, this); - } - public AMQChannel getChannel() { return _channel; @@ -585,12 +562,18 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _queue; } + public void onDequeue(final QueueEntry queueEntry) + { + restoreCredit(queueEntry); + } + public void restoreCredit(final QueueEntry queueEntry) { - _creditManager.addCredit(1, queueEntry.getSize()); + _creditManager.restoreCredit(1, queueEntry.getSize()); } + public void creditStateChanged(boolean hasCredit) { @@ -628,22 +611,14 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } - public QueueEntry getLastSeenEntry() + public AMQQueue.Context getQueueContext() { - QueueEntry entry = _queueContext.get(); - - if(_logger.isDebugEnabled()) - { - _logger.debug(_logActor + ": lastSeenEntry: " + (entry == null ? "null" : entry.debugIdentity())); - } - - return entry; + return _queueContext; } - public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) + public void setQueueContext(AMQQueue.Context context) { - _logger.debug(debugIdentity() + " Setting Last Seen To:" + (newvalue == null ? "nullNV" : newvalue.debugIdentity())); - return _queueContext.compareAndSet(expected,newvalue); + _queueContext = context; } @@ -670,4 +645,43 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _owningState; } + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return _assignedState; + } + + + public void confirmAutoClose() + { + ProtocolOutputConverter converter = getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(getChannel().getChannelId(), getConsumerTag()); + } + + public boolean acquires() + { + return !isBrowser(); + } + + public boolean seesRequeues() + { + return !isBrowser(); + } + + public void set(String key, Object value) + { + _properties.put(key, value); + } + + public Object get(String key) + { + return _properties.get(key); + } + + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + abstract boolean isBrowser(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java new file mode 100644 index 0000000000..fb0a5cf2c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -0,0 +1,658 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.CreditCreditManager; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.SubscriptionActor; +import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentHeaderProperties; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.AMQException; +import org.apache.qpid.transport.*; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.nio.ByteBuffer; + +public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener +{ + + private static final AtomicLong idGenerator = new AtomicLong(0); + // Create a simple ID that increments for ever new Subscription + private final long _subscriptionID = idGenerator.getAndIncrement(); + + private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this); + + private final Lock _stateChangeLock = new ReentrantLock(); + + private final AtomicReference _state = new AtomicReference(State.ACTIVE); + private AMQQueue.Context _queueContext; + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + + private FlowCreditManager_0_10 _creditManager; + + + private StateListener _stateListener = new StateListener() + { + + public void stateChange(Subscription sub, State oldState, State newState) + { + + } + }; + private AMQQueue _queue; + private final String _destination; + private boolean _noLocal; + private final FilterManager _filters; + private final MessageAcceptMode _acceptMode; + private final MessageAcquireMode _acquireMode; + private MessageFlowMode _flowMode; + private final ServerSession _session; + private AtomicBoolean _stopped = new AtomicBoolean(true); + private ConcurrentHashMap _sentMap = new ConcurrentHashMap(); + private static final Struct[] EMPTY_STRUCT_ARRAY = new Struct[0]; + + private LogSubject _logSubject; + private LogActor _logActor; + private Map _properties = new ConcurrentHashMap(); + + + public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, + MessageAcquireMode acquireMode, + MessageFlowMode flowMode, + FlowCreditManager_0_10 creditManager, + FilterManager filters) + { + _session = session; + _destination = destination; + _acceptMode = acceptMode; + _acquireMode = acquireMode; + _creditManager = creditManager; + _flowMode = flowMode; + _filters = filters; + _creditManager.addStateListener(this); + _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED); + + + } + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public QueueEntry.SubscriptionAcquiredState getOwningState() + { + return _owningState; + } + + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return _assignedState; + } + + public void setQueue(AMQQueue queue, boolean exclusive) + { + if(getQueue() != null) + { + throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); + } + _queue = queue; + _logSubject = new SubscriptionLogSubject(this); + _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); + + } + + public AMQShortString getConsumerTag() + { + return new AMQShortString(_destination); + } + + public boolean isSuspended() + { + return !isActive() || _deleted.get(); // TODO check for Session suspension + } + + public boolean hasInterest(QueueEntry entry) + { + + + + //check that the message hasn't been rejected + if (entry.isRejectedBy(this)) + { + + return false; + } + + + + if (_noLocal + && (entry.getMessage() instanceof MessageTransferMessage) + && ((MessageTransferMessage)entry.getMessage()).getSession() == _session) + { + return false; + } + + + return checkFilters(entry); + + + } + + private boolean checkFilters(QueueEntry entry) + { + return (_filters == null) || _filters.allAllow(entry); + } + + public boolean isAutoClose() + { + // no such thing in 0-10 + return false; + } + + public boolean isClosed() + { + return getState() == State.CLOSED; + } + + public boolean isBrowser() + { + return _acquireMode == MessageAcquireMode.NOT_ACQUIRED; + } + + public boolean seesRequeues() + { + return _acquireMode != MessageAcquireMode.NOT_ACQUIRED || _acceptMode == MessageAcceptMode.EXPLICIT; + } + + public void close() + { + boolean closed = false; + State state = getState(); + + _stateChangeLock.lock(); + try + { + while(!closed && state != State.CLOSED) + { + closed = _state.compareAndSet(state, State.CLOSED); + if(!closed) + { + state = getState(); + } + else + { + _stateListener.stateChange(this,state, State.CLOSED); + } + } + _creditManager.removeListener(this); + } + finally + { + _stateChangeLock.unlock(); + } + + + + } + + public void creditStateChanged(boolean hasCredit) + { + + if(hasCredit) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + else + { + // this is a hack to get round the issue of increasing bytes credit + _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE); + } + } + else + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + } + } + + + private class AddMessageDispositionListnerAction implements Runnable + { + public MessageTransfer _xfr; + public ServerSession.MessageDispositionChangeListener _action; + + public void run() + { + _session.onMessageDispositionChange(_xfr, _action); + } + } + + private final AddMessageDispositionListnerAction _postIdSettingAction = new AddMessageDispositionListnerAction(); + + public void send(final QueueEntry entry) throws AMQException + { + ServerMessage serverMsg = entry.getMessage(); + + + MessageTransfer xfr; + + if(serverMsg instanceof MessageTransferMessage) + { + + MessageTransferMessage msg = (MessageTransferMessage) serverMsg; + + + Struct[] headers; + if(msg.getHeader() == null) + { + headers = EMPTY_STRUCT_ARRAY; + } + else + { + headers = msg.getHeader().getStructs(); + } + + ArrayList newHeaders = new ArrayList(headers.length); + DeliveryProperties origDeliveryProps = null; + for(Struct header : headers) + { + if(header instanceof DeliveryProperties) + { + origDeliveryProps = (DeliveryProperties) header; + } + else + { + newHeaders.add(header); + } + } + + DeliveryProperties deliveryProps = new DeliveryProperties(); + if(origDeliveryProps != null) + { + if(origDeliveryProps.hasDeliveryMode()) + { + deliveryProps.setDeliveryMode(origDeliveryProps.getDeliveryMode()); + } + if(origDeliveryProps.hasExchange()) + { + deliveryProps.setExchange(origDeliveryProps.getExchange()); + } + if(origDeliveryProps.hasExpiration()) + { + deliveryProps.setExpiration(origDeliveryProps.getExpiration()); + } + if(origDeliveryProps.hasPriority()) + { + deliveryProps.setPriority(origDeliveryProps.getPriority()); + } + if(origDeliveryProps.hasRoutingKey()) + { + deliveryProps.setRoutingKey(origDeliveryProps.getRoutingKey()); + } + + } + + deliveryProps.setRedelivered(entry.isRedelivered()); + + newHeaders.add(deliveryProps); + Header header = new Header(newHeaders); + + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); + } + else + { + AMQMessage message_0_8 = (AMQMessage) serverMsg; + DeliveryProperties deliveryProps = new DeliveryProperties(); + MessageProperties messageProps = new MessageProperties(); + + int size = (int) message_0_8.getSize(); + ByteBuffer body = ByteBuffer.allocate(size); + message_0_8.getContent(body, 0); + body.flip(); + + Struct[] headers = new Struct[] { deliveryProps, messageProps }; + + BasicContentHeaderProperties properties = + (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().properties; + final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange(); + if(exchange != null) + { + deliveryProps.setExchange(exchange.toString()); + } + deliveryProps.setExpiration(message_0_8.getExpiration()); + deliveryProps.setImmediate(message_0_8.isImmediate()); + deliveryProps.setPriority(MessageDeliveryPriority.get(properties.getPriority())); + deliveryProps.setRedelivered(entry.isRedelivered()); + deliveryProps.setRoutingKey(message_0_8.getRoutingKey()); + deliveryProps.setTimestamp(properties.getTimestamp()); + + messageProps.setContentEncoding(properties.getEncodingAsString()); + messageProps.setContentLength(size); + if(properties.getAppId() != null) + { + messageProps.setAppId(properties.getAppId().getBytes()); + } + messageProps.setContentType(properties.getContentTypeAsString()); + if(properties.getCorrelationId() != null) + { + messageProps.setCorrelationId(properties.getCorrelationId().getBytes()); + } + + // TODO - ReplyTo + + if(properties.getUserId() != null) + { + messageProps.setUserId(properties.getUserId().getBytes()); + } + + final Map appHeaders = new HashMap(); + + properties.getHeaders().processOverElements( + new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + Object val = value.getValue(); + if(val instanceof AMQShortString) + { + val = val.toString(); + } + appHeaders.put(propertyName, val); + return true; + } + + public Object getResult() + { + return appHeaders; + } + }); + + + messageProps.setApplicationHeaders(appHeaders); + + Header header = new Header(headers); + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + } + + if(_acceptMode == MessageAcceptMode.NONE) + { + xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + } + else if(_flowMode == MessageFlowMode.WINDOW) + { + xfr.setCompletionListener(new Method.CompletionListener() + { + public void onComplete(Method method) + { + restoreCredit(entry); + } + }); + } + + + _postIdSettingAction._xfr = xfr; + if(_acceptMode == MessageAcceptMode.EXPLICIT) + { + _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + } + else + { + _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + } + + _session.sendMessage(xfr, _postIdSettingAction); + + } + + void reject(QueueEntry entry) + { + entry.setRedelivered(); + entry.routeToAlternate(); + + } + + void release(QueueEntry entry) + { + entry.setRedelivered(); + entry.release(); + } + + public void queueDeleted(AMQQueue queue) + { + _deleted.set(true); + } + + public boolean wouldSuspend(QueueEntry msg) + { + return !_creditManager.useCreditForMessage(msg.getMessage()); + } + + public void getSendLock() + { + _stateChangeLock.lock(); + } + + public void releaseSendLock() + { + _stateChangeLock.unlock(); + } + + public void restoreCredit(QueueEntry queueEntry) + { + _creditManager.restoreCredit(1, queueEntry.getSize()); + } + + public void onDequeue(QueueEntry queueEntry) + { + + } + + public void setStateListener(StateListener listener) + { + _stateListener = listener; + } + + public State getState() + { + return _state.get(); + } + + public AMQQueue.Context getQueueContext() + { + return _queueContext; + } + + public void setQueueContext(AMQQueue.Context queueContext) + { + _queueContext = queueContext; + } + + public boolean isActive() + { + return getState() == State.ACTIVE; + } + + public void confirmAutoClose() + { + //No such thing in 0-10 + } + + public void set(String key, Object value) + { + _properties.put(key, value); + } + + public Object get(String key) + { + return _properties.get(key); + } + + + public FlowCreditManager_0_10 getCreditManager() + { + return _creditManager; + } + + + public void stop() + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + _stopped.set(true); + FlowCreditManager_0_10 creditManager = getCreditManager(); + creditManager.clearCredit(); + } + + public void addCredit(MessageCreditUnit unit, long value) + { + FlowCreditManager_0_10 creditManager = getCreditManager(); + + switch (unit) + { + case MESSAGE: + + creditManager.addCredit(value, 0L); + break; + case BYTE: + creditManager.addCredit(0l, value); + break; + } + + _stopped.set(false); + + if(creditManager.hasCredit()) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + } + + } + + public void setFlowMode(MessageFlowMode flowMode) + { + + + _creditManager.removeListener(this); + + switch(flowMode) + { + case CREDIT: + _creditManager = new CreditCreditManager(0l,0l); + break; + case WINDOW: + _creditManager = new WindowCreditManager(0l,0l); + break; + default: + throw new RuntimeException("Unknown message flow mode: " + flowMode); + } + _flowMode = flowMode; + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + + _creditManager.addStateListener(this); + + } + + public boolean isStopped() + { + return _stopped.get(); + } + + public boolean acquires() + { + return _acquireMode == MessageAcquireMode.PRE_ACQUIRED; + } + + public void acknowledge(QueueEntry entry) + { + // TODO Fix Store Context / cleanup + if(entry.isAcquiredBy(this)) + { + entry.discard(); + } + } + + public void flush() throws AMQException + { + _queue.flushSubscription(this); + stop(); + } + + public long getSubscriptionID() + { + return _subscriptionID; + } + + public LogActor getLogActor() + { + return _logActor; + } + + ServerSession getSession() + { + return _session; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java new file mode 100644 index 0000000000..2a8b99ddac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.Method; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ServerConnection extends Connection +{ + @Override + protected void invoke(Method method) + { + super.invoke(method); + } + + @Override + protected void setState(State state) + { + super.setState(state); + } + + @Override + public ServerConnectionDelegate getConnectionDelegate() + { + return (ServerConnectionDelegate) super.getConnectionDelegate(); + } + + public void setConnectionDelegate(ServerConnectionDelegate delegate) + { + super.setConnectionDelegate(delegate); + } + + private VirtualHost _virtualHost; + + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java new file mode 100644 index 0000000000..cfc5bb3a72 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -0,0 +1,120 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; + +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import java.util.*; + + +public class ServerConnectionDelegate extends ServerDelegate +{ + + private String _localFQDN; + private final IApplicationRegistry _appRegistry; + + + public ServerConnectionDelegate(IApplicationRegistry appRegistry, + String localFQDN) + { + this(Collections.EMPTY_MAP, Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); + } + + + public ServerConnectionDelegate(Map properties, + List locales, + IApplicationRegistry appRegistry, + String localFQDN) + { + super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales); + _appRegistry = appRegistry; + _localFQDN = localFQDN; + } + + private static List parseToList(String mechanisms) + { + List list = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(mechanisms, " "); + while(tokenizer.hasMoreTokens()) + { + list.add(tokenizer.nextToken()); + } + return list; + } + + @Override public ServerSession getSession(Connection conn, SessionAttach atc) + { + + SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry); + + ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0); + //ssn.setSessionListener(new Echo()); + return ssn; + } + + + + + @Override + protected SaslServer createSaslServer(String mechanism) throws SaslException + { + return _appRegistry.getAuthenticationManager().createSaslServer(mechanism, _localFQDN); + + } + + + @Override public void connectionOpen(Connection conn, ConnectionOpen open) + { + ServerConnection sconn = (ServerConnection) conn; + + VirtualHost vhost; + String vhostName; + if(open.hasVirtualHost()) + { + vhostName = open.getVirtualHost(); + } + else + { + vhostName = ""; + } + vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName); + + if(vhost != null) + { + sconn.setVirtualHost(vhost); + + sconn.invoke(new ConnectionOpenOk(Collections.EMPTY_LIST)); + + sconn.setState(Connection.State.OPEN); + } + else + { + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown vistrulhost '"+vhostName+"'")); + sconn.setState(Connection.State.CLOSING); + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java new file mode 100644 index 0000000000..77dfbc0376 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -0,0 +1,398 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.AMQException; + +import java.util.*; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.security.Principal; +import java.lang.ref.WeakReference; + +import static org.apache.qpid.util.Serial.*; +import com.sun.security.auth.UserPrincipal; + +public class ServerSession extends Session implements PrincipalHolder +{ + private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); + + public static interface MessageDispositionChangeListener + { + public void onAccept(); + + public void onRelease(); + + public void onReject(); + + public boolean acquire(); + + + } + + public static interface Task + { + public void doTask(ServerSession session); + } + + + private final SortedMap _messageDispositionListenerMap = + new ConcurrentSkipListMap(); + + private ServerTransaction _transaction; + + private Principal _principal; + + private Map _subscriptions = new ConcurrentHashMap(); + + private final List _taskList = new CopyOnWriteArrayList(); + + private final WeakReference _reference; + + + ServerSession(Connection connection, Binary name, long expiry) + { + super(connection, name, expiry); + + _transaction = new AutoCommitTransaction(this.getMessageStore()); + _principal = new UserPrincipal(connection.getAuthorizationID()); + _reference = new WeakReference(this); + } + + ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) + { + super(connection, delegate, name, expiry); + _transaction = new AutoCommitTransaction(this.getMessageStore()); + _principal = new UserPrincipal(connection.getAuthorizationID()); + _reference = new WeakReference(this); + } + + @Override + protected boolean isFull(int id) + { + return isCommandsFull(id); + } + + public void enqueue(final ServerMessage message, final ArrayList queues) + { + + _transaction.enqueue(queues,message, new ServerTransaction.Action() + { + + AMQQueue[] _queues = queues.toArray(new AMQQueue[queues.size()]); + + public void postCommit() + { + for(int i = 0; i < _queues.length; i++) + { + try + { + _queues[i].enqueue(message); + } + catch (AMQException e) + { + // TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); + } + } + } + + public void onRollback() + { + // NO-OP + } + }); + + + } + + + public void sendMessage(MessageTransfer xfr, + Runnable postIdSettingAction) + { + invoke(xfr, postIdSettingAction); + } + + public void onMessageDispositionChange(MessageTransfer xfr, MessageDispositionChangeListener acceptListener) + { + _messageDispositionListenerMap.put(xfr.getId(), acceptListener); + } + + + private static interface MessageDispositionAction + { + void performAction(MessageDispositionChangeListener listener); + } + + public void accept(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onAccept(); + } + }); + } + + + public void release(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onRelease(); + } + }); + } + + public void reject(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onReject(); + } + }); + } + + public RangeSet acquire(RangeSet transfers) + { + RangeSet acquired = new RangeSet(); + + if(!_messageDispositionListenerMap.isEmpty()) + { + Iterator unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); + Iterator rangeIter = transfers.iterator(); + + if(rangeIter.hasNext()) + { + Range range = rangeIter.next(); + + while(range != null && unacceptedMessages.hasNext()) + { + int next = unacceptedMessages.next(); + while(gt(next, range.getUpper())) + { + if(rangeIter.hasNext()) + { + range = rangeIter.next(); + } + else + { + range = null; + break; + } + } + if(range != null && range.includes(next)) + { + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.get(next); + if(changeListener.acquire()) + { + acquired.add(next); + } + } + + + } + + } + + + } + + return acquired; + } + + public void dispositionChange(RangeSet ranges, MessageDispositionAction action) + { + if(ranges != null && !_messageDispositionListenerMap.isEmpty()) + { + Iterator unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); + Iterator rangeIter = ranges.iterator(); + + if(rangeIter.hasNext()) + { + Range range = rangeIter.next(); + + while(range != null && unacceptedMessages.hasNext()) + { + int next = unacceptedMessages.next(); + while(gt(next, range.getUpper())) + { + if(rangeIter.hasNext()) + { + range = rangeIter.next(); + } + else + { + range = null; + break; + } + } + if(range != null && range.includes(next)) + { + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next); + action.performAction(changeListener); + } + + + } + + } + + } + } + + public void removeDispositionListener(Method method) + { + _messageDispositionListenerMap.remove(method.getId()); + } + + public void onClose() + { + _transaction.rollback(); + for(MessageDispositionChangeListener listener : _messageDispositionListenerMap.values()) + { + listener.onRelease(); + } + _messageDispositionListenerMap.clear(); + + for (Task task : _taskList) + { + task.doTask(this); + } + + } + + public void acknowledge(final Subscription_0_10 sub, final QueueEntry entry) + { + _transaction.dequeue(entry.getQueue(), entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + sub.acknowledge(entry); + } + + public void onRollback() + { + entry.release(); + } + }); + } + + public Collection getSubscriptions() + { + return _subscriptions.values(); + } + + public void register(String destination, Subscription_0_10 sub) + { + _subscriptions.put(destination == null ? NULL_DESTINTATION : destination, sub); + } + + public Subscription_0_10 getSubscription(String destination) + { + return _subscriptions.get(destination == null ? NULL_DESTINTATION : destination); + } + + public void unregister(Subscription_0_10 sub) + { + _subscriptions.remove(sub.getConsumerTag().toString()); + try + { + sub.getSendLock(); + AMQQueue queue = sub.getQueue(); + if(queue != null) + { + queue.unregisterSubscription(sub); + } + + } + catch (AMQException e) + { + // TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + finally + { + sub.releaseSendLock(); + } + } + + public void selectTx() + { + _transaction = new LocalTransaction(this.getMessageStore()); + } + + public void commit() + { + _transaction.commit(); + } + + public void rollback() + { + _transaction.rollback(); + } + + public Principal getPrincipal() + { + return _principal; + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + public WeakReference getReference() + { + return _reference; + } + + public MessageStore getMessageStore() + { + return ((ServerConnection)getConnection()).getVirtualHost().getMessageStore(); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java new file mode 100644 index 0000000000..df2754c16b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -0,0 +1,1193 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.flow.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +public class ServerSessionDelegate extends SessionDelegate +{ + private final IApplicationRegistry _appRegistry; + + public ServerSessionDelegate(IApplicationRegistry appRegistry) + { + _appRegistry = appRegistry; + } + + @Override + public void command(Session session, Method method) + { + super.command(session, method); + if (method.isSync()) + { + session.flushProcessed(); + } + } + + @Override + public void messageAccept(Session session, MessageAccept method) + { + ((ServerSession)session).accept(method.getTransfers()); + } + + + + @Override + public void messageReject(Session session, MessageReject method) + { + ((ServerSession)session).reject(method.getTransfers()); + } + + @Override + public void messageRelease(Session session, MessageRelease method) + { + ((ServerSession)session).release(method.getTransfers()); + } + + @Override + public void messageAcquire(Session session, MessageAcquire method) + { + RangeSet acquiredRanges = ((ServerSession)session).acquire(method.getTransfers()); + + Acquired result = new Acquired(acquiredRanges); + + + session.executionResult((int) method.getId(), result); + + + } + + @Override + public void messageResume(Session session, MessageResume method) + { + super.messageResume(session, method); + } + + @Override + public void messageSubscribe(Session session, MessageSubscribe method) + { + + //TODO - work around broken Python tests + if(!method.hasAcceptMode()) + { + method.setAcceptMode(MessageAcceptMode.EXPLICIT); + } + if(!method.hasAcquireMode()) + { + method.setAcquireMode(MessageAcquireMode.PRE_ACQUIRED); + + } + + /* if(!method.hasAcceptMode()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Accept-mode not supplied"); + } + else if(!method.hasAcquireMode()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Acquire-mode not supplied"); + } + else */if(!method.hasQueue()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not supplied"); + } + else + { + String destination = method.getDestination(); + + if(((ServerSession)session).getSubscription(destination)!=null) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Subscription already exists with destaination: '"+destination+"'"); + } + else + { + String queueName = method.getQueue(); + QueueRegistry queueRegistry = getQueueRegistry(session); + + + AMQQueue queue = queueRegistry.getQueue(queueName); + + if(queue == null) + { + exception(session,method,ExecutionErrorCode.NOT_FOUND, "Queue: " + queueName + " not found"); + } + else if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + { + exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); + } + else + { + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); + + // TODO filters + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + destination, + method.getAcceptMode(), + method.getAcquireMode(), + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(destination, sub); + try + { + queue.registerSubscription(sub, method.getExclusive()); + } + catch (AMQQueue.ExistingExclusiveSubscription existing) + { + exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an exclusive consumer"); + } + catch (AMQQueue.ExistingSubscriptionPreventsExclusive exclusive) + { + exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an existing consumer - can't subscribe exclusively"); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + } + } + } + } + + + @Override + public void messageTransfer(Session ssn, MessageTransfer xfr) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(ssn); + Exchange exchange; + if(xfr.hasDestination()) + { + exchange = exchangeRegistry.getExchange(xfr.getDestination()); + if(exchange == null) + { + exchange = exchangeRegistry.getDefaultExchange(); + } + } + else + { + exchange = exchangeRegistry.getDefaultExchange(); + } + + + DeliveryProperties delvProps = null; + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + { + delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); + } + + MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); + final MessageStore store = getVirtualHost(ssn).getMessageStore(); + StoredMessage storeMessage = store.addMessage(messageMetaData); + storeMessage.addContent(0,xfr.getBody()); + storeMessage.flushToStore(); + MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference()); + + ArrayList queues = exchange.route(message); + + + + if(queues != null && queues.size() != 0) + { + ((ServerSession) ssn).enqueue(message, queues); + } + else + { + if(delvProps == null || !delvProps.hasDiscardUnroutable() || !delvProps.getDiscardUnroutable()) + { + if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) + { + RangeSet rejects = new RangeSet(); + rejects.add(xfr.getId()); + MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); + ssn.invoke(reject); + } + else + { + Exchange alternate = exchange.getAlternateExchange(); + if(alternate != null) + { + queues = alternate.route(message); + if(queues != null && queues.size() != 0) + { + ((ServerSession) ssn).enqueue(message, queues); + } + else + { + //TODO - log the message discard + } + } + else + { + //TODO - log the message discard + } + + + } + } + + + } + + ssn.processed(xfr); + + } + + @Override + public void messageCancel(Session session, MessageCancel method) + { + String destination = method.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + else + { + ((ServerSession)session).unregister(sub); + } + } + + @Override + public void messageFlush(Session session, MessageFlush method) + { + String destination = method.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + else + { + + try + { + sub.flush(); + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); + } + } + } + + @Override + public void txSelect(Session session, TxSelect method) + { + // TODO - check current tx mode + ((ServerSession)session).selectTx(); + } + + @Override + public void txCommit(Session session, TxCommit method) + { + // TODO - check current tx mode + ((ServerSession)session).commit(); + } + + @Override + public void txRollback(Session session, TxRollback method) + { + // TODO - check current tx mode + ((ServerSession)session).rollback(); + } + + + @Override + public void exchangeDeclare(Session session, ExchangeDeclare method) + { + String exchangeName = method.getExchange(); + VirtualHost virtualHost = getVirtualHost(session); + Exchange exchange = getExchange(session, exchangeName); + + if(method.getPassive()) + { + if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: exchange-name '"+exchangeName+"'"); + + } + else + { + // TODO - check exchange has same properties + if(!exchange.getType().toString().equals(method.getType())) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); + } + } + + } + else + { + if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(), + method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(), + new AMQShortString(method.getType()))) + { + + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "permission denied: exchange-name '" + exchangeName + "'"; + + exception(session, method, errorCode, description); + + + } + else if(exchange == null) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + + + try + { + + exchange = exchangeFactory.createExchange(method.getExchange(), + method.getType(), + method.getDurable(), + method.getAutoDelete()); + + String alternateExchangeName = method.getAlternateExchange(); + if(alternateExchangeName != null && alternateExchangeName.length() != 0) + { + Exchange alternate = getExchange(session, alternateExchangeName); + exchange.setAlternateExchange(alternate); + } + + if (exchange.isDurable() && !exchange.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.createExchange(exchange); + } + + exchangeRegistry.registerExchange(exchange); + } + catch(AMQUnknownExchangeType e) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType()); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + else + { + if(!exchange.getType().toString().equals(method.getType())) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); + } + } + + } + } + + private void exception(Session session, Method method, ExecutionErrorCode errorCode, String description) + { + ExecutionException ex = new ExecutionException(); + ex.setErrorCode(errorCode); + ex.setCommandId(method.getId()); + ex.setDescription(description); + + session.invoke(ex); + + } + + private Exchange getExchange(Session session, String exchangeName) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + return exchangeRegistry.getExchange(exchangeName); + } + + private ExchangeRegistry getExchangeRegistry(Session session) + { + VirtualHost virtualHost = getVirtualHost(session); + return virtualHost.getExchangeRegistry(); + + } + + private VirtualHost getVirtualHost(Session session) + { + ServerConnection conn = getServerConnection(session); + VirtualHost vhost = conn.getVirtualHost(); + return vhost; + } + + private ServerConnection getServerConnection(Session session) + { + ServerConnection conn = (ServerConnection) session.getConnection(); + return conn; + } + + @Override + public void exchangeDelete(Session session, ExchangeDelete method) + { + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session, + exchangeRegistry.getExchange(method.getExchange()))) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); + + } + else + { + + try + { + Exchange exchange = getExchange(session, method.getExchange()); + + if(exchange != null && exchange.hasReferrers()) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); + } + else + { + exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); + + if (exchange.isDurable() && !exchange.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeExchange(exchange); + } + + } + } + catch (ExchangeInUseException e) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + } + + } + + @Override + public void exchangeQuery(Session session, ExchangeQuery method) + { + + ExchangeQueryResult result = new ExchangeQueryResult(); + + Exchange exchange = getExchange(session, method.getName()); + + if(exchange != null) + { + result.setDurable(exchange.isDurable()); + result.setType(exchange.getType().toString()); + result.setNotFound(false); + } + else + { + result.setNotFound(true); + } + + session.executionResult((int) method.getId(), result); + } + + @Override + public void exchangeBind(Session session, ExchangeBind method) + { + + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + if (!method.hasQueue()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set"); + } + else if (!method.hasExchange()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set"); + } +/* + else if (!method.hasBindingKey()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set"); + } +*/ + else + { + //TODO - here because of non-compiant python tests + if (!method.hasBindingKey()) + { + method.setBindingKey(method.getQueue()); + } + AMQQueue queue = queueRegistry.getQueue(method.getQueue()); + Exchange exchange = exchangeRegistry.getExchange(method.getExchange()); + if(queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found"); + } + else if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); + } + else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange, + queue, new AMQShortString(method.getBindingKey()))) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() + + "' to Queue: '" + method.getQueue() + + "' not allowed"); + } + else if(exchange.getType().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) + { + exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); + } + else + { + try + { + AMQShortString routingKey = new AMQShortString(method.getBindingKey()); + FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); + + if (!exchange.isBound(routingKey, fieldTable, queue)) + { + queue.bind(exchange, routingKey, fieldTable); + + } + else + { + // todo + } + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + + } + + + + } + + @Override + public void exchangeUnbind(Session session, ExchangeUnbind method) + { + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + if (!method.hasQueue()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set"); + } + else if (!method.hasExchange()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set"); + } + else if (!method.hasBindingKey()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set"); + } + else + { + AMQQueue queue = queueRegistry.getQueue(method.getQueue()); + Exchange exchange = exchangeRegistry.getExchange(method.getExchange()); + if(queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found"); + } + else if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); + } + else + { + try + { + queue.unBind(exchange, new AMQShortString(method.getBindingKey()), null); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + + + super.exchangeUnbind(session, method); + } + + @Override + public void exchangeBound(Session session, ExchangeBound method) + { + + ExchangeBoundResult result = new ExchangeBoundResult(); + Exchange exchange; + AMQQueue queue; + if(method.hasExchange()) + { + exchange = getExchange(session, method.getExchange()); + + if(exchange == null) + { + result.setExchangeNotFound(true); + } + } + else + { + exchange = getExchangeRegistry(session).getDefaultExchange(); + } + + + if(method.hasQueue()) + { + + queue = getQueue(session, method.getQueue()); + if(queue == null) + { + result.setQueueNotFound(true); + } + + + if(exchange != null && queue != null) + { + + boolean queueMatched = exchange.isBound(queue); + + result.setQueueNotMatched(!queueMatched); + + + if(method.hasBindingKey()) + { + + if(method.hasArguments()) + { + // TODO + } + if(queueMatched) + { + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey(), queue)); + } + else + { + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + } + } + else if (method.hasArguments()) + { + // TODO + + } + + result.setQueueNotMatched(!exchange.isBound(queue)); + + } + else if(exchange != null && method.hasBindingKey()) + { + if(method.hasArguments()) + { + // TODO + } + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + + } + + } + else if(exchange != null && method.hasBindingKey()) + { + if(method.hasArguments()) + { + // TODO + } + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + + } + + + session.executionResult((int) method.getId(), result); + + + } + + private AMQQueue getQueue(Session session, String queue) + { + QueueRegistry queueRegistry = getQueueRegistry(session); + return queueRegistry.getQueue(queue); + } + + private QueueRegistry getQueueRegistry(Session session) + { + return getVirtualHost(session).getQueueRegistry(); + } + + @Override + public void queueDeclare(Session session, QueueDeclare method) + { + + VirtualHost virtualHost = getVirtualHost(session); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + + String queueName = method.getQueue(); + + if (!method.getPassive()) + { + // Perform ACL if request is not passive + + if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(), + method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName))) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "permission denied: queue-name '" + queueName + "'"; + + exception(session, method, errorCode, description); + + // TODO control flow + return; + } + } + + + AMQQueue queue; + QueueRegistry queueRegistry = getQueueRegistry(session); + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + synchronized (queueRegistry) + { + + if (((queue = queueRegistry.getQueue(queueName)) == null)) + { + + if (method.getPassive()) + { + String description = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_FOUND; + + exception(session, method, errorCode, description); + + return; + } + else + { + try + { + queue = createQueue(queueName, method, virtualHost, (ServerSession)session); + if(method.getExclusive()) + { + queue.setPrincipalHolder((ServerSession)session); + queue.setExclusiveOwner(session); + } + final String alternateExchangeName = method.getAlternateExchange(); + if(alternateExchangeName != null && alternateExchangeName.length() != 0) + { + Exchange alternate = getExchange(session, alternateExchangeName); + queue.setAlternateExchange(alternate); + } + + if(method.hasArguments() && method.getArguments() != null) + { + if(method.getArguments().containsKey("no-local")) + { + Object no_local = method.getArguments().get("no-local"); + if(no_local instanceof Boolean && ((Boolean)no_local)) + { + queue.setNoLocal(true); + } + } + } + + + if (queue.isDurable() && !queue.isAutoDelete()) + { + if(method.hasArguments() && method.getArguments() != null) + { + Map args = method.getArguments(); + FieldTable ftArgs = new FieldTable(); + for(Map.Entry entry : args.entrySet()) + { + ftArgs.put(new AMQShortString(entry.getKey()), entry.getValue()); + } + store.createQueue(queue, ftArgs); + } + else + { + store.createQueue(queue); + } + } + queueRegistry.registerQueue(queue); + boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister(); + + if (autoRegister) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + + Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); + + queue.bind(defaultExchange, new AMQShortString(queueName), null); + + } + + if(method.hasAutoDelete() + && method.getAutoDelete() + && method.hasExclusive() + && method.getExclusive()) + { + final AMQQueue q = queue; + final ServerSession.Task deleteQueueTask = new ServerSession.Task() + { + + public void doTask(ServerSession session) + { + try + { + q.delete(); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + }; + final ServerSession s = (ServerSession) session; + s.addSessionCloseTask(deleteQueueTask); + queue.addQueueDeleteTask(new AMQQueue.Task() + { + + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(deleteQueueTask); + } + }); + } + else if(method.getExclusive()) + { + { + final AMQQueue q = queue; + final ServerSession.Task removeExclusive = new ServerSession.Task() + { + + public void doTask(ServerSession session) + { + q.setPrincipalHolder(null); + } + }; + final ServerSession s = (ServerSession) session; + s.addSessionCloseTask(removeExclusive); + queue.addQueueDeleteTask(new AMQQueue.Task() + { + + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(removeExclusive); + } + }); + } + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session))) + { + + String description = "Cannot declare queue('" + queueName + "')," + + " as exclusive queue with same name " + + "declared on another session"; + ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED; + + exception(session, method, errorCode, description); + + return; + } + + } + } + + + protected AMQQueue createQueue(final String queueName, + QueueDeclare body, + VirtualHost virtualHost, + final ServerSession session) + throws AMQException + { + final QueueRegistry registry = virtualHost.getQueueRegistry(); + + String owner = body.getExclusive() ? session.getPrincipal().getName() : null; + + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost, + body.getArguments()); + + + if (body.getExclusive() && !body.getDurable()) + { + final ServerSession.Task deleteQueueTask = + new ServerSession.Task() + { + public void doTask(ServerSession session) + { + if (registry.getQueue(queueName) == queue) + { + try + { + queue.delete(); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + } + } + }; + + session.addSessionCloseTask(deleteQueueTask); + + queue.addQueueDeleteTask(new AMQQueue.Task() + { + public void doTask(AMQQueue queue) + { + session.removeSessionCloseTask(deleteQueueTask); + } + }); + }// if exclusive and not durable + + return queue; + } + + @Override + public void queueDelete(Session session, QueueDelete method) + { + + String queueName = method.getQueue(); + if(queueName == null || queueName.length()==0) + { + exception(session, method, ExecutionErrorCode.INVALID_ARGUMENT, "No queue name supplied"); + + } + else + { + AMQQueue queue = getQueue(session, queueName); + + + if (queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); + } + else + { + if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + { + exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); + } + else if (method.getIfEmpty() && !queue.isEmpty()) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " not empty"); + } + else if (method.getIfUnused() && !queue.isUnused()) + { + // TODO - Error code + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " in use"); + + } + else + { + VirtualHost virtualHost = getVirtualHost(session); + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue)) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName); + } + else + { + try + { + int purged = queue.delete(); + if (queue.isDurable() && !queue.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeQueue(queue); + } + + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + + } + } + } + + } + + @Override + public void queuePurge(Session session, QueuePurge method) + { + String queueName = method.getQueue(); + if(queueName == null || queueName.length()==0) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied"); + + } + else + { + AMQQueue queue = getQueue(session, queueName); + + + if (queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); + } + else + { + //TODO + queue.clearQueue(); + } + } + + } + + @Override + public void queueQuery(Session session, QueueQuery method) + { + QueueQueryResult result = new QueueQueryResult(); + + AMQQueue queue = getQueue(session, method.getQueue()); + + if(queue != null) + { + result.setQueue(queue.getName().toString()); + result.setDurable(queue.isDurable()); + result.setExclusive(queue.isExclusive()); + result.setAutoDelete(queue.isAutoDelete()); + result.setArguments(queue.getArguments()); + result.setMessageCount(queue.getMessageCount()); + result.setSubscriberCount(queue.getConsumerCount()); + + } + + + session.executionResult((int) method.getId(), result); + + } + + @Override + public void messageSetFlowMode(Session session, MessageSetFlowMode sfm) + { + String destination = sfm.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, sfm, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + if(sub.isStopped()) + { + sub.setFlowMode(sfm.getFlowMode()); + } + } + + @Override + public void messageStop(Session session, MessageStop stop) + { + String destination = stop.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, stop, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + sub.stop(); + + } + + @Override + public void messageFlow(Session session, MessageFlow flow) + { + String destination = flow.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, flow, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + sub.addCredit(flow.getUnit(), flow.getValue()); + + } + + @Override + public void closed(Session session) + { + super.closed(session); + for(Subscription_0_10 sub : getSubscriptions(session)) + { + ((ServerSession)session).unregister(sub); + } + ((ServerSession)session).onClose(); + } + + public Collection getSubscriptions(Session session) + { + return ((ServerSession)session).getSubscriptions(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java new file mode 100755 index 0000000000..7b29106ba6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -0,0 +1,170 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.Collection; + +public class AutoCommitTransaction implements ServerTransaction +{ + + private final TransactionLog _transactionLog; + + public AutoCommitTransaction(TransactionLog transactionLog) + { + _transactionLog = transactionLog; + } + + + public void addPostCommitAction(Action postCommitAction) + { + postCommitAction.postCommit(); + } + + public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + + try + { + if(message.isPersistent() && queue.isDurable()) + { + + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.dequeueMessage(queue, message.getMessageNumber()); + // store.remove enqueue + // store.commit + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + } + + public void dequeue(Collection ackedMessages, Action postCommitAction) + { + try + { + TransactionLog.Transaction txn = null; + for(QueueEntry entry : ackedMessages) + { + ServerMessage message = entry.getMessage(); + AMQQueue queue = entry.getQueue(); + + if(message.isPersistent() && queue.isDurable()) + { + if(txn == null) + { + txn = _transactionLog.newTransaction(); + } + txn.dequeueMessage(queue, message.getMessageNumber()); + } + + } + if(txn != null) + { + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + } + + + public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + try + { + if(message.isPersistent() && queue.isDurable()) + { + + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.enqueueMessage(queue, message.getMessageNumber()); + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + + } + + public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + { + try + { + + if(message.isPersistent()) + { + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + Long id = message.getMessageNumber(); + for(AMQQueue q : queues) + { + if(q.isDurable()) + { + txn.enqueueMessage(q, id); + } + } + txn.commitTran(); + + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + + } + + public void commit() + { + + } + + public void rollback() + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java new file mode 100755 index 0000000000..9997fbe767 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -0,0 +1,243 @@ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; + +public class LocalTransaction implements ServerTransaction +{ + private final List _postCommitActions = new ArrayList(); + + private volatile TransactionLog.Transaction _transaction; + private TransactionLog _transactionLog; + + public LocalTransaction(TransactionLog transactionLog) + { + _transactionLog = transactionLog; + } + + public void addPostCommitAction(Action postCommitAction) + { + _postCommitActions.add(postCommitAction); + } + + public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + if(message.isPersistent() && queue.isDurable()) + { + try + { + + beginTranIfNecessary(); + _transaction.dequeueMessage(queue, message.getMessageNumber()); + + } + catch(AMQException e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + } + + public void dequeue(Collection queueEntries, Action postCommitAction) + { + try + { + + for(QueueEntry entry : queueEntries) + { + ServerMessage message = entry.getMessage(); + AMQQueue queue = entry.getQueue(); + if(message.isPersistent() && queue.isDurable()) + { + beginTranIfNecessary(); + _transaction.dequeueMessage(queue, message.getMessageNumber()); + } + + } + } + catch(AMQException e) + { + tidyUpOnError(e); + } + _postCommitActions.add(postCommitAction); + + } + + private void tidyUpOnError(Exception e) + { + try + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + } + finally + { + try + { + _transaction.abortTran(); + } + catch (Exception e1) + { + // TODO could try to chain the information to the original error + } + _transaction = null; + _postCommitActions.clear(); + } + + throw new RuntimeException(e); + } + + private void beginTranIfNecessary() + { + if(_transaction == null) + { + try + { + _transaction = _transactionLog.newTransaction(); + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + } + + public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + if(message.isPersistent() && queue.isDurable()) + { + beginTranIfNecessary(); + try + { + _transaction.enqueueMessage(queue, message.getMessageNumber()); + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + + + } + + public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + { + + + if(message.isPersistent()) + { + if(_transaction == null) + { + for(AMQQueue queue : queues) + { + if(queue.isDurable()) + { + beginTranIfNecessary(); + break; + } + } + + + } + + + try + { + for(AMQQueue queue : queues) + { + if(queue.isDurable()) + { + _transaction.enqueueMessage(queue, message.getMessageNumber()); + } + } + + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + + + } + + public void commit() + { + try + { + if(_transaction != null) + { + + _transaction.commitTran(); + } + + for(Action action : _postCommitActions) + { + action.postCommit(); + } + } + catch (Exception e) + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + //TODO + throw new RuntimeException(e); + } + finally + { + _transaction = null; + _postCommitActions.clear(); + } + + } + + public void rollback() + { + + try + { + + if(_transaction != null) + { + + _transaction.abortTran(); + } + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); + throw new RuntimeException(e); + } + finally + { + try + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + } + finally + { + _transaction = null; + _postCommitActions.clear(); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java deleted file mode 100644 index 450852cef7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -import java.util.List; -import java.util.ArrayList; - -/** A transactional context that only supports local transactions. */ -public class LocalTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); - - private final TxnBuffer _txnBuffer = new TxnBuffer(); - - private final List _postCommitDeliveryList = new ArrayList(); - - /** - * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are - * consolidated into a single operation - */ - private TxAck _ackOp; - - private boolean _inTran = false; - - /** Are there messages to deliver. NOT Has the message been delivered */ - private boolean _messageDelivered = false; - private final AMQChannel _channel; - - - private abstract class DeliveryAction - { - - abstract public void process() throws AMQException; - - } - - private class RequeueAction extends DeliveryAction - { - public QueueEntry entry; - - public RequeueAction(QueueEntry entry) - { - this.entry = entry; - } - - public void process() throws AMQException - { - entry.requeue(getStoreContext()); - } - } - - private class PublishAction extends DeliveryAction - { - private final AMQQueue _queue; - private final AMQMessage _message; - - public PublishAction(final AMQQueue queue, final AMQMessage message) - { - _queue = queue; - _message = message; - } - - public void process() throws AMQException - { - - _message.incrementReference(); - try - { - QueueEntry entry = _queue.enqueue(getStoreContext(),_message); - _queue.checkCapacity(_channel); - - if(entry.immediateAndNotDelivered()) - { - getReturnMessages().add(new NoConsumersException(_message)); - } - } - finally - { - _message.decrementReference(getStoreContext()); - } - } - } - - public LocalTransactionalContext(final AMQChannel channel) - { - _channel = channel; - } - - public StoreContext getStoreContext() - { - return _channel.getStoreContext(); - } - - public List getReturnMessages() - { - return _channel.getReturnMessages(); - } - - public MessageStore getMessageStore() - { - return _channel.getMessageStore(); - } - - - public void rollback() throws AMQException - { - _txnBuffer.rollback(getStoreContext()); - // Hack to deal with uncommitted non-transactional writes - if (getMessageStore().inTran(getStoreContext())) - { - getMessageStore().abortTran(getStoreContext()); - _inTran = false; - } - - _postCommitDeliveryList.clear(); - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - // A publication will result in the enlisting of several - // TxnOps. The first is an op that will store the message. - // Following that (and ordering is important), an op will - // be added for every queue onto which the message is - // enqueued. - _postCommitDeliveryList.add(new PublishAction(queue, message)); - _messageDelivered = true; - - } - - public void requeue(QueueEntry entry) throws AMQException - { - _postCommitDeliveryList.add(new RequeueAction(entry)); - _messageDelivered = true; - - } - - - private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - - public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - // check that the tag exists to give early failure - if (!multiple || (deliveryTag > 0)) - { - checkAck(deliveryTag, unacknowledgedMessageMap); - } - // we use a single txn op for all acks and update this op - // as new acks come in. If this is the first ack in the txn - // we will need to create and enlist the op. - if (_ackOp == null) - { - _ackOp = new TxAck(unacknowledgedMessageMap); - _txnBuffer.enlist(_ackOp); - } - // update the op to include this ack request - if (multiple && (deliveryTag == 0)) - { - // if have signalled to ack all, that refers only - // to all at this time - _ackOp.update(lastDeliveryTag, multiple); - } - else - { - _ackOp.update(deliveryTag, multiple); - } - if(!_inTran && _ackOp.checkPersistent()) - { - beginTranIfNecessary(); - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - // Not required in this transactional context - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - // Not required in this transactional context - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - if (_log.isDebugEnabled()) - { - _log.debug("Starting transaction on message store: " + this); - } - - getMessageStore().beginTran(getStoreContext()); - _inTran = true; - } - } - - public void commit() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing transactional context: " + this); - } - - if (_ackOp != null) - { - - _messageDelivered = true; - _ackOp.consolidate(); - // already enlisted, after commit will reset regardless of outcome - _ackOp = null; - } - - if (_messageDelivered && _inTran) - { - _txnBuffer.enlist(new StoreMessageOperation(getMessageStore())); - } - // fixme fail commit here ... QPID-440 - try - { - _txnBuffer.commit(getStoreContext()); - } - finally - { - _messageDelivered = false; - _inTran = getMessageStore().inTran(getStoreContext()); - } - - try - { - postCommitDelivery(); - } - catch (AMQException e) - { - // OK so what do we do now...? - _log.error("Failed to deliver messages following txn commit: " + e, e); - } - } - - private void postCommitDelivery() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Performing post commit delivery"); - } - - try - { - for (DeliveryAction dd : _postCommitDeliveryList) - { - dd.process(); - } - } - finally - { - _postCommitDeliveryList.clear(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java deleted file mode 100644 index 10d6021d27..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** @author Apache Software Foundation */ -public class NonTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - - /** Channel is useful for logging */ - private final AMQChannel _channel; - - /** Where to put undeliverable messages */ - private final List _returnMessages; - - - - private final MessageStore _messageStore; - - private final StoreContext _storeContext; - - /** Whether we are in a transaction */ - private boolean _inTran; - - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, - List returnMessages) - { - _channel = channel; - _storeContext = storeContext; - _returnMessages = returnMessages; - _messageStore = messageStore; - - } - - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _messageStore.beginTran(_storeContext); - _inTran = true; - } - } - - public void commit() throws AMQException - { - // Does not apply to this context - } - - public void rollback() throws AMQException - { - // Does not apply to this context - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - QueueEntry entry = queue.enqueue(_storeContext, message); - queue.checkCapacity(_channel); - - - //following check implements the functionality - //required by the 'immediate' flag: - if(entry.immediateAndNotDelivered()) - { - _returnMessages.add(new NoConsumersException(entry.getMessage())); - } - - } - - public void requeue(QueueEntry entry) throws AMQException - { - entry.requeue(_storeContext); - } - - public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, - boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) - throws AMQException - { - - final boolean debug = _log.isDebugEnabled(); - ; - if (multiple) - { - if (deliveryTag == 0) - { - - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, - // tells the server to acknowledge all outstanding mesages. - _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + - unacknowledgedMessageMap.size()); - unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException - { - if (debug) - { - _log.debug("Discarding message: " + message.getMessage().getMessageId()); - } - if(message.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } - //Message has been ack so discard it. This will dequeue and decrement the reference. - message.discard(_storeContext); - - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } - else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - - unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext); - } - } - else - { - QueueEntry msg; - msg = unacknowledgedMessageMap.get(deliveryTag); - - if (msg == null) - { - _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - } - - if (debug) - { - _log.debug("Discarding message: " + msg.getMessage().getMessageId()); - } - if(msg.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); - - unacknowledgedMessageMap.remove(deliveryTag); - - - if (debug) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - msg.getMessage().getMessageId()); - } - } - if(_inTran) - { - _messageStore.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - if (persistent) - { - _messageStore.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - _channel.processReturns(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java new file mode 100755 index 0000000000..88bdc363c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.AMQChannel; + +import java.util.List; +import java.util.SortedSet; +import java.util.Collection; + +public interface ServerTransaction +{ + + void addPostCommitAction(Action postCommitAction); + + + + + public static interface Action + { + public void postCommit(); + + public void onRollback(); + } + + void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + + void dequeue(Collection ackedMessages, Action postCommitAction); + + void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + + void enqueue(List queues, EnqueableMessage message, Action postCommitAction); + + + void commit(); + + void rollback(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java deleted file mode 100644 index 0e4d6c2030..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * A transactional operation to store messages in an underlying persistent store. When this operation - * commits it will do everything to ensure that all messages are safely committed to persistent - * storage. - */ -public class StoreMessageOperation implements TxnOp -{ - private final MessageStore _messsageStore; - - public StoreMessageOperation(MessageStore messageStore) - { - _messsageStore = messageStore; - } - - public void prepare(StoreContext context) throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit(StoreContext context) throws AMQException - { - _messsageStore.commitTran(context); - } - - public void rollback(StoreContext context) throws AMQException - { - _messsageStore.abortTran(context); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java deleted file mode 100644 index 647ba66fb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -/** - * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. - * Different levels of transactional support for the delivery of messages may be provided by different implementations - * of this interface. - * - *

      The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. - * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} - * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. - * - *

      - *
      CRC Card
      Responsibilities - *
      Explicitly accept a transaction start notification. - *
      Commit all pending operations in a transaction. - *
      Rollback all pending operations in a transaction. - *
      Deliver a message to a queue as part of a transaction. - *
      Redeliver a message to a queue as part of a transaction. - *
      Mark a message as acknowledged as part of a transaction. - *
      Accept notification that a message has been completely received as part of a transaction. - *
      Accept notification that a message has been fully processed as part of a transaction. - *
      Associate a message store context with this transaction context. - *
      - * - * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional - * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them - * somewhere else, a seperate interface for example. - * - * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides - * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any - * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean - * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be - * conceptually neater. - * - * For example: - *

      - * public interface Transactional
      - * {
      - *    public void commit();
      - *    public void rollback();
      - * }
      - *
      - * public interface TransactionalQueue extends Transactional, SizeableQueue
      - * {}
      - *
      - * public class Queues
      - * {
      - *    ...
      - *    // For transactional messaging, take a transactional view onto the queue.
      - *    public static  TransactionalQueue getTransactionalQueue(SizeableQueue queue) { ... }
      - *
      - *    // For non-transactional messaging, take a non-transactional view onto the queue.
      - *    public static  TransactionalQueue getNonTransactionalQueue(SizeableQueue queue) { ... }
      - * }
      - * 
      - */ -public interface TransactionalContext -{ - /** - * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} - * should automatically begin the next transaction in the chain. - * - * @throws AMQException If the transaction cannot be started for any reason. - */ - void beginTranIfNecessary() throws AMQException; - - /** - * Makes all pending operations on the transaction permanent and visible. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void commit() throws AMQException; - - /** - * Erases all pending operations on the transaction. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void rollback() throws AMQException; - - /** - * Delivers the specified message to the specified queue. - * - *

      This is an 'enqueue' operation. - * - * @param queue - * @param message The message to deliver - * @throws AMQException If the message cannot be delivered for any reason. - */ - void deliver(final AMQQueue queue, AMQMessage message) throws AMQException; - - /** - * Requeues the specified message entry (message queue pair) - * - * - * @param queueEntry The message,queue pair - * - * @throws AMQException If the message cannot be delivered for any reason. - */ - void requeue(QueueEntry queueEntry) throws AMQException; - - - /** - * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by - * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' - * flag is set, in which case an acknowledgement up to the latest delivered message should be done. - * - *

      This is a 'dequeue' operation. - * - * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement - * up to the latest message. - * @param lastDeliveryTag The latest message delivered. - * @param multiple true if all message ids up the acknowledged one or latest delivered, are - * to be acknowledged, false otherwise. - * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message - * from. - * - * @throws AMQException If the message cannot be acknowledged for any reason. - */ - void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - - /** - * Notifies the transactional context that a message has been fully received. The actual message that was received - * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, - * flushing its data to disk. - * - * @param persistent true if the received message is persistent, false otherwise. - * - * @throws AMQException If the fully received event cannot be processed for any reason. - */ - void messageFullyReceived(boolean persistent) throws AMQException; - - /** - * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual - * message that was delivered is not specified. This event may be used to trigger a process related to the - * outcome of the delivery of the message, for example, cleaning up failed deliveries. - * - * @param protocolSession The protocol session of the deliverable message. - * - * @throws AMQException If the message processed event cannot be handled for any reason. - */ - void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; - - /** - * Gets the message store context associated with this transactional context. - * - * @return The message store context associated with this transactional context. - */ - StoreContext getStoreContext(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java deleted file mode 100644 index 46a68b6a23..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** Holds a list of TxnOp instance representing transactional operations. */ -public class TxnBuffer -{ - private final List _ops = new ArrayList(); - private static final Logger _log = Logger.getLogger(TxnBuffer.class); - - public TxnBuffer() - { - } - - public void commit(StoreContext context) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); - } - - if (prepare(context)) - { - for (TxnOp op : _ops) - { - op.commit(context); - } - } - _ops.clear(); - } - - private boolean prepare(StoreContext context) throws AMQException - { - for (int i = 0; i < _ops.size(); i++) - { - TxnOp op = _ops.get(i); - try - { - op.prepare(context); - } - catch (AMQException e) - { - undoPrepare(i); - throw e; - } - catch (RuntimeException e) - { - undoPrepare(i); - throw e; - } - } - return true; - } - - private void undoPrepare(int lastPrepared) - { - //compensate previously prepared ops - for (int j = 0; j < lastPrepared; j++) - { - _ops.get(j).undoPrepare(); - } - } - - - - public void rollback(StoreContext context) throws AMQException - { - for (TxnOp op : _ops) - { - op.rollback(context); - } - _ops.clear(); - } - - public void enlist(TxnOp op) - { - _ops.add(op); - } - - public void cancel(TxnOp op) - { - _ops.remove(op); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java deleted file mode 100644 index 919c078cf0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** - * This provides the abstraction of an individual operation within a - * transaction. It is used by the TxnBuffer class. - */ -public interface TxnOp -{ - /** - * Do the part of the operation that updates persistent state - */ - public void prepare(StoreContext context) throws AMQException; - /** - * Complete the operation started by prepare. Can now update in - * memory state or make netork transfers. - */ - public void commit(StoreContext context) throws AMQException; - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback(StoreContext context) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java deleted file mode 100644 index cf5e71a6e2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue -{ - public int size() - { - if (isEmpty()) - { - return 0; - } - else - { - return 1; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java old mode 100644 new mode 100755 index 3b776a62b4..e4a382d275 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,624 +1,62 @@ /* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ package org.apache.qpid.server.virtualhost; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.messages.VirtualHostMessages; -import org.apache.qpid.server.configuration.ExchangeConfiguration; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.access.plugins.SimpleXML; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -import javax.management.NotCompliantMBeanException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.management.ManagedObject; -public class VirtualHost implements Accessable +public interface VirtualHost { - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - private final String _name; - - private ConnectionRegistry _connectionRegistry; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private ACLManager _accessManager; - - private final Timer _houseKeepingTimer; - private VirtualHostConfiguration _configuration; - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - public IConnectionRegistry getConnectionRegistry() - { - return _connectionRegistry; - } - - public VirtualHostConfiguration getConfiguration() - { - return _configuration; - } - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - } // End of MBean class - - /** - * Normal Constructor - * - * @param hostConfig - * - * @throws Exception - */ - public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception - { - this(hostConfig, null); - } - - public VirtualHost(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception - { - _configuration = hostConfig; - _name = hostConfig.getName(); - - CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); - - if (_name == null || _name.length() == 0) - { - throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); - } - - _virtualHostMBean = new VirtualHostMBean(); - - _connectionRegistry = new ConnectionRegistry(this); - - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); - - _queueRegistry = new DefaultQueueRegistry(this); - - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - - _exchangeRegistry = new DefaultExchangeRegistry(this); - - //Create a temporary RT to store the durable entries from the config file - // so we can replay them in to the real _RT after it has been loaded. - /// This should be removed after the _RT has been fully split from the the TL - - StartupRoutingTable configFileRT = new StartupRoutingTable(); - - _messageStore = configFileRT; - - // This needs to be after the RT has been defined as it creates the default durable exchanges. - _exchangeRegistry.initialise(); - - // We don't need to store the Default queues in the store as we always - // create them first on start up so don't clear them from the startup - // configuration here. This also ensures that we don't attempt to - // perform a createExchange twice with the same details in the - // MessageStore(RoutingTable) as some instances may not like that. - // Derby being one. - // todo this can be removed with the resolution fo QPID-2096 - configFileRT.exchange.clear(); - - initialiseModel(hostConfig); - - //todo REMOVE Work Around for QPID-2096 - // This means that all durable exchanges declared in the configuration - // will not be stored in the MessageStore. - // They will still be created/registered/available on startup for as - // long as they are contained in the configuration. However, when they - // are removed from the configuration they will no longer exist. - // This differs from durable queues as they will be writen to to the - // store. After QPID-2096 has been resolved exchanges will mirror that - // functionality. - configFileRT.exchange.clear(); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config - // file and write them in to the new routing Table. - for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) - { - _messageStore.createQueue(cqt.queue, cqt.arguments); - } - - for (Exchange exchange : configFileRT.exchange) - { - _messageStore.createExchange(exchange); - } - - for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) - { - _messageStore.bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - } - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); - - _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); - } - - private void initialiseHouseKeeping(long period) - { - /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if (period != 0L) - { - class RemoveExpiredMessagesTask extends TimerTask - { - public void run() - { - for (AMQQueue q : _queueRegistry.getQueues()) - { - - try - { - q.checkMessageStatus(); - } - catch (AMQException e) - { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); - throw new RuntimeException(e); - } - } - } - } - - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); - - class ForceChannelClosuresTask extends TimerTask - { - public void run() - { - _connectionRegistry.expireClosedChannels(); - } - } - } - } - - private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception - { - String messageStoreClass = hostConfig.getMessageStoreClass(); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - MessageStore messageStore = (MessageStore) o; - messageStore.configure(this, "store", hostConfig); - _messageStore = messageStore; - } - - private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException - { - _logger.debug("Loading configuration for virtualhost: " + config.getName()); - - List exchangeNames = config.getExchanges(); - - for (Object exchangeNameObj : exchangeNames) - { - String exchangeName = String.valueOf(exchangeNameObj); - configureExchange(config.getExchangeConfiguration(exchangeName)); - } - - String[] queueNames = config.getQueueNames(); - - for (Object queueNameObj : queueNames) - { - String queueName = String.valueOf(queueNameObj); - configureQueue(config.getQueueConfiguration(queueName)); - } - } - - private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException - { - AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); - - Exchange exchange; - exchange = _exchangeRegistry.getExchange(exchangeName); - if (exchange == null) - { - - AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); - boolean durable = exchangeConfiguration.getDurable(); - boolean autodelete = exchangeConfiguration.getAutoDelete(); - - Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); - _exchangeRegistry.registerExchange(newExchange); - } - } - - private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException - { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); - - if (queue.isDurable()) - { - _messageStore.createQueue(queue); - } - - String exchangeName = queueConfiguration.getExchange(); - - Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - - if (exchange == null) - { - exchange = _exchangeRegistry.getDefaultExchange(); - } - - if (exchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); - } - - List routingKeys = queueConfiguration.getRoutingKeys(); - if (routingKeys == null || routingKeys.isEmpty()) - { - routingKeys = Collections.singletonList(queue.getName()); - } - - for (Object routingKeyNameObj : routingKeys) - { - AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - if (_logger.isInfoEnabled()) - { - _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); - } - queue.bind(exchange, routingKey, null); - } - - if (exchange != _exchangeRegistry.getDefaultExchange()) - { - queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); - } - } - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public ACLManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - - //Stop Connections - _connectionRegistry.close(); - - //Stop the Queues processing - if (_queueRegistry != null) - { - for (AMQQueue queue : _queueRegistry.getQueues()) - { - queue.stop(); - } - } - - //Stop Housekeeping - if (_houseKeepingTimer != null) - { - _houseKeepingTimer.cancel(); - } - - //Close MessageStore - if (_messageStore != null) - { - _messageStore.close(); - } - - CurrentActor.get().message(VirtualHostMessages.VHT_1002()); - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } - - /** - * Temporary Startup RT class to record the creation of persistent queues / exchanges. - * - * - * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. - * This should be removed after the _RT has been fully split from the the TL - */ - private class StartupRoutingTable implements MessageStore - { - public List exchange = new LinkedList(); - public List queue = new LinkedList(); - public List bindings = new LinkedList(); - - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - } - - public void close() throws Exception - { - } - - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void createExchange(Exchange exchange) throws AMQException - { - if (exchange.isDurable()) - { - this.exchange.add(exchange); - } - } - - public void removeExchange(Exchange exchange) throws AMQException - { - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - if (exchange.isDurable() && queue.isDurable()) - { - bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); - } - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - } - - public void createQueue(AMQQueue queue) throws AMQException - { - createQueue(queue, null); - } - - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException - { - if (queue.isDurable()) - { - this.queue.add(new CreateQueueTuple(queue, arguments)); - } - } - - public void removeQueue(AMQQueue queue) throws AMQException - { - } - - public void enqueueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void beginTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void commitTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + IConnectionRegistry getConnectionRegistry(); - public void abortTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + VirtualHostConfiguration getConfiguration(); - public boolean inTran(StoreContext context) - { - return false; //To change body of implemented methods use File | Settings | File Templates. - } + String getName(); - public Long getNewMessageId() - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + QueueRegistry getQueueRegistry(); - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + ExchangeRegistry getExchangeRegistry(); - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + ExchangeFactory getExchangeFactory(); - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + MessageStore getMessageStore(); - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + TransactionLog getTransactionLog(); - public boolean isPersistent() - { - return false; //To change body of implemented methods use File | Settings | File Templates. - } + DurableConfigurationStore getDurableConfigurationStore(); - private class CreateQueueTuple - { - public AMQQueue queue; - public FieldTable arguments; + AuthenticationManager getAuthenticationManager(); - public CreateQueueTuple(AMQQueue queue, FieldTable arguments) - { - this.queue = queue; - this.arguments = arguments; - } - } + ACLManager getAccessManager(); - private class CreateBindingTuple - { - public AMQQueue queue; - public FieldTable arguments; - public Exchange exchange; - public AMQShortString routingKey; + void close() throws Exception; - public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - { - this.exchange = exchange; - this.routingKey = routingKey; - this.queue = queue; - arguments = args; - } - } - } + ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java new file mode 100755 index 0000000000..7fa5a26436 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -0,0 +1,340 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.virtualhost; + +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.MessageStoreRecoveryHandler; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.store.TransactionLogRecoveryHandler; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +import org.apache.log4j.Logger; + +import java.nio.ByteBuffer; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; + +public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHandler, + ConfigurationRecoveryHandler.QueueRecoveryHandler, + ConfigurationRecoveryHandler.ExchangeRecoveryHandler, + ConfigurationRecoveryHandler.BindingRecoveryHandler, + MessageStoreRecoveryHandler, + MessageStoreRecoveryHandler.StoredMessageRecoveryHandler, + TransactionLogRecoveryHandler, + TransactionLogRecoveryHandler.QueueEntryRecoveryHandler +{ + private static final Logger _logger = Logger.getLogger(VirtualHostConfigRecoveryHandler.class); + + + private final VirtualHost _virtualHost; + + private MessageStoreLogSubject _logSubject; + private List _actions; + + private MessageStore _store; + private TransactionLog _transactionLog; + + private final Map _queueRecoveries = new TreeMap(); + private Map _recoveredMessages = new HashMap(); + private Map _unusedMessages = new HashMap(); + + + + public VirtualHostConfigRecoveryHandler(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public QueueRecoveryHandler begin(MessageStore store) + { + _logSubject = new MessageStoreLogSubject(_virtualHost,store); + _store = store; + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(null, false)); + + return this; + } + + public void queue(String queueName, String owner, FieldTable arguments) + { + AMQShortString queueNameShortString = new AMQShortString(queueName); + + AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + if (q == null) + { + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + arguments); + _virtualHost.getQueueRegistry().registerQueue(q); + } + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true)); + + //Record that we have a queue for recovery + _queueRecoveries.put(queueName, 0); + } + + public ExchangeRecoveryHandler completeQueueRecovery() + { + return this; + } + + public void exchange(String exchangeName, String type, boolean autoDelete) + { + try + { + Exchange exchange; + AMQShortString exchangeNameSS = new AMQShortString(exchangeName); + exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS); + if (exchange == null) + { + exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public BindingRecoveryHandler completeExchangeRecovery() + { + return this; + } + + public StoredMessageRecoveryHandler begin() + { + // TODO - log begin + return this; + } + + public void message(StoredMessage message) + { + ServerMessage serverMessage; + switch(message.getMetaData().getType()) + { + case META_DATA_0_8: + serverMessage = new AMQMessage(message); + break; + case META_DATA_0_10: + serverMessage = new MessageTransferMessage(message, null); + break; + default: + throw new RuntimeException("Unknown message type retreived from store " + message.getMetaData().getClass()); + } + + + _recoveredMessages.put(message.getMessageNumber(), serverMessage); + _unusedMessages.put(message.getMessageNumber(), message); + } + + public void completeMessageRecovery() + { + //TODO - log end + //To change body of implemented methods use File | Settings | File Templates. + } + + public TransactionLogRecoveryHandler.QueueEntryRecoveryHandler begin(TransactionLog log) + { + _transactionLog = log; + return this; + } + + private static final class ProcessAction + { + private final AMQQueue _queue; + private final AMQMessage _message; + + public ProcessAction(AMQQueue queue, AMQMessage message) + { + _queue = queue; + _message = message; + } + + public void process() + { + try + { + _queue.enqueue(_message); + } + catch(AMQException e) + { + throw new RuntimeException(e); + } + } + + } + + public void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf) + { + _actions = new ArrayList(); + try + { + QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + Exchange exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeName); + AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " + + exchange.getName()); + } + else + { + + + FieldTable argumentsFT = null; + if(buf != null) + { + argumentsFT = new FieldTable(org.apache.mina.common.ByteBuffer.wrap(buf),buf.limit()); + } + + _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + + queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void completeBindingRecovery() + { + //return this; + } + + public void complete() + { + + + } + + public void queueEntry(final String queueName, long messageId) + { + AMQShortString queueNameShortString = new AMQShortString(queueName); + + AMQQueue queue = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + try + { + if(queue != null) + { + ServerMessage message = _recoveredMessages.get(messageId); + _unusedMessages.remove(messageId); + + if(message != null) + { + + + if (_logger.isDebugEnabled()) + { + _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getName()); + } + + Integer count = _queueRecoveries.get(queueName); + if (count == null) + { + count = 0; + } + + queue.enqueue(message); + + _queueRecoveries.put(queueName, ++count); + } + else + { + _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getName() + " is unknwon, entry will be discarded"); + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.dequeueMessage(queue, messageId); + txn.commitTranAsync(); + } + } + else + { + _logger.warn("Message id " + messageId + " in log references queue " + queueName + " which is not in the configuration, entry will be discarded"); + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + TransactionLogResource mockQueue = + new TransactionLogResource() + { + + public String getResourceName() + { + return queueName; + } + }; + txn.dequeueMessage(mockQueue, messageId); + txn.commitTranAsync(); + } + + } + catch(AMQException e) + { + throw new RuntimeException(e); + } + + + + } + + public void completeQueueEntryRecovery() + { + + for(StoredMessage m : _unusedMessages.values()) + { + _logger.warn("Message id " + m.getMessageNumber() + " in store, but not in any queue - removing...."); + m.remove(); + } + + for(Map.Entry entry : _queueRecoveries.entrySet()) + { + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey())); + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true)); + } + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false)); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java new file mode 100644 index 0000000000..c321fdf3e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -0,0 +1,608 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.configuration.ExchangeConfiguration; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.connection.ConnectionRegistry; +import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; + +import javax.management.NotCompliantMBeanException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class VirtualHostImpl implements Accessable, VirtualHost +{ + private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class); + + private final String _name; + + private ConnectionRegistry _connectionRegistry; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private ACLManager _accessManager; + + private final Timer _houseKeepingTimer; + private VirtualHostConfiguration _configuration; + private DurableConfigurationStore _durableConfigurationStore; + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + public IConnectionRegistry getConnectionRegistry() + { + return _connectionRegistry; + } + + public VirtualHostConfiguration getConfiguration() + { + return _configuration; + } + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHostImpl getVirtualHost() + { + return VirtualHostImpl.this; + } + + } // End of MBean class + + /** + * Normal Constructor + * + * @param hostConfig + * + * @throws Exception + */ + public VirtualHostImpl(VirtualHostConfiguration hostConfig) throws Exception + { + this(hostConfig, null); + } + + public VirtualHostImpl(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception + { + _configuration = hostConfig; + _name = hostConfig.getName(); + + CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); + + if (_name == null || _name.length() == 0) + { + throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); + } + + _virtualHostMBean = new VirtualHostMBean(); + + _connectionRegistry = new ConnectionRegistry(this); + + _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + + _queueRegistry = new DefaultQueueRegistry(this); + + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + + _exchangeRegistry = new DefaultExchangeRegistry(this); + + //Create a temporary RT to store the durable entries from the config file + // so we can replay them in to the real _RT after it has been loaded. + /// This should be removed after the _RT has been fully split from the the TL + + StartupRoutingTable configFileRT = new StartupRoutingTable(); + + _durableConfigurationStore = configFileRT; + + // This needs to be after the RT has been defined as it creates the default durable exchanges. + _exchangeRegistry.initialise(); + + // We don't need to store the Default queues in the store as we always + // create them first on start up so don't clear them from the startup + // configuration here. This also ensures that we don't attempt to + // perform a createExchange twice with the same details in the + // MessageStore(RoutingTable) as some instances may not like that. + // Derby being one. + // todo this can be removed with the resolution fo QPID-2096 + configFileRT.exchange.clear(); + + initialiseModel(hostConfig); + + //todo REMOVE Work Around for QPID-2096 + // This means that all durable exchanges declared in the configuration + // will not be stored in the MessageStore. + // They will still be created/registered/available on startup for as + // long as they are contained in the configuration. However, when they + // are removed from the configuration they will no longer exist. + // This differs from durable queues as they will be writen to to the + // store. After QPID-2096 has been resolved exchanges will mirror that + // functionality. + configFileRT.exchange.clear(); + + if (store != null) + { + _messageStore = store; + _durableConfigurationStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config + // file and write them in to the new routing Table. + for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) + { + getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); + } + + for (Exchange exchange : configFileRT.exchange) + { + getDurableConfigurationStore().createExchange(exchange); + } + + for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) + { + getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); + } + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); + + _accessManager = ApplicationRegistry.getInstance().getAccessManager(); + _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); + } + + private void initialiseHouseKeeping(long period) + { + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ + if (period != 0L) + { + class RemoveExpiredMessagesTask extends TimerTask + { + public void run() + { + for (AMQQueue q : _queueRegistry.getQueues()) + { + + try + { + q.checkMessageStatus(); + } + catch (AMQException e) + { + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + throw new RuntimeException(e); + } + } + } + } + + _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), + period / 2, + period); + + class ForceChannelClosuresTask extends TimerTask + { + public void run() + { + _connectionRegistry.expireClosedChannels(); + } + } + } + } + + private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception + { + String messageStoreClass = hostConfig.getMessageStoreClass(); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + MessageStore messageStore = (MessageStore) o; + VirtualHostConfigRecoveryHandler recoveryHandler = new VirtualHostConfigRecoveryHandler(this); + + MessageStoreLogSubject storeLogSubject = new MessageStoreLogSubject(this, messageStore); + + messageStore.configureConfigStore(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + + messageStore.configureMessageStore(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + messageStore.configureTransactionLog(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + + _messageStore = messageStore; + _durableConfigurationStore = messageStore; + } + + private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException + { + _logger.debug("Loading configuration for virtualhost: " + config.getName()); + + List exchangeNames = config.getExchanges(); + + for (Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(config.getExchangeConfiguration(exchangeName)); + } + + String[] queueNames = config.getQueueNames(); + + for (Object queueNameObj : queueNames) + { + String queueName = String.valueOf(queueNameObj); + configureQueue(config.getQueueConfiguration(queueName)); + } + } + + private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException + { + AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); + + Exchange exchange; + exchange = _exchangeRegistry.getExchange(exchangeName); + if (exchange == null) + { + + AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); + boolean durable = exchangeConfiguration.getDurable(); + boolean autodelete = exchangeConfiguration.getAutoDelete(); + + Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); + _exchangeRegistry.registerExchange(newExchange); + } + } + + private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException + { + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); + + if (queue.isDurable()) + { + getDurableConfigurationStore().createQueue(queue); + } + + String exchangeName = queueConfiguration.getExchange(); + + Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if (exchange == null) + { + exchange = _exchangeRegistry.getDefaultExchange(); + } + + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } + + List routingKeys = queueConfiguration.getRoutingKeys(); + if (routingKeys == null || routingKeys.isEmpty()) + { + routingKeys = Collections.singletonList(queue.getName()); + } + + for (Object routingKeyNameObj : routingKeys) + { + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); + } + queue.bind(exchange, routingKey, null); + } + + if (exchange != _exchangeRegistry.getDefaultExchange()) + { + queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + } + } + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public TransactionLog getTransactionLog() + { + return _messageStore; + } + + public DurableConfigurationStore getDurableConfigurationStore() + { + return _durableConfigurationStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public ACLManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + + //Stop Connections + _connectionRegistry.close(); + + //Stop the Queues processing + if (_queueRegistry != null) + { + for (AMQQueue queue : _queueRegistry.getQueues()) + { + queue.stop(); + } + } + + //Stop Housekeeping + if (_houseKeepingTimer != null) + { + _houseKeepingTimer.cancel(); + } + + //Close MessageStore + if (_messageStore != null) + { + _messageStore.close(); + } + + CurrentActor.get().message(VirtualHostMessages.VHT_1002()); + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } + + /** + * Temporary Startup RT class to record the creation of persistent queues / exchanges. + * + * + * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. + * This should be removed after the _RT has been fully split from the the TL + */ + private class StartupRoutingTable implements DurableConfigurationStore + { + public List exchange = new LinkedList(); + public List queue = new LinkedList(); + public List bindings = new LinkedList(); + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + } + + public void close() throws Exception + { + } + + public void removeMessage(Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (exchange.isDurable()) + { + this.exchange.add(exchange); + } + } + + public void removeExchange(Exchange exchange) throws AMQException + { + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + if (exchange.isDurable() && queue.isDurable()) + { + bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); + } + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + } + + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + if (queue.isDurable()) + { + this.queue.add(new CreateQueueTuple(queue, arguments)); + } + } + + public void removeQueue(AMQQueue queue) throws AMQException + { + } + + + private class CreateQueueTuple + { + public AMQQueue queue; + public FieldTable arguments; + + public CreateQueueTuple(AMQQueue queue, FieldTable arguments) + { + this.queue = queue; + this.arguments = arguments; + } + } + + private class CreateBindingTuple + { + public AMQQueue queue; + public FieldTable arguments; + public Exchange exchange; + public AMQShortString routingKey; + + public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + { + this.exchange = exchange; + this.routingKey = routingKey; + this.queue = queue; + arguments = args; + } + } + } + + @Override + public String toString() + { + return _name; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 5543adbeb5..b86e0d0baf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.virtualhost; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import java.util.ArrayList; import java.util.Collection; @@ -31,7 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; public class VirtualHostRegistry { - private final Map _registry = new ConcurrentHashMap(); + private final Map _registry = new ConcurrentHashMap(); private String _defaultVirtualHostName; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java index 0869d9a497..ef3599bdc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -14,14 +14,16 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; public class Copy extends Move { @@ -49,7 +51,9 @@ public class Copy extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); + ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), txn); + txn.commit(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java index 731f6140f9..a7d58dc6dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -21,16 +21,13 @@ package org.apache.qpid.tools.messagestore.commands; import org.apache.commons.codec.binary.Hex; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; import java.io.UnsupportedEncodingException; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -100,7 +97,7 @@ public class Dump extends Show for (QueueEntry entry : messages) { - AMQMessage msg = entry.getMessage(); + ServerMessage msg = entry.getMessage(); if (!includeMsg(msg, msgids)) { continue; @@ -112,7 +109,7 @@ public class Dump extends Show // Show general message information hex.add(Show.Columns.ID.name()); - ascii.add(msg.getMessageId().toString()); + ascii.add(msg.getMessageNumber().toString()); hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); @@ -136,10 +133,10 @@ public class Dump extends Show hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); - Iterator bodies = msg.getContentBodyIterator(); - if (bodies.hasNext()) - { + final int messageSize = (int) msg.getSize(); + if (messageSize != 0) + { hex.add("Hex"); hex.add(Console.ROW_DIVIDER); @@ -147,14 +144,19 @@ public class Dump extends Show ascii.add("ASCII"); ascii.add(Console.ROW_DIVIDER); - while (bodies.hasNext()) + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024); + + int position = 0; + + while(position < messageSize) { - ContentChunk chunk = (ContentChunk) bodies.next(); + position += msg.getContent(buf, position); + buf.flip(); //Duplicate so we don't destroy original data :) - ByteBuffer hexBuffer = chunk.getData().duplicate(); + java.nio.ByteBuffer hexBuffer = buf; - ByteBuffer charBuffer = hexBuffer.duplicate(); + java.nio.ByteBuffer charBuffer = hexBuffer.duplicate(); Hex hexencoder = new Hex(); @@ -232,6 +234,7 @@ public class Dump extends Show ascii.add(asciiLine); } + buf.clear(); } } else @@ -252,7 +255,7 @@ public class Dump extends Show return display; } - private void addShowInformation(List column1, List column2, AMQMessage msg, + private void addShowInformation(List column1, List column2, ServerMessage msg, String title, boolean routing, boolean headers, boolean messageHeaders) { List single = new LinkedList(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java index df8b59ec19..ab8e781df5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -14,9 +14,9 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index a8dd58ca83..6a5e2a6025 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -14,17 +14,17 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.tools.messagestore.MessageStoreTool; import java.util.LinkedList; @@ -33,12 +33,6 @@ import java.util.List; public class Move extends AbstractCommand { - /** - * Since the Coopy command is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - protected StoreContext _storeContext = new StoreContext(); - public Move(MessageStoreTool tool) { super(tool); @@ -172,7 +166,7 @@ public class Move extends AbstractCommand { for (QueueEntry msg : messages) { - ids.add(msg.getMessage().getMessageId()); + ids.add(msg.getMessage().getMessageNumber()); } } } @@ -201,6 +195,8 @@ public class Move extends AbstractCommand protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) { - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), txn); + txn.commit(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java index 5e99997863..8df4afa2db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -62,6 +62,6 @@ public class Purge extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { - fromQueue.removeMessagesFromQueue(start, end, _storeContext); + fromQueue.removeMessagesFromQueue(start, end); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index 2fa017fc64..4fd4999b19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -25,10 +25,10 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntryImpl; +import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; @@ -171,7 +171,7 @@ public class Show extends AbstractCommand // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageNumber(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); @@ -182,14 +182,14 @@ public class Show extends AbstractCommand // //Print out all the property names // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); // -// msg.getMessageId(); +// msg.getMessageNumber(); // msg.getSize(); // msg.getArrivalTime(); // msg.getDeliveredSubscription(); // msg.getDeliveredToConsumer(); // msg.getMessageHandle(); -// msg.getMessageId(); +// msg.getMessageNumber(); // msg.getMessagePublishInfo(); // msg.getPublisher(); @@ -337,30 +337,24 @@ public class Show extends AbstractCommand //Add create the table of data for (QueueEntry entry : messages) { - AMQMessage msg = entry.getMessage(); + ServerMessage msg = entry.getMessage(); if (!includeMsg(msg, msgids)) { continue; } - id.add(msg.getMessageId().toString()); + id.add(msg.getMessageNumber().toString()); size.add("" + msg.getSize()); arrival.add("" + msg.getArrivalTime()); - try - { - ispersitent.add(msg.isPersistent() ? "true" : "false"); - } - catch (AMQException e) - { - ispersitent.add("n/a"); - } + ispersitent.add(msg.isPersistent() ? "true" : "false"); + - isredelivered.add(msg.isRedelivered() ? "true" : "false"); + isredelivered.add(entry.isRedelivered() ? "true" : "false"); - isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false"); // msg.getMessageHandle(); @@ -368,7 +362,10 @@ public class Show extends AbstractCommand try { - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + if(msg instanceof AMQMessage) + { + headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().properties); + } } catch (AMQException e) { @@ -417,7 +414,11 @@ public class Show extends AbstractCommand MessagePublishInfo info = null; try { - info = msg.getMessagePublishInfo(); + if(msg instanceof AMQMessage) + { + info = ((AMQMessage)msg).getMessagePublishInfo(); + } + } catch (AMQException e) { @@ -457,14 +458,14 @@ public class Show extends AbstractCommand return data; } - protected boolean includeMsg(AMQMessage msg, List msgids) + protected boolean includeMsg(ServerMessage msg, List msgids) { if (msgids == null) { return true; } - Long msgid = msg.getMessageId(); + Long msgid = msg.getMessageNumber(); boolean found = false; -- cgit v1.2.1 From 73edf329801752fba83376c02fd473b184611a8b Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Mon, 26 Oct 2009 20:37:36 +0000 Subject: Added AMQP 0-9-1 support git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@829944 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/AccessRequestHandler.java | 60 ++-- .../handler/BasicRecoverSyncMethodHandler.java | 50 +-- .../qpid/server/handler/ChannelOpenHandler.java | 25 ++ .../handler/ConnectionOpenMethodHandler.java | 7 +- .../server/handler/ServerMethodDispatcherImpl.java | 8 + .../handler/ServerMethodDispatcherImpl_0_91.java | 168 +++++++++ .../output/ProtocolOutputConverterRegistry.java | 1 + .../amqp0_9_1/ProtocolOutputConverterImpl.java | 383 +++++++++++++++++++++ 8 files changed, 657 insertions(+), 45 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_91.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java index e64eaeae76..d587ef0c16 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java @@ -1,31 +1,34 @@ package org.apache.qpid.server.handler; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.qpid.framing.*; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; /** * @author Apache Software Foundation @@ -54,7 +57,20 @@ public class AccessRequestHandler implements StateAwareMethodListener maxBodySize ? maxBodySize : bodySize; + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(capacity); + + int writtenSize = 0; + + + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + AMQBody firstContentBody = PROTOCOL_CONVERTER.convertToBody(buf); + + CompositeAMQBodyBlock + compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + while(writtenSize < bodySize) + { + buf = java.nio.ByteBuffer.allocate(capacity); + + writtenSize += message.getContent(buf, writtenSize); + buf.flip(); + writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf))); + } + } + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException + { + AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize); + writeMessageDelivery(entry, channelId, deliver); + } + + + private AMQBody createEncodedDeliverBody(QueueEntry entry, + final long deliveryTag, + final AMQShortString consumerTag) + throws AMQException + { + + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize) + throws AMQException + { + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + isRedelivered, + exchangeName, + routingKey, + queueSize); + + return getOkBody; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, + int replyCode, + AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); + + + return basicReturnBody; + } + + public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + + AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText); + + writeMessageDelivery(message, header, channelId, returnFrame); + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(ByteBuffer buffer) + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} \ No newline at end of file -- cgit v1.2.1 From c1b0efc381581a58b69d4e098224e5f8d1fdf0ec Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 6 Nov 2009 15:56:14 +0000 Subject: QPID-2178: expand the return from channels() to indicate whether the channel is blocked git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@833446 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 5 +++++ .../org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 262bb2f226..f0f65cc4c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -1188,4 +1188,9 @@ public class AMQChannel AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow); _session.writeFrame(responseBody.generateFrame(_channelId)); } + + public boolean getBlocking() + { + return _blocking.get(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 67c1e51f6e..72788bdb0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -85,7 +85,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed // openmbean data types for representing the channel attributes private static final OpenType[] _channelAttributeTypes = - { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN }; private static CompositeType _channelType = null; // represents the data type for channel data private static TabularType _channelsType = null; // Data type for list of channels type private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = @@ -256,7 +256,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { channel.getChannelId(), channel.isTransactional(), (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, - channel.getUnacknowledgedMessageMap().size() + channel.getUnacknowledgedMessageMap().size(), channel.getBlocking() }; CompositeData channelData = new CompositeDataSupport(_channelType, COMPOSITE_ITEM_NAMES, itemValues); -- cgit v1.2.1 From 67d52c4f42fc59b5d340a63cacc735fb2f394937 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 11 Nov 2009 22:59:29 +0000 Subject: QPID-2184: make sure global security plugins are reconfigured properly ServerConfigurationTest: add test for reloading firewall config in main section, not just as a combined file FirewallConfigTest: add a systest for firewalls with real broker QpidTestCase: add a reloadBroker() method git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@835115 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/ServerConfiguration.java | 2 +- .../org/apache/qpid/server/security/access/ACLManager.java | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 7bf28c7560..441369d064 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -311,13 +311,13 @@ public class ServerConfiguration implements SignalHandler { Configuration newConfig = parseConfig(_configFile); _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); - ApplicationRegistry.getInstance().getAccessManager().configurePlugins(_securityConfiguration); VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); for (String hostname : _virtualHosts.keySet()) { VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security")); + vhost.getAccessManager().configureGlobalPlugins(_securityConfiguration); vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index af0a1944cd..7d6ae285c5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -67,14 +67,18 @@ public class ACLManager _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); } - _globalPlugins = configurePlugins(configuration); + configureGlobalPlugins(configuration); } - public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException { _hostPlugins = configurePlugins(hostConfig); } + + public void configureGlobalPlugins(SecurityConfiguration configuration) throws ConfigurationException + { + _globalPlugins = configurePlugins(configuration); + } public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException { @@ -93,7 +97,7 @@ public class ACLManager { if (plugin.supportsTag(tag)) { - _logger.warn("Plugin handling security section "+tag+" is "+plugin.getClass().getSimpleName()); + _logger.info("Plugin handling security section "+tag+" is "+plugin); handledTags.add(tag); plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); } -- cgit v1.2.1 From d37f3ad0906b4ff7742e2853204da4ef333eb1f9 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 26 Nov 2009 16:14:19 +0000 Subject: Fixes for 0-9-1 support git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@884619 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/handler/QueueUnbindHandler.java | 6 +++--- .../java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index d4272239d1..31401ce9d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -78,7 +78,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener Date: Fri, 27 Nov 2009 11:44:54 +0000 Subject: QPID-2222: Add CRAM-MD5-HEX support to broker to enable .net client to connect to broker when using Base64MD5 password file. Changes merged from M2.x branch r664001 with update to implement the newer reload() PD method. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@884838 13f79535-47bb-0310-9956-ffa450edef68 --- .../Base64MD5PasswordFilePrincipalDatabase.java | 6 + .../auth/sasl/crammd5/CRAMMD5HexInitialiser.java | 144 +++++++++++++++++++++ .../auth/sasl/crammd5/CRAMMD5HexSaslServer.java | 105 +++++++++++++++ .../auth/sasl/crammd5/CRAMMD5HexServerFactory.java | 61 +++++++++ 4 files changed, 316 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 581eeabbc3..889ce815f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -24,6 +24,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; import org.apache.qpid.util.FileUtils; @@ -79,6 +80,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase cram.initialise(this); _saslServers.put(cram.getMechanismName(), cram); + //Add the Hex initialiser + CRAMMD5HexInitialiser cramHex = new CRAMMD5HexInitialiser(); + cramHex.initialise(this); + _saslServers.put(cramHex.getMechanismName(), cramHex); + //fixme The PDs should setup a PD Mangement MBean // try // { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java new file mode 100644 index 0000000000..38e84c799b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java @@ -0,0 +1,144 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; + +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.util.Map; +import java.util.List; +import java.security.Principal; +import java.io.IOException; + +public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return CRAMMD5HexSaslServer.MECHANISM; + } + + public Class getServerFactoryClassForJCARegistration() + { + return CRAMMD5HexServerFactory.class; + } + + public Map getProperties() + { + return null; + } + + public void initialise(PrincipalDatabase db) + { + super.initialise(new HexifyPrincipalDatabase(db)); + + } + + private class HexifyPrincipalDatabase implements PrincipalDatabase + { + private PrincipalDatabase _realPricipalDatabase; + + HexifyPrincipalDatabase(PrincipalDatabase db) + { + _realPricipalDatabase = db; + } + + private char[] toHex(char[] password) + { + StringBuilder sb = new StringBuilder(); + for (char c : password) + { + //toHexString does not prepend 0 so we have to + if (((byte) c > -1) && (byte) c < 10) + { + sb.append(0); + } + + sb.append(Integer.toHexString(c & 0xFF)); + } + + //Extract the hex string as char[] + char[] hex = new char[sb.length()]; + + sb.getChars(0, sb.length(), hex, 0); + + return hex; + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException + { + //Let the read DB set the password + _realPricipalDatabase.setPassword(principal, callback); + + //Retrieve the setpassword + char[] plainPassword = callback.getPassword(); + + char[] hexPassword = toHex(plainPassword); + + callback.setPassword(hexPassword); + } + + // Simply delegate to the real PrincipalDB + public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException + { + return _realPricipalDatabase.verifyPassword(principal, password); + } + + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + return _realPricipalDatabase.updatePassword(principal, password); + } + + public boolean createPrincipal(Principal principal, char[] password) + { + return _realPricipalDatabase.createPrincipal(principal, password); + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return _realPricipalDatabase.deletePrincipal(principal); + } + + public Principal getUser(String username) + { + return _realPricipalDatabase.getUser(username); + } + + public Map getMechanisms() + { + return _realPricipalDatabase.getMechanisms(); + } + + public List getUsers() + { + return _realPricipalDatabase.getUsers(); + } + + public void reload() throws IOException + { + _realPricipalDatabase.reload(); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java new file mode 100644 index 0000000000..192ff74bff --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.CallbackHandler; +import java.util.Enumeration; +import java.util.Map; + +public class CRAMMD5HexSaslServer implements SaslServer +{ + public static final String MECHANISM = "CRAM-MD5-HEX"; + + private SaslServer _realServer; + + public CRAMMD5HexSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + Enumeration factories = Sasl.getSaslServerFactories(); + + while (factories.hasMoreElements()) + { + SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); + + if (factory instanceof CRAMMD5HexServerFactory) + { + continue; + } + + String[] mechs = factory.getMechanismNames(props); + + for (String mech : mechs) + { + if (mech.equals("CRAM-MD5")) + { + _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); + return; + } + } + } + + throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return _realServer.evaluateResponse(response); + } + + public boolean isComplete() + { + return _realServer.isComplete(); + } + + public String getAuthorizationID() + { + return _realServer.getAuthorizationID(); + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return _realServer.unwrap(incoming, offset, len); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return _realServer.wrap(outgoing, offset, len); + } + + public Object getNegotiatedProperty(String propName) + { + return _realServer.getNegotiatedProperty(propName); + } + + public void dispose() throws SaslException + { + _realServer.dispose(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java new file mode 100644 index 0000000000..ce0e19abf9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.crammd5; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5HexServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (mechanism.equals(CRAMMD5HexSaslServer.MECHANISM)) + { + return new CRAMMD5HexSaslServer(mechanism, protocol, serverName, props, cbh); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{CRAMMD5HexSaslServer.MECHANISM}; + } +} -- cgit v1.2.1 From b6b8b1d803d8dd21ece5969d4ce73fe496330d16 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 1 Dec 2009 14:22:44 +0000 Subject: QPID-2184: replace random 1second wait with a LogMonitor check that the reload has occured. Also update some method and paramter names git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@885765 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/ServerConfiguration.java | 11 +++++++---- .../management/ConfigurationManagementMBean.java | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 441369d064..66a7279134 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -57,7 +57,8 @@ public class ServerConfiguration implements SignalHandler public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; public static final String DEFAULT_STATUS_UPDATES = "on"; - + public static final String SECURITY_CONFIG_RELOADED = "SECURITY CONFIGURATION RELOADED"; + private static final int DEFAULT_FRAME_SIZE = 65536; private static final int DEFAULT_PORT = 5672; private static final int DEFAUL_SSL_PORT = 8672; @@ -297,15 +298,15 @@ public class ServerConfiguration implements SignalHandler { try { - reparseConfigFile(); + reparseConfigFileSecuritySections(); } catch (ConfigurationException e) { - _log.error("Could not reload configuration file", e); + _log.error("Could not reload configuration file security sections", e); } } - public void reparseConfigFile() throws ConfigurationException + public void reparseConfigFileSecuritySections() throws ConfigurationException { if (_configFile != null) { @@ -320,6 +321,8 @@ public class ServerConfiguration implements SignalHandler vhost.getAccessManager().configureGlobalPlugins(_securityConfiguration); vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); } + + _log.warn(SECURITY_CONFIG_RELOADED); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java index 9954719866..24f8e8878e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -42,7 +42,7 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co public void reloadSecurityConfiguration() throws Exception { - ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile(); + ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections(); } } -- cgit v1.2.1 From d55b46ed1644be65a774e211e5ff14c214301cc1 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Dec 2009 16:19:14 +0000 Subject: Merged r 886719:886722 from 0.5.x-dev. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@886842 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 14 +- .../src/main/java/org/apache/qpid/server/Main.java | 10 +- .../qpid/server/exchange/AbstractExchange.java | 4 +- .../org/apache/qpid/server/logging/LogActor.java | 6 + .../server/logging/actors/AMQPChannelActor.java | 6 + .../server/logging/actors/AMQPConnectionActor.java | 96 ++++--- .../qpid/server/logging/actors/AbstractActor.java | 9 +- .../qpid/server/logging/actors/BrokerActor.java | 6 + .../server/logging/actors/ManagementActor.java | 18 +- .../qpid/server/logging/actors/QueueActor.java | 5 + .../server/logging/actors/SubscriptionActor.java | 10 +- .../server/logging/messages/LogMessages.properties | 297 +++++++++++++++++---- .../logging/messages/LogMessages_en_US.properties | 132 --------- .../logging/subjects/SubscriptionLogSubject.java | 6 +- .../management/JMXManagedObjectRegistry.java | 20 +- .../management/MBeanInvocationHandlerImpl.java | 7 +- .../qpid/server/protocol/AMQProtocolEngine.java | 12 +- .../apache/qpid/server/queue/ExchangeBinding.java | 4 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 10 +- .../qpid/server/registry/ApplicationRegistry.java | 4 +- .../ConfigurationFileApplicationRegistry.java | 2 +- .../qpid/server/store/AbstractMessageStore.java | 4 +- .../qpid/server/store/DerbyMessageStore.java | 12 +- .../qpid/server/store/MemoryMessageStore.java | 4 +- .../qpid/server/subscription/SubscriptionImpl.java | 6 +- .../VirtualHostConfigRecoveryHandler.java | 1 + .../qpid/server/virtualhost/VirtualHostImpl.java | 4 +- 27 files changed, 403 insertions(+), 306 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index f0f65cc4c8..333c1b9cac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -133,7 +133,7 @@ public class AMQChannel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); - _actor.message(ChannelMessages.CHN_1001()); + _actor.message(ChannelMessages.CHN_CREATE()); _messageStore = messageStore; @@ -417,7 +417,7 @@ public class AMQChannel { _closing = closing; - CurrentActor.get().message(_logSubject, ChannelMessages.CHN_1003()); + CurrentActor.get().message(_logSubject, ChannelMessages.CHN_CLOSE()); } private void unsubscribeAllConsumers() throws AMQException @@ -737,7 +737,7 @@ public class AMQChannel // Log Flow Started before we start the subscriptions if (!suspended) { - _actor.message(_logSubject, ChannelMessages.CHN_1002("Started")); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Started")); } @@ -788,7 +788,7 @@ public class AMQChannel // stopped. if (suspended) { - _actor.message(_logSubject, ChannelMessages.CHN_1002("Stopped")); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Stopped")); } } @@ -904,7 +904,7 @@ public class AMQChannel public void setCredit(final long prefetchSize, final int prefetchCount) { - _actor.message(ChannelMessages.CHN_1004(prefetchSize, prefetchCount)); + _actor.message(ChannelMessages.CHN_PREFETCH_SIZE(prefetchSize, prefetchCount)); _creditManager.setCreditLimits(prefetchSize, prefetchCount); } @@ -1163,7 +1163,7 @@ public class AMQChannel if(_blocking.compareAndSet(false,true)) { - _actor.message(_logSubject, ChannelMessages.CHN_1005(queue.getName().toString())); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getName().toString())); flow(false); } } @@ -1175,7 +1175,7 @@ public class AMQChannel { if(_blocking.compareAndSet(true,false)) { - _actor.message(_logSubject, ChannelMessages.CHN_1006()); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW_REMOVED()); flow(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 0a2bd6e8b0..845983857c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -266,7 +266,7 @@ public class Main } else { - CurrentActor.get().message(BrokerMessages.BRK_1006(configFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.BRK_CONFIG(configFile.getAbsolutePath())); } String logConfig = commandLine.getOptionValue("l"); @@ -417,7 +417,7 @@ public class Main serverConfig.getNetworkConfiguration(), null); ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP", port)); } @@ -431,14 +431,14 @@ public class Main new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory); ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, serverConfig.getSSLPort()), new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_1002("TCP/SSL", serverConfig.getSSLPort())); + CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP/SSL", serverConfig.getSSLPort())); } //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - CurrentActor.get().message(BrokerMessages.BRK_1004()); + CurrentActor.get().message(BrokerMessages.BRK_READY()); } finally @@ -558,7 +558,7 @@ public class Main { if (logConfigFile.exists() && logConfigFile.canRead()) { - CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.BRK_LOG_CONFIG(logConfigFile.getAbsolutePath())); System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 7983c62443..33af910f1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -185,7 +185,7 @@ public abstract class AbstractExchange implements Exchange, Managable _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation - CurrentActor.get().message(ExchangeMessages.EXH_1001(String.valueOf(getType()), String.valueOf(name), durable)); + CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getType()), String.valueOf(name), durable)); } public abstract Logger getLogger(); @@ -216,7 +216,7 @@ public abstract class AbstractExchange implements Exchange, Managable _alternateExchange.removeReference(this); } - CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_1002()); + CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); } public String toString() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java index d5683b3c7b..18f03c2716 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java @@ -57,4 +57,10 @@ public interface LogActor * @return the RootMessageLogger that is currently in use by this LogActor. */ RootMessageLogger getRootMessageLogger(); + + /** + * + * @return the String representing this LogActor + */ + public String getLogMessage(); } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java index d4d41bc1d4..a4f178eba7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java @@ -40,6 +40,7 @@ import java.text.MessageFormat; */ public class AMQPChannelActor extends AbstractActor { + private final String _logString; /** * Create a new ChannelActor @@ -74,5 +75,10 @@ public class AMQPChannelActor extends AbstractActor channel.getChannelId()) + "] "; } + + public String getLogMessage() + { + return _logString; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java index d459fc0f06..20c416fed0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java @@ -54,6 +54,15 @@ public class AMQPConnectionActor extends AbstractActor */ public static final String USER_FORMAT = "con:{0}({1}@{2})"; + // The log string prefix for each message + private String _logString; + + // The Session this Actor is representing + private AMQProtocolSession _session; + + // Used to stop re-creating the _logString when we reach our final format + private boolean _upToDate = false; + public AMQPConnectionActor(AMQProtocolSession session, RootMessageLogger rootLogger) { super(rootLogger); @@ -61,55 +70,66 @@ public class AMQPConnectionActor extends AbstractActor _logString = "[" + MessageFormat.format(SOCKET_FORMAT, session.getSessionID(), session.getRemoteAddress()) - + "] "; + + _session = session; } /** - * Call when the connection has been authorized so that the logString - * can be updated with the new user identity. + * Update the LogString as the Connection process proceeds. + * + * When the Session has an authorized ID add that to the string. * - * @param session the authorized session + * When the Session then gains a Vhost add that to the string, at this point + * we can set upToDate = true as the _logString will not need to be updated + * from this point onwards. */ - public void connectionAuthorized(AMQProtocolSession session) + private void updateLogString() { - _logString = "[" + MessageFormat.format(USER_FORMAT, - session.getSessionID(), - session.getPrincipal().getName(), - session.getRemoteAddress()) - + "] "; + if (!_upToDate) + { + if (_session.getPrincipal() != null) + { + if (_session.getVirtualHost() != null) + { + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ConnectionLogSubject.CONNECTION_FORMAT : + * con:{0}({1}@{2}/{3}) + * + * Uses a MessageFormat call to insert the required values according to + * these indices: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, + _session.getSessionID(), + _session.getPrincipal().getName(), + _session.getRemoteAddress(), + _session.getVirtualHost().getName()) + + "] "; + _upToDate = true; + } + else + { + _logString = "[" + MessageFormat.format(USER_FORMAT, + _session.getSessionID(), + _session.getPrincipal().getName(), + _session.getRemoteAddress()) + + "] "; + } + } + } } - /** - * Called once the user has been authenticated and they are now selecting - * the virtual host they wish to use. - * - * @param session the session that now has a virtualhost associated with it. - */ - public void virtualHostSelected(AMQProtocolSession session) + public String getLogMessage() { - - /** - * LOG FORMAT used by the AMQPConnectorActor follows - * ConnectionLogSubject.CONNECTION_FORMAT : - * con:{0}({1}@{2}/{3}) - * - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost - */ - _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, - session.getSessionID(), - session.getPrincipal().getName(), - session.getRemoteAddress(), - session.getVirtualHost().getName()) - + "] "; - + updateLogString(); + return _logString; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 0059a48c06..1fa2bd9600 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -27,7 +27,6 @@ import org.apache.qpid.server.logging.RootMessageLogger; public abstract class AbstractActor implements LogActor { - protected String _logString; protected RootMessageLogger _rootLogger; public AbstractActor(RootMessageLogger rootLogger) @@ -43,7 +42,7 @@ public abstract class AbstractActor implements LogActor { if (_rootLogger.isMessageEnabled(this, subject)) { - _rootLogger.rawMessage(_logString + String.valueOf(subject) + message); + _rootLogger.rawMessage(getLogMessage() + String.valueOf(subject) + message); } } @@ -51,7 +50,7 @@ public abstract class AbstractActor implements LogActor { if (_rootLogger.isMessageEnabled(this)) { - _rootLogger.rawMessage(_logString + message); + _rootLogger.rawMessage(getLogMessage() + message); } } @@ -62,7 +61,9 @@ public abstract class AbstractActor implements LogActor public String toString() { - return _logString; + return getLogMessage(); } + abstract public String getLogMessage(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java index 5d2762fd1d..9e77452228 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java @@ -24,6 +24,7 @@ import org.apache.qpid.server.logging.RootMessageLogger; public class BrokerActor extends AbstractActor { + private final String _logString; /** * Create a new BrokerActor @@ -44,4 +45,9 @@ public class BrokerActor extends AbstractActor _logString = "[Broker(" + name + ")] "; } + public String getLogMessage() + { + return _logString; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java index 85fbb8f1ac..2825fa1b75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java @@ -53,11 +53,15 @@ public class ManagementActor extends AbstractActor */ public static final String MANAGEMENT_FORMAT = "mng:{0}({1})"; + /** + * The logString to be used for logging + */ + private String _logString; + /** @param rootLogger The RootLogger to use for this Actor */ public ManagementActor(RootMessageLogger rootLogger) { super(rootLogger); - } private void updateLogString() @@ -101,18 +105,10 @@ public class ManagementActor extends AbstractActor } } - @Override - public void message(LogSubject subject, LogMessage message) - { - updateLogString(); - super.message(subject, message); - } - - @Override - public void message(LogMessage message) + public String getLogMessage() { updateLogString(); - super.message(message); + return _logString; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java index acac447ff6..e62e711514 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java @@ -32,6 +32,7 @@ import java.text.MessageFormat; */ public class QueueActor extends AbstractActor { + private final String _logString; /** * Create an QueueLogSubject that Logs in the following format. @@ -46,7 +47,11 @@ public class QueueActor extends AbstractActor _logString = "[" + MessageFormat.format(QueueLogSubject.LOG_FORMAT, queue.getVirtualHost().getName(), queue.getName()) + "] "; + } + public String getLogMessage() + { + return _logString; } } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java index ab33a29eac..63892e6353 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java @@ -21,6 +21,8 @@ package org.apache.qpid.server.logging.actors; import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.subjects.QueueLogSubject; +import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; import org.apache.qpid.server.subscription.Subscription; import java.text.MessageFormat; @@ -28,15 +30,21 @@ import java.text.MessageFormat; public class SubscriptionActor extends AbstractActor { public static String SUBSCRIBER_FORMAT = "sub:{0}(vh({1})/qu({2}))"; + private final String _logString; public SubscriptionActor(RootMessageLogger logger, Subscription subscription) { super(logger); - _logString = "[" + MessageFormat.format(SUBSCRIBER_FORMAT, + _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT, subscription.getSubscriptionID(), subscription.getQueue().getVirtualHost().getName(), subscription.getQueue().getName()) + "] "; } + + public String getLogMessage() + { + return _logString; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index 1a2cb7251c..7159c6b02c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -17,116 +17,307 @@ # under the License. # # Default File used for all non-defined locales. +# +# LogMessages used within the Java Broker as originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded through a ResourceBundle named LogMessages. the en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is requried then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat peforms its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addtion of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexepcted. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formating. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the first and final stage of processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# paramters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important is it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java +# Currently the following classes are created and are populated with the +# messages that bear their 3-digit type identifier: +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage BRK_SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain paramters +# however nesting of options is not permitted. Identification is performed on +# first matchings so give the message: +# Msg = Log Message [option1] [option2] +# Two options will be identifed and enabled to select text 'option1 and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# The final processing that is done in the generation is the conversion of the +# property name. As a '-' is an illegal character in the method name it is +# converted to '_' This processing gives the final method signature as follows: +# Message._(,) +# +# +# Default File used for all non-defined locales. #Broker # 0 - Version # 1 = Build -BRK-1001 = Startup : Version: {0} Build: {1} +BRK_STARTUP = BRK-1001 : Startup : Version: {0} Build: {1} # 0 - Transport # 1 - Port -BRK-1002 = Starting : Listening on {0} port {1,number,#} +BRK_LISTENING = BRK-1002 : Starting : Listening on {0} port {1,number,#} # 0 - Transport # 1 - Port -BRK-1003 = Shuting down : {0} port {1,number,#} -BRK-1004 = Ready -BRK-1005 = Stopped +BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +BRK_READY = BRK-1004 : Ready +BRK_STOPPED = BRK-1005 : Stopped # 0 - path -BRK-1006 = Using configuration : {0} +BRK_CONFIG = BRK-1006 : Using configuration : {0} # 0 - path -BRK-1007 = Using logging configuration : {0} +BRK_LOG_CONFIG = BRK-1007 : Using logging configuration : {0} #ManagementConsole -MNG-1001 = Startup +MNG_STARTUP = MNG-1001 : Startup # 0 - Service # 1 - Port -MNG-1002 = Starting : {0} : Listening on port {1,number,#} +MNG_LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} # 0 - Service # 1 - Port -MNG-1003 = Shuting down : {0} : port {1,number,#} -MNG-1004 = Ready -MNG-1005 = Stopped +MNG_SHUTTING_DOWN = MNG-1003 : Shuting down : {0} : port {1,number,#} +MNG_READY = MNG-1004 : Ready +MNG_STOPPED = MNG-1005 : Stopped # 0 - Path -MNG-1006 = Using SSL Keystore : {0} -MNG-1007 = Open : User {0} -MNG-1008 = Close +MNG_SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0} +MNG_OPEN = MNG-1007 : Open : User {0} +MNG_CLOSE = MNG-1008 : Close #VirtualHost # 0 - name -VHT-1001 = Created : {0} -VHT-1002 = Closed +VHT_CREATED = VHT-1001 : Created : {0} +VHT_CLOSED = VHT-1002 : Closed #MessageStore # 0 - name -MST-1001 = Created : {0} +MST_CREATED = MST-1001 : Created : {0} # 0 - path -MST-1002 = Store location : {0} -MST-1003 = Closed -MST-1004 = Recovery Start -MST-1005 = Recovered {0,number} messages -MST-1006 = Recovery Complete +MST_STORE_LOCATION = MST-1002 : Store location : {0} +MST_CLOSED = MST-1003 : Closed +MST_RECOVERY_START = MST-1004 : Recovery Start +MST_RECOVERED = MST-1005 : Recovered {0,number} messages +MST_RECOVERY_COMPLETE = MST-1006 : Recovery Complete #ConfigStore # 0 - name -CFG-1001 = Created : {0} +CFG-1001 = CFG-1001 : Created : {0} # 0 - path -CFG-1002 = Store location : {0} -CFG-1003 = Closed -CFG-1004 = Recovery Start -CFG-1005 = Recovery Complete +CFG-1002 = CFG-1002 : Store location : {0} +CFG-1003 = CFG-1003 : Closed +CFG-1004 = CFG-1004 : Recovery Start +CFG-1005 = CFG-1005 : Recovery Complete #TransactionLog # 0 - name -TXN-1001 = Created : {0} +TXN-1001 = TXN-1001 : Created : {0} # 0 - path -TXN-1002 = Store location : {0} -TXN-1003 = Closed +TXN-1002 = TXN-1002 : Store location : {0} +TXN-1003 = TXN-1003 : Closed # 0 - queue name -TXN-1004 = Recovery Start[ : {0}] +TXN-1004 = TXN-1004 : Recovery Start[ : {0}] # 0 - count # 1 - queue count -TXN-1005 = Recovered {0,number} messages for queue {1} +TXN-1005 = TXN-1005 : Recovered {0,number} messages for queue {1} # 0 - queue name -TXN-1006 = Recovery Complete[ : {0}] +TXN-1006 = TXN-1006 : Recovery Complete[ : {0}] #Connection # 0 - Client id # 1 - Protocol Version -CON-1001 = Open[ : Client ID : {0}][ : Protocol Version : {1}] -CON-1002 = Close +CON_OPEN = CON-1001 : Open[ : Client ID : {0}][ : Protocol Version : {1}] +CON_CLOSE = CON-1002 : Close #Channel -CHN-1001 = Create +CHN_CREATE = CHN-1001 : Create # 0 - flow -CHN-1002 = Flow {0} -CHN-1003 = Close +CHN_FLOW = CHN-1002 : Flow {0} +CHN_CLOSE = CHN-1003 : Close # 0 - bytes allowed in prefetch # 1 - number of messagse. -CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +CHN_PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} # 0 - queue causing flow control -CHN-1005 = Flow Control Enforced (Queue {0}) -CHN-1006 = Flow Control Removed +CHN_FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0}) +CHN_FLOW_REMOVED = CHN-1006 : Flow Control Removed #Queue # 0 - owner # 1 - priority -QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -QUE-1002 = Deleted -QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} -QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} +QUE_CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +QUE_DELETED = QUE-1002 : Deleted +QUE_OVERFULL = QUE-1003 : Overfull : Size : {0,number} bytes, Capacity : {1,number} +QUE_UNDERFULL = QUE-1004 : Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} #Exchange # 0 - type # 1 - name -EXH-1001 = Create :[ Durable] Type: {0} Name: {1} -EXH-1002 = Deleted +EXH_CREATED = EXH-1001 : Create :[ Durable] Type: {0} Name: {1} +EXH_DELETED = EXH-1002 : Deleted #Binding -BND-1001 = Create[ : Arguments : {0}] -BND-1002 = Deleted +BND_CREATED = BND-1001 : Create[ : Arguments : {0}] +BND_DELETED = BND-1002 : Deleted #Subscription -SUB-1001 = Create[ : Durable][ : Arguments : {0}] -SUB-1002 = Close +SUB_CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}] +SUB_CLOSE = SUB-1002 : Close # 0 - The current subscription state -SUB-1003 = State : {0} +SUB_STATE = SUB-1003 : State : {0} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties deleted file mode 100644 index 1a2cb7251c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ /dev/null @@ -1,132 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# Default File used for all non-defined locales. -#Broker -# 0 - Version -# 1 = Build -BRK-1001 = Startup : Version: {0} Build: {1} -# 0 - Transport -# 1 - Port -BRK-1002 = Starting : Listening on {0} port {1,number,#} -# 0 - Transport -# 1 - Port -BRK-1003 = Shuting down : {0} port {1,number,#} -BRK-1004 = Ready -BRK-1005 = Stopped -# 0 - path -BRK-1006 = Using configuration : {0} -# 0 - path -BRK-1007 = Using logging configuration : {0} - -#ManagementConsole -MNG-1001 = Startup -# 0 - Service -# 1 - Port -MNG-1002 = Starting : {0} : Listening on port {1,number,#} -# 0 - Service -# 1 - Port -MNG-1003 = Shuting down : {0} : port {1,number,#} -MNG-1004 = Ready -MNG-1005 = Stopped -# 0 - Path -MNG-1006 = Using SSL Keystore : {0} -MNG-1007 = Open : User {0} -MNG-1008 = Close - - -#VirtualHost -# 0 - name -VHT-1001 = Created : {0} -VHT-1002 = Closed - -#MessageStore -# 0 - name -MST-1001 = Created : {0} -# 0 - path -MST-1002 = Store location : {0} -MST-1003 = Closed -MST-1004 = Recovery Start -MST-1005 = Recovered {0,number} messages -MST-1006 = Recovery Complete - -#ConfigStore -# 0 - name -CFG-1001 = Created : {0} -# 0 - path -CFG-1002 = Store location : {0} -CFG-1003 = Closed -CFG-1004 = Recovery Start -CFG-1005 = Recovery Complete - -#TransactionLog -# 0 - name -TXN-1001 = Created : {0} -# 0 - path -TXN-1002 = Store location : {0} -TXN-1003 = Closed -# 0 - queue name -TXN-1004 = Recovery Start[ : {0}] -# 0 - count -# 1 - queue count -TXN-1005 = Recovered {0,number} messages for queue {1} -# 0 - queue name -TXN-1006 = Recovery Complete[ : {0}] - -#Connection -# 0 - Client id -# 1 - Protocol Version -CON-1001 = Open[ : Client ID : {0}][ : Protocol Version : {1}] -CON-1002 = Close - -#Channel -CHN-1001 = Create -# 0 - flow -CHN-1002 = Flow {0} -CHN-1003 = Close -# 0 - bytes allowed in prefetch -# 1 - number of messagse. -CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} -# 0 - queue causing flow control -CHN-1005 = Flow Control Enforced (Queue {0}) -CHN-1006 = Flow Control Removed - -#Queue -# 0 - owner -# 1 - priority -QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -QUE-1002 = Deleted -QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} -QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} - - -#Exchange -# 0 - type -# 1 - name -EXH-1001 = Create :[ Durable] Type: {0} Name: {1} -EXH-1002 = Deleted - -#Binding -BND-1001 = Create[ : Arguments : {0}] -BND-1002 = Deleted - -#Subscription -SUB-1001 = Create[ : Durable][ : Arguments : {0}] -SUB-1002 = Close -# 0 - The current subscription state -SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java index b68ef2e9a9..c842da4db0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -33,7 +33,7 @@ public class SubscriptionLogSubject extends AbstractLogSubject * 0 - Subscription ID * 1 - queue name */ - protected static String BINDING_FORMAT = "sub:{0}(qu({1}))"; + public static String SUBSCRIPTION_FORMAT = "sub:{0}(vh(/{1})/qu({2}))"; /** * Create an QueueLogSubject that Logs in the following format. @@ -42,8 +42,8 @@ public class SubscriptionLogSubject extends AbstractLogSubject */ public SubscriptionLogSubject(Subscription subscription) { - - setLogStringWithFormat(BINDING_FORMAT, subscription.getSubscriptionID(), + setLogStringWithFormat(SUBSCRIPTION_FORMAT, subscription.getSubscriptionID(), + subscription.getQueue().getVirtualHost().getName(), subscription.getQueue().getName()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 92657d7f3c..048551010e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -100,7 +100,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry public void start() throws IOException, ConfigurationException { - CurrentActor.get().message(ManagementConsoleMessages.MNG_1001()); + CurrentActor.get().message(ManagementConsoleMessages.MNG_STARTUP()); //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) @@ -171,7 +171,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1006(ksf.getAbsolutePath())); + CurrentActor.get().message(ManagementConsoleMessages.MNG_SSL_KEYSTORE(ksf.getAbsolutePath())); } //check the key store password is set @@ -199,8 +199,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + (port +PORT_EXPORT_OFFSET) + ") with SSL"); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("SSL RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); } else @@ -211,8 +211,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1002("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server @@ -301,7 +301,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _cs.start(); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1004()); + CurrentActor.get().message(ManagementConsoleMessages.MNG_READY()); } /* @@ -389,8 +389,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry try { _cs.stop(); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); - CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI ConnectorServer", _cs.getAddress().getPort())); + CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort())); } catch (IOException e) { @@ -421,7 +421,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } } - CurrentActor.get().message(ManagementConsoleMessages.MNG_1005()); + CurrentActor.get().message(ManagementConsoleMessages.MNG_STOPPED()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 20410ba5ce..0ee5763d91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -26,8 +26,6 @@ import org.apache.qpid.management.common.mbeans.UserManagement; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; -import org.apache.qpid.server.logging.messages.ConnectionMessages; -import org.apache.qpid.server.logging.LogActor; import org.apache.log4j.Logger; import javax.management.remote.MBeanServerForwarder; @@ -47,7 +45,6 @@ import java.lang.reflect.Method; import java.security.AccessController; import java.security.Principal; import java.security.AccessControlContext; -import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.Properties; @@ -276,12 +273,12 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati if (notification.getType().equals(JMXConnectionNotification.OPENED)) { - _logActor.message(ManagementConsoleMessages.MNG_1007(user)); + _logActor.message(ManagementConsoleMessages.MNG_OPEN(user)); } else if (notification.getType().equals(JMXConnectionNotification.CLOSED) || notification.getType().equals(JMXConnectionNotification.FAILED)) { - _logActor.message(ManagementConsoleMessages.MNG_1008()); + _logActor.message(ManagementConsoleMessages.MNG_CLOSE()); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 0824d12416..0a1fdb686f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -178,7 +178,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false); _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); - _actor.message(ConnectionMessages.CON_1001(null, null, false, false)); + _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false)); } @@ -329,7 +329,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol try { // Log incomming protocol negotiation request - _actor.message(ConnectionMessages.CON_1001(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); + _actor.message(ConnectionMessages.CON_OPEN(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); ProtocolVersion pv = pi.checkVersion(); // Fails if not correct @@ -720,7 +720,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol notifyAll(); } _poolReference.releaseExecutorService(); - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_CLOSE()); } } else @@ -840,7 +840,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol setContextKey(new AMQShortString(clientID)); // Log the Opening of the connection for this client - _actor.message(ConnectionMessages.CON_1001(clientID, _protocolVersion.toString(), true, true)); + _actor.message(ConnectionMessages.CON_OPEN(clientID, _protocolVersion.toString(), true, true)); } if (_clientProperties.getString(ClientProperties.version.toString()) != null) @@ -898,7 +898,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _virtualHost = virtualHost; - _actor.virtualHostSelected(this); _logSubject = new ConnectionLogSubject(this); _virtualHost.getConnectionRegistry().registerConnection(this); @@ -932,9 +931,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void setAuthorizedID(Principal authorizedID) { _authorizedID = authorizedID; - - // Let the actor know that this connection is now Authorized - _actor.connectionAuthorized(this); } public Principal getAuthorizedID() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java index 6e87cfbb76..2fd8e32fcd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java @@ -45,7 +45,7 @@ public class ExchangeBinding _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; _logSubject = new BindingLogSubject(routingKey,exchange,queue); - CurrentActor.get().message(_logSubject, BindingMessages.BND_1001(String.valueOf(_arguments), arguments != null)); + CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(_arguments), arguments != null)); } @@ -54,7 +54,7 @@ public class ExchangeBinding { _exchange.deregisterQueue(_routingKey, queue, _arguments); - CurrentActor.get().message(_logSubject, BindingMessages.BND_1002()); + CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); } public Exchange getExchange() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 77a6fb9328..d7d0414936 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -200,7 +200,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Log the creation of this Queue. // The priorities display is toggled on if we set priorities > 0 CurrentActor.get().message(_logSubject, - QueueMessages.QUE_1001(String.valueOf(_owner), + QueueMessages.QUE_CREATED(String.valueOf(_owner), priorities, _owner != null, autoDelete, @@ -1297,7 +1297,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener stop(); //Log Queue Deletion - CurrentActor.get().message(_logSubject, QueueMessages.QUE_1002()); + CurrentActor.get().message(_logSubject, QueueMessages.QUE_DELETED()); } return getMessageCount(); @@ -1320,7 +1320,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _overfull.set(true); //Overfull log message - _logActor.message(_logSubject, QueueMessages.QUE_1003(_atomicQueueSize.get(), _capacity)); + _logActor.message(_logSubject, QueueMessages.QUE_OVERFULL(_atomicQueueSize.get(), _capacity)); if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null) { @@ -1331,7 +1331,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { //Underfull log message - _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); channel.unblock(this); _blockedChannels.remove(channel); @@ -1353,7 +1353,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if(_overfull.compareAndSet(true,false)) {//Underfull log message - _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity)); + _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 1affdd6590..5cb379f10d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -248,7 +248,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry // _pluginManager.close(); - CurrentActor.get().message(BrokerMessages.BRK_1005()); + CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); } private void unbind() @@ -259,7 +259,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { QpidAcceptor acceptor = _acceptors.get(bindAddress); acceptor.getNetworkDriver().close(); - CurrentActor.get().message(BrokerMessages.BRK_1003(acceptor.toString(), bindAddress.getPort())); + CurrentActor.get().message(BrokerMessages.BRK_SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 8e8581b66f..f325b53dfb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -59,7 +59,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry // Set the Actor for current log messages CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); + CurrentActor.get().message(BrokerMessages.BRK_STARTUP(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); initialiseManagedObjectRegistry(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java index f8bc530aa6..ef8f1ab70e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java @@ -34,11 +34,11 @@ public abstract class AbstractMessageStore implements MessageStore public void configure(VirtualHost virtualHost) throws Exception { _logSubject = new MessageStoreLogSubject(virtualHost, this); - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); } public void close() throws Exception { - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index ba5574d1fa..1764e2324e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -173,7 +173,7 @@ public class DerbyMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); if(!_configured) { @@ -231,7 +231,7 @@ public class DerbyMessageStore implements MessageStore } } - CurrentActor.get().message(logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_STORE_LOCATION(environmentPath.getAbsolutePath())); createOrOpenDatabase(name, databasePath); } @@ -369,6 +369,7 @@ public class DerbyMessageStore implements MessageStore { stateTransition(State.CONFIGURING, State.RECOVERING); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_RECOVERY_START()); try { @@ -380,8 +381,6 @@ public class DerbyMessageStore implements MessageStore ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery(); recoverBindings(brh, exchanges); brh.completeBindingRecovery(); - - } catch (SQLException e) { @@ -408,9 +407,6 @@ public class DerbyMessageStore implements MessageStore qrh.queue(queueName, owner, null); queues.add(queueName); - - - } return queues; } @@ -505,7 +501,7 @@ public class DerbyMessageStore implements MessageStore public void close() throws Exception { - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); _closed.getAndSet(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index f43177bfc1..e3e9432e6b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -102,13 +102,13 @@ public class MemoryMessageStore implements MessageStore } int hashtableCapacity = config.getInt(name + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); _log.info("Using capacity " + hashtableCapacity + " for hash tables"); - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); } public void close() throws Exception { _closed.getAndSet(true); - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index bb2e5ae918..5302a3c5d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -365,7 +365,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage CurrentActor.get(). message(_logSubject, - SubscriptionMessages.SUB_1001(filterLogString, + SubscriptionMessages.SUB_CREATE(filterLogString, queue.isDurable() && exclusive, filterLogString != null)); } @@ -508,7 +508,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage //Log Subscription closed - CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_1002()); + CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_CLOSE()); } public boolean isClosed() @@ -596,7 +596,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); } } - CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_1003(_state.get().toString())); + CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_STATE(_state.get().toString())); } public State getState() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 7fa5a26436..c543531210 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index c321fdf3e0..6826dcf324 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -158,7 +158,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _configuration = hostConfig; _name = hostConfig.getName(); - CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); + CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); if (_name == null || _name.length() == 0) { @@ -482,7 +482,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _messageStore.close(); } - CurrentActor.get().message(VirtualHostMessages.VHT_1002()); + CurrentActor.get().message(VirtualHostMessages.VHT_CLOSED()); } public ManagedObject getBrokerMBean() -- cgit v1.2.1 From bb33aeba13dccaa677c2bed740a3da6842e612fe Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Dec 2009 10:34:15 +0000 Subject: Merged r887145 from 0.5.x-dev QPID-1992 : Ensure there is only one location where strings are built for logging. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@887152 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/actors/AMQPChannelActor.java | 26 +----- .../server/logging/actors/AMQPConnectionActor.java | 89 +------------------- .../qpid/server/logging/actors/QueueActor.java | 10 +-- .../server/logging/actors/SubscriptionActor.java | 15 ++-- .../logging/subjects/AbstractLogSubject.java | 6 +- .../server/logging/subjects/ChannelLogSubject.java | 25 ++++-- .../logging/subjects/ConnectionLogSubject.java | 97 +++++++++++++++++++++- .../logging/subjects/SubscriptionLogSubject.java | 23 +++-- 8 files changed, 151 insertions(+), 140 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java index a4f178eba7..d961836acc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java @@ -40,7 +40,7 @@ import java.text.MessageFormat; */ public class AMQPChannelActor extends AbstractActor { - private final String _logString; + private final ChannelLogSubject _logString; /** * Create a new ChannelActor @@ -52,33 +52,13 @@ public class AMQPChannelActor extends AbstractActor { super(rootLogger); - AMQProtocolSession session = channel.getProtocolSession(); - /** - * LOG FORMAT used by the AMQPConnectorActor follows - * ChannelLogSubject.CHANNEL_FORMAT : - * con:{0}({1}@{2}/{3})/ch:{4} - * - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost - */ - _logString = "[" + MessageFormat.format(ChannelLogSubject.CHANNEL_FORMAT, - session.getSessionID(), - session.getPrincipal().getName(), - session.getRemoteAddress(), - session.getVirtualHost().getName(), - channel.getChannelId()) - + "] "; + _logString = new ChannelLogSubject(channel); } public String getLogMessage() { - return _logString; + return _logString.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java index 20c416fed0..4149aed529 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java @@ -24,7 +24,7 @@ import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; import org.apache.qpid.server.protocol.AMQProtocolSession; -import java.text.MessageFormat; + /** * An AMQPConnectionActor represtents a connectionthrough the AMQP port. @@ -37,99 +37,18 @@ import java.text.MessageFormat; */ public class AMQPConnectionActor extends AbstractActor { - /** - * 0 - Connection ID - * 1 - Remote Address - */ - public static String SOCKET_FORMAT = "con:{0}({1})"; - - /** - * LOG FORMAT for the ConnectionLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - */ - public static final String USER_FORMAT = "con:{0}({1}@{2})"; - - // The log string prefix for each message - private String _logString; - - // The Session this Actor is representing - private AMQProtocolSession _session; - - // Used to stop re-creating the _logString when we reach our final format - private boolean _upToDate = false; + private ConnectionLogSubject _logSubject; public AMQPConnectionActor(AMQProtocolSession session, RootMessageLogger rootLogger) { super(rootLogger); - _logString = "[" + MessageFormat.format(SOCKET_FORMAT, - session.getSessionID(), - session.getRemoteAddress()) - + "] "; - - _session = session; - } - - /** - * Update the LogString as the Connection process proceeds. - * - * When the Session has an authorized ID add that to the string. - * - * When the Session then gains a Vhost add that to the string, at this point - * we can set upToDate = true as the _logString will not need to be updated - * from this point onwards. - */ - private void updateLogString() - { - if (!_upToDate) - { - if (_session.getPrincipal() != null) - { - if (_session.getVirtualHost() != null) - { - /** - * LOG FORMAT used by the AMQPConnectorActor follows - * ConnectionLogSubject.CONNECTION_FORMAT : - * con:{0}({1}@{2}/{3}) - * - * Uses a MessageFormat call to insert the required values according to - * these indices: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost - */ - _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, - _session.getSessionID(), - _session.getPrincipal().getName(), - _session.getRemoteAddress(), - _session.getVirtualHost().getName()) - + "] "; - _upToDate = true; - } - else - { - _logString = "[" + MessageFormat.format(USER_FORMAT, - _session.getSessionID(), - _session.getPrincipal().getName(), - _session.getRemoteAddress()) - + "] "; - - } - } - } + _logSubject = new ConnectionLogSubject(session); } public String getLogMessage() { - updateLogString(); - return _logString; + return _logSubject.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java index e62e711514..7d81b03de4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java @@ -32,7 +32,7 @@ import java.text.MessageFormat; */ public class QueueActor extends AbstractActor { - private final String _logString; + private QueueLogSubject _logSubject; /** * Create an QueueLogSubject that Logs in the following format. @@ -44,14 +44,12 @@ public class QueueActor extends AbstractActor { super(rootLogger); - _logString = "[" + MessageFormat.format(QueueLogSubject.LOG_FORMAT, - queue.getVirtualHost().getName(), - queue.getName()) + "] "; + _logSubject = new QueueLogSubject(queue); } public String getLogMessage() { - return _logString; + return _logSubject.toString(); } } - \ No newline at end of file + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java index 63892e6353..542984e76c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java @@ -27,24 +27,23 @@ import org.apache.qpid.server.subscription.Subscription; import java.text.MessageFormat; +/** + * The subscription actor provides formatted logging for actions that are + * performed by the subsciption. Such as SUB_STATE changes. + */ public class SubscriptionActor extends AbstractActor { - public static String SUBSCRIBER_FORMAT = "sub:{0}(vh({1})/qu({2}))"; - private final String _logString; + private SubscriptionLogSubject _logSubject; public SubscriptionActor(RootMessageLogger logger, Subscription subscription) { super(logger); - _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT, - subscription.getSubscriptionID(), - subscription.getQueue().getVirtualHost().getName(), - subscription.getQueue().getName()) - + "] "; + _logSubject = new SubscriptionLogSubject(subscription); } public String getLogMessage() { - return _logString; + return _logSubject.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java index 4fb5bdcc93..d7be9ea4c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java @@ -36,7 +36,7 @@ public abstract class AbstractLogSubject implements LogSubject /** * The logString that will be returned via toString */ - protected String logString; + protected String _logString; /** * Set the toString logging of this LogSubject. Based on a format provided @@ -46,7 +46,7 @@ public abstract class AbstractLogSubject implements LogSubject */ protected void setLogStringWithFormat(String format, Object... args) { - logString = "[" + MessageFormat.format(format, args) + "] "; + _logString = "[" + MessageFormat.format(format, args) + "] "; } /** @@ -58,7 +58,7 @@ public abstract class AbstractLogSubject implements LogSubject @Override public String toString() { - return logString; + return _logString; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index 03afd0b772..62cff049d0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -43,12 +43,25 @@ public class ChannelLogSubject extends AbstractLogSubject { AMQProtocolSession session = channel.getProtocolSession(); - // Provide the value for the 4th replacement. + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ChannelLogSubject.CHANNEL_FORMAT : + * con:{0}({1}@{2}/{3})/ch:{4} + * + * Uses a MessageFormat call to insert the required values according to + * these indices: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + * 4 - Channel ID + */ setLogStringWithFormat(CHANNEL_FORMAT, - session.getSessionID(), - session.getPrincipal().getName(), - session.getRemoteAddress(), - session.getVirtualHost().getName(), - channel.getChannelId()); + session.getSessionID(), + session.getAuthorizedID().getName(), + session.getRemoteAddress(), + session.getVirtualHost().getName(), + channel.getChannelId()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index 65d65a24d2..77576eddfb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -22,10 +22,18 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.protocol.AMQProtocolSession; +import java.text.MessageFormat; + /** The Connection LogSubject */ public class ConnectionLogSubject extends AbstractLogSubject { + /** + * 0 - Connection ID + * 1 - Remote Address + */ + public static String SOCKET_FORMAT = "con:{0}({1})"; + /** * LOG FORMAT for the ConnectionLogSubject, * Uses a MessageFormat call to insert the requried values according to @@ -34,15 +42,96 @@ public class ConnectionLogSubject extends AbstractLogSubject * 0 - Connection ID * 1 - User ID * 2 - IP + */ + public static final String USER_FORMAT = "con:{0}({1}@{2})"; + + /** + * LOG FORMAT for the ConnectionLogSubject, + * Uses a MessageFormat call to insert the required values according to + * these indices: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP * 3 - Virtualhost */ public static final String CONNECTION_FORMAT = "con:{0}({1}@{2}/{3})"; + public ConnectionLogSubject(AMQProtocolSession session) { - setLogStringWithFormat(CONNECTION_FORMAT, session.getSessionID(), - session.getPrincipal().getName(), - session.getRemoteAddress(), - session.getVirtualHost().getName()); + _session = session; + } + + // The Session this Actor is representing + private AMQProtocolSession _session; + + // Used to stop re-creating the _logString when we reach our final format + private boolean _upToDate = false; + + /** + * Update the LogString as the Connection process proceeds. + * + * When the Session has an authorized ID add that to the string. + * + * When the Session then gains a Vhost add that to the string, at this point + * we can set upToDate = true as the _logString will not need to be updated + * from this point onwards. + */ + private void updateLogString() + { + if (!_upToDate) + { + if (_session.getAuthorizedID() != null) + { + if (_session.getVirtualHost() != null) + { + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ConnectionLogSubject.CONNECTION_FORMAT : + * con:{0}({1}@{2}/{3}) + * + * Uses a MessageFormat call to insert the required values according to + * these indices: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, + _session.getSessionID(), + _session.getAuthorizedID().getName(), + _session.getRemoteAddress(), + _session.getVirtualHost().getName()) + + "] "; + + _upToDate = true; + } + else + { + _logString = "[" + MessageFormat.format(USER_FORMAT, + _session.getSessionID(), + _session.getAuthorizedID().getName(), + _session.getRemoteAddress()) + + "] "; + + } + } + else + { + _logString = "[" + MessageFormat.format(SOCKET_FORMAT, + _session.getSessionID(), + _session.getRemoteAddress()) + + "] "; + } + } + } + + @Override + public String toString() + { + updateLogString(); + return super.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java index c842da4db0..2dde1b6b41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.subscription.Subscription; +import java.text.MessageFormat; + public class SubscriptionLogSubject extends AbstractLogSubject { @@ -31,9 +33,8 @@ public class SubscriptionLogSubject extends AbstractLogSubject * these indicies: * * 0 - Subscription ID - * 1 - queue name */ - public static String SUBSCRIPTION_FORMAT = "sub:{0}(vh(/{1})/qu({2}))"; + public static String SUBSCRIPTION_FORMAT = "sub:{0}"; /** * Create an QueueLogSubject that Logs in the following format. @@ -42,8 +43,20 @@ public class SubscriptionLogSubject extends AbstractLogSubject */ public SubscriptionLogSubject(Subscription subscription) { - setLogStringWithFormat(SUBSCRIPTION_FORMAT, subscription.getSubscriptionID(), - subscription.getQueue().getVirtualHost().getName(), - subscription.getQueue().getName()); + // Delegate the formating of the Queue to the QueueLogSubject. So final + // log string format is: + // [ sub:(vh()/qu()) ] + + String queueString = new QueueLogSubject(subscription.getQueue()).toString(); + + _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT, + subscription.getSubscriptionID()) + + "(" + // queueString is [vh(/{0})/qu({1}) ] so need to trim + // ^ ^^ + + queueString.substring(1,queueString.length() - 3) + + ")" + + "] "; + } } -- cgit v1.2.1 From fd98b6a4804e09faf94fa9c64368b281f86df51a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Dec 2009 10:53:16 +0000 Subject: QPID-1992 : Fix compilation error missed during merge. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@887154 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/logging/subjects/ChannelLogSubject.java | 2 +- .../apache/qpid/server/logging/subjects/ConnectionLogSubject.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index 62cff049d0..dc6e79a214 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -59,7 +59,7 @@ public class ChannelLogSubject extends AbstractLogSubject */ setLogStringWithFormat(CHANNEL_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName(), channel.getChannelId()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index 77576eddfb..f3df87c432 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -82,7 +82,7 @@ public class ConnectionLogSubject extends AbstractLogSubject { if (!_upToDate) { - if (_session.getAuthorizedID() != null) + if (_session.getPrincipal() != null) { if (_session.getVirtualHost() != null) { @@ -101,7 +101,7 @@ public class ConnectionLogSubject extends AbstractLogSubject */ _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, _session.getSessionID(), - _session.getAuthorizedID().getName(), + _session.getPrincipal().getName(), _session.getRemoteAddress(), _session.getVirtualHost().getName()) + "] "; @@ -112,7 +112,7 @@ public class ConnectionLogSubject extends AbstractLogSubject { _logString = "[" + MessageFormat.format(USER_FORMAT, _session.getSessionID(), - _session.getAuthorizedID().getName(), + _session.getPrincipal().getName(), _session.getRemoteAddress()) + "] "; -- cgit v1.2.1 From 71d12ff35b88465850dd06f2114ca18fcc510a42 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 7 Dec 2009 15:14:07 +0000 Subject: QPID-1992 : Update ProtocolEngine to create LogSubject in constructor as it now correctly formats based on the current sate of the Engine. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@887945 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 0a1fdb686f..ea8fbbd68f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -178,6 +178,9 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false); _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger()); + + _logSubject = new ConnectionLogSubject(this); + _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false)); } @@ -898,8 +901,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _virtualHost = virtualHost; - _logSubject = new ConnectionLogSubject(this); - _virtualHost.getConnectionRegistry().registerConnection(this); try -- cgit v1.2.1 From b283d75d642581115f1df5dc2674ef26fe3de221 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 7 Dec 2009 15:14:52 +0000 Subject: QPID-2244 : Added initial support of 0-10 Messages via JMX viewMessages. There are a still a few headers that need to be investigated and displayed. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@887946 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/messages/LogMessages_de_DE.properties | 81 ++++++++++++++++++++++ .../qpid/server/message/MessageTransferHeader.java | 18 ++++- .../apache/qpid/server/queue/AMQQueueMBean.java | 48 ++++++++++++- 3 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties new file mode 100644 index 0000000000..c50b1cca41 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties @@ -0,0 +1,81 @@ +#Broker +# 0 - Version +# 1 = Build +BRK-1001 = Anfang : Version: {0} Bau: {1} +# 0 - Transport +# 1 - Port +BRK-1002 = Starting : Listening on {0} port {1,number,#} +# 0 - Transport +# 1 - Port +BRK-1003 = Shuting down : {0} port {1,number,#} +BRK-1004 = Ready +BRK-1005 = Stopped +# 0 - path +BRK-1006 = Using configuration : {0} +# 0 - path +BRK-1007 = Using logging configuration : {0} + +#ManagementConsole +MNG-1001 = Startup +# 0 - Service +# 1 - Port +MNG-1002 = Starting : {0} : Listening on port {1,number,#} +# 0 - Service +# 1 - Port +MNG-1003 = Shuting down : {0} : port {1,number,#} +MNG-1004 = Ready +MNG-1005 = Stopped +# 0 - Path +MNG-1006 = Using SSL Keystore : {0} + +#VirtualHost +# 0 - name +VHT-1001 = Created : {0} +VHT-1002 = Schliessen + +#MessageStore +# 0 - name +MST-1001 = Created : {0} +# 0 - path +MST-1002 = Store location : {0} +MST-1003 = Schliessen +# 0 - queue name +MST-1004 = Recovery Anfang[ : {0}] +# 0 - count +# 1 - queue count +MST-1005 = Recovered {0,number} messages for queue {1} +# 0 - queue name +MST-1006 = Recovery Complete[ : {0}] + +#Connection +# 0 - Client id +# 1 - Protocol Version +CON-1001 = Oeffen : Client ID {0}[ : Protocol Version : {1}] +CON-1002 = Schliessen + +#Channel +# 0 - count +CHN-1001 = Create : Prefetch {0, number} +# 0 - flow +CHN-1002 = Flow {0} +CHN-1003 = Schliessen + +#Queue +# 0 - owner +# 1 - priority +QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +QUE-1002 = Deleted + +#Exchange +# 0 - type +# 1 - name +EXH-1001 = Create :[ Durable] Type: {0} Name: {1} +EXH-1002 = Deleted + +#Binding +BND-1001 = Create[ : Arguments : {0}] +BND-1002 = Deleted + +#Subscription +SUB-1001 = Create[ : Durable][ : Arguments : {0}] +SUB-1002 = Schliessen diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index 1a75d7ca65..7fac7ab164 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -44,7 +44,14 @@ class MessageTransferHeader implements AMQMessageHeader public String getCorrelationId() { - return _messageProps == null ? null : new String(_messageProps.getCorrelationId()); + if (_messageProps != null && _messageProps.getCorrelationId() != null) + { + return new String(_messageProps.getCorrelationId()); + } + else + { + return null; + } } public long getExpiration() @@ -88,7 +95,14 @@ class MessageTransferHeader implements AMQMessageHeader public String getReplyTo() { - return _messageProps == null ? null : _messageProps.getReplyTo().toString(); + if (_messageProps != null && _messageProps.getReplyTo() != null) + { + return _messageProps.getReplyTo().toString(); + } + else + { + return null; + } } public Object getHeader(String name) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 8e5310bc16..78c956ef19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -33,6 +33,7 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.LocalTransaction; @@ -403,13 +404,25 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; + Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); _messageList.put(messageData); + } else { - // TODO 0-10 Message + // We have a 0-10 message + if (serverMsg instanceof MessageTransferMessage) + { + MessageTransferMessage msg = (MessageTransferMessage) serverMsg; + + AMQMessageHeader header = msg.getMessageHeader(); + // Create header attributes list + String[] headerAttributes = getAMQMessageHeaderProperties(header); + Object[] itemValues = {msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); + _messageList.put(messageData); + } } } } @@ -453,6 +466,37 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return list.toArray(new String[list.size()]); } + private String[] getAMQMessageHeaderProperties(AMQMessageHeader header) + { + List list = new ArrayList(); + + list.add("reply-to = " + header.getReplyTo()); + //TODO - Complete header property extraction +// list.add("propertyFlags = " + header.getgetPropertyFlags()); +// list.add("ApplicationID = " + header.getAppIdAsString()); +// list.add("ClusterID = " + header.getClusterIdAsString()); +// list.add("UserId = " + header.getUserIdAsString()); + list.add("JMSMessageID = " + header.getMessageId()); + list.add("JMSCorrelationID = " + header.getCorrelationId()); + +// int delMode = header.getDeliveryMode(); +// list.add("JMSDeliveryMode = " + +// ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); + + list.add("JMSPriority = " + header.getPriority()); + list.add("JMSType = " + header.getType()); + + long longDate = header.getExpiration(); + String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSExpiration = " + strDate); + + longDate = header.getTimestamp(); + strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; + list.add("JMSTimestamp = " + strDate); + + return list.toArray(new String[list.size()]); + } + /** * @see ManagedQueue#moveMessages * @param fromMessageId -- cgit v1.2.1 From ee310803413b09793e1eb78755b25c13b2d24ed9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 7 Dec 2009 15:21:50 +0000 Subject: QPID-2244 : Remove LogMessages_de_DE.properties that was erroneously added in commit r887946 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@887953 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/messages/LogMessages_de_DE.properties | 81 ---------------------- 1 file changed, 81 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties deleted file mode 100644 index c50b1cca41..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_de_DE.properties +++ /dev/null @@ -1,81 +0,0 @@ -#Broker -# 0 - Version -# 1 = Build -BRK-1001 = Anfang : Version: {0} Bau: {1} -# 0 - Transport -# 1 - Port -BRK-1002 = Starting : Listening on {0} port {1,number,#} -# 0 - Transport -# 1 - Port -BRK-1003 = Shuting down : {0} port {1,number,#} -BRK-1004 = Ready -BRK-1005 = Stopped -# 0 - path -BRK-1006 = Using configuration : {0} -# 0 - path -BRK-1007 = Using logging configuration : {0} - -#ManagementConsole -MNG-1001 = Startup -# 0 - Service -# 1 - Port -MNG-1002 = Starting : {0} : Listening on port {1,number,#} -# 0 - Service -# 1 - Port -MNG-1003 = Shuting down : {0} : port {1,number,#} -MNG-1004 = Ready -MNG-1005 = Stopped -# 0 - Path -MNG-1006 = Using SSL Keystore : {0} - -#VirtualHost -# 0 - name -VHT-1001 = Created : {0} -VHT-1002 = Schliessen - -#MessageStore -# 0 - name -MST-1001 = Created : {0} -# 0 - path -MST-1002 = Store location : {0} -MST-1003 = Schliessen -# 0 - queue name -MST-1004 = Recovery Anfang[ : {0}] -# 0 - count -# 1 - queue count -MST-1005 = Recovered {0,number} messages for queue {1} -# 0 - queue name -MST-1006 = Recovery Complete[ : {0}] - -#Connection -# 0 - Client id -# 1 - Protocol Version -CON-1001 = Oeffen : Client ID {0}[ : Protocol Version : {1}] -CON-1002 = Schliessen - -#Channel -# 0 - count -CHN-1001 = Create : Prefetch {0, number} -# 0 - flow -CHN-1002 = Flow {0} -CHN-1003 = Schliessen - -#Queue -# 0 - owner -# 1 - priority -QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -QUE-1002 = Deleted - -#Exchange -# 0 - type -# 1 - name -EXH-1001 = Create :[ Durable] Type: {0} Name: {1} -EXH-1002 = Deleted - -#Binding -BND-1001 = Create[ : Arguments : {0}] -BND-1002 = Deleted - -#Subscription -SUB-1001 = Create[ : Durable][ : Arguments : {0}] -SUB-1002 = Schliessen -- cgit v1.2.1 From f9edf5fc5a33865ae70ddc783aac46acb359d425 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 8 Dec 2009 04:01:54 +0000 Subject: QPID-2244: output additional MessageTransferMessage header properties, add fallback support to ensure display of other types of message git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@888244 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/AMQQueueMBean.java | 58 +++++++++++++--------- 1 file changed, 35 insertions(+), 23 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 78c956ef19..eafc73dc97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -36,6 +36,7 @@ import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.transport.MessageProperties; import javax.management.JMException; import javax.management.MBeanNotificationInfo; @@ -409,20 +410,24 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _messageList.put(messageData); } - else + else if(serverMsg instanceof MessageTransferMessage) { // We have a 0-10 message - if (serverMsg instanceof MessageTransferMessage) - { - MessageTransferMessage msg = (MessageTransferMessage) serverMsg; - - AMQMessageHeader header = msg.getMessageHeader(); - // Create header attributes list - String[] headerAttributes = getAMQMessageHeaderProperties(header); - Object[] itemValues = {msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); - } + MessageTransferMessage msg = (MessageTransferMessage) serverMsg; + + // Create header attributes list + String[] headerAttributes = getMessageTransferMessageHeaderProps(msg); + Object[] itemValues = {msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); + _messageList.put(messageData); + } + else + { + //unknown message + String[] headerAttributes = new String[]{"N/A"}; + Object[] itemValues = { serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); + _messageList.put(messageData); } } } @@ -466,23 +471,30 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return list.toArray(new String[list.size()]); } - private String[] getAMQMessageHeaderProperties(AMQMessageHeader header) + private String[] getMessageTransferMessageHeaderProps(MessageTransferMessage msg) { List list = new ArrayList(); + + AMQMessageHeader header = msg.getMessageHeader(); + MessageProperties msgProps = msg.getHeader().get(MessageProperties.class); + + String appID = null; + String userID = null; + + if(msgProps != null) + { + appID = msgProps.getAppId() == null ? "null" : new String(msgProps.getAppId()); + userID = msgProps.getUserId() == null ? "null" : new String(msgProps.getUserId()); + } list.add("reply-to = " + header.getReplyTo()); - //TODO - Complete header property extraction -// list.add("propertyFlags = " + header.getgetPropertyFlags()); -// list.add("ApplicationID = " + header.getAppIdAsString()); -// list.add("ClusterID = " + header.getClusterIdAsString()); -// list.add("UserId = " + header.getUserIdAsString()); + list.add("propertyFlags = "); //TODO + list.add("ApplicationID = " + appID); + list.add("ClusterID = "); //TODO + list.add("UserId = " + userID); list.add("JMSMessageID = " + header.getMessageId()); list.add("JMSCorrelationID = " + header.getCorrelationId()); - -// int delMode = header.getDeliveryMode(); -// list.add("JMSDeliveryMode = " + -// ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); - + list.add("JMSDeliveryMode = " + (msg.isPersistent() ? "Persistent" : "Non_Persistent")); list.add("JMSPriority = " + header.getPriority()); list.add("JMSType = " + header.getType()); -- cgit v1.2.1 From 329094fe3cee90244ccd42c064161ec322aba756 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 8 Dec 2009 04:03:50 +0000 Subject: QPID-2177: expose Capacity, FlowResumeCapacity, and FlowOverfull as attributes of the Queue MBeans git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@888248 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 2 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 35 ++++++++++++++++++++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 6 ++++ 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index c9d20c53e4..a459c64946 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -186,7 +186,7 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer void setFlowResumeCapacity(long flowResumeCapacity); - + boolean isOverfull(); void deleteMessageFromTop(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index eafc73dc97..021128d2fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -241,6 +241,41 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _queue.getQueueDepth(); } + public Long getCapacity() + { + return _queue.getCapacity(); + } + + public void setCapacity(Long capacity) throws IllegalArgumentException + { + if( _queue.getFlowResumeCapacity() > capacity ) + { + throw new IllegalArgumentException("Capacity must not be less than FlowResumeCapacity"); + } + + _queue.setCapacity(capacity); + } + + public Long getFlowResumeCapacity() + { + return _queue.getFlowResumeCapacity(); + } + + public void setFlowResumeCapacity(Long flowResumeCapacity) throws IllegalArgumentException + { + if( _queue.getCapacity() < flowResumeCapacity ) + { + throw new IllegalArgumentException("FlowResumeCapacity must not exceed Capacity"); + } + + _queue.setFlowResumeCapacity(flowResumeCapacity); + } + + public boolean isFlowOverfull() + { + return _queue.isOverfull(); + } + /** * Checks if there is any notification to be send to the listeners */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d7d0414936..b4cebda09a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1799,8 +1799,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setFlowResumeCapacity(long flowResumeCapacity) { _flowResumeCapacity = flowResumeCapacity; + + checkCapacity(); } + public boolean isOverfull() + { + return _overfull.get(); + } public Set getNotificationChecks() { -- cgit v1.2.1 From 57d9d61d5fe2cff10b130a03ed08b802b80d43ab Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 8 Dec 2009 04:06:59 +0000 Subject: QPID-2250: Remove requirement for message persistence and queue durability from the copy process git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@888251 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 34 ++++++++++------------ 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b4cebda09a..6915850376 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1037,30 +1037,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { final ServerMessage message = entry.getMessage(); - if (message.isPersistent() && toQueue.isDurable()) + txn.enqueue(toQueue, message, new ServerTransaction.Action() { - - txn.enqueue(toQueue, message, new ServerTransaction.Action() + public void postCommit() + { + try { - public void postCommit() - { - try - { - toQueue.enqueue(message); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - } + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } - public void onRollback() - { + public void onRollback() + { - } - }); + } + }); - } } } -- cgit v1.2.1 From db6241e3cfb4ef420025ba5c8b8ddae888c7171c Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Wed, 9 Dec 2009 23:58:25 +0000 Subject: QPID-2258 : AMQP0-9-1 Compliance fixes git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@889022 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/exchange/DirectExchange.java | 2 +- .../server/handler/BasicConsumeMethodHandler.java | 5 ++ .../qpid/server/handler/BasicGetMethodHandler.java | 10 +++ .../qpid/server/handler/ExchangeDeleteHandler.java | 5 ++ .../qpid/server/handler/QueueBindHandler.java | 5 ++ .../qpid/server/handler/QueueDeclareHandler.java | 74 ++++++++++++++++------ .../qpid/server/handler/QueueDeleteHandler.java | 6 +- .../qpid/server/handler/QueuePurgeHandler.java | 5 ++ .../org/apache/qpid/server/queue/AMQQueue.java | 3 + .../apache/qpid/server/queue/SimpleAMQQueue.java | 16 ++++- .../qpid/server/subscription/Subscription.java | 2 + .../qpid/server/subscription/SubscriptionImpl.java | 5 ++ .../server/subscription/Subscription_0_10.java | 5 ++ .../server/transport/ServerSessionDelegate.java | 5 ++ 14 files changed, 124 insertions(+), 24 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 4788f96d6c..3c3902c545 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -212,7 +212,7 @@ public class DirectExchange extends AbstractExchange final String routingKey = payload.getRoutingKey(); - final ArrayList queues = (routingKey == null) ? null : _index.get(routingKey); + final ArrayList queues = (routingKey == null) ? _index.get("") : _index.get(routingKey); if (_logger.isDebugEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 859a3477e6..0343457a73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -102,6 +102,11 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); } + else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + } if (!exch.isBound(routingKey, body.getArguments(), queue)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 4f69afe755..bb57fdbc36 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -114,25 +114,37 @@ public class QueueDeclareHandler implements StateAwareMethodListener, ExchangeReferrer, TransactionLogResource { + boolean getDeleteOnNoConsumers(); + + void setDeleteOnNoConsumers(boolean b); public interface Context diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 6915850376..3d5d99f0b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -150,6 +150,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private boolean _nolocal; private final AtomicBoolean _overfull = new AtomicBoolean(false); + private boolean _deleteOnNoConsumers; protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) { @@ -374,7 +375,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throw new ExistingExclusiveSubscription(); } - if (exclusive) + if (exclusive && !subscription.isTransient()) { if (getConsumerCount() != 0) { @@ -431,7 +432,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // auto-delete queues must be deleted if there are no remaining subscribers - if (_autoDelete && getConsumerCount() == 0 && !isExclusive()) + if (_autoDelete && getDeleteOnNoConsumers() && !subscription.isTransient() && getConsumerCount() == 0 ) { if (_logger.isInfoEnabled()) { @@ -448,6 +449,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public boolean getDeleteOnNoConsumers() + { + return _deleteOnNoConsumers; + } + + public void setDeleteOnNoConsumers(boolean b) + { + _deleteOnNoConsumers = b; + } + + // ------ Enqueue / Dequeue public QueueEntry enqueue(ServerMessage message) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 4db9c305b2..9e9d2da579 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -31,6 +31,8 @@ public interface Subscription { LogActor getLogActor(); + boolean isTransient(); + public static enum State { ACTIVE, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 5302a3c5d4..684d3c2e74 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -667,6 +667,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return !isBrowser(); } + public boolean isTransient() + { + return false; + } + public void set(String key, Object value) { _properties.put(key, value); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index fb0a5cf2c7..5b3668ab64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -649,6 +649,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr return _logActor; } + public boolean isTransient() + { + return false; + } + ServerSession getSession() { return _session; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index df2754c16b..36ed8e24ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -823,6 +823,11 @@ public class ServerSessionDelegate extends SessionDelegate queue.setPrincipalHolder((ServerSession)session); queue.setExclusiveOwner(session); } + else if(method.getAutoDelete()) + { + queue.setDeleteOnNoConsumers(true); + } + final String alternateExchangeName = method.getAlternateExchange(); if(alternateExchangeName != null && alternateExchangeName.length() != 0) { -- cgit v1.2.1 From e8e44b32794658553c2f08786cf80f634edba3f9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 11 Dec 2009 15:03:29 +0000 Subject: QPID-2263 : Stop Exceptions killing the HouseKeeping thread. Also prevented Deleted Messages from being processed by the notification checks. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@889645 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 27 ++++++++++++++++------ .../qpid/server/virtualhost/VirtualHostImpl.java | 5 ++-- 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 3d5d99f0b0..825aa9795e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1689,15 +1689,28 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.expired() && node.acquire()) + // Only process nodes that are not currently deleted + if (!node.isDeleted()) { - dequeueEntry(node); - } - else - { - if(_managedObject!=null) + // If the node has exired then aquire it + if (node.expired() && node.acquire()) + { + // Then dequeue it. + dequeueEntry(node); + } + else { - _managedObject.checkForNotification(node.getMessage()); + if (_managedObject != null) + { + // There is a chance that the node could be deleted by + // the time the check actually occurs. So verify we + // can actually get the message to perform the check. + ServerMessage msg = node.getMessage(); + if (msg != null) + { + _managedObject.checkForNotification(msg); + } + } } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 6826dcf324..78deeeb164 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -268,10 +268,11 @@ public class VirtualHostImpl implements Accessable, VirtualHost { q.checkMessageStatus(); } - catch (AMQException e) + catch (Exception e) { _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); - throw new RuntimeException(e); + //Don't throw exceptions as this will stop the + // house keeping task from running. } } } -- cgit v1.2.1 From 2f4f05218183bbe4db291724d0fedd94f5afc09c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Dec 2009 17:14:30 +0000 Subject: QPID-2274 : Addressed initial issues with Async compressing deleting log files git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@891322 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/log4j/QpidCompositeRollingAppender.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 7e0c4defe1..ea0fab17bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -749,16 +749,17 @@ public class QpidCompositeRollingAppender extends FileAppender } File file = new File(from); - if (compress) + if (!file.getPath().equals(target.getPath())) { - compress(file, target); + file.renameTo(target); } - else + + // Compress file after it has been moved out the way... this is safe + // as it will gain a .gz ending and we can then safely delete this file + // as it will not be the statically named value. + if (compress) { - if (!file.getPath().equals(target.getPath())) - { - file.renameTo(target); - } + compress(to); } LogLog.debug(from + " -> " + to); -- cgit v1.2.1 From f034a9a0449e4fdf68d5cc6f591c114216a0449e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Dec 2009 17:16:10 +0000 Subject: QPID-2275: Update so that CountDirection +ve,-ve work correctly in conjunction with exiting log files and MaxSizeRollBackups Adding .n to the end of the name and calculating the .n value based on existing log files. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@891324 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 217 ++++++++++++++++----- 1 file changed, 163 insertions(+), 54 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index ea0fab17bd..5aae336918 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -157,6 +157,7 @@ public class QpidCompositeRollingAppender extends FileAppender protected String backupFilesToPath = null; private final ConcurrentLinkedQueue _compress = new ConcurrentLinkedQueue(); private AtomicBoolean _compressing = new AtomicBoolean(false); + private static final String COMPRESS_EXTENSION = ".gz"; /** The default constructor does nothing. */ public QpidCompositeRollingAppender() @@ -689,16 +690,8 @@ public class QpidCompositeRollingAppender extends FileAppender // close current file, and rename it to datedFilename this.closeFile(); - // we may have to roll over a large number of backups here - String from, to; - for (int i = 1; i <= curSizeRollBackups; i++) - { - from = fileName + '.' + i; - to = scheduledFilename + '.' + i; - rollFile(from, to, false); - } - rollFile(fileName, scheduledFilename, compress); + rollFile(); } else { @@ -742,11 +735,6 @@ public class QpidCompositeRollingAppender extends FileAppender } File target = new File(to); - if (target.exists()) - { - LogLog.debug("deleting existing target file: " + target); - target.delete(); - } File file = new File(from); if (!file.getPath().equals(target.getPath())) @@ -838,69 +826,190 @@ public class QpidCompositeRollingAppender extends FileAppender // If maxBackups <= 0, then there is no file renaming to be done. if (maxSizeRollBackups != 0) { + rollFile(); + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(baseFileName, false); + } + catch (IOException e) + { + LogLog.error("setFile(" + fileName + ", false) call failed.", e); + } + } - if (countDirection < 0) + /** + * Perform file Rollover ensuring the countDirection is applied along with + * the other options + */ + private void rollFile() + { + if (countDirection < 0) + { + + // If we haven't rolled yet then validate we have the right value + // for curSizeRollBackups + if (curSizeRollBackups == 0) { - // Delete the oldest file, to keep Windows happy. - if (curSizeRollBackups == maxSizeRollBackups) + //Validate curSizeRollBackups + curSizeRollBackups = countFileIndex(fileName); + // decrement to offset the later increment + curSizeRollBackups--; + } + + + // If we are not keeping an infinite set of backups the delete oldest + if (maxSizeRollBackups > 0) + { + // Delete the oldest file. + // curSizeRollBackups is never -1 so infinite backups are ok here + if ((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups) { - deleteFile(fileName + '.' + maxSizeRollBackups); + //The oldest file is the one with the largest number + // as the 0 is always fileName + // which moves to fileName.1 etc. + deleteFile(fileName + '.' + curSizeRollBackups); + // decrement to offset the later increment curSizeRollBackups--; } + } + // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} + for (int i = curSizeRollBackups; i >= 1; i--) + { + rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); + } - // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} - for (int i = curSizeRollBackups; i >= 1; i--) - { - rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); - } + curSizeRollBackups++; + // Rename fileName to fileName.1 + rollFile(fileName, fileName + ".1", compress); - curSizeRollBackups++; - // Rename fileName to fileName.1 - rollFile(fileName, fileName + ".1", compress); + } // REMOVE This code branching for Alexander Cerna's request + else if (countDirection == 0) + { + // rollFile based on date pattern + curSizeRollBackups++; + now.setTime(System.currentTimeMillis()); + scheduledFilename = fileName + sdf.format(now); + rollFile(fileName, scheduledFilename, compress); + } + else + { // countDirection > 0 - } // REMOVE This code branching for Alexander Cerna's request - else if (countDirection == 0) + // If we haven't rolled yet then validate we have the right value + // for curSizeRollBackups + if (curSizeRollBackups == 0) { - // rollFile based on date pattern - curSizeRollBackups++; - now.setTime(System.currentTimeMillis()); - scheduledFilename = fileName + sdf.format(now); - rollFile(fileName, scheduledFilename, compress); + //Validate curSizeRollBackups + curSizeRollBackups = countFileIndex(fileName); + // to balance the increment just coming up. as the count returns + // the next free number not the last used. + curSizeRollBackups--; } - else - { // countDirection > 0 - if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0)) + + // If we are not keeping an infinite set of backups the delete oldest + if (maxSizeRollBackups > 0) + { + // Don't prune older files if they exist just go for the last + // one based on our maxSizeRollBackups. This means we may have + // more files left on disk that maxSizeRollBackups if this value + // is adjusted between runs but that is an acceptable state. + // Otherwise we would have to check on startup that we didn't + // have more than maxSizeRollBackups and prune then. + + if (((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups)) { // delete the first and keep counting up. int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; deleteFile(fileName + '.' + oldestFileIndex); } + } - if (staticLogFileName) - { - curSizeRollBackups++; - rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); - } - else + + curSizeRollBackups++; + + rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); + } + } + + /** + * Use filename as a base name and find what count number we are up to by + * looking at the files in this format: + * + * .[COMPRESS_EXTENSION] + * + * If a count value of 1 cannot be found then a directory listing is + * performed to try and identify if there is a valid value for . + * + * + * @param fileName the basefilename to use + * @return int the next free index + */ + private int countFileIndex(String fileName) + { + String testFileName; + + // It is possible for index 1..n to be missing leaving n+1..n+1+m logs + // in this scenario we should still return n+1+m+1 + int index=1; + + testFileName = fileName + "." + index; + + // Check that we do not have the 1..n missing scenario + if (!(new File(testFileName).exists() + || new File(testFileName + COMPRESS_EXTENSION).exists())) + + { + int max=0; + String prunedFileName = new File(fileName).getName(); + + // Look through all files to find next index + for (File file : new File(fileName).getParentFile().listFiles()) + { + String name = file.getName(); + + if (name.startsWith(prunedFileName) && !name.equals(prunedFileName)) { - if (compress) + String parsedCount = name.substring(prunedFileName.length() + 1 ); + + if (parsedCount.endsWith(COMPRESS_EXTENSION)) + { + parsedCount = parsedCount.substring(0, parsedCount.indexOf(COMPRESS_EXTENSION)); + } + + try + { + max = Integer.parseInt(parsedCount); + + // if we got a good value then update our index value. + if (max > index) + { + // +1 as we want to return the next free value. + index = max + 1; + } + } + catch (NumberFormatException nfe) { - compress(fileName); + //ignore it assume file doesn't exist. } } } - } - try - { - // This will also close the file. This is OK since multiple - // close operations are safe. - this.setFile(baseFileName, false); + // Update testFileName + testFileName = fileName + "." + index; } - catch (IOException e) + + + while (new File(testFileName).exists() + || new File(testFileName + COMPRESS_EXTENSION).exists()) { - LogLog.error("setFile(" + fileName + ", false) call failed.", e); + index++; + testFileName = fileName + "." + index; } + + return index; } protected synchronized void doCompress(File from, File to) @@ -908,11 +1017,11 @@ public class QpidCompositeRollingAppender extends FileAppender String toFile; if (backupFilesToPath == null) { - toFile = to.getPath() + ".gz"; + toFile = to.getPath() + COMPRESS_EXTENSION; } else { - toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz"; + toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + COMPRESS_EXTENSION; } File target = new File(toFile); -- cgit v1.2.1 From 54e144a946893b420b25ba4d16921c6241a60d0a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Dec 2009 17:18:49 +0000 Subject: QPID-2275 : Update to address CountDirection 0 increments when MaxFileSize kicks in before DatePattern. Now it is possible to specify a DatePattern with small units (seconds/minutes) and not lose log file date when the MaxFileSize causes the file to roll over git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@891329 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 51 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 5aae336918..634fffdbc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -890,10 +890,51 @@ public class QpidCompositeRollingAppender extends FileAppender else if (countDirection == 0) { // rollFile based on date pattern - curSizeRollBackups++; now.setTime(System.currentTimeMillis()); - scheduledFilename = fileName + sdf.format(now); - rollFile(fileName, scheduledFilename, compress); + String newFile = fileName + sdf.format(now); + + // If we haven't rolled yet then validate we have the right value + // for curSizeRollBackups + if (curSizeRollBackups == 0) + { + //Validate curSizeRollBackups + curSizeRollBackups = countFileIndex(newFile); + // to balance the increment just coming up. as the count returns + // the next free number not the last used. + curSizeRollBackups--; + } + + // If we are not keeping an infinite set of backups the delete oldest + if (maxSizeRollBackups > 0) + { + // Don't prune older files if they exist just go for the last + // one based on our maxSizeRollBackups. This means we may have + // more files left on disk that maxSizeRollBackups if this value + // is adjusted between runs but that is an acceptable state. + // Otherwise we would have to check on startup that we didn't + // have more than maxSizeRollBackups and prune then. + + if (((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups)) + { + // delete the first and keep counting up. + int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + deleteFile(newFile + '.' + oldestFileIndex); + } + } + + + String finalName = newFile; + + curSizeRollBackups++; + + // Add rollSize if it is > 0 + if (curSizeRollBackups > 0 ) + { + finalName = newFile + '.' + curSizeRollBackups; + + } + + rollFile(fileName, finalName, compress); } else { // countDirection > 0 @@ -954,7 +995,7 @@ public class QpidCompositeRollingAppender extends FileAppender // It is possible for index 1..n to be missing leaving n+1..n+1+m logs // in this scenario we should still return n+1+m+1 int index=1; - + testFileName = fileName + "." + index; // Check that we do not have the 1..n missing scenario @@ -1008,7 +1049,7 @@ public class QpidCompositeRollingAppender extends FileAppender index++; testFileName = fileName + "." + index; } - + return index; } -- cgit v1.2.1 From 0506cf3f1b4ad10c7a8fe163662c2a8176a6d552 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Dec 2009 17:20:07 +0000 Subject: QPID-2155 : Update addressing issues with compression and maintaining backup counts. Because a compressed file is renamed the .n value is not recognised so this update makes it check for the COMPRESSION_EXTENSION (.gz) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@891330 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 169 +++++---------------- 1 file changed, 41 insertions(+), 128 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 634fffdbc3..853247be58 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -371,10 +371,6 @@ public class QpidCompositeRollingAppender extends FileAppender if (!staticLogFileName) { scheduledFilename = fileName = fileName.trim() + sdf.format(now); - if (countDirection > 0) - { - scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups); - } } super.setFile(fileName, append, bufferedIO, bufferSize); @@ -514,75 +510,10 @@ public class QpidCompositeRollingAppender extends FileAppender */ protected void existingInit() { - - if (zeroBased) - { - curSizeRollBackups = -1; - } - curTimeRollBackups = 0; // part A starts here - String filter; - if (staticLogFileName || !rollDate) - { - filter = baseFileName + ".*"; - } - else - { - filter = scheduledFilename + ".*"; - } - - File f = new File(baseFileName); - f = f.getParentFile(); - if (f == null) - { - f = new File("."); - } - - LogLog.debug("Searching for existing files in: " + f); - String[] files = f.list(); - - if (files != null) - { - for (int i = 0; i < files.length; i++) - { - if (!files[i].startsWith(baseFileName)) - { - continue; - } - - int index = files[i].lastIndexOf("."); - - if (staticLogFileName) - { - int endLength = files[i].length() - index; - if ((baseFileName.length() + endLength) != files[i].length()) - { - // file is probably scheduledFilename + .x so I don't care - continue; - } - } - - try - { - int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length())); - LogLog.debug("From file: " + files[i] + " -> " + backup); - if (backup > curSizeRollBackups) - { - curSizeRollBackups = backup; - } - } - catch (Exception e) - { - // this happens when file.log -> file.log.yyyy-mm-dd which is normal - // when staticLogFileName == false - LogLog.debug("Encountered a backup file not ending in .x " + files[i]); - } - } - } - - LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups); + // This is now down at first log when curSizeRollBackup==0 see rollFile // part A ends here // part B not yet implemented @@ -664,47 +595,11 @@ public class QpidCompositeRollingAppender extends FileAppender this.closeFile(); // keep windows happy. - // delete the old stuff here - if (staticLogFileName) - { - /* Compute filename, but only if datePattern is specified */ - if (datePattern == null) - { - errorHandler.error("Missing DatePattern option in rollOver()."); - - return; - } - - // is the new file name equivalent to the 'current' one - // something has gone wrong if we hit this -- we should only - // roll over if the new file will be different from the old - String dateFormat = sdf.format(now); - if (scheduledFilename.equals(fileName + dateFormat)) - { - errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat); - - return; - } - - // close current file, and rename it to datedFilename - this.closeFile(); - - - rollFile(); - } - else - { - if (compress) - { - compress(fileName); - } - } + rollFile(); try { - // This will also close the file. This is OK since multiple - // close operations are safe. curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new // new scheduled name @@ -728,7 +623,7 @@ public class QpidCompositeRollingAppender extends FileAppender { if (compress) { - LogLog.debug("Attempting to compress file with same output name."); + LogLog.error("Attempting to compress file with same output name."); } return; @@ -737,6 +632,7 @@ public class QpidCompositeRollingAppender extends FileAppender File target = new File(to); File file = new File(from); + // Perform Roll by renaming if (!file.getPath().equals(target.getPath())) { file.renameTo(target); @@ -747,32 +643,26 @@ public class QpidCompositeRollingAppender extends FileAppender // as it will not be the statically named value. if (compress) { - compress(to); + compress(target); } LogLog.debug(from + " -> " + to); } - protected void compress(String file) - { - File f = new File(file); - compress(f, f); - } - - private void compress(File from, File target) + private void compress(File target) { if (compressAsync) { synchronized (_compress) { - _compress.offer(new CompressJob(from, target)); + _compress.offer(new CompressJob(target, target)); } startCompression(); } else { - doCompress(from, target); + doCompress(target, target); } } @@ -785,9 +675,9 @@ public class QpidCompositeRollingAppender extends FileAppender } /** Delete's the specified file if it exists */ - protected static void deleteFile(String fileName) + protected void deleteFile(String fileName) { - File file = new File(fileName); + File file = compress ? new File(fileName + COMPRESS_EXTENSION) : new File(fileName); if (file.exists()) { file.delete(); @@ -847,11 +737,11 @@ public class QpidCompositeRollingAppender extends FileAppender */ private void rollFile() { + LogLog.debug("CD="+countDirection+",start"); if (countDirection < 0) { - // If we haven't rolled yet then validate we have the right value - // for curSizeRollBackups + // for curSizeRollBackups if (curSizeRollBackups == 0) { //Validate curSizeRollBackups @@ -860,17 +750,20 @@ public class QpidCompositeRollingAppender extends FileAppender curSizeRollBackups--; } - // If we are not keeping an infinite set of backups the delete oldest if (maxSizeRollBackups > 0) { + LogLog.debug("CD=-1,curSizeRollBackups:"+curSizeRollBackups); + LogLog.debug("CD=-1,maxSizeRollBackups:"+maxSizeRollBackups); + // Delete the oldest file. // curSizeRollBackups is never -1 so infinite backups are ok here - if ((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups) + if ((curSizeRollBackups - maxSizeRollBackups) >= 0) { //The oldest file is the one with the largest number // as the 0 is always fileName // which moves to fileName.1 etc. + LogLog.debug("CD=-1,deleteFile:"+curSizeRollBackups); deleteFile(fileName + '.' + curSizeRollBackups); // decrement to offset the later increment curSizeRollBackups--; @@ -879,7 +772,18 @@ public class QpidCompositeRollingAppender extends FileAppender // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} for (int i = curSizeRollBackups; i >= 1; i--) { - rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false); + String oldName = (fileName + "." + i); + String newName = (fileName + '.' + (i + 1)); + + // Ensure that when compressing we rename the compressed archives + if (compress) + { + rollFile(oldName + COMPRESS_EXTENSION, newName + COMPRESS_EXTENSION, false); + } + else + { + rollFile(oldName, newName, false); + } } curSizeRollBackups++; @@ -914,10 +818,14 @@ public class QpidCompositeRollingAppender extends FileAppender // Otherwise we would have to check on startup that we didn't // have more than maxSizeRollBackups and prune then. - if (((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups)) + if (((curSizeRollBackups - maxSizeRollBackups) >= 0)) { + LogLog.debug("CD=0,curSizeRollBackups:"+curSizeRollBackups); + LogLog.debug("CD=0,maxSizeRollBackups:"+maxSizeRollBackups); + // delete the first and keep counting up. int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + LogLog.debug("CD=0,deleteFile:"+oldestFileIndex); deleteFile(newFile + '.' + oldestFileIndex); } } @@ -938,7 +846,6 @@ public class QpidCompositeRollingAppender extends FileAppender } else { // countDirection > 0 - // If we haven't rolled yet then validate we have the right value // for curSizeRollBackups if (curSizeRollBackups == 0) @@ -953,6 +860,9 @@ public class QpidCompositeRollingAppender extends FileAppender // If we are not keeping an infinite set of backups the delete oldest if (maxSizeRollBackups > 0) { + LogLog.debug("CD=1,curSizeRollBackups:"+curSizeRollBackups); + LogLog.debug("CD=1,maxSizeRollBackups:"+maxSizeRollBackups); + // Don't prune older files if they exist just go for the last // one based on our maxSizeRollBackups. This means we may have // more files left on disk that maxSizeRollBackups if this value @@ -960,10 +870,11 @@ public class QpidCompositeRollingAppender extends FileAppender // Otherwise we would have to check on startup that we didn't // have more than maxSizeRollBackups and prune then. - if (((curSizeRollBackups - maxSizeRollBackups) >= maxSizeRollBackups)) + if (((curSizeRollBackups - maxSizeRollBackups) >= 0)) { // delete the first and keep counting up. int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; + LogLog.debug("CD=1,deleteFile:"+oldestFileIndex); deleteFile(fileName + '.' + oldestFileIndex); } } @@ -972,7 +883,9 @@ public class QpidCompositeRollingAppender extends FileAppender curSizeRollBackups++; rollFile(fileName, fileName + '.' + curSizeRollBackups, compress); + } + LogLog.debug("CD="+countDirection+",done"); } /** -- cgit v1.2.1 From eb39d0480f3ca0103116e58d3b8adb484e411666 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 16 Dec 2009 17:20:38 +0000 Subject: QPID-2155 : Added NPE checks for path errors, updated to check the backup location for existing backup files to initialise the .n count git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@891331 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 65 +++++++++++++++------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 853247be58..be52b82789 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -823,7 +823,7 @@ public class QpidCompositeRollingAppender extends FileAppender LogLog.debug("CD=0,curSizeRollBackups:"+curSizeRollBackups); LogLog.debug("CD=0,maxSizeRollBackups:"+maxSizeRollBackups); - // delete the first and keep counting up. + // delete the first and keep counting up. int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1; LogLog.debug("CD=0,deleteFile:"+oldestFileIndex); deleteFile(newFile + '.' + oldestFileIndex); @@ -888,6 +888,11 @@ public class QpidCompositeRollingAppender extends FileAppender LogLog.debug("CD="+countDirection+",done"); } + + private int countFileIndex(String fileName) + { + return countFileIndex(fileName, true); + } /** * Use filename as a base name and find what count number we are up to by * looking at the files in this format: @@ -899,9 +904,10 @@ public class QpidCompositeRollingAppender extends FileAppender * * * @param fileName the basefilename to use + * @param checkBackupLocation should backupFilesToPath location be checked for existing backups * @return int the next free index */ - private int countFileIndex(String fileName) + private int countFileIndex(String fileName, boolean checkBackupLocation) { String testFileName; @@ -911,6 +917,14 @@ public class QpidCompositeRollingAppender extends FileAppender testFileName = fileName + "." + index; + // Bail out early if there is a problem with the file + if (new File(testFileName) == null + || new File(testFileName + COMPRESS_EXTENSION) == null) + + { + return index; + } + // Check that we do not have the 1..n missing scenario if (!(new File(testFileName).exists() || new File(testFileName + COMPRESS_EXTENSION).exists())) @@ -920,33 +934,36 @@ public class QpidCompositeRollingAppender extends FileAppender String prunedFileName = new File(fileName).getName(); // Look through all files to find next index - for (File file : new File(fileName).getParentFile().listFiles()) + if (new File(fileName).getParentFile() != null) { - String name = file.getName(); - - if (name.startsWith(prunedFileName) && !name.equals(prunedFileName)) + for (File file : new File(fileName).getParentFile().listFiles()) { - String parsedCount = name.substring(prunedFileName.length() + 1 ); + String name = file.getName(); - if (parsedCount.endsWith(COMPRESS_EXTENSION)) + if (name.startsWith(prunedFileName) && !name.equals(prunedFileName)) { - parsedCount = parsedCount.substring(0, parsedCount.indexOf(COMPRESS_EXTENSION)); - } + String parsedCount = name.substring(prunedFileName.length() + 1); - try - { - max = Integer.parseInt(parsedCount); + if (parsedCount.endsWith(COMPRESS_EXTENSION)) + { + parsedCount = parsedCount.substring(0, parsedCount.indexOf(COMPRESS_EXTENSION)); + } - // if we got a good value then update our index value. - if (max > index) + try { - // +1 as we want to return the next free value. - index = max + 1; + max = Integer.parseInt(parsedCount); + + // if we got a good value then update our index value. + if (max > index) + { + // +1 as we want to return the next free value. + index = max + 1; + } + } + catch (NumberFormatException nfe) + { + //ignore it assume file doesn't exist. } - } - catch (NumberFormatException nfe) - { - //ignore it assume file doesn't exist. } } } @@ -963,6 +980,12 @@ public class QpidCompositeRollingAppender extends FileAppender testFileName = fileName + "." + index; } + if (checkBackupLocation && index == 1 && backupFilesToPath != null) + { + LogLog.debug("Trying backup location:"+backupFilesToPath + System.getProperty("file.separator") + fileName); + return countFileIndex(backupFilesToPath + System.getProperty("file.separator") + new File(fileName).getName(), false); + } + return index; } -- cgit v1.2.1 From 6f5d96325706a81a91e5bdfbdafb37a296478bf0 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 18 Dec 2009 16:23:19 +0000 Subject: QPID-2273 : Fix Protocol Negotiation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@892301 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 15 ++++ .../server/configuration/ServerConfiguration.java | 5 ++ .../output/ProtocolOutputConverterRegistry.java | 1 - .../protocol/MultiVersionProtocolEngine.java | 83 ++++++++++++++++++---- 4 files changed, 91 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 845983857c..90afd2e4ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -140,6 +140,12 @@ public class Main .withDescription("when listening on the specified port do not accept AMQP0-10 connections. The specified port must be one specified on the command line") .withLongOpt("exclude-0-10").create(); + Option exclude0_9_1 = + OptionBuilder.withArgName("exclude-0-9-1").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-9-1 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-9-1").create(); + + Option exclude0_9 = OptionBuilder.withArgName("exclude-0-9").hasArg() .withDescription("when listening on the specified port do not accept AMQP0-9 connections. The specified port must be one specified on the command line") @@ -179,6 +185,7 @@ public class Main options.addOption(logwatchconfig); options.addOption(port); options.addOption(exclude0_10); + options.addOption(exclude0_9_1); options.addOption(exclude0_9); options.addOption(exclude0_8); options.addOption(mport); @@ -335,6 +342,7 @@ public class Main Set ports = new HashSet(); Set exclude_0_10 = new HashSet(); + Set exclude_0_9_1 = new HashSet(); Set exclude_0_9 = new HashSet(); Set exclude_0_8 = new HashSet(); @@ -343,6 +351,7 @@ public class Main parsePortList(ports, serverConfig.getPorts()); parsePortList(exclude_0_10, serverConfig.getPortExclude010()); + parsePortList(exclude_0_9_1, serverConfig.getPortExclude091()); parsePortList(exclude_0_9, serverConfig.getPortExclude09()); parsePortList(exclude_0_8, serverConfig.getPortExclude08()); @@ -351,6 +360,7 @@ public class Main { parsePortArray(ports, portStr); parsePortArray(exclude_0_10, commandLine.getOptionValues("exclude-0-10")); + parsePortArray(exclude_0_9_1, commandLine.getOptionValues("exclude-0-9-1")); parsePortArray(exclude_0_9, commandLine.getOptionValues("exclude-0-9")); parsePortArray(exclude_0_8, commandLine.getOptionValues("exclude-0-8")); @@ -399,6 +409,11 @@ public class Main { supported.remove(VERSION.v0_10); } + + if(exclude_0_9_1.contains(port)) + { + supported.remove(VERSION.v0_9_1); + } if(exclude_0_9.contains(port)) { supported.remove(VERSION.v0_9); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 66a7279134..879eb7c9e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -538,6 +538,11 @@ public class ServerConfiguration implements SignalHandler return getConfig().getList("connector.non010port", Collections.EMPTY_LIST); } + public List getPortExclude091() + { + return getConfig().getList("connector.non091port", Collections.EMPTY_LIST); + } + public List getPortExclude09() { return getConfig().getList("connector.non09port", Collections.EMPTY_LIST); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java index 3a94160e22..dbefeb61f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java @@ -45,7 +45,6 @@ public class ProtocolOutputConverterRegistry register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory()); register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory()); register(ProtocolVersion.v0_91, org.apache.qpid.server.output.amqp0_9_1.ProtocolOutputConverterImpl.getInstanceFactory()); - } private static void register(ProtocolVersion version, Factory converter) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java index 78e21a8f14..9a1c6c9418 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -135,7 +135,7 @@ private static final byte[] AMQP_0_9_1_HEADER = (byte) 'M', (byte) 'Q', (byte) 'P', - (byte) 1, + (byte) 0, (byte) 0, (byte) 9, (byte) 1 @@ -250,6 +250,59 @@ private static final byte[] AMQP_0_9_1_HEADER = new DelegateCreator[] { creator_0_8, creator_0_9, creator_0_9_1, creator_0_10 }; + private class ClosedDelegateProtocolEngine implements ProtocolEngine + { + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public long getWrittenBytes() + { + return 0; + } + + public long getReadBytes() + { + return 0; + } + + public void received(ByteBuffer msg) + { + _logger.error("Error processing incoming data, could not negotiate a common protocol"); + } + + public void exception(Throwable t) + { + _logger.error("Error establishing session", t); + } + + public void closed() + { + + } + + public void writerIdle() + { + + } + + public void readerIdle() + { + + } + } + private class SelfDelegateProtocolEngine implements ProtocolEngine { @@ -303,12 +356,14 @@ private static final byte[] AMQP_0_9_1_HEADER = ProtocolEngine newDelegate = null; + byte[] newestSupported = null; for(int i = 0; newDelegate == null && i < _creators.length; i++) { if(_supported.contains(_creators[i].getVersion())) { + newestSupported = _creators[i].getHeaderIdentifier(); byte[] compareBytes = _creators[i].getHeaderIdentifier(); boolean equal = true; for(int j = 0; equal && j Date: Mon, 4 Jan 2010 18:12:57 +0000 Subject: QPID-2096: decouple the addition of durable exchanges to the store from exchange registration. Remove auto-delete related persistence restriction from 0-10 based exchange declarations git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@895735 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/AMQBrokerManagerMBean.java | 4 ++++ .../qpid/server/exchange/DefaultExchangeRegistry.java | 6 +----- .../qpid/server/exchange/ExchangeInitialiser.java | 17 ++++++++++++----- .../qpid/server/handler/ExchangeDeclareHandler.java | 5 +++++ .../qpid/server/transport/ServerSessionDelegate.java | 2 +- .../apache/qpid/server/virtualhost/VirtualHostImpl.java | 5 +++++ 6 files changed, 28 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 08b3c08215..de1b69b0a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -203,6 +203,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, false, 0); _exchangeRegistry.registerExchange(exchange); + if (durable) + { + _durableConfig.createExchange(exchange); + } } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 2a8a87be7d..7b21ad6b91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -54,7 +54,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void initialise() throws AMQException { - new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); + new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this, getDurableConfigurationStore()); } @@ -68,10 +68,6 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { _exchangeMap.put(exchange.getName(), exchange); _exchangeMapStr.put(exchange.getName().toString(), exchange); - if (exchange.isDurable()) - { - getDurableConfigurationStore().createExchange(exchange); - } } public void setDefaultExchange(Exchange exchange) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java index 59fe94ddc0..4dfcce7bbe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java @@ -23,25 +23,32 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.store.DurableConfigurationStore; public class ExchangeInitialiser { - public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ + public void initialise(ExchangeFactory factory, ExchangeRegistry registry, DurableConfigurationStore store) throws AMQException{ for (ExchangeType type : factory.getRegisteredTypes()) { - define (registry, factory, type.getDefaultExchangeName(), type.getName()); + define (registry, factory, type.getDefaultExchangeName(), type.getName(), store); } - define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS, store); registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); } private void define(ExchangeRegistry r, ExchangeFactory f, - AMQShortString name, AMQShortString type) throws AMQException + AMQShortString name, AMQShortString type, DurableConfigurationStore store) throws AMQException { if(r.getExchange(name)== null) { - r.registerExchange(f.createExchange(name, type, true, false, 0)); + Exchange exchange = f.createExchange(name, type, true, false, 0); + r.registerExchange(exchange); + + if(exchange.isDurable()) + { + store.createExchange(exchange); + } } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index b0ee5fff08..1dd6f1413b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -97,6 +97,11 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener Date: Mon, 4 Jan 2010 18:13:37 +0000 Subject: QPID-2308: Update the DerbyStore createExchange() method to check for existing exchange entry in the store first. Remove the no-longer-required workarounds for QPID-2096 that prevent addition of the default and config-defined durable exchanges to the store at startup and so lead to failure to recover the associated bindings on subsequent store recovery cycles git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@895736 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 22 ++++++++++++++++------ .../qpid/server/virtualhost/VirtualHostImpl.java | 20 -------------------- 2 files changed, 16 insertions(+), 26 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 1764e2324e..5ca75aa9ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -101,6 +101,7 @@ public class DerbyMessageStore implements MessageStore "SELECT * FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ? "; private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; + private static final String FIND_EXCHANGE = "SELECT name FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; @@ -588,13 +589,22 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); stmt.setString(1, exchange.getName().toString()); - stmt.setString(2, exchange.getType().toString()); - stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); - stmt.execute(); - stmt.close(); - conn.commit(); + + ResultSet rs = stmt.executeQuery(); + + // If we don't have any data in the result set then we can add this exchange + if (!rs.next()) + { + stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + stmt.setString(1, exchange.getName().toString()); + stmt.setString(2, exchange.getType().toString()); + stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); + stmt.execute(); + stmt.close(); + conn.commit(); + } } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 9c4913e1af..48581c0290 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -189,28 +189,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost // This needs to be after the RT has been defined as it creates the default durable exchanges. _exchangeRegistry.initialise(); - // We don't need to store the Default queues in the store as we always - // create them first on start up so don't clear them from the startup - // configuration here. This also ensures that we don't attempt to - // perform a createExchange twice with the same details in the - // MessageStore(RoutingTable) as some instances may not like that. - // Derby being one. - // todo this can be removed with the resolution fo QPID-2096 - configFileRT.exchange.clear(); - initialiseModel(hostConfig); - //todo REMOVE Work Around for QPID-2096 - // This means that all durable exchanges declared in the configuration - // will not be stored in the MessageStore. - // They will still be created/registered/available on startup for as - // long as they are contained in the configuration. However, when they - // are removed from the configuration they will no longer exist. - // This differs from durable queues as they will be writen to to the - // store. After QPID-2096 has been resolved exchanges will mirror that - // functionality. - configFileRT.exchange.clear(); - if (store != null) { _messageStore = store; -- cgit v1.2.1 From ea4eb270376f384e8efbe9ab1b5c2eb594d3976b Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Wed, 6 Jan 2010 13:06:41 +0000 Subject: QPID-2325 : Fix SASL server for PLAIN so that it works with C++ and Ruby clients git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@896435 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java index 45fb9a4e42..731ac70c0e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -68,7 +68,7 @@ public class PlainSaslServer implements SaslServer // 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"); + String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - authzidNullPosition - 1, "utf8"); // we do not care about the prompt but it throws if null NameCallback nameCb = new NameCallback("prompt", authzid); -- cgit v1.2.1 From 34a8997d6993a6815f2f45beb553f73310b24f4e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 6 Jan 2010 21:19:44 +0000 Subject: QPID-2322: remove unused version key from the MBean ObjectName's git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@896674 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../management/ConfigurationManagementMBean.java | 2 +- .../org/apache/qpid/server/exchange/AbstractExchange.java | 2 +- .../server/information/management/ServerInformationMBean.java | 2 +- .../server/logging/management/LoggingManagementMBean.java | 2 +- .../org/apache/qpid/server/management/AMQManagedObject.java | 4 ++-- .../apache/qpid/server/management/DefaultManagedObject.java | 11 +---------- .../apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 2 +- .../main/java/org/apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../security/access/management/AMQUserManagementMBean.java | 2 +- .../org/apache/qpid/server/virtualhost/VirtualHostImpl.java | 2 +- 11 files changed, 12 insertions(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index de1b69b0a4..41ae52e9b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -86,7 +86,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr @MBeanConstructor("Creates the Broker Manager MBean") public AMQBrokerManagerMBean(VirtualHostImpl.VirtualHostMBean virtualHostMBean) throws JMException { - super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); + super(ManagedBroker.class, ManagedBroker.TYPE); _virtualHostMBean = virtualHostMBean; VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java index 24f8e8878e..cc402d5b4a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java @@ -32,7 +32,7 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co public ConfigurationManagementMBean() throws NotCompliantMBeanException { - super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION); + super(ConfigurationManagement.class, ConfigurationManagement.TYPE); } public String getObjectInstanceName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 33af910f1a..07f33b4a8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -90,7 +90,7 @@ public abstract class AbstractExchange implements Exchange, Managable public ExchangeMBean() throws NotCompliantMBeanException { - super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); + super(ManagedExchange.class, ManagedExchange.TYPE); } protected void init() throws OpenDataException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java index 6247404d90..db2cc970b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java @@ -37,7 +37,7 @@ public class ServerInformationMBean extends AMQManagedObject implements ServerIn public ServerInformationMBean(String buildVersion, String productVersion) throws JMException { - super(ServerInformation.class, ServerInformation.TYPE, ServerInformation.VERSION); + super(ServerInformation.class, ServerInformation.TYPE); this.buildVersion = buildVersion; this.productVersion = productVersion; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index c36eeb5016..36e8f6cf84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -109,7 +109,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException { - super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION); + super(LoggingManagement.class, LoggingManagement.TYPE); _log4jConfigFileName = log4jConfigFileName; _log4jLogWatchInterval = log4jLogWatchInterval; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java index 594ae24502..c4ffcd26bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java @@ -56,10 +56,10 @@ public abstract class AMQManagedObject extends DefaultManagedObject protected LogActor _logActor; - protected AMQManagedObject(Class managementInterface, String typeName, int version) + protected AMQManagedObject(Class managementInterface, String typeName) throws NotCompliantMBeanException { - super(managementInterface, typeName, version); + super(managementInterface, typeName); // CurrentActor will be defined as these objects are created during // broker startup. _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index d72b8f24ec..0a739af695 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -39,15 +39,13 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana private Class _managementInterface; private String _typeName; - private int _version; - protected DefaultManagedObject(Class managementInterface, String typeName, int version) + protected DefaultManagedObject(Class managementInterface, String typeName) throws NotCompliantMBeanException { super(managementInterface); _managementInterface = managementInterface; _typeName = typeName; - _version = version; } public String getType() @@ -110,10 +108,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(getHierarchicalName(this)); objectName.append("name=").append(name); - objectName.append(","); - objectName.append("version=").append(_version); - - return new ObjectName(objectName.toString()); } @@ -131,9 +125,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(","))); } - objectName.append(","); - objectName.append("version=").append(_version); - return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 72788bdb0f..0562d04b7b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -94,7 +94,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException { - super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION); + super(ManagedConnection.class, ManagedConnection.TYPE); _protocolSession = amqProtocolSession; String remote = getRemoteAddress(); remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 021128d2fc..c21d73cc41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -93,7 +93,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que @MBeanConstructor("Creates an MBean exposing an AMQQueue") public AMQQueueMBean(AMQQueue queue) throws JMException { - super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION); + super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 69abac7bd6..45ab57ca90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -100,7 +100,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public AMQUserManagementMBean() throws JMException { - super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION); + super(UserManagement.class, UserManagement.TYPE); } public String getObjectInstanceName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 48581c0290..2f1528eb43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -121,7 +121,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost { public VirtualHostMBean() throws NotCompliantMBeanException { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE); } public String getObjectInstanceName() -- cgit v1.2.1 From ead585d36cf7c2a9d5f2e6cd50998660bae46923 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 6 Jan 2010 22:03:39 +0000 Subject: QPID-2322: change the JMX parameter name for the password parameter to prevent the 0.5 management console from sending an MD5-hashed password to the once again versionless UserManagement MBean. Add compatibility check to alert users of the old console they should upgrade to a newer release. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@896692 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/MBeanInvocationHandlerImpl.java | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 0ee5763d91..74ca0399a1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -38,6 +38,7 @@ import javax.management.MBeanOperationInfo; import javax.management.JMException; import javax.management.NotificationListener; import javax.management.Notification; +import javax.management.OperationsException; import javax.security.auth.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; @@ -139,6 +140,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati Principal principal = principals.iterator().next(); String identity = principal.getName(); + + checkCompatibility(proxy, method, args); if (isAdminMethod(args)) { @@ -168,6 +171,49 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati throw new SecurityException("Access denied"); } + private void checkCompatibility(final Object proxy, final Method method, final Object[] args) throws Throwable + { + if (args[0] instanceof ObjectName && method.getName().equals("invoke")) + { + //get the ObjectName and invoked Method name + final ObjectName objectName = (ObjectName) args[0]; + + final String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + return; + } + + //UserManagement MBean compatibility checks + if(objectName.getKeyProperty("type").equals(UserManagement.TYPE)) + { + if (mbeanMethod.equals("createUser") || mbeanMethod.equals("setPassword")) + { + //get the provided argument values and types for the method + if( args.length > 2 && args[2] != null && args[2] instanceof Object[] && + args.length > 3 && args[3] != null && args[3] instanceof String[]) + { + //check the 2nd argument value is a char[] + final Object[] argValues = (Object[]) args[2]; + final String[] argTypes = (String[]) args[3]; + + final Object actualValue = (argValues.length > 1) ? argValues[1] : null; + final String expectedType = (argTypes.length > 1) ? (String) argTypes[1] : null; + + if (expectedType != null && expectedType.equals("[C")) + { + if (actualValue != null && actualValue instanceof String) + { + throw new OperationsException("Incorrect parameter type provided.\n" + + "Please upgrade to a newer management console release to correct this issue."); + } + } + } + } + } + } + } + private boolean isAdminMethod(Object[] args) { if (args[0] instanceof ObjectName) -- cgit v1.2.1 From 2a58f6125dde16a132ac89f7b34778dbc58b4986 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 6 Jan 2010 22:04:43 +0000 Subject: QPID-2322: Add new createUser and setPassword methods using String for passwords. Position these after the older now-deprecated char[] methods within the UserManagement interface to manipulate the MBeanInfo generated, resulting in overwriting the OperationData of the deprecated method on the old 0.5 management console and forcing use of these newer methods rather than the incompatible char[] based methods. Remove previously added compatibility check as it is no longer required. Update current management console to use the new String based methods when available. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@896693 13f79535-47bb-0310-9956-ffa450edef68 --- .../management/MBeanInvocationHandlerImpl.java | 46 ---------------------- .../access/management/AMQUserManagementMBean.java | 10 +++++ 2 files changed, 10 insertions(+), 46 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 74ca0399a1..0ee5763d91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -38,7 +38,6 @@ import javax.management.MBeanOperationInfo; import javax.management.JMException; import javax.management.NotificationListener; import javax.management.Notification; -import javax.management.OperationsException; import javax.security.auth.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; @@ -140,8 +139,6 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati Principal principal = principals.iterator().next(); String identity = principal.getName(); - - checkCompatibility(proxy, method, args); if (isAdminMethod(args)) { @@ -171,49 +168,6 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati throw new SecurityException("Access denied"); } - private void checkCompatibility(final Object proxy, final Method method, final Object[] args) throws Throwable - { - if (args[0] instanceof ObjectName && method.getName().equals("invoke")) - { - //get the ObjectName and invoked Method name - final ObjectName objectName = (ObjectName) args[0]; - - final String mbeanMethod = (args.length > 1) ? (String) args[1] : null; - if (mbeanMethod == null) - { - return; - } - - //UserManagement MBean compatibility checks - if(objectName.getKeyProperty("type").equals(UserManagement.TYPE)) - { - if (mbeanMethod.equals("createUser") || mbeanMethod.equals("setPassword")) - { - //get the provided argument values and types for the method - if( args.length > 2 && args[2] != null && args[2] instanceof Object[] && - args.length > 3 && args[3] != null && args[3] instanceof String[]) - { - //check the 2nd argument value is a char[] - final Object[] argValues = (Object[]) args[2]; - final String[] argTypes = (String[]) args[3]; - - final Object actualValue = (argValues.length > 1) ? argValues[1] : null; - final String expectedType = (argTypes.length > 1) ? (String) argTypes[1] : null; - - if (expectedType != null && expectedType.equals("[C")) - { - if (actualValue != null && actualValue instanceof String) - { - throw new OperationsException("Incorrect parameter type provided.\n" + - "Please upgrade to a newer management console release to correct this issue."); - } - } - } - } - } - } - } - private boolean isAdminMethod(Object[] args) { if (args[0] instanceof ObjectName) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java index 45ab57ca90..5a2965cb32 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java @@ -108,6 +108,11 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return UserManagement.TYPE; } + public boolean setPassword(String username, String password) + { + return setPassword(username, password.toCharArray()); + } + public boolean setPassword(String username, char[] password) { try @@ -196,6 +201,11 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return true; } + + public boolean createUser(String username, String password, boolean read, boolean write, boolean admin) + { + return createUser(username, password.toCharArray(), read, write, admin); + } public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) { -- cgit v1.2.1 From 5efcd04d4557a6902a3ba85aa5114b0f282937f5 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 31 Jan 2010 00:31:49 +0000 Subject: QPID-2379 : Initial work on adding QMF and federation to the Java Broker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@904934 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/qmf/CompletionCode.java | 36 + .../org/apache/qpid/qmf/ManagementExchange.java | 559 +++++++ .../apache/qpid/qmf/QMFBrokerRequestCommand.java | 78 + .../apache/qpid/qmf/QMFBrokerResponseCommand.java | 46 + .../main/java/org/apache/qpid/qmf/QMFClass.java | 158 ++ .../apache/qpid/qmf/QMFClassIndicationCommand.java | 50 + .../org/apache/qpid/qmf/QMFClassQueryCommand.java | 90 ++ .../main/java/org/apache/qpid/qmf/QMFCommand.java | 54 + .../qpid/qmf/QMFCommandCompletionCommand.java | 56 + .../org/apache/qpid/qmf/QMFCommandDecoder.java | 98 ++ .../java/org/apache/qpid/qmf/QMFCommandHeader.java | 63 + .../java/org/apache/qpid/qmf/QMFEventClass.java | 42 + .../java/org/apache/qpid/qmf/QMFEventCommand.java | 49 + .../java/org/apache/qpid/qmf/QMFEventSeverity.java | 33 + .../org/apache/qpid/qmf/QMFGetQueryCommand.java | 182 +++ .../main/java/org/apache/qpid/qmf/QMFMessage.java | 205 +++ .../main/java/org/apache/qpid/qmf/QMFMethod.java | 157 ++ .../org/apache/qpid/qmf/QMFMethodInvocation.java | 26 + .../apache/qpid/qmf/QMFMethodRequestCommand.java | 88 ++ .../apache/qpid/qmf/QMFMethodResponseCommand.java | 43 + .../main/java/org/apache/qpid/qmf/QMFObject.java | 76 + .../java/org/apache/qpid/qmf/QMFObjectClass.java | 44 + .../java/org/apache/qpid/qmf/QMFOperation.java | 67 + .../main/java/org/apache/qpid/qmf/QMFPackage.java | 67 + .../qpid/qmf/QMFPackageIndicationCommand.java | 46 + .../apache/qpid/qmf/QMFPackageQueryCommand.java | 86 ++ .../main/java/org/apache/qpid/qmf/QMFProperty.java | 123 ++ .../apache/qpid/qmf/QMFSchemaRequestCommand.java | 88 ++ .../apache/qpid/qmf/QMFSchemaResponseCommand.java | 83 + .../main/java/org/apache/qpid/qmf/QMFService.java | 1583 ++++++++++++++++++++ .../java/org/apache/qpid/qmf/QMFStatistic.java | 61 + .../src/main/java/org/apache/qpid/qmf/QMFType.java | 53 + .../java/org/apache/qpid/server/AMQChannel.java | 269 +++- .../org/apache/qpid/server/binding/Binding.java | 117 ++ .../apache/qpid/server/binding/BindingFactory.java | 290 ++++ .../qpid/server/configuration/BindingConfig.java | 43 + .../server/configuration/BindingConfigType.java | 112 ++ .../qpid/server/configuration/BridgeConfig.java | 50 + .../server/configuration/BridgeConfigType.java | 169 +++ .../qpid/server/configuration/BrokerConfig.java | 59 + .../server/configuration/BrokerConfigType.java | 143 ++ .../server/configuration/ConfigObjectType.java | 30 + .../qpid/server/configuration/ConfigProperty.java | 66 + .../qpid/server/configuration/ConfigStore.java | 184 +++ .../server/configuration/ConfiguredObject.java | 36 + .../server/configuration/ConnectionConfig.java | 45 + .../server/configuration/ConnectionConfigType.java | 145 ++ .../qpid/server/configuration/ExchangeConfig.java | 57 + .../server/configuration/ExchangeConfigType.java | 113 ++ .../qpid/server/configuration/LinkConfig.java | 59 + .../qpid/server/configuration/LinkConfigType.java | 136 ++ .../qpid/server/configuration/QueueConfig.java | 72 + .../qpid/server/configuration/QueueConfigType.java | 121 ++ .../server/configuration/QueueConfiguration.java | 9 + .../qpid/server/configuration/SessionConfig.java | 41 + .../server/configuration/SessionConfigType.java | 136 ++ .../server/configuration/SubscriptionConfig.java | 47 + .../configuration/SubscriptionConfigType.java | 136 ++ .../qpid/server/configuration/SystemConfig.java | 44 + .../server/configuration/SystemConfigImpl.java | 136 ++ .../server/configuration/SystemConfigType.java | 128 ++ .../server/configuration/VirtualHostConfig.java | 36 + .../configuration/VirtualHostConfigType.java | 96 ++ .../qpid/server/exchange/AbstractExchange.java | 330 ++-- .../server/exchange/AbstractExchangeMBean.java | 139 ++ .../server/exchange/DefaultExchangeFactory.java | 10 +- .../server/exchange/DefaultExchangeRegistry.java | 4 +- .../qpid/server/exchange/DirectExchange.java | 237 ++- .../qpid/server/exchange/DirectExchangeMBean.java | 79 + .../org/apache/qpid/server/exchange/Exchange.java | 48 +- .../qpid/server/exchange/FanoutExchange.java | 202 ++- .../qpid/server/exchange/FanoutExchangeMBean.java | 68 + .../qpid/server/exchange/HeadersExchange.java | 197 +-- .../qpid/server/exchange/HeadersExchangeMBean.java | 96 ++ .../org/apache/qpid/server/exchange/Index.java | 114 -- .../apache/qpid/server/exchange/TopicExchange.java | 439 +----- .../qpid/server/exchange/TopicExchangeMBean.java | 74 + .../qpid/server/exchange/topic/TopicBinding.java | 70 + .../server/exchange/topic/TopicExchangeResult.java | 179 +++ .../server/exchange/topic/TopicNormalizer.java | 96 ++ .../org/apache/qpid/server/federation/Bridge.java | 807 ++++++++++ .../apache/qpid/server/federation/BrokerLink.java | 497 ++++++ .../qpid/server/filter/JMSSelectorFilter.java | 3 +- .../server/handler/BasicConsumeMethodHandler.java | 9 +- .../server/handler/ExchangeDeclareHandler.java | 5 +- .../qpid/server/handler/QueueBindHandler.java | 38 +- .../qpid/server/handler/QueueDeclareHandler.java | 13 +- .../qpid/server/handler/QueueDeleteHandler.java | 12 +- .../qpid/server/handler/QueueUnbindHandler.java | 17 +- .../server/logging/subjects/BindingLogSubject.java | 9 +- .../logging/subjects/ExchangeLogSubject.java | 2 +- .../server/logging/subjects/QueueLogSubject.java | 2 +- .../qpid/server/message/AMQMessageHeader.java | 4 + .../server/message/ContentHeaderBodyAdapter.java | 13 + .../qpid/server/message/MessageMetaData.java | 12 + .../qpid/server/message/MessageTransferHeader.java | 24 + .../server/message/MessageTransferMessage.java | 2 +- .../qpid/server/protocol/AMQProtocolEngine.java | 140 +- .../server/protocol/AMQProtocolSessionMBean.java | 37 +- .../protocol/MultiVersionProtocolEngine.java | 14 +- .../protocol/ProtocolEngineFactory_0_10.java | 46 - .../qpid/server/protocol/ProtocolEngine_0_10.java | 102 +- .../apache/qpid/server/queue/AMQPriorityQueue.java | 14 +- .../org/apache/qpid/server/queue/AMQQueue.java | 50 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 126 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 12 +- .../org/apache/qpid/server/queue/BaseQueue.java | 42 + .../apache/qpid/server/queue/ConflationQueue.java | 42 + .../qpid/server/queue/ConflationQueueList.java | 168 +++ .../qpid/server/queue/DefaultQueueRegistry.java | 3 +- .../apache/qpid/server/queue/ExchangeBinding.java | 91 -- .../apache/qpid/server/queue/ExchangeBindings.java | 82 - .../apache/qpid/server/queue/IncomingMessage.java | 6 +- .../org/apache/qpid/server/queue/QueueEntry.java | 3 + .../apache/qpid/server/queue/QueueEntryImpl.java | 30 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 351 +++-- .../qpid/server/queue/SimpleQueueEntryList.java | 14 +- .../qpid/server/registry/ApplicationRegistry.java | 92 +- .../qpid/server/registry/BrokerConfigAdapter.java | 163 ++ .../ConfigurationFileApplicationRegistry.java | 14 +- .../qpid/server/registry/IApplicationRegistry.java | 40 +- .../security/access/PrincipalPermissions.java | 32 +- .../auth/sasl/anonymous/AnonymousInitialiser.java | 39 + .../auth/sasl/anonymous/AnonymousSaslServer.java | 88 ++ .../sasl/anonymous/AnonymousSaslServerFactory.java | 63 + .../qpid/server/store/DerbyMessageStore.java | 57 +- .../server/store/DurableConfigurationStore.java | 5 + .../qpid/server/subscription/SubscriptionImpl.java | 119 +- .../server/subscription/Subscription_0_10.java | 246 ++- .../qpid/server/transport/ServerConnection.java | 29 +- .../server/transport/ServerConnectionDelegate.java | 2 +- .../qpid/server/transport/ServerSession.java | 132 +- .../server/transport/ServerSessionDelegate.java | 55 +- .../qpid/server/txn/AutoCommitTransaction.java | 9 +- .../apache/qpid/server/txn/LocalTransaction.java | 11 +- .../apache/qpid/server/txn/ServerTransaction.java | 15 +- .../qpid/server/virtualhost/VirtualHost.java | 30 +- .../VirtualHostConfigRecoveryHandler.java | 24 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 185 ++- .../server/virtualhost/VirtualHostRegistry.java | 13 +- .../qpid/tools/messagestore/MessageStoreTool.java | 6 +- .../qpid/tools/messagestore/commands/Copy.java | 2 +- .../qpid/tools/messagestore/commands/List.java | 4 +- .../qpid/tools/messagestore/commands/Move.java | 2 +- 144 files changed, 12429 insertions(+), 1887 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java delete mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java new file mode 100644 index 0000000000..706ab3974a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +public enum CompletionCode +{ + OK, + UNKNOWN_OBJECT, + UNKNOWN_METHOD, + NOT_IMPLEMENTED, + INVALID_PARAMETER, + FEATURE_NOT_IMPLEMENTED, + FORBIDDEN, + EXCEPTION, + UNKNOWN_PACKAGE, + UNKNOWN_CLASS; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java new file mode 100644 index 0000000000..b639cb9fc1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -0,0 +1,559 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ExchangeConfigType; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeReferrer; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.exchange.topic.TopicBinding; +import org.apache.qpid.server.exchange.topic.TopicExchangeResult; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; +import org.apache.qpid.server.exchange.topic.TopicNormalizer; +import org.apache.qpid.server.exchange.topic.TopicParser; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; + +public class ManagementExchange implements Exchange, QMFService.Listener +{ + private static final AMQShortString QPID_MANAGEMENT = new AMQShortString("qpid.management"); + private static final AMQShortString QPID_MANAGEMENT_TYPE = new AMQShortString("management"); + + private VirtualHost _virtualHost; + + private final TopicParser _parser = new TopicParser(); + + private final Map _topicExchangeResults = + new ConcurrentHashMap(); + + private final Map _topicBindings = new HashMap(); + private final Set _bindingSet = new HashSet(); + private UUID _id; + private static final String AGENT_BANK = "0"; + + private int _bindingCountHigh; + private final AtomicLong _msgReceived = new AtomicLong(); + private final AtomicLong _bytesReceived = new AtomicLong(); + + private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); + + // TODO + private long _createTime = System.currentTimeMillis(); + + + private class ManagementQueue implements BaseQueue + { + private final String NAME_AS_STRING = "##__mgmt_pseudo_queue__##" + UUID.randomUUID().toString(); + private final AMQShortString NAME_AS_SHORT_STRING = new AMQShortString(NAME_AS_STRING); + + public void enqueue(ServerMessage message) throws AMQException + { + AMQMessageHeader h = message.getMessageHeader(); + long size = message.getSize(); + + ByteBuffer buf = ByteBuffer.allocate((int) size); + + int offset = 0; + + while(offset < size) + { + offset += message.getContent(buf,offset); + } + + buf.flip(); + QMFCommandDecoder commandDecoder = new QMFCommandDecoder(getQMFService(),buf); + QMFCommand cmd; + while((cmd = commandDecoder.decode()) != null) + { + cmd.process(_virtualHost, message); + } + + } + + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException + { + enqueue(message); + } + + public boolean isDurable() + { + return false; + } + + public AMQShortString getNameShortString() + { + return NAME_AS_SHORT_STRING; + } + + public String getResourceName() + { + return NAME_AS_STRING; + } + } + + + private final ManagementQueue _mgmtQueue = new ManagementQueue(); + + public ManagementExchange() + { + } + + public static final ExchangeType TYPE = new ExchangeType() + { + + public AMQShortString getName() + { + return QPID_MANAGEMENT_TYPE; + } + + public Class getExchangeClass() + { + return ManagementExchange.class; + } + + public ManagementExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + ManagementExchange exch = new ManagementExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return QPID_MANAGEMENT; + } + }; + + + public AMQShortString getNameShortString() + { + return QPID_MANAGEMENT; + } + + public AMQShortString getTypeShortString() + { + return QPID_MANAGEMENT_TYPE; + } + + public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException + { + if(!QPID_MANAGEMENT.equals(name)) + { + throw new AMQException("Can't create more than one Management exchange"); + } + _virtualHost = host; + _id = host.getConfigStore().createId(); + _virtualHost.scheduleTask(_virtualHost.getBroker().getManagementPublishInterval(),_updateTask); + getConfigStore().addConfiguredObject(this); + getQMFService().addListener(this); + } + + public UUID getId() + { + return _id; + } + + public ExchangeConfigType getConfigType() + { + return ExchangeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public boolean isDurable() + { + return true; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public String getName() + { + return QPID_MANAGEMENT.toString(); + } + + public ExchangeType getType() + { + return TYPE; + } + + public boolean isAutoDelete() + { + return false; + } + + public int getTicket() + { + return 0; + } + + public void close() throws AMQException + { + getConfigStore().removeConfiguredObject(this); + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public synchronized void addBinding(final Binding b) + { + + _bindingSet.add(b); + + for(BindingListener listener : _listeners) + { + listener.bindingAdded(this, b); + } + + if(_bindingSet.size() > _bindingCountHigh) + { + _bindingCountHigh = _bindingSet.size(); + } + + TopicBinding binding = new TopicBinding(new AMQShortString(b.getBindingKey()), b.getQueue(), null); + + if(!_topicBindings.containsKey(binding)) + { + AMQShortString routingKey = TopicNormalizer.normalize(new AMQShortString(b.getBindingKey())); + + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + if(result == null) + { + result = new TopicExchangeResult(); + result.addUnfilteredQueue(b.getQueue()); + _parser.addBinding(routingKey, result); + _topicExchangeResults.put(routingKey,result); + } + else + { + result.addUnfilteredQueue(b.getQueue()); + } + _topicBindings.put(binding, null); + + + } + String bindingKey = b.getBindingKey(); + + if(bindingKey.startsWith("schema.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#.")) + { + publishAllSchema(); + } + if(bindingKey.startsWith("console.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#.")) + { + publishAllConsole(); + } + + } + + void publishAllConsole() + { + QMFService qmfService = getQMFService(); + + long sampleTime = System.currentTimeMillis(); + + for(QMFPackage pkg : qmfService.getSupportedSchemas()) + { + for(QMFClass qmfClass : pkg.getClasses()) + { + Collection qmfObjects = qmfService.getObjects(qmfClass); + + publishObjectsToConsole(sampleTime, qmfObjects); + } + + } + + } + + private QMFService getQMFService() + { + return _virtualHost.getApplicationRegistry().getQMFService(); + } + + void publishObjectsToConsole(final long sampleTime, + final Collection qmfObjects) + { + if(!qmfObjects.isEmpty() && hasBindings()) + { + QMFClass qmfClass = qmfObjects.iterator().next().getQMFClass(); + ArrayList commands = new ArrayList(); + + + for(QMFObject obj : qmfObjects) + { + commands.add(obj.asConfigInfoCmd(sampleTime)); + commands.add(obj.asInstrumentInfoCmd(sampleTime)); + } + + publishToConsole(qmfClass, commands); + } + } + + private void publishToConsole(final QMFClass qmfClass, final ArrayList commands) + { + if(!commands.isEmpty() && hasBindings()) + { + String routingKey = "console.obj.1." + AGENT_BANK + "." + qmfClass.getPackage().getName() + "." + qmfClass.getName(); + QMFMessage message = new QMFMessage(routingKey,commands.toArray(new QMFCommand[commands.size()])); + + Collection results = _parser.parse(new AMQShortString(routingKey)); + HashSet queues = new HashSet(); + for(TopicMatcherResult result : results) + { + queues.addAll(((TopicExchangeResult)result).getUnfilteredQueues()); + } + for(AMQQueue queue : queues) + { + try + { + queue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + } + + void publishAllSchema() + { + + } + + public synchronized void removeBinding(final Binding binding) + { + _bindingSet.remove(binding); + + TopicBinding topicBinding = new TopicBinding(new AMQShortString(binding.getBindingKey()), binding.getQueue(), null); + + if(_topicBindings.containsKey(topicBinding)) + { + AMQShortString bindingKey = TopicNormalizer.normalize(topicBinding.getBindingKey()); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + result.removeUnfilteredQueue(binding.getQueue()); + } + + for(BindingListener listener : _listeners) + { + listener.bindingRemoved(this, binding); + } + } + + public synchronized Collection getBindings() + { + return new ArrayList(_bindingSet); + } + + public ArrayList route(InboundMessage message) + { + ArrayList queues = new ArrayList(1); + _msgReceived.incrementAndGet(); + _bytesReceived.addAndGet(message.getSize()); + queues.add(_mgmtQueue); + return queues; + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQShortString routingKey) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean hasBindings() + { + return !_bindingSet.isEmpty(); + } + + public boolean isBound(String bindingKey, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(String bindingKey) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addCloseTask(final Task task) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeCloseTask(final Task task) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + + + public Exchange getAlternateExchange() + { + return null; + } + + public Map getArguments() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setAlternateExchange(Exchange exchange) + { + + } + + public void removeReference(ExchangeReferrer exchange) + { + } + + public void addReference(ExchangeReferrer exchange) + { + } + + public boolean hasReferrers() + { + return true; + } + + + + private final TimerTask _updateTask = new UpdateTask(); + + + private class UpdateTask extends TimerTask + { + + public void run() + { + publishAllConsole(); + publishAllSchema(); + + } + + } + + public void objectCreated(final QMFObject obj) + { + publishObjectsToConsole(System.currentTimeMillis(), Collections.singleton(obj)); + } + + public void objectDeleted(final QMFObject obj) + { + publishObjectsToConsole(System.currentTimeMillis(), Collections.singleton(obj)); + } + + public long getBindingCount() + { + return getBindings().size(); + } + + public long getBindingCountHigh() + { + return _bindingCountHigh; + } + + public long getMsgReceives() + { + return _msgReceived.get(); + } + + public long getMsgRoutes() + { + return getMsgReceives(); + } + + public long getByteReceives() + { + return _bytesReceived.get(); + } + + public long getByteRoutes() + { + return getByteReceives(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void addBindingListener(final BindingListener listener) + { + _listeners.add(listener); + } + + public void removeBindingListener(final BindingListener listener) + { + _listeners.remove(listener); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java new file mode 100644 index 0000000000..b98daf7cb1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.transport.codec.BBEncoder; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; +import org.apache.qpid.management.common.mbeans.ManagedConnection; + +import java.util.ArrayList; + +public class QMFBrokerRequestCommand extends QMFCommand +{ + + public QMFBrokerRequestCommand(QMFCommandHeader header, BBDecoder buf) + { + super(header); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String queueName = message.getMessageHeader().getReplyToRoutingKey(); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = new QMFBrokerResponseCommand(this, virtualHost); + commands[1] = new QMFCommandCompletionCommand(this); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(queueName, cmd); + + + ArrayList queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java new file mode 100644 index 0000000000..ac01c47fe8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFBrokerResponseCommand extends QMFCommand +{ + private QMFCommandHeader _header; + private VirtualHost _virtualHost; + + public QMFBrokerResponseCommand(QMFBrokerRequestCommand qmfBrokerRequestCommand, VirtualHost virtualHost) + { + super( new QMFCommandHeader(qmfBrokerRequestCommand.getHeader().getVersion(), + qmfBrokerRequestCommand.getHeader().getSeq(), + QMFOperation.BROKER_RESPONSE)); + _virtualHost = virtualHost; + } + + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUuid(_virtualHost.getBrokerId()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java new file mode 100644 index 0000000000..3408ff09f4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java @@ -0,0 +1,158 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.configuration.ConfiguredObject; + +import java.util.Collection; +import java.util.Map; +import java.util.List; +import java.util.LinkedHashMap; + +abstract public class QMFClass +{ + + + public enum Type + { + OBJECT((byte)1), + EVENT((byte)2); + + private final byte _value; + + Type(byte value) + { + _value = value; + } + + public byte getValue() + { + return _value; + } + } + + private final Type _type; + private QMFPackage _package; + private final String _name; + private byte[] _schemaHash; + + private Map _properties = new LinkedHashMap(); + private Map _statistics = new LinkedHashMap(); + private Map _methods = new LinkedHashMap(); + + + + public QMFClass(Type type, String name, byte[] schemaHash, List properties, + List statistics, List methods) + { + this(type, name, schemaHash); + setProperties(properties); + setStatistics(statistics); + setMethods(methods); + } + + + public QMFClass(Type type, String name, byte[] schemaHash) + + { + _type = type; + _name = name; + _schemaHash = schemaHash; + + } + + protected void setProperties(List properties) + { + for(QMFProperty prop : properties) + { + _properties.put(prop.getName(), prop); + } + } + + protected void setStatistics(List statistics) + { + for(QMFStatistic stat : statistics) + { + _statistics.put(stat.getName(), stat); + } + } + + + protected void setMethods(List methods) + { + for(QMFMethod method : methods) + { + _methods.put(method.getName(), method); + } + } + + public void setPackage(QMFPackage aPackage) + { + _package = aPackage; + for(QMFProperty prop : _properties.values()) + { + prop.setQMFClass(this); + } + // TODO Statisics, Methods + } + + public Type getType() + { + return _type; + } + + public QMFPackage getPackage() + { + return _package; + } + + public String getName() + { + return _name; + } + + public byte[] getSchemaHash() + { + return _schemaHash; + } + + public Collection getProperties() + { + return _properties.values(); + } + + public Collection getStatistics() + { + return _statistics.values(); + } + + public Collection getMethods() + { + return _methods.values(); + } + + public QMFMethod getMethod(String methodName) + { + return _methods.get(methodName); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java new file mode 100644 index 0000000000..a956a9bd70 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFClassIndicationCommand extends QMFCommand +{ + private QMFClass _qmfClass; + + public QMFClassIndicationCommand(QMFClassQueryCommand qmfClassQueryCommand, QMFClass qmfClass) + { + super(new QMFCommandHeader(qmfClassQueryCommand.getHeader().getVersion(), + qmfClassQueryCommand.getHeader().getSeq(), + QMFOperation.CLASS_INDICATION)); + _qmfClass = qmfClass; + } + + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint8(_qmfClass.getType().getValue()); + encoder.writeStr8(_qmfClass.getPackage().getName()); + encoder.writeStr8(_qmfClass.getName()); + encoder.writeBin128(_qmfClass.getSchemaHash()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java new file mode 100644 index 0000000000..26a27cfa19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java @@ -0,0 +1,90 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.ArrayList; +import java.util.Collection; + +public class QMFClassQueryCommand extends QMFCommand +{ + private final String _package; + + public QMFClassQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + _package = decoder.readStr8(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + QMFPackage qmfPackage = service.getPackage(_package); + Collection qmfClasses = qmfPackage.getClasses(); + + QMFCommand[] commands = new QMFCommand[ qmfClasses.size() + 1 ]; + + int i = 0; + for(QMFClass qmfClass : qmfClasses) + { + commands[i++] = new QMFClassIndicationCommand(this, qmfClass); + } + commands[ commands.length - 1 ] = new QMFCommandCompletionCommand(this); + + + for(QMFCommand cmd : commands) + { + + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java new file mode 100644 index 0000000000..4f143701af --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.codec.BBEncoder; + +public abstract class QMFCommand +{ + + private final QMFCommandHeader _header; + + protected QMFCommand(QMFCommandHeader header) + { + _header = header; + } + + + public void process(final VirtualHost virtualHost, final ServerMessage message) + { + throw new UnsupportedOperationException(); + } + + public void encode(BBEncoder encoder) + { + _header.encode(encoder); + + } + + public QMFCommandHeader getHeader() + { + return _header; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java new file mode 100644 index 0000000000..f163e434d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java @@ -0,0 +1,56 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFCommandCompletionCommand extends QMFCommand +{ + + private final CompletionCode _status; + private final String _text; + + public QMFCommandCompletionCommand(QMFCommand command) + { + this(command, CompletionCode.OK, ""); + } + public QMFCommandCompletionCommand(QMFCommand command, CompletionCode status, String text) + { + super( new QMFCommandHeader(command.getHeader().getVersion(), + command.getHeader().getSeq(), + QMFOperation.COMMAND_COMPLETION)); + + _status = status; + _text = text; + } + + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeInt32(_status.ordinal()); + encoder.writeStr8(_text); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java new file mode 100644 index 0000000000..ac036dfa19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; + +import java.nio.ByteBuffer; + +public class QMFCommandDecoder +{ + private BBDecoder _decoder; + + + private static final QMFOperation[] OP_CODES = new QMFOperation[256]; + private final QMFService _qmfService; + + static + { + for(QMFOperation op : QMFOperation.values()) + { + OP_CODES[op.getOpcode()] = op; + } + } + + public QMFCommandDecoder(final QMFService qmfService, ByteBuffer buf) + { + _qmfService = qmfService; + _decoder = new BBDecoder(); + _decoder.init(buf); + } + + public QMFCommand decode() + { + if(_decoder.hasRemaining()) + { + QMFCommandHeader header = readQMFHeader(); + + switch(header.getOperation()) + { + case BROKER_REQUEST: + return new QMFBrokerRequestCommand(header, _decoder); + case PACKAGE_QUERY: + return new QMFPackageQueryCommand(header, _decoder); + case CLASS_QUERY: + return new QMFClassQueryCommand(header, _decoder); + case SCHEMA_REQUEST: + return new QMFSchemaRequestCommand(header, _decoder); + case METHOD_REQUEST: + return new QMFMethodRequestCommand(header, _decoder, _qmfService); + case GET_QUERY: + return new QMFGetQueryCommand(header, _decoder); + default: + System.out.println("Unknown command"); + + } + + return null; + } + else + { + return null; + } + } + + private QMFCommandHeader readQMFHeader() + { + if(_decoder.readInt8() == (byte) 'A' + && _decoder.readInt8() == (byte) 'M') + { + byte version = _decoder.readInt8(); + short opCode = _decoder.readUint8(); + int seq = _decoder.readInt32(); + + return new QMFCommandHeader(version, seq, OP_CODES[opCode]); + + } + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java new file mode 100644 index 0000000000..c4d771317f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFCommandHeader +{ + private final byte _version; + private final int _seq; + + private final QMFOperation _operation; + + public QMFCommandHeader(byte version, int seq, QMFOperation operation) + { + _version = version; + _seq = seq; + _operation = operation; + } + + public byte getVersion() + { + return _version; + } + + public int getSeq() + { + return _seq; + } + + public QMFOperation getOperation() + { + return _operation; + } + + public void encode(BBEncoder encoder) + { + encoder.writeUint8((short)'A'); + encoder.writeUint8((short)'M'); + encoder.writeInt8(_version); + encoder.writeUint8((short)_operation.getOpcode()); + encoder.writeInt32(_seq); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java new file mode 100644 index 0000000000..ec471f18e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import java.util.List; + +public abstract class QMFEventClass extends QMFClass +{ + public QMFEventClass(String name, + byte[] schemaHash, + List properties, + List statistics, List methods) + { + super(Type.EVENT, name, schemaHash, properties, statistics, methods); + } + + public QMFEventClass(String name, byte[] schemaHash) + { + super(Type.EVENT, name, schemaHash); + } + + abstract public QMFEventSeverity getSeverity(); + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java new file mode 100644 index 0000000000..d70c12db19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public abstract class QMFEventCommand extends QMFCommand +{ + private final long _timestamp; + + protected QMFEventCommand() + { + super(new QMFCommandHeader((byte)'2',0, QMFOperation.EVENT)); + _timestamp = System.currentTimeMillis(); + } + + abstract public T getEventClass(); + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + encoder.writeStr8(getEventClass().getPackage().getName()); + encoder.writeStr8(getEventClass().getName()); + encoder.writeBin128(new byte[16]); + encoder.writeUint64(_timestamp * 1000000L); + encoder.writeUint8((short) getEventClass().getSeverity().ordinal()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java new file mode 100644 index 0000000000..9f9c832732 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +public enum QMFEventSeverity +{ + EMERGENCY, + ALERT, + CRITICAL, + ERROR, + WARN, + NOTICE, + INFORM, + DEBUG +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java new file mode 100644 index 0000000000..8e8cb55a0d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java @@ -0,0 +1,182 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.*; + +public class QMFGetQueryCommand extends QMFCommand +{ + private Map _map; + + + public QMFGetQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + + _map = decoder.readMap(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + String className = (String) _map.get("_class"); + String packageName = (String) _map.get("_package"); + byte[] objectIdBytes = (byte[]) _map.get("_objectId"); + UUID objectId; + if(objectIdBytes != null) + { + long msb = 0; + long lsb = 0; + + for (int i = 0; i != 8; i++) + { + msb = (msb << 8) | (objectIdBytes[i] & 0xff); + } + for (int i = 8; i != 16; i++) + { + lsb = (lsb << 8) | (objectIdBytes[i] & 0xff); + } + objectId = new UUID(msb, lsb); + } + else + { + objectId = null; + } + + List commands = new ArrayList(); + final long sampleTime = System.currentTimeMillis() * 1000000l; + + Collection packages; + + if(packageName != null && packageName.length() != 0) + { + QMFPackage qmfPackage = service.getPackage(packageName); + if(qmfPackage == null) + { + packages = Collections.EMPTY_LIST; + } + else + { + packages = Collections.singleton(qmfPackage); + } + } + else + { + packages = service.getSupportedSchemas(); + } + + for(QMFPackage qmfPackage : packages) + { + + Collection qmfClasses; + + if(className != null && className.length() != 0) + { + QMFClass qmfClass = qmfPackage.getQMFClass(className); + if(qmfClass == null) + { + qmfClasses = Collections.EMPTY_LIST; + } + else + { + qmfClasses = Collections.singleton(qmfClass); + } + } + else + { + qmfClasses = qmfPackage.getClasses(); + } + + + for(QMFClass qmfClass : qmfClasses) + { + Collection objects; + + if(objectId != null) + { + QMFObject obj = service.getObjectById(qmfClass, objectId); + if(obj == null) + { + objects = Collections.EMPTY_LIST; + } + else + { + objects = Collections.singleton(obj); + } + } + else + { + objects = service.getObjects(qmfClass); + } + + for(QMFObject object : objects) + { + + commands.add(object.asGetQueryResponseCmd(this, sampleTime)); + } + } + + + } + + + commands.add( new QMFCommandCompletionCommand(this)); + + + for(QMFCommand cmd : commands) + { + + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java new file mode 100644 index 0000000000..c250b2c011 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -0,0 +1,205 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.message.*; +import org.apache.qpid.transport.codec.BBEncoder; + +import java.nio.ByteBuffer; +import java.util.Set; + +public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHeader +{ + + private ByteBuffer _content; + private String _routingKey; + + public QMFMessage(String routingKey, QMFCommand command) + { + this(routingKey, new QMFCommand[] { command }); + } + + + public QMFMessage(String routingKey, QMFCommand[] commands) + { + _routingKey = routingKey; + BBEncoder encoder = new BBEncoder(256); + + for(QMFCommand cmd : commands) + { + cmd.encode(encoder); + } + + + _content = encoder.buffer(); + } + + public String getRoutingKey() + { + return _routingKey; + } + + public AMQMessageHeader getMessageHeader() + { + return this; + } + + public boolean isPersistent() + { + return false; + } + + public boolean isRedelivered() + { + return false; + } + + public long getSize() + { + return _content.limit(); + } + + public boolean isImmediate() + { + return false; + } + + public String getCorrelationId() + { + return null; + } + + public long getExpiration() + { + return 0; + } + + public String getMessageId() + { + return null; + } + + public String getMimeType() + { + return null; + } + + public String getEncoding() + { + return null; + } + + public byte getPriority() + { + return 4; + } + + public long getTimestamp() + { + return 0; + } + + public String getType() + { + return null; + } + + public String getReplyTo() + { + return null; + } + + public String getReplyToExchange() + { + return null; + } + + public String getReplyToRoutingKey() + { + return null; + } + + public Object getHeader(String name) + { + return null; + } + + public boolean containsHeaders(Set names) + { + return false; + } + + public boolean containsHeader(String name) + { + return false; + } + + public MessageReference newReference() + { + return new QMFMessageReference(this); + } + + public Long getMessageNumber() + { + return null; + } + + public long getArrivalTime() + { + return 0; + } + + public int getContent(ByteBuffer buf, int offset) + { + ByteBuffer src = _content.duplicate(); + _content.position(offset); + _content = _content.slice(); + int len = _content.remaining(); + if(len > buf.remaining()) + { + len = buf.remaining(); + } + + buf.put(src); + + return len; + } + + private class QMFMessageReference extends MessageReference + { + public QMFMessageReference(QMFMessage message) + { + super(message); + } + + protected void onReference(QMFMessage message) + { + + } + + protected void onRelease(QMFMessage message) + { + + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java new file mode 100644 index 0000000000..63e8fa6a1e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java @@ -0,0 +1,157 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; +import org.apache.qpid.transport.codec.BBDecoder; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; + +public abstract class QMFMethod +{ + private final LinkedHashMap _map = new LinkedHashMap(); + private final List _arguments = new ArrayList(); + + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String REF_PACKAGE = "refPackage"; + private static final String REF_CLASS = "refClass"; + private static final String UNIT = "unit"; + private static final String MIN = "min"; + private static final String MAX = "max"; + private static final String MAX_LENGTH = "maxlen"; + private static final String DESCRIPTION = "desc"; + private static final String DEFAULT = "default"; + private static final String DIRECTION = "dir"; + private static final String ARG_COUNT = "argCount"; + + + + public enum Direction + { + I, + O, + IO; + } + + public class Argument + { + private final LinkedHashMap _map = new LinkedHashMap(); + + public Argument(String name, QMFType type) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + } + + public void setRefPackage(String refPackage) + { + _map.put(REF_PACKAGE, refPackage); + } + + public void setRefClass(String refClass) + { + _map.put(REF_CLASS, refClass); + } + + public void setUnit(String unit) + { + _map.put(UNIT, unit); + } + + public void setMax(Number max) + { + _map.put(MAX, max); + } + + public void setMin(Number min) + { + _map.put(MIN, min); + } + + public void setMaxLength(int len) + { + _map.put(MAX_LENGTH, len); + } + + public void setDefault(Object dflt) + { + _map.put(DEFAULT, dflt); + } + + public void setDescription(String desc) + { + _map.put(DESCRIPTION, desc); + } + + public void setDirection(Direction direction) + { + _map.put(DIRECTION, direction.toString()); + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + + public String getName() + { + return (String) _map.get(NAME); + } + } + + public QMFMethod(String name, String description) + { + _map.put(NAME, name); + _map.put(ARG_COUNT, 0); + if(description != null) + { + _map.put(DESCRIPTION, description); + } + + } + + abstract public QMFMethodInvocation parse(final BBDecoder decoder); + + protected void addArgument(Argument arg) + { + _arguments.add(arg); + _map.put(ARG_COUNT, _arguments.size()); + } + + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + for(Argument arg : _arguments) + { + arg.encode(encoder); + } + } + + public String getName() + { + return (String) _map.get(NAME); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java new file mode 100644 index 0000000000..5348c2783f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +public interface QMFMethodInvocation +{ + QMFMethodResponseCommand execute(T obj, QMFMethodRequestCommand cmd); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java new file mode 100644 index 0000000000..cf27e4b970 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java @@ -0,0 +1,88 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; + +import java.util.UUID; +import java.util.ArrayList; + +public class QMFMethodRequestCommand extends QMFCommand +{ + private QMFMethodInvocation _methodInstance; + private QMFObject _object; + + public QMFMethodRequestCommand(final QMFCommandHeader header, final BBDecoder decoder, final QMFService qmfService) + { + super(header); + UUID objectId = decoder.readUuid(); + String packageName = decoder.readStr8(); + String className = decoder.readStr8(); + byte[] hash = decoder.readBin128(); + String methodName = decoder.readStr8(); + + QMFPackage qmfPackage = qmfService.getPackage(packageName); + QMFClass qmfClass = qmfPackage.getQMFClass(className); + _object = qmfService.getObjectById(qmfClass, objectId); + QMFMethod method = qmfClass.getMethod(methodName); + _methodInstance = method.parse(decoder); + + } + + public void process(final VirtualHost virtualHost, final ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String queueName = message.getMessageHeader().getReplyToRoutingKey(); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = _methodInstance.execute(_object, this); + commands[1] = new QMFCommandCompletionCommand(this); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(queueName, cmd); + + + ArrayList queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java new file mode 100644 index 0000000000..529b04ebdb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFMethodResponseCommand extends QMFCommand +{ + public QMFMethodResponseCommand(final QMFMethodRequestCommand cmd) + { + super( new QMFCommandHeader(cmd.getHeader().getVersion(), + cmd.getHeader().getSeq(), + QMFOperation.METHOD_RESPONSE)); + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint32(0); + encoder.writeStr16("OK"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java new file mode 100644 index 0000000000..d126717fc8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import java.util.UUID; + +public abstract class QMFObject +{ + private long _deleteTime; + + public interface Delegate + { + UUID getId(); + long getCreateTime(); + } + + + private D _delegate; + + protected QMFObject(D delegate) + { + _delegate = delegate; + } + + public D getDelegate() + { + return _delegate; + } + + abstract public C getQMFClass(); + + public final UUID getId() + { + return _delegate.getId(); + } + + public final long getCreateTime() + { + return _delegate.getCreateTime(); + } + + public final void setDeleteTime() + { + _deleteTime = System.currentTimeMillis(); + } + + public final long getDeleteTime() + { + return _deleteTime; + } + + + + abstract public QMFCommand asConfigInfoCmd(long sampleTime); + abstract public QMFCommand asInstrumentInfoCmd(long sampleTime); + abstract public QMFCommand asGetQueryResponseCmd(final QMFGetQueryCommand queryCommand, long sampleTime); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java new file mode 100644 index 0000000000..fefdecb8d7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +import java.util.List; + +public abstract class QMFObjectClass extends QMFClass +{ + public QMFObjectClass(String name, + byte[] schemaHash, + List properties, + List statistics, List methods) + { + super(QMFClass.Type.OBJECT, name, schemaHash, properties, statistics, methods); + } + + public QMFObjectClass(String name, byte[] schemaHash) + { + super(QMFClass.Type.OBJECT, name, schemaHash); + } + + + public abstract T newInstance(S delegate); + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java new file mode 100644 index 0000000000..6736b5d460 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +public enum QMFOperation +{ + + + BROKER_REQUEST('B'), + BROKER_RESPONSE('b'), // This message contains a broker response, sent from the broker in response to a broker request message. + COMMAND_COMPLETION('z'), // This message is sent to indicate the completion of a request. + CLASS_QUERY('Q'), // Class query messages are used by a management console to request a list of schema classes that are known by the management broker. + CLASS_INDICATION('q'), // Sent by the management broker, a class indication notifies the peer of the existence of a schema class. + SCHEMA_REQUEST('S'), // Schema request messages are used to request the full schema details for a class. + SCHEMA_RESPONSE('s'), // Schema response message contain a full description of the schema for a class. + HEARTBEAT_INDEICATION('h'), // This message is published once per publish-interval. It can be used by a client to positively determine which objects did not change during the interval (since updates are not published for objects with no changes). + CONFIG_INDICATION('c'), + INSTRUMENTATION_INDICATION('i'), + GET_QUERY_RESPONSE('g'), // This message contains a content record. Content records contain the values of all properties or statistics in an object. Such records are broadcast on a periodic interval if 1) a change has been made in the value of one of the elements, or 2) if a new management client has bound a queue to the management exchange. + GET_QUERY('G'), // Sent by a management console, a get query requests that the management broker provide content indications for all objects that match the query criteria. + METHOD_REQUEST('M'), // This message contains a method request. + METHOD_RESPONSE('m'), // This message contains a method result. + PACKAGE_QUERY('P'), // This message contains a schema package query request, requesting that the broker dump the list of known packages + PACKAGE_INDICATION('p'), // This message contains a schema package indication, identifying a package known by the broker + AGENT_ATTACH_REUQEST('A'), // This message is sent by a remote agent when it wishes to attach to a management broker + AGENT_ATTACH_RESPONSE('a'), // The management broker sends this response if an attaching remote agent is permitted to join + CONSOLE_ADDED_INDICATION('x'), // This message is sent to all remote agents by the management broker when a new console binds to the management exchange + EVENT('e') + ; + + + private final char _opcode; + + private static final QMFOperation[] OP_CODES = new QMFOperation[256]; + + + QMFOperation(char opcode) + { + _opcode = opcode; + } + + + public char getOpcode() + { + return _opcode; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java new file mode 100644 index 0000000000..681e64b799 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import java.util.Collection; +import java.util.Map; +import java.util.HashMap; + +public class QMFPackage +{ + private final String _name; + private final Map _classes = new HashMap(); + + public QMFPackage(String name) + { + _name = name; + } + + public QMFPackage(String name, Collection classes) + { + this(name); + setClasses(classes); + } + + protected void setClasses(Collection classes) + { + for(QMFClass qmfClass : classes) + { + qmfClass.setPackage(this); + _classes.put(qmfClass.getName(), qmfClass); + } + } + + public String getName() + { + return _name; + } + + public Collection getClasses() + { + return _classes.values(); + } + + public QMFClass getQMFClass(String className) + { + return _classes.get(className); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java new file mode 100644 index 0000000000..7053b80655 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFPackageIndicationCommand extends QMFCommand +{ + private String _supportedSchema; + + public QMFPackageIndicationCommand(QMFPackageQueryCommand qmfPackageQueryCommand, String supportedSchema) + { + super( new QMFCommandHeader(qmfPackageQueryCommand.getHeader().getVersion(), + qmfPackageQueryCommand.getHeader().getSeq(), + QMFOperation.PACKAGE_INDICATION)); + _supportedSchema = supportedSchema; + + } + + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeStr8(_supportedSchema); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java new file mode 100644 index 0000000000..6defd088de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.ArrayList; +import java.util.Collection; + +public class QMFPackageQueryCommand extends QMFCommand +{ + public QMFPackageQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + Collection supportedSchemas = service.getSupportedSchemas(); + + QMFCommand[] commands = new QMFCommand[ supportedSchemas.size() + 1 ]; + + int i = 0; + for(QMFPackage p : supportedSchemas) + { + commands[i++] = new QMFPackageIndicationCommand(this, p.getName()); + } + commands[ commands.length - 1 ] = new QMFCommandCompletionCommand(this); + + + for(QMFCommand cmd : commands) + { + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java new file mode 100644 index 0000000000..5748722afe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java @@ -0,0 +1,123 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; + +import java.util.Map; +import java.util.HashMap; +import java.util.LinkedHashMap; + +public class QMFProperty +{ + private final Map _map = new LinkedHashMap(); + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String ACCESS = "access"; + private static final String INDEX = "index"; + private static final String OPTIONAL = "optional"; + private static final String REF_PACKAGE = "refPackage"; + private static final String REF_CLASS = "refClass"; + private static final String UNIT = "unit"; + private static final String MIN = "min"; + private static final String MAX = "max"; + private static final String MAX_LENGTH = "maxlen"; + private static final String DESCRIPTION = "desc"; + + + public static enum AccessCode + { + RC, + RW, + RO; + + public int codeValue() + { + return ordinal()+1; + } + } + + public QMFProperty(String name, QMFType type, AccessCode accessCode, boolean index, boolean optional) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + _map.put(ACCESS, accessCode.codeValue()); + _map.put(INDEX, index ? 1 : 0); + _map.put(OPTIONAL, optional ? 1 :0); + } + + + public void setQMFClass(QMFClass qmfClass) + { + /* _map.put(REF_CLASS, qmfClass.getName()); + _map.put(REF_PACKAGE, qmfClass.getPackage().getName());*/ + } + + public void setReferencedClass(String refClass) + { + _map.put(REF_CLASS, refClass); + } + + public void setReferencedPackage(String refPackage) + { + _map.put(REF_CLASS, refPackage); + } + + + public String getName() + { + return (String) _map.get(NAME); + } + + + public void setUnit(String unit) + { + _map.put(UNIT, unit); + } + + public void setMin(Number min) + { + _map.put(MIN, min); + } + + public void setMax(Number max) + { + _map.put(MAX, max); + } + + public void setMaxLength(int maxlen) + { + _map.put(MAX_LENGTH, maxlen); + } + + + public void setDescription(String description) + { + _map.put(DESCRIPTION, description); + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java new file mode 100644 index 0000000000..3141676f10 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java @@ -0,0 +1,88 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; + +import java.util.Collection; +import java.util.ArrayList; + +public class QMFSchemaRequestCommand extends QMFCommand +{ + private final String _packageName; + private final String _className; + private final byte[] _hash; + + public QMFSchemaRequestCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + _packageName = decoder.readStr8(); + _className = decoder.readStr8(); + _hash = decoder.readBin128(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + QMFPackage qmfPackage = service.getPackage(_packageName); + QMFClass qmfClass = qmfPackage.getQMFClass( _className ); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = new QMFSchemaResponseCommand(this, qmfClass); + commands[ 1 ] = new QMFCommandCompletionCommand(this); + + + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + + ArrayList queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java new file mode 100644 index 0000000000..fea2430130 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java @@ -0,0 +1,83 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +import java.util.Collection; + +public class QMFSchemaResponseCommand extends QMFCommand +{ + private final QMFClass _qmfClass; + + + public QMFSchemaResponseCommand(QMFSchemaRequestCommand qmfSchemaRequestCommand, QMFClass qmfClass) + { + super(new QMFCommandHeader(qmfSchemaRequestCommand.getHeader().getVersion(), + qmfSchemaRequestCommand.getHeader().getSeq(), + QMFOperation.SCHEMA_RESPONSE)); + _qmfClass = qmfClass; + } + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint8(_qmfClass.getType().getValue()); + encoder.writeStr8(_qmfClass.getPackage().getName()); + encoder.writeStr8(_qmfClass.getName()); + encoder.writeBin128(_qmfClass.getSchemaHash()); + + Collection props = _qmfClass.getProperties(); + Collection stats = _qmfClass.getStatistics(); + Collection methods = _qmfClass.getMethods(); + + encoder.writeUint16(props.size()); + if(_qmfClass.getType() == QMFClass.Type.OBJECT) + { + encoder.writeUint16(stats.size()); + encoder.writeUint16(methods.size()); + } + + for(QMFProperty prop : props) + { + prop.encode(encoder); + } + + if(_qmfClass.getType() == QMFClass.Type.OBJECT) + { + + for(QMFStatistic stat : stats) + { + stat.encode(encoder); + } + + for(QMFMethod method : methods) + { + method.encode(encoder); + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java new file mode 100644 index 0000000000..6a1c24b5a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -0,0 +1,1583 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.qmf.schema.BrokerSchema; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.registry.IApplicationRegistry; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class QMFService implements ConfigStore.ConfigEventListener +{ + + + private IApplicationRegistry _applicationRegistry; + private ConfigStore _configStore; + + + private final Map _supportedSchemas = new HashMap(); + private static final Map _qmfClassMapping = new HashMap(); + + static + { + _qmfClassMapping.put("system", SystemConfigType.getInstance()); + _qmfClassMapping.put("broker", BrokerConfigType.getInstance()); + _qmfClassMapping.put("vhost", VirtualHostConfigType.getInstance()); + _qmfClassMapping.put("exchange", ExchangeConfigType.getInstance()); + _qmfClassMapping.put("queue", QueueConfigType.getInstance()); + _qmfClassMapping.put("binding", BindingConfigType.getInstance()); + _qmfClassMapping.put("connection", ConnectionConfigType.getInstance()); + _qmfClassMapping.put("session", SessionConfigType.getInstance()); + _qmfClassMapping.put("subscription", SubscriptionConfigType.getInstance()); + _qmfClassMapping.put("link", LinkConfigType.getInstance()); + _qmfClassMapping.put("bridge", BridgeConfigType.getInstance()); + } + + private final Map _adapterMap = + new HashMap(); + private final Map _classMap = + new HashMap(); + + + private final ConcurrentHashMap> _managedObjects = + new ConcurrentHashMap>(); + + private final ConcurrentHashMap> _managedObjectsById = + new ConcurrentHashMap>(); + + private static final BrokerSchema PACKAGE = BrokerSchema.getPackage(); + + public static interface Listener + { + public void objectCreated(QMFObject obj); + public void objectDeleted(QMFObject obj); + } + + private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); + + abstract class ConfigObjectAdapter, S extends QMFObjectClass, D extends QMFObject.Delegate, T extends ConfigObjectType, C extends ConfiguredObject> + { + private final T _type; + private final S _qmfClass; + + + protected ConfigObjectAdapter(final T type, final S qmfClass) + { + _type = type; + _qmfClass = qmfClass; + _adapterMap.put(type,this); + _classMap.put(type,qmfClass); + } + + public T getType() + { + return _type; + } + + public S getQMFClass() + { + return _qmfClass; + } + + protected final Q newInstance(D delegate) + { + return _qmfClass.newInstance(delegate); + } + + public abstract Q createQMFObject(C configObject); + } + + private ConfigObjectAdapter _systemObjectAdapter = + new ConfigObjectAdapter(SystemConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SystemClass.class)) + { + + + public BrokerSchema.SystemObject createQMFObject( + final SystemConfig configObject) + { + return newInstance(new SystemDelegate(configObject)); + } + }; + + private ConfigObjectAdapter _brokerObjectAdapter = + new ConfigObjectAdapter(BrokerConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BrokerClass.class)) + { + + public BrokerSchema.BrokerObject createQMFObject( + final BrokerConfig configObject) + { + return newInstance(new BrokerDelegate(configObject)); + } + }; + + private ConfigObjectAdapter _vhostObjectAdapter = + new ConfigObjectAdapter(VirtualHostConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.VhostClass.class)) + { + + public BrokerSchema.VhostObject createQMFObject( + final VirtualHostConfig configObject) + { + return newInstance(new VhostDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _exchangeObjectAdapter = + new ConfigObjectAdapter(ExchangeConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.ExchangeClass.class)) + { + + public BrokerSchema.ExchangeObject createQMFObject( + final ExchangeConfig configObject) + { + return newInstance(new ExchangeDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _queueObjectAdapter = + new ConfigObjectAdapter(QueueConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.QueueClass.class)) + { + + public BrokerSchema.QueueObject createQMFObject( + final QueueConfig configObject) + { + return newInstance(new QueueDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _bindingObjectAdapter = + new ConfigObjectAdapter(BindingConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BindingClass.class)) + { + + public BrokerSchema.BindingObject createQMFObject( + final BindingConfig configObject) + { + return newInstance(new BindingDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _connectionObjectAdapter = + new ConfigObjectAdapter(ConnectionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.ConnectionClass.class)) + { + + public BrokerSchema.ConnectionObject createQMFObject( + final ConnectionConfig configObject) + { + return newInstance(new ConnectionDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _sessionObjectAdapter = + new ConfigObjectAdapter(SessionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SessionClass.class)) + { + + public BrokerSchema.SessionObject createQMFObject( + final SessionConfig configObject) + { + return newInstance(new SessionDelegate(configObject)); + } + }; + + private ConfigObjectAdapter _subscriptionObjectAdapter = + new ConfigObjectAdapter(SubscriptionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SubscriptionClass.class)) + { + + public BrokerSchema.SubscriptionObject createQMFObject( + final SubscriptionConfig configObject) + { + return newInstance(new SubscriptionDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _linkObjectAdapter = + new ConfigObjectAdapter(LinkConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.LinkClass.class)) + { + + public BrokerSchema.LinkObject createQMFObject( + final LinkConfig configObject) + { + return newInstance(new LinkDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter _bridgeObjectAdapter = + new ConfigObjectAdapter(BridgeConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BridgeClass.class)) + { + + public BrokerSchema.BridgeObject createQMFObject( + final BridgeConfig configObject) + { + return newInstance(new BridgeDelegate(configObject)); + } + }; + + + + public QMFService(ConfigStore configStore, IApplicationRegistry applicationRegistry) + { + _configStore = configStore; + _applicationRegistry = applicationRegistry; + registerSchema(PACKAGE); + + for(ConfigObjectType v : _qmfClassMapping.values()) + { + configStore.addConfigEventListener(v, this); + } + init(); + } + + public void close() + { + _managedObjects.clear(); + _managedObjectsById.clear(); + _classMap.clear(); + _adapterMap.clear(); + _supportedSchemas.clear(); + } + + + public void registerSchema(QMFPackage qmfPackage) + { + _supportedSchemas.put(qmfPackage.getName(), qmfPackage); + } + + + public Collection getSupportedSchemas() + { + return _supportedSchemas.values(); + } + + public QMFPackage getPackage(String aPackage) + { + return _supportedSchemas.get(aPackage); + } + + public void onEvent(final ConfiguredObject object, final ConfigStore.Event evt) + { + + switch (evt) + { + case CREATED: + manageObject(object); + break; + + case DELETED: + unmanageObject(object); + break; + } + } + + public QMFObject getObjectById(QMFClass qmfclass, UUID id) + { + ConcurrentHashMap map = _managedObjectsById.get(qmfclass); + if(map != null) + { + return map.get(id); + } + else + { + return null; + } + } + + private void unmanageObject(final ConfiguredObject object) + { + final QMFClass qmfClass = _classMap.get(object.getConfigType()); + + ConcurrentHashMap classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + QMFObject qmfObject = classObjects.remove(object); + if(qmfObject != null) + { + _managedObjectsById.get(qmfClass).remove(object.getId()); + objectRemoved(qmfObject); + } + } + } + + private void manageObject(final ConfiguredObject object) + { + ConfigObjectAdapter adapter = _adapterMap.get(object.getConfigType()); + QMFObject qmfObject = adapter.createQMFObject(object); + final QMFClass qmfClass = qmfObject.getQMFClass(); + ConcurrentHashMap classObjects = _managedObjects.get(qmfClass); + + if(classObjects == null) + { + classObjects = new ConcurrentHashMap(); + if(_managedObjects.putIfAbsent(qmfClass, classObjects) != null) + { + classObjects = _managedObjects.get(qmfClass); + } + } + + ConcurrentHashMap classObjectsById = _managedObjectsById.get(qmfClass); + if(classObjectsById == null) + { + classObjectsById = new ConcurrentHashMap(); + if(_managedObjectsById.putIfAbsent(qmfClass, classObjectsById) != null) + { + classObjectsById = _managedObjectsById.get(qmfClass); + } + } + + classObjectsById.put(object.getId(),qmfObject); + + if(classObjects.putIfAbsent(object, qmfObject) == null); + { + objectAdded(qmfObject); + } + } + + private void objectRemoved(final QMFObject qmfObject) + { + qmfObject.setDeleteTime(); + for(Listener l : _listeners) + { + l.objectDeleted(qmfObject); + } + } + + private void objectAdded(final QMFObject qmfObject) + { + for(Listener l : _listeners) + { + l.objectCreated(qmfObject); + } + } + + public void addListener(Listener l) + { + _listeners.add(l); + } + + public void removeListener(Listener l) + { + _listeners.remove(l); + } + + + private void init() + { + for(QMFClass qmfClass : PACKAGE.getClasses()) + { + ConfigObjectType configType = getConfigType(qmfClass); + if(configType != null) + { + Collection objects = _configStore.getConfiguredObjects(configType); + for(ConfiguredObject object : objects) + { + manageObject(object); + } + } + } + } + + public Collection getObjects(QMFClass qmfClass) + { + ConcurrentHashMap classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + return classObjects.values(); + } + else + { + return Collections.EMPTY_SET; + } + } + + private QMFObject adapt(final ConfiguredObject object) + { + if(object == null) + { + return null; + } + + QMFClass qmfClass = _classMap.get(object.getConfigType()); + ConcurrentHashMap classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + QMFObject qmfObject = classObjects.get(object); + if(qmfObject != null) + { + return qmfObject; + } + } + + return _adapterMap.get(object.getConfigType()).createQMFObject(object); + } + + private ConfigObjectType getConfigType(final QMFClass qmfClass) + { + return _qmfClassMapping.get(qmfClass.getName()); + } + + private static class SystemDelegate implements BrokerSchema.SystemDelegate + { + private final SystemConfig _obj; + + public SystemDelegate(final SystemConfig obj) + { + _obj = obj; + } + + public UUID getSystemId() + { + return _obj.getId(); + } + + public String getOsName() + { + return _obj.getOperatingSystemName(); + } + + public String getNodeName() + { + return _obj.getNodeName(); + } + + public String getRelease() + { + return _obj.getOSRelease(); + } + + public String getVersion() + { + return _obj.getOSVersion(); + } + + public String getMachine() + { + return _obj.getOSArchitecture(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class BrokerDelegate implements BrokerSchema.BrokerDelegate + { + private final BrokerConfig _obj; + + public BrokerDelegate(final BrokerConfig obj) + { + _obj = obj; + } + + public BrokerSchema.SystemObject getSystemRef() + { + return (BrokerSchema.SystemObject) adapt(_obj.getSystem()); + } + + public Integer getPort() + { + return _obj.getPort(); + } + + public Integer getWorkerThreads() + { + return _obj.getWorkerThreads(); + } + + public Integer getMaxConns() + { + return _obj.getMaxConnections(); + } + + public Integer getConnBacklog() + { + return _obj.getConnectionBacklogLimit(); + } + + public Long getStagingThreshold() + { + return _obj.getStagingThreshold(); + } + + public Integer getMgmtPubInterval() + { + return _obj.getManagementPublishInterval(); + } + + public String getVersion() + { + return _obj.getVersion(); + } + + public String getDataDir() + { + return _obj.getDataDirectory(); + } + + public Long getUptime() + { + return (System.currentTimeMillis() - _obj.getCreateTime()) * 1000000L; + } + + public BrokerSchema.BrokerClass.EchoMethodResponseCommand echo(final BrokerSchema.BrokerClass.EchoMethodResponseCommandFactory factory, + final Long sequence, + final String body) + { + return factory.createResponseCommand(sequence, body); + } + + public BrokerSchema.BrokerClass.ConnectMethodResponseCommand connect(final BrokerSchema.BrokerClass.ConnectMethodResponseCommandFactory factory, + final String host, + final Long port, + final Boolean durable, + final String authMechanism, + final String username, + final String password, + final String transport) + { + _obj.createBrokerConnection(transport, host, port.intValue(), durable, authMechanism, username, password); + + return factory.createResponseCommand(); + } + + public BrokerSchema.BrokerClass.QueueMoveMessagesMethodResponseCommand queueMoveMessages(final BrokerSchema.BrokerClass.QueueMoveMessagesMethodResponseCommandFactory factory, + final String srcQueue, + final String destQueue, + final Long qty) + { + // todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class VhostDelegate implements BrokerSchema.VhostDelegate + { + private final VirtualHostConfig _obj; + + public VhostDelegate(final VirtualHostConfig obj) + { + _obj = obj; + } + + public BrokerSchema.BrokerObject getBrokerRef() + { + return (BrokerSchema.BrokerObject) adapt(_obj.getBroker()); + } + + public String getName() + { + return _obj.getName(); + } + + public String getFederationTag() + { + return _obj.getFederationTag(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class ExchangeDelegate implements BrokerSchema.ExchangeDelegate + { + private final ExchangeConfig _obj; + + public ExchangeDelegate(final ExchangeConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getName(); + } + + public String getType() + { + return _obj.getType().getName().toString(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public Boolean getAutoDelete() + { + return _obj.isAutoDelete(); + } + + public BrokerSchema.ExchangeObject getAltExchange() + { + if(_obj.getAlternateExchange() != null) + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getAlternateExchange()); + } + else + { + return null; + } + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public Long getProducerCount() + { + // TODO + return 0l; + } + + public Long getProducerCountHigh() + { + // TODO + return 0l; + } + + public Long getProducerCountLow() + { + // TODO + return 0l; + } + + public Long getBindingCount() + { + return _obj.getBindingCount(); + } + + public Long getBindingCountHigh() + { + return _obj.getBindingCountHigh(); + } + + public Long getBindingCountLow() + { + // TODO + return 0l; + } + + public Long getMsgReceives() + { + return _obj.getMsgReceives(); + } + + public Long getMsgDrops() + { + return getMsgReceives() - getMsgRoutes(); + } + + public Long getMsgRoutes() + { + return _obj.getMsgRoutes(); + } + + public Long getByteReceives() + { + return _obj.getByteReceives(); + } + + public Long getByteDrops() + { + return getByteReceives() - getByteRoutes(); + } + + public Long getByteRoutes() + { + return _obj.getByteRoutes(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class QueueDelegate implements BrokerSchema.QueueDelegate + { + private final QueueConfig _obj; + + public QueueDelegate(final QueueConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getName(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public Boolean getAutoDelete() + { + return _obj.isAutoDelete(); + } + + public Boolean getExclusive() + { + return _obj.isExclusive(); + } + + public BrokerSchema.ExchangeObject getAltExchange() + { + if(_obj.getAlternateExchange() != null) + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getAlternateExchange()); + } + else + { + return null; + } + } + + public Long getMsgTotalEnqueues() + { + return _obj.getReceivedMessageCount(); + } + + public Long getMsgTotalDequeues() + { + return _obj.getMessageDequeueCount(); + } + + public Long getMsgTxnEnqueues() + { + // TODO + return 0l; + } + + public Long getMsgTxnDequeues() + { + // TODO + return 0l; + } + + public Long getMsgPersistEnqueues() + { + return _obj.getPersistentMsgEnqueues(); + } + + public Long getMsgPersistDequeues() + { + return _obj.getPersistentMsgDequeues(); + } + + public Long getMsgDepth() + { + return (long) _obj.getMessageCount(); + } + + public Long getByteDepth() + { + return _obj.getQueueDepth(); + } + + public Long getByteTotalEnqueues() + { + return _obj.getTotalEnqueueSize(); + } + + public Long getByteTotalDequeues() + { + return _obj.getTotalDequeueSize(); + } + + public Long getByteTxnEnqueues() + { + // TODO + return 0l; + } + + public Long getByteTxnDequeues() + { + // TODO + return 0l; + } + + public Long getBytePersistEnqueues() + { + return _obj.getPersistentByteEnqueues(); + } + + public Long getBytePersistDequeues() + { + return _obj.getPersistentByteDequeues(); + } + + public Long getConsumerCount() + { + return (long) _obj.getConsumerCount(); + } + + public Long getConsumerCountHigh() + { + // TODO + return 0l; + } + + public Long getConsumerCountLow() + { + // TODO + return 0l; + } + + public Long getBindingCount() + { + return (long) _obj.getBindingCount(); + } + + public Long getBindingCountHigh() + { + return (long) _obj.getBindingCountHigh(); + } + + public Long getBindingCountLow() + { + // TODO + return 0l; + } + + public Long getUnackedMessages() + { + // TODO + return 0l; + } + + public Long getUnackedMessagesHigh() + { + // TODO + return 0l; + } + + public Long getUnackedMessagesLow() + { + // TODO + return 0l; + } + + public Long getMessageLatencySamples() + { + // TODO + return 0l; + } + + public Long getMessageLatencyMin() + { + // TODO + return 0l; + } + + public Long getMessageLatencyMax() + { + // TODO + return 0l; + } + + public Long getMessageLatencyAverage() + { + // TODO + return 0l; + } + + public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, + final Long request) + { + _obj.purge(request); + return factory.createResponseCommand(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class BindingDelegate implements BrokerSchema.BindingDelegate + { + private final BindingConfig _obj; + + public BindingDelegate(final BindingConfig obj) + { + _obj = obj; + } + + public BrokerSchema.ExchangeObject getExchangeRef() + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getExchange()); + } + + public BrokerSchema.QueueObject getQueueRef() + { + return (BrokerSchema.QueueObject) adapt(_obj.getQueue()); + } + + public String getBindingKey() + { + return _obj.getBindingKey(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public String getOrigin() + { + return _obj.getOrigin(); + } + + public Long getMsgMatched() + { + // TODO + return _obj.getMatches(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class ConnectionDelegate implements BrokerSchema.ConnectionDelegate + { + private final ConnectionConfig _obj; + + public ConnectionDelegate(final ConnectionConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getAddress() + { + return _obj.getAddress(); + } + + public Boolean getIncoming() + { + return _obj.isIncoming(); + } + + public Boolean getSystemConnection() + { + return _obj.isSystemConnection(); + } + + public Boolean getFederationLink() + { + return _obj.isFederationLink(); + } + + public String getAuthIdentity() + { + return _obj.getAuthId(); + } + + public String getRemoteProcessName() + { + return _obj.getRemoteProcessName(); + } + + public Long getRemotePid() + { + Integer remotePID = _obj.getRemotePID(); + return remotePID == null ? null : (long) remotePID; + } + + public Long getRemoteParentPid() + { + Integer remotePPID = _obj.getRemoteParentPID(); + return remotePPID == null ? null : (long) remotePPID; + + } + + public Boolean getClosing() + { + return false; + } + + public Long getFramesFromClient() + { + // TODO + return 0l; + } + + public Long getFramesToClient() + { + // TODO + return 0l; + } + + public Long getBytesFromClient() + { + // TODO + return 0l; + } + + public Long getBytesToClient() + { + // TODO + return 0l; + } + + public BrokerSchema.ConnectionClass.CloseMethodResponseCommand close(final BrokerSchema.ConnectionClass.CloseMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; + } + } + + private class SessionDelegate implements BrokerSchema.SessionDelegate + { + private final SessionConfig _obj; + + public SessionDelegate(final SessionConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getSessionName(); + } + + public Integer getChannelId() + { + return _obj.getChannel(); + } + + public BrokerSchema.ConnectionObject getConnectionRef() + { + return (BrokerSchema.ConnectionObject) adapt(_obj.getConnectionConfig()); + } + + public Long getDetachedLifespan() + { + return _obj.getDetachedLifespan(); + } + + public Boolean getAttached() + { + return _obj.isAttached(); + } + + public Long getExpireTime() + { + return _obj.getExpiryTime(); + } + + public Long getMaxClientRate() + { + return _obj.getMaxClientRate(); + } + + public Long getFramesOutstanding() + { + // TODO + return 0l; + } + + public Long getTxnStarts() + { + // TODO + return 0l; + } + + public Long getTxnCommits() + { + // TODO + return 0l; + } + + public Long getTxnRejects() + { + // TODO + return 0l; + } + + public Long getTxnCount() + { + // TODO + return 0l; + } + + public Long getClientCredit() + { + // TODO + return 0l; + } + + public BrokerSchema.SessionClass.SolicitAckMethodResponseCommand solicitAck(final BrokerSchema.SessionClass.SolicitAckMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.DetachMethodResponseCommand detach(final BrokerSchema.SessionClass.DetachMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.ResetLifespanMethodResponseCommand resetLifespan(final BrokerSchema.SessionClass.ResetLifespanMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.CloseMethodResponseCommand close(final BrokerSchema.SessionClass.CloseMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + } + + private class SubscriptionDelegate implements BrokerSchema.SubscriptionDelegate + { + private final SubscriptionConfig _obj; + + private SubscriptionDelegate(final SubscriptionConfig obj) + { + _obj = obj; + } + + + public BrokerSchema.SessionObject getSessionRef() + { + return (BrokerSchema.SessionObject) adapt(_obj.getSessionConfig()); + } + + public BrokerSchema.QueueObject getQueueRef() + { + return (BrokerSchema.QueueObject) adapt(_obj.getQueue()); + } + + public String getName() + { + return _obj.getName(); + } + + public Boolean getBrowsing() + { + return _obj.isBrowsing(); + } + + public Boolean getAcknowledged() + { + return _obj.isExplicitAcknowledge(); + } + + public Boolean getExclusive() + { + return _obj.isExclusive(); + } + + public String getCreditMode() + { + return _obj.getCreditMode(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public Long getDelivered() + { + // TODO + return 0l; + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + } + + private class BridgeDelegate implements BrokerSchema.BridgeDelegate + { + private final BridgeConfig _obj; + + private BridgeDelegate(final BridgeConfig obj) + { + _obj = obj; + } + + public BrokerSchema.LinkObject getLinkRef() + { + return (BrokerSchema.LinkObject) adapt(_obj.getLink()); + } + + public Integer getChannelId() + { + return _obj.getChannelId(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public String getSrc() + { + return _obj.getSource(); + } + + public String getDest() + { + return _obj.getDestination(); + } + + public String getKey() + { + return _obj.getKey(); + } + + public Boolean getSrcIsQueue() + { + return _obj.isQueueBridge(); + } + + public Boolean getSrcIsLocal() + { + return _obj.isLocalSource(); + } + + public String getTag() + { + return _obj.getTag(); + } + + public String getExcludes() + { + return _obj.getExcludes(); + } + + public Boolean getDynamic() + { + return _obj.isDynamic(); + } + + public Integer getSync() + { + return _obj.getAckBatching(); + } + + public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory) + { + return null; + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class LinkDelegate implements BrokerSchema.LinkDelegate + { + private final LinkConfig _obj; + + private LinkDelegate(final LinkConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getHost() + { + return _obj.getHost(); + } + + public Integer getPort() + { + return _obj.getPort(); + } + + public String getTransport() + { + return _obj.getTransport(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public String getState() + { + // TODO + return ""; + } + + public String getLastError() + { + // TODO + return ""; + } + + public BrokerSchema.LinkClass.CloseMethodResponseCommand close(final BrokerSchema.LinkClass.CloseMethodResponseCommandFactory factory) + { + _obj.close(); + return factory.createResponseCommand(); + } + + public BrokerSchema.LinkClass.BridgeMethodResponseCommand bridge(final BrokerSchema.LinkClass.BridgeMethodResponseCommandFactory factory, + final Boolean durable, + final String src, + final String dest, + final String key, + final String tag, + final String excludes, + final Boolean srcIsQueue, + final Boolean srcIsLocal, + final Boolean dynamic, + final Integer sync) + { + _obj.createBridge(durable, dynamic, srcIsQueue, srcIsLocal, src, dest, key, tag, excludes); + return factory.createResponseCommand(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java new file mode 100644 index 0000000000..89d650e03b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; + +import java.util.LinkedHashMap; + +public class QMFStatistic +{ + private final LinkedHashMap _map = new LinkedHashMap(); + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String UNIT = "unit"; + private static final String DESCRIPTION = "desc"; + + + public QMFStatistic(String name, QMFType type, String unit, String description) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + if(unit != null) + { + _map.put(UNIT, unit); + } + if(description != null) + { + _map.put(DESCRIPTION, description); + } + + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + + public String getName() + { + return (String) _map.get(NAME); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java new file mode 100644 index 0000000000..0e01c27db5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qmf; + +public enum QMFType +{ + + UINT8, + UINT16, + UINT32, + UINT64, + UNKNOWN, + STR8, + STR16, + ABSTIME, + DELTATIME, + OBJECTREFERENCE, + BOOLEAN, + FLOAT, + DOUBLE, + UUID, + MAP, + INT8, + INT16, + INT32, + INT64, + OBJECT, + LIST, + ARRAY; + + public int codeValue() + { + return ordinal()+1; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 333c1b9cac..1b03ee2334 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,45 +20,72 @@ */ package org.apache.qpid.server; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SessionConfigType; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.txn.*; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.messages.ChannelMessages; -import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.logging.actors.AMQPChannelActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ChannelMessages; +import org.apache.qpid.server.logging.subjects.ChannelLogSubject; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolEngine; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; -public class AMQChannel +public class AMQChannel implements SessionConfig { public static final int DEFAULT_PREFETCH = 5000; @@ -123,6 +150,7 @@ public class AMQChannel private List _resendList = new ArrayList(); private static final AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible."); + private final UUID _id; public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -132,15 +160,22 @@ public class AMQChannel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); - + _id = getConfigStore().createId(); _actor.message(ChannelMessages.CHN_CREATE()); + getConfigStore().addConfiguredObject(this); + _messageStore = messageStore; // by default the session is non-transactional _transaction = new AutoCommitTransaction(_messageStore); } + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { @@ -220,7 +255,7 @@ public class AMQChannel try { - final ArrayList destinationQueues = _currentMessage.getDestinationQueues(); + final ArrayList destinationQueues = _currentMessage.getDestinationQueues(); if(!checkMessageUserId(_currentMessage.getContentHeader())) { @@ -411,6 +446,8 @@ public class AMQChannel _logger.error("Caught AMQException whilst attempting to reque:" + e); } + getConfigStore().removeConfiguredObject(this); + } private void setClosing(boolean closing) @@ -970,10 +1007,10 @@ public class AMQChannel private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; - private ArrayList _destinationQueues; + private ArrayList _destinationQueues; public MessageDeliveryAction(IncomingMessage currentMessage, - ArrayList destinationQueues) + ArrayList destinationQueues) { _incommingMessage = currentMessage; _destinationQueues = destinationQueues; @@ -988,53 +1025,24 @@ public class AMQChannel final AMQMessage amqMessage = createAMQMessage(_incommingMessage); MessageReference ref = amqMessage.newReference(); - for(AMQQueue queue : _destinationQueues) + for(final BaseQueue queue : _destinationQueues) { + BaseQueue.PostEnqueueAction action; - QueueEntry entry = queue.enqueue(amqMessage); - queue.checkCapacity(AMQChannel.this); - - - if(immediate && !entry.getDeliveredToConsumer() && entry.acquire()) + if(immediate) { + action = new ImmediateAction(queue); + } + else + { + action = null; + } + queue.enqueue(amqMessage, action); - ServerTransaction txn = new LocalTransaction(_messageStore); - Collection entries = new ArrayList(1); - entries.add(entry); - final AMQMessage message = (AMQMessage) entry.getMessage(); - txn.dequeue(queue, entry.getMessage(), - new MessageAcknowledgeAction(entries) - { - @Override - public void postCommit() - { - try - { - final - ProtocolOutputConverter outputConverter = - _session.getProtocolOutputConverter(); - - outputConverter.writeReturn(message.getMessagePublishInfo(), - message.getContentHeaderBody(), - message, - _channelId, - AMQConstant.NO_CONSUMERS.getCode(), - IMMEDIATE_DELIVERY_REPLY_TEXT); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - super.postCommit(); - } - } - ); - txn.commit(); - - - - + if(queue instanceof AMQQueue) + { + ((AMQQueue)queue).checkCapacity(AMQChannel.this); } } @@ -1057,6 +1065,60 @@ public class AMQChannel // Maybe keep track of entries that were created and then delete them here in case of failure // to in memory enqueue } + + private class ImmediateAction implements BaseQueue.PostEnqueueAction + { + private final BaseQueue _queue; + + public ImmediateAction(BaseQueue queue) + { + _queue = queue; + } + + public void onEnqueue(QueueEntry entry) + { + if (!entry.getDeliveredToConsumer() && entry.acquire()) + { + + + ServerTransaction txn = new LocalTransaction(_messageStore); + Collection entries = new ArrayList(1); + entries.add(entry); + final AMQMessage message = (AMQMessage) entry.getMessage(); + txn.dequeue(_queue, entry.getMessage(), + new MessageAcknowledgeAction(entries) + { + @Override + public void postCommit() + { + try + { + final + ProtocolOutputConverter outputConverter = + _session.getProtocolOutputConverter(); + + outputConverter.writeReturn(message.getMessagePublishInfo(), + message.getContentHeaderBody(), + message, + _channelId, + AMQConstant.NO_CONSUMERS.getCode(), + IMMEDIATE_DELIVERY_REPLY_TEXT); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + super.postCommit(); + } + } + ); + txn.commit(); + + + } + + } + } } private class MessageAcknowledgeAction implements ServerTransaction.Action @@ -1163,7 +1225,7 @@ public class AMQChannel if(_blocking.compareAndSet(false,true)) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getName().toString())); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getNameShortString().toString())); flow(false); } } @@ -1188,9 +1250,70 @@ public class AMQChannel AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow); _session.writeFrame(responseBody.generateFrame(_channelId)); } - + public boolean getBlocking() { return _blocking.get(); } + + public VirtualHost getVirtualHost() + { + return getProtocolSession().getVirtualHost(); + } + + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public SessionConfigType getConfigType() + { + return SessionConfigType.getInstance(); + } + + public int getChannel() + { + return getChannelId(); + } + + public boolean isAttached() + { + return true; + } + + public long getDetachedLifespan() + { + return 0; + } + + public ConnectionConfig getConnectionConfig() + { + return (AMQProtocolEngine)getProtocolSession(); + } + + public Long getExpiryTime() + { + return null; + } + + public Long getMaxClientRate() + { + return null; + } + + public boolean isDurable() + { + return false; + } + + public UUID getId() + { + return _id; + } + + public String getSessionName() + { + return getConnectionConfig().getAddress() + "/" + getChannelId(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java new file mode 100644 index 0000000000..0b689c16a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java @@ -0,0 +1,117 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.binding; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +public class Binding +{ + private final String _bindingKey; + private final AMQQueue _queue; + private final Exchange _exchange; + private final Map _arguments; + private final UUID _id; + private final AtomicLong _matches = new AtomicLong(); + + Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) + { + _id = id; + _bindingKey = bindingKey; + _queue = queue; + _exchange = exchange; + _arguments = arguments == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(arguments); + } + + public UUID getId() + { + return _id; + } + + public String getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public Exchange getExchange() + { + return _exchange; + } + + public Map getArguments() + { + return _arguments; + } + + public void incrementMatches() + { + _matches.incrementAndGet(); + } + + public long getMatches() + { + return _matches.get(); + } + + boolean isDurable() + { + return _queue.isDurable() && _exchange.isDurable(); + } + + @Override + public boolean equals(final Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Binding binding = (Binding) o; + + if (!_bindingKey.equals(binding._bindingKey)) return false; + if (!_exchange.equals(binding._exchange)) return false; + if (!_queue.equals(binding._queue)) return false; + + return true; + } + + @Override + public int hashCode() + { + int result = _bindingKey.hashCode(); + result = 31 * result + _queue.hashCode(); + result = 31 * result + _exchange.hashCode(); + return result; + } + + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java new file mode 100644 index 0000000000..e11af5d553 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -0,0 +1,290 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.binding; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.configuration.BindingConfig; +import org.apache.qpid.server.configuration.BindingConfigType; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BindingMessages; +import org.apache.qpid.server.logging.subjects.BindingLogSubject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BindingFactory +{ + + private final VirtualHost _virtualHost; + private final DurableConfigurationStore.Source _configSource; + private final Exchange _defaultExchange; + + private final ConcurrentHashMap _bindings = new ConcurrentHashMap(); + + + public BindingFactory(final VirtualHost vhost) + { + this(vhost,vhost.getExchangeRegistry().getDefaultExchange()); + } + + public BindingFactory(final DurableConfigurationStore.Source configSource, final Exchange defaultExchange) + { + _configSource = configSource; + _defaultExchange = defaultExchange; + if(configSource instanceof VirtualHost) + { + _virtualHost = (VirtualHost) configSource; + } + else + { + _virtualHost = null; + } + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + + + private final class BindingImpl extends Binding implements AMQQueue.Task, Exchange.Task, BindingConfig + { + private final BindingLogSubject _logSubject; + //TODO + private long _createTime = System.currentTimeMillis(); + + private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) + { + super(queue.getVirtualHost().getConfigStore().createId(),bindingKey, queue, exchange, arguments); + _logSubject = new BindingLogSubject(bindingKey,exchange,queue); + + } + + + public void doTask(final AMQQueue queue) throws AMQException + { + removeBinding(this); + } + + public void onClose(final Exchange exchange) + { + removeBinding(this); + } + + void logCreation() + { + CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(getArguments()), getArguments() != null && !getArguments().isEmpty())); + } + + void logDestruction() + { + CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); + } + + public String getOrigin() + { + return (String) getArguments().get("qpid.fed.origin"); + } + + public long getCreateTime() + { + return _createTime; + } + + public BindingConfigType getConfigType() + { + return BindingConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public boolean isDurable() + { + return getQueue().isDurable() && getExchange().isDurable(); + } + + } + + + + public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) + { + return makeBinding(bindingKey, queue, exchange, arguments, false, false); + } + + + public boolean replaceBinding(final String bindingKey, + final AMQQueue queue, + final Exchange exchange, + final Map arguments) + { + return makeBinding(bindingKey, queue, exchange, arguments, false, true); + } + + private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments, boolean restore, boolean force) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); + BindingImpl existingMapping = _bindings.putIfAbsent(b,b); + if(existingMapping == null || force) + { + if(existingMapping != null) + { + removeBinding(existingMapping); + } + + if(b.isDurable() && !restore) + { + try + { + _configSource.getDurableConfigurationStore().bindQueue(exchange,new AMQShortString(bindingKey),queue,FieldTable.convertToFieldTable(arguments)); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + queue.addQueueDeleteTask(b); + exchange.addCloseTask(b); + queue.addBinding(b); + exchange.addBinding(b); + getConfigStore().addConfiguredObject(b); + b.logCreation(); + return true; + } + else + { + return false; + } + + + } + + private ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map argumentMap) + { + makeBinding(bindingKey,queue,exchange,argumentMap,true, false); + } + + public void removeBinding(final Binding b) + { + removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments()); + } + + + public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments)); + + if(b != null) + { + exchange.removeBinding(b); + queue.removeBinding(b); + exchange.removeCloseTask(b); + queue.removeQueueDeleteTask(b); + + if(b.isDurable()) + { + try + { + _configSource.getDurableConfigurationStore().unbindQueue(exchange, + new AMQShortString(bindingKey), + queue, + FieldTable.convertToFieldTable(arguments)); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + b.logDestruction(); + getConfigStore().removeConfiguredObject(b); + + } + + return b; + } + + public Binding getBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); + return _bindings.get(b); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java new file mode 100644 index 0000000000..9414edcec4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.Map; + + +public interface BindingConfig extends ConfiguredObject +{ + + ExchangeConfig getExchange(); + + QueueConfig getQueue(); + + String getBindingKey(); + + Map getArguments(); + + String getOrigin(); + + long getCreateTime(); + + long getMatches(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java new file mode 100644 index 0000000000..5cd064ff42 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class BindingConfigType extends ConfigObjectType +{ + private static final List> BINDING_PROPERTIES = new ArrayList>(); + + public static interface BindingProperty extends ConfigProperty + { + } + + private abstract static class BindingReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements BindingProperty + { + public BindingReadWriteProperty(String name) + { + super(name); + BINDING_PROPERTIES.add(this); + } + } + + private abstract static class BindingReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements BindingProperty + { + public BindingReadOnlyProperty(String name) + { + super(name); + BINDING_PROPERTIES.add(this); + } + } + + public static final BindingReadOnlyProperty EXCHANGE_PROPERTY = new BindingReadOnlyProperty("exchange") + { + public ExchangeConfig getValue(BindingConfig object) + { + return object.getExchange(); + } + }; + + public static final BindingReadOnlyProperty QUEUE_PROPERTY = new BindingReadOnlyProperty("queue") + { + public QueueConfig getValue(BindingConfig object) + { + return object.getQueue(); + } + }; + + public static final BindingReadOnlyProperty BINDING_KEY_PROPERTY = new BindingReadOnlyProperty("bindingKey") + { + public String getValue(BindingConfig object) + { + return object.getBindingKey(); + } + }; + + public static final BindingReadOnlyProperty> ARGUMENTS = new BindingReadOnlyProperty>("arguments") + { + public Map getValue(BindingConfig object) + { + return object.getArguments(); + } + }; + + public static final BindingReadOnlyProperty ORIGIN_PROPERTY = new BindingReadOnlyProperty("origin") + { + public String getValue(BindingConfig object) + { + return object.getOrigin(); + } + }; + + private static final BindingConfigType INSTANCE = new BindingConfigType(); + + private BindingConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(BINDING_PROPERTIES); + } + + public static BindingConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java new file mode 100644 index 0000000000..f999bf4578 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface BridgeConfig extends ConfiguredObject +{ + + boolean isDynamic(); + + boolean isQueueBridge(); + + boolean isLocalSource(); + + String getSource(); + + String getDestination(); + + String getKey(); + + String getTag(); + + String getExcludes(); + + LinkConfig getLink(); + + Integer getChannelId(); + + int getAckBatching(); + + long getCreateTime(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java new file mode 100644 index 0000000000..a8d3cd9ec3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class BridgeConfigType extends ConfigObjectType +{ + private static final List> BRIDGE_PROPERTIES = new ArrayList>(); + + public static interface BridgeProperty extends ConfigProperty + { + } + + private abstract static class BridgeReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements BridgeProperty + { + public BridgeReadWriteProperty(String name) + { + super(name); + BRIDGE_PROPERTIES.add(this); + } + } + + private abstract static class BridgeReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements BridgeProperty + { + public BridgeReadOnlyProperty(String name) + { + super(name); + BRIDGE_PROPERTIES.add(this); + } + } + + public static final BridgeReadOnlyProperty LINK_PROPERTY = new BridgeReadOnlyProperty("link") + { + public LinkConfig getValue(BridgeConfig object) + { + return object.getLink(); + } + }; + + public static final BridgeReadOnlyProperty CHANNEL_ID_PROPERTY = new BridgeReadOnlyProperty("channelId") + { + public Integer getValue(BridgeConfig object) + { + return object.getChannelId(); + } + }; + + public static final BridgeReadOnlyProperty DURABLE_PROPERTY = new BridgeReadOnlyProperty("durable") + { + public Boolean getValue(BridgeConfig object) + { + return object.isDurable(); + } + }; + + public static final BridgeReadOnlyProperty SOURCE_PROPERTY = new BridgeReadOnlyProperty("source") + { + public String getValue(BridgeConfig object) + { + return object.getSource(); + } + }; + + public static final BridgeReadOnlyProperty DESTINATION_PROPERTY = new BridgeReadOnlyProperty("destination") + { + public String getValue(BridgeConfig object) + { + return object.getDestination(); + } + }; + + public static final BridgeReadOnlyProperty KEY_PROPERTY = new BridgeReadOnlyProperty("key") + { + public String getValue(BridgeConfig object) + { + return object.getKey(); + } + }; + + public static final BridgeReadOnlyProperty QUEUE_BRIDGE_PROPERTY = new BridgeReadOnlyProperty("queueBridge") + { + public Boolean getValue(BridgeConfig object) + { + return object.isQueueBridge(); + } + }; + + public static final BridgeReadOnlyProperty LOCAL_SOURCE_PROPERTY = new BridgeReadOnlyProperty("localSource") + { + public Boolean getValue(BridgeConfig object) + { + return object.isLocalSource(); + } + }; + + public static final BridgeReadOnlyProperty TAG_PROPERTY = new BridgeReadOnlyProperty("tag") + { + public String getValue(BridgeConfig object) + { + return object.getTag(); + } + }; + + public static final BridgeReadOnlyProperty EXCLUDES_PROPERTY = new BridgeReadOnlyProperty("excludes") + { + public String getValue(BridgeConfig object) + { + return object.getExcludes(); + } + }; + + public static final BridgeReadOnlyProperty DYNAMIC_PROPERTY = new BridgeReadOnlyProperty("dynamic") + { + public Boolean getValue(BridgeConfig object) + { + return object.isDynamic(); + } + }; + + public static final BridgeReadOnlyProperty ACK_BATCHING_PROPERTY = new BridgeReadOnlyProperty("ackBatching") + { + public Integer getValue(BridgeConfig object) + { + return object.getAckBatching(); + } + }; + + + private static final BridgeConfigType INSTANCE = new BridgeConfigType(); + + private BridgeConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(BRIDGE_PROPERTIES); + } + + public static BridgeConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java new file mode 100644 index 0000000000..4f74a72344 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + + +public interface BrokerConfig extends ConfiguredObject +{ + void setSystem(SystemConfig system); + + SystemConfig getSystem(); + + Integer getPort(); + + Integer getWorkerThreads(); + + Integer getMaxConnections(); + + Integer getConnectionBacklogLimit(); + + Long getStagingThreshold(); + + Integer getManagementPublishInterval(); + + String getVersion(); + + String getDataDirectory(); + + void addVirtualHost(VirtualHostConfig virtualHost); + + long getCreateTime(); + + void createBrokerConnection(String transport, + String host, + int port, + boolean durable, + String authMechanism, + String username, String password); + + String getFederationTag(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java new file mode 100644 index 0000000000..82b2fc82d2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java @@ -0,0 +1,143 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.*; +import java.io.File; + +public final class BrokerConfigType extends ConfigObjectType +{ + private static final List> BROKER_PROPERTIES = new ArrayList>(); + + public static interface BrokerProperty extends ConfigProperty + { + } + + private abstract static class BrokerReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements BrokerProperty + { + public BrokerReadWriteProperty(String name) + { + super(name); + BROKER_PROPERTIES.add(this); + } + } + + private abstract static class BrokerReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements BrokerProperty + { + public BrokerReadOnlyProperty(String name) + { + super(name); + BROKER_PROPERTIES.add(this); + } + } + + public static final BrokerReadOnlyProperty SYSTEM_PROPERTY = new BrokerReadOnlyProperty("system") + { + public SystemConfig getValue(BrokerConfig object) + { + return object.getSystem(); + } + }; + + public static final BrokerReadOnlyProperty PORT_PROPERTY = new BrokerReadOnlyProperty("port") + { + public Integer getValue(BrokerConfig object) + { + return object.getPort(); + } + }; + + public static final BrokerReadOnlyProperty WORKER_THREADS_PROPERTY = new BrokerReadOnlyProperty("workerThreads") + { + public Integer getValue(BrokerConfig object) + { + return object.getWorkerThreads(); + } + }; + + public static final BrokerReadOnlyProperty MAX_CONNECTIONS_PROPERTY = new BrokerReadOnlyProperty("maxConnections") + { + public Integer getValue(BrokerConfig object) + { + return object.getMaxConnections(); + } + }; + + public static final BrokerReadOnlyProperty CONNECTION_BACKLOG_LIMIT_PROPERTY = new BrokerReadOnlyProperty("connectionBacklog") + { + public Integer getValue(BrokerConfig object) + { + return object.getConnectionBacklogLimit(); + } + }; + + public static final BrokerReadOnlyProperty STAGING_THRESHOLD_PROPERTY = new BrokerReadOnlyProperty("stagingThreshold") + { + public Long getValue(BrokerConfig object) + { + return object.getStagingThreshold(); + } + }; + + public static final BrokerReadOnlyProperty MANAGEMENT_PUBLISH_INTERVAL_PROPERTY = new BrokerReadOnlyProperty("mgmtPublishInterval") + { + public Integer getValue(BrokerConfig object) + { + return object.getManagementPublishInterval(); + } + }; + + public static final BrokerReadOnlyProperty VERSION_PROPERTY = new BrokerReadOnlyProperty("version") + { + public String getValue(BrokerConfig object) + { + return object.getVersion(); + } + }; + + public static final BrokerReadOnlyProperty DATA_DIR_PROPERTY = new BrokerReadOnlyProperty("dataDirectory") + { + public String getValue(BrokerConfig object) + { + return object.getDataDirectory(); + } + }; + + private static final BrokerConfigType INSTANCE = new BrokerConfigType(); + + private BrokerConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(BROKER_PROPERTIES); + } + + public static BrokerConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java new file mode 100644 index 0000000000..c45aaaf1ee --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.Collection; + +public abstract class ConfigObjectType, C extends ConfiguredObject> +{ + public abstract Collection> getProperties(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java new file mode 100644 index 0000000000..2d88ba00a0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface ConfigProperty, C extends ConfiguredObject, S> +{ + public String getName(); + + public S getValue(C object); + + public void setValue(C object, S value); + + public void clearValue(C object); + + public abstract static class ReadWriteConfigProperty, C extends ConfiguredObject,S> implements ConfigProperty + { + private final String _name; + + protected ReadWriteConfigProperty(String name) + { + _name = name; + } + + public final String getName() + { + return _name; + } + } + + public abstract static class ReadOnlyConfigProperty, C extends ConfiguredObject, S> extends ReadWriteConfigProperty + { + protected ReadOnlyConfigProperty(String name) + { + super(name); + } + + public final void setValue(C object, S value) + { + throw new UnsupportedOperationException("Cannot set value '"+getName()+"' as this property is read-only"); + } + + public final void clearValue(C object) + { + throw new UnsupportedOperationException("Cannot set value '"+getName()+"' as this property is read-only"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java new file mode 100644 index 0000000000..572d886c18 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java @@ -0,0 +1,184 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.UUID; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; + +public class ConfigStore +{ + private ConcurrentHashMap> _typeMap = + new ConcurrentHashMap>(); + + private ConcurrentHashMap> _listenerMap = + new ConcurrentHashMap>(); + + private SystemConfig _root; + + private final AtomicLong _objectIdSource = new AtomicLong(0l); + + + public enum Event + { + CREATED, DELETED; + } + + public interface ConfigEventListener, C extends ConfiguredObject> + { + void onEvent(C object, Event evt); + } + + private ConfigStore() + { + } + + public , C extends ConfiguredObject> ConfiguredObject getConfiguredObject(ConfigObjectType type, UUID id) + { + ConcurrentHashMap typeMap = _typeMap.get(type); + if(typeMap != null) + { + return typeMap.get(id); + } + else + { + return null; + } + + } + + public , C extends ConfiguredObject> Collection getConfiguredObjects(ConfigObjectType type) + { + ConcurrentHashMap typeMap = _typeMap.get(type); + if(typeMap != null) + { + return typeMap.values(); + } + else + { + return Collections.EMPTY_LIST; + } + + } + + public , C extends ConfiguredObject> void addConfiguredObject(ConfiguredObject object) + { + ConcurrentHashMap typeMap = _typeMap.get(object.getConfigType()); + if(typeMap == null) + { + typeMap = new ConcurrentHashMap(); + ConcurrentHashMap oldMap = _typeMap.putIfAbsent(object.getConfigType(), typeMap); + if(oldMap != null) + { + typeMap = oldMap; + } + + } + + typeMap.put(object.getId(), object); + sendEvent(Event.CREATED, object); + } + + + public , C extends ConfiguredObject> void removeConfiguredObject(ConfiguredObject object) + { + ConcurrentHashMap typeMap = _typeMap.get(object.getConfigType()); + if(typeMap != null) + { + typeMap.remove(object.getId()); + sendEvent(Event.DELETED, object); + } + } + + public , C extends ConfiguredObject> void addConfigEventListener(T type, ConfigEventListener listener) + { + CopyOnWriteArrayList listeners = _listenerMap.get(type); + if(listeners == null) + { + listeners = new CopyOnWriteArrayList(); + CopyOnWriteArrayList oldListeners = _listenerMap.putIfAbsent(type, listeners); + if(oldListeners != null) + { + listeners = oldListeners; + } + + } + + listeners.add(listener); + + } + + public , C extends ConfiguredObject> void removeConfigEventListener(T type, ConfigEventListener listener) + { + CopyOnWriteArrayList listeners = _listenerMap.get(type); + if(listeners != null) + { + listeners.remove(listener); + } + } + + private void sendEvent(Event e, ConfiguredObject o) + { + CopyOnWriteArrayList listeners = _listenerMap.get(o.getConfigType()); + if(listeners != null) + { + for(ConfigEventListener listener : listeners) + { + listener.onEvent(o, e); + } + } + } + + public synchronized boolean setRoot(SystemConfig object) + { + if(_root == null) + { + _root = object; + addConfiguredObject(object); + return true; + } + else + { + return false; + } + } + + public UUID createId() + { + return new UUID(0l, _objectIdSource.getAndIncrement()); + } + + + public SystemConfig getRoot() + { + return _root; + } + + public static ConfigStore newInstance() + { + return new ConfigStore(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java new file mode 100644 index 0000000000..dd116ea29a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.UUID; + +public interface ConfiguredObject, C extends ConfiguredObject> +{ + public UUID getId(); + + public T getConfigType(); + + public ConfiguredObject getParent(); + + public boolean isDurable(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java new file mode 100644 index 0000000000..95fb7d39a1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface ConnectionConfig extends ConfiguredObject +{ + VirtualHostConfig getVirtualHost(); + + String getAddress(); + + Boolean isIncoming(); + + Boolean isSystemConnection(); + + Boolean isFederationLink(); + + String getAuthId(); + + String getRemoteProcessName(); + + Integer getRemotePID(); + + Integer getRemoteParentPID(); + + ConfigStore getConfigStore(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java new file mode 100644 index 0000000000..9750b12dea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java @@ -0,0 +1,145 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class ConnectionConfigType extends ConfigObjectType +{ + private static final List> CONNECTION_PROPERTIES = new ArrayList>(); + + public static interface ConnectionProperty extends ConfigProperty + { + } + + private abstract static class ConnectionReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements ConnectionProperty + { + public ConnectionReadWriteProperty(String name) + { + super(name); + CONNECTION_PROPERTIES.add(this); + } + } + + private abstract static class ConnectionReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements ConnectionProperty + { + public ConnectionReadOnlyProperty(String name) + { + super(name); + CONNECTION_PROPERTIES.add(this); + } + } + + public static final ConnectionReadOnlyProperty VIRTUAL_HOST_PROPERTY = new ConnectionReadOnlyProperty("virtualHost") + { + public VirtualHostConfig getValue(ConnectionConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final ConnectionReadOnlyProperty ADDRESS_PROPERTY = new ConnectionReadOnlyProperty("address") + { + public String getValue(ConnectionConfig object) + { + return object.getAddress(); + } + }; + + public static final ConnectionReadOnlyProperty INCOMING_PROPERTY = new ConnectionReadOnlyProperty("incoming") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isIncoming(); + } + }; + + public static final ConnectionReadOnlyProperty SYSTEM_CONNECTION_PROPERTY = new ConnectionReadOnlyProperty("systemConnection") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isSystemConnection(); + } + }; + + public static final ConnectionReadOnlyProperty FEDERATION_LINK_PROPERTY = new ConnectionReadOnlyProperty("federationLink") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isFederationLink(); + } + }; + + public static final ConnectionReadOnlyProperty AUTH_ID_PROPERTY = new ConnectionReadOnlyProperty("authId") + { + public String getValue(ConnectionConfig object) + { + return object.getAuthId(); + } + }; + + public static final ConnectionReadOnlyProperty REMOTE_PROCESS_NAME_PROPERTY = new ConnectionReadOnlyProperty("remoteProcessName") + { + public String getValue(ConnectionConfig object) + { + return object.getRemoteProcessName(); + } + }; + + + public static final ConnectionReadOnlyProperty REMOTE_PID_PROPERTY = new ConnectionReadOnlyProperty("remotePid") + { + public Integer getValue(ConnectionConfig object) + { + return object.getRemotePID(); + } + }; + + public static final ConnectionReadOnlyProperty REMOTE_PARENT_PID_PROPERTY = new ConnectionReadOnlyProperty("remoteParentPid") + { + public Integer getValue(ConnectionConfig object) + { + return object.getRemoteParentPID(); + } + }; + + private static final ConnectionConfigType INSTANCE = new ConnectionConfigType(); + + private ConnectionConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(CONNECTION_PROPERTIES); + } + + public static ConnectionConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java new file mode 100644 index 0000000000..40dc88c28c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.Map; + + +public interface ExchangeConfig extends ConfiguredObject +{ + VirtualHostConfig getVirtualHost(); + + String getName(); + + ExchangeType getType(); + + boolean isAutoDelete(); + + ExchangeConfig getAlternateExchange(); + + Map getArguments(); + + + long getBindingCount(); + + long getBindingCountHigh(); + + long getMsgReceives(); + + long getMsgRoutes(); + + long getByteReceives(); + + long getByteRoutes(); + + long getCreateTime(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java new file mode 100644 index 0000000000..2095301ad6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java @@ -0,0 +1,113 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class ExchangeConfigType extends ConfigObjectType +{ + private static final List> EXCHANGE_PROPERTIES = new ArrayList>(); + + public static interface ExchangeProperty extends ConfigProperty + { + } + + private abstract static class ExchangeReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements ExchangeProperty + { + public ExchangeReadWriteProperty(String name) + { + super(name); + EXCHANGE_PROPERTIES.add(this); + } + } + + private abstract static class ExchangeReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements ExchangeProperty + { + public ExchangeReadOnlyProperty(String name) + { + super(name); + EXCHANGE_PROPERTIES.add(this); + } + } + + public static final ExchangeReadOnlyProperty VIRTUAL_HOST_PROPERTY = new ExchangeReadOnlyProperty("virtualHost") + { + public VirtualHostConfig getValue(ExchangeConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final ExchangeReadOnlyProperty NAME_PROPERTY = new ExchangeReadOnlyProperty("name") + { + public String getValue(ExchangeConfig object) + { + return object.getName(); + } + }; + + public static final ExchangeReadOnlyProperty AUTODELETE_PROPERTY = new ExchangeReadOnlyProperty("autodelete") + { + public Boolean getValue(ExchangeConfig object) + { + return object.isAutoDelete(); + } + }; + + + public static final ExchangeReadOnlyProperty ALTERNATE_EXCHANGE_PROPERTY = new ExchangeReadOnlyProperty("alternateExchange") + { + public ExchangeConfig getValue(ExchangeConfig object) + { + return object.getAlternateExchange(); + } + }; + + public static final ExchangeReadOnlyProperty> ARGUMENTS = new ExchangeReadOnlyProperty>("arguments") + { + public Map getValue(ExchangeConfig object) + { + return object.getArguments(); + } + }; + + private static final ExchangeConfigType INSTANCE = new ExchangeConfigType(); + + private ExchangeConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(EXCHANGE_PROPERTIES); + } + + public static ExchangeConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java new file mode 100644 index 0000000000..82e0647917 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.Map; + + +public interface LinkConfig extends ConfiguredObject +{ + VirtualHostConfig getVirtualHost(); + + + String getTransport(); + + String getHost(); + + int getPort(); + + String getRemoteVhost(); + + String getAuthMechanism(); + + String getUsername(); + + String getPassword(); + + void close(); + + long getCreateTime(); + + void createBridge(boolean durable, + boolean dynamic, + boolean srcIsQueue, + boolean srcIsLocal, + String src, + String dest, + String key, String tag, String excludes); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java new file mode 100644 index 0000000000..4dc46b70c9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java @@ -0,0 +1,136 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class LinkConfigType extends ConfigObjectType +{ + private static final List> LINK_PROPERTIES = new ArrayList>(); + + public static interface LinkProperty extends ConfigProperty + { + } + + private abstract static class LinkReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements LinkProperty + { + public LinkReadWriteProperty(String name) + { + super(name); + LINK_PROPERTIES.add(this); + } + } + + private abstract static class LinkReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements LinkProperty + { + public LinkReadOnlyProperty(String name) + { + super(name); + LINK_PROPERTIES.add(this); + } + } + + public static final LinkReadOnlyProperty VIRTUAL_HOST_PROPERTY = new LinkReadOnlyProperty("virtualHost") + { + public VirtualHostConfig getValue(LinkConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final LinkReadOnlyProperty TRANSPORT_PROPERTY = new LinkReadOnlyProperty("transport") + { + public String getValue(LinkConfig object) + { + return object.getTransport(); + } + }; + + public static final LinkReadOnlyProperty HOST_PROPERTY = new LinkReadOnlyProperty("host") + { + public String getValue(LinkConfig object) + { + return object.getHost(); + } + }; + + public static final LinkReadOnlyProperty PORT_PROPERTY = new LinkReadOnlyProperty("host") + { + public Integer getValue(LinkConfig object) + { + return object.getPort(); + } + }; + + public static final LinkReadOnlyProperty REMOTE_VHOST_PROPERTY = new LinkReadOnlyProperty("remoteVhost") + { + public String getValue(LinkConfig object) + { + return object.getRemoteVhost(); + } + }; + + public static final LinkReadOnlyProperty AUTH_MECHANISM_PROPERTY = new LinkReadOnlyProperty("authMechanism") + { + public String getValue(LinkConfig object) + { + return object.getAuthMechanism(); + } + }; + + public static final LinkReadOnlyProperty USERNAME_PROPERTY = new LinkReadOnlyProperty("username") + { + public String getValue(LinkConfig object) + { + return object.getUsername(); + } + }; + + public static final LinkReadOnlyProperty PASSWORD_PROPERTY = new LinkReadOnlyProperty("password") + { + public String getValue(LinkConfig object) + { + return object.getPassword(); + } + }; + + private static final LinkConfigType INSTANCE = new LinkConfigType(); + + private LinkConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(LINK_PROPERTIES); + } + + public static LinkConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java new file mode 100644 index 0000000000..a451091fee --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -0,0 +1,72 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.Map; + + +public interface QueueConfig extends ConfiguredObject +{ + VirtualHostConfig getVirtualHost(); + + String getName(); + + boolean isExclusive(); + + boolean isAutoDelete(); + + ExchangeConfig getAlternateExchange(); + + Map getArguments(); + + long getReceivedMessageCount(); + + int getMessageCount(); + + long getQueueDepth(); + + int getConsumerCount(); + + int getBindingCount(); + + ConfigStore getConfigStore(); + + long getMessageDequeueCount(); + + long getTotalEnqueueSize(); + + long getTotalDequeueSize(); + + int getBindingCountHigh(); + + long getPersistentByteEnqueues(); + + long getPersistentByteDequeues(); + + long getPersistentMsgEnqueues(); + + long getPersistentMsgDequeues(); + + void purge(long request); + + long getCreateTime(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java new file mode 100644 index 0000000000..a794ed9747 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java @@ -0,0 +1,121 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class QueueConfigType extends ConfigObjectType +{ + private static final List> QUEUE_PROPERTIES = new ArrayList>(); + + public static interface QueueProperty extends ConfigProperty + { + } + + private abstract static class QueueReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements QueueProperty + { + public QueueReadWriteProperty(String name) + { + super(name); + QUEUE_PROPERTIES.add(this); + } + } + + private abstract static class QueueReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements QueueProperty + { + public QueueReadOnlyProperty(String name) + { + super(name); + QUEUE_PROPERTIES.add(this); + } + } + + public static final QueueReadOnlyProperty VISTUAL_HOST_PROPERTY = new QueueReadOnlyProperty("virtualHost") + { + public VirtualHostConfig getValue(QueueConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final QueueReadOnlyProperty NAME_PROPERTY = new QueueReadOnlyProperty("name") + { + public String getValue(QueueConfig object) + { + return object.getName(); + } + }; + + public static final QueueReadOnlyProperty AUTODELETE_PROPERTY = new QueueReadOnlyProperty("autodelete") + { + public Boolean getValue(QueueConfig object) + { + return object.isAutoDelete(); + } + }; + + public static final QueueReadOnlyProperty EXCLUSIVE_PROPERTY = new QueueReadOnlyProperty("exclusive") + { + public Boolean getValue(QueueConfig object) + { + return object.isExclusive(); + } + }; + + public static final QueueReadOnlyProperty ALTERNATE_EXCHANGE_PROPERTY = new QueueReadOnlyProperty("alternateExchange") + { + public ExchangeConfig getValue(QueueConfig object) + { + return object.getAlternateExchange(); + } + }; + + public static final QueueReadOnlyProperty> ARGUMENTS = new QueueReadOnlyProperty>("arguments") + { + public Map getValue(QueueConfig object) + { + return object.getArguments(); + } + }; + + + private static final QueueConfigType INSTANCE = new QueueConfigType(); + + private QueueConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(QUEUE_PROPERTIES); + } + + public static QueueConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 5c73e353de..44759bb4b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -118,4 +118,13 @@ public class QueueConfiguration return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity()); } + public boolean isLVQ() + { + return _config.getBoolean("lvq", false); + } + + public String getLVQKey() + { + return _config.getString("lvqKey", null); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java new file mode 100644 index 0000000000..ae01ab25ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface SessionConfig extends ConfiguredObject +{ + VirtualHostConfig getVirtualHost(); + + String getSessionName(); + + int getChannel(); + + ConnectionConfig getConnectionConfig(); + + boolean isAttached(); + + long getDetachedLifespan(); + + Long getExpiryTime(); + + Long getMaxClientRate(); +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java new file mode 100644 index 0000000000..97cf275575 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java @@ -0,0 +1,136 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class SessionConfigType extends ConfigObjectType +{ + private static final List> SESSION_PROPERTIES = new ArrayList>(); + + public static interface SessionProperty extends ConfigProperty + { + } + + private abstract static class SessionReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements SessionProperty + { + public SessionReadWriteProperty(String name) + { + super(name); + SESSION_PROPERTIES.add(this); + } + } + + private abstract static class SessionReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements SessionProperty + { + public SessionReadOnlyProperty(String name) + { + super(name); + SESSION_PROPERTIES.add(this); + } + } + + public static final SessionReadOnlyProperty VIRTUAL_HOST_PROPERTY = new SessionReadOnlyProperty("virtualHost") + { + public VirtualHostConfig getValue(SessionConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final SessionReadOnlyProperty NAME_PROPERTY = new SessionReadOnlyProperty("name") + { + public String getValue(SessionConfig object) + { + return object.getSessionName(); + } + }; + + public static final SessionReadOnlyProperty CHANNEL_ID_PROPERTY = new SessionReadOnlyProperty("channelId") + { + public Integer getValue(SessionConfig object) + { + return object.getChannel(); + } + }; + + public static final SessionReadOnlyProperty CONNECTION_PROPERTY = new SessionReadOnlyProperty("connection") + { + public ConnectionConfig getValue(SessionConfig object) + { + return object.getConnectionConfig(); + } + }; + + public static final SessionReadOnlyProperty ATTACHED_PROPERTY = new SessionReadOnlyProperty("attached") + { + public Boolean getValue(SessionConfig object) + { + return object.isAttached(); + } + }; + + public static final SessionReadOnlyProperty DETACHED_LIFESPAN_PROPERTY = new SessionReadOnlyProperty("detachedLifespan") + { + public Long getValue(SessionConfig object) + { + return object.getDetachedLifespan(); + } + }; + + public static final SessionReadOnlyProperty EXPIRE_TIME_PROPERTY = new SessionReadOnlyProperty("expireTime") + { + public Long getValue(SessionConfig object) + { + return object.getExpiryTime(); + } + }; + + public static final SessionReadOnlyProperty MAX_CLIENT_RATE_PROPERTY = new SessionReadOnlyProperty("maxClientRate") + { + public Long getValue(SessionConfig object) + { + return object.getMaxClientRate(); + } + }; + + private static final SessionConfigType INSTANCE = new SessionConfigType(); + + private SessionConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(SESSION_PROPERTIES); + } + + public static SessionConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java new file mode 100644 index 0000000000..985ecb2be9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.Map; + + +public interface SubscriptionConfig extends ConfiguredObject +{ + + SessionConfig getSessionConfig(); + + QueueConfig getQueue(); + + String getName(); + + Map getArguments(); + + String getCreditMode(); + + boolean isBrowsing(); + + boolean isExclusive(); + + boolean isExplicitAcknowledge(); + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java new file mode 100644 index 0000000000..99d3273b55 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java @@ -0,0 +1,136 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + + +import java.util.*; + +public final class SubscriptionConfigType extends ConfigObjectType +{ + private static final List> SUBSCRIPTION_PROPERTIES = new ArrayList>(); + + public static interface SubscriptionProperty extends ConfigProperty + { + } + + private abstract static class SubscriptionReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements SubscriptionProperty + { + public SubscriptionReadWriteProperty(String name) + { + super(name); + SUBSCRIPTION_PROPERTIES.add(this); + } + } + + private abstract static class SubscriptionReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements SubscriptionProperty + { + public SubscriptionReadOnlyProperty(String name) + { + super(name); + SUBSCRIPTION_PROPERTIES.add(this); + } + } + + public static final SubscriptionReadOnlyProperty SESSION_PROPERTY = new SubscriptionReadOnlyProperty("session") + { + public SessionConfig getValue(SubscriptionConfig object) + { + return object.getSessionConfig(); + } + }; + + public static final SubscriptionReadOnlyProperty QUEUE_PROPERTY = new SubscriptionReadOnlyProperty("queue") + { + public QueueConfig getValue(SubscriptionConfig object) + { + return object.getQueue(); + } + }; + + public static final SubscriptionReadOnlyProperty NAME_PROPERTY = new SubscriptionReadOnlyProperty("name") + { + public String getValue(SubscriptionConfig object) + { + return object.getName(); + } + }; + + public static final SubscriptionReadOnlyProperty> ARGUMENTS = new SubscriptionReadOnlyProperty>("arguments") + { + public Map getValue(SubscriptionConfig object) + { + return object.getArguments(); + } + }; + + public static final SubscriptionReadOnlyProperty CREDIT_MODE_PROPERTY = new SubscriptionReadOnlyProperty("creditMode") + { + public String getValue(SubscriptionConfig object) + { + return object.getCreditMode(); + } + }; + + public static final SubscriptionReadOnlyProperty BROWSING_PROPERTY = new SubscriptionReadOnlyProperty("browsing") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isBrowsing(); + } + }; + + public static final SubscriptionReadOnlyProperty EXCLUSIVE_PROPERTY = new SubscriptionReadOnlyProperty("exclusive") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isExclusive(); + } + }; + + public static final SubscriptionReadOnlyProperty EXPLICIT_ACK_PROPERTY = new SubscriptionReadOnlyProperty("explicitAck") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isExplicitAcknowledge(); + } + }; + + private static final SubscriptionConfigType INSTANCE = new SubscriptionConfigType(); + + private SubscriptionConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(SUBSCRIPTION_PROPERTIES); + } + + + public static SubscriptionConfigType getInstance() + { + return INSTANCE; + } + + + +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java new file mode 100644 index 0000000000..1e722ea191 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface SystemConfig extends ConfiguredObject +{ + String getName(); + + String getOperatingSystemName(); + + String getNodeName(); + + + String getOSRelease(); + + String getOSVersion(); + + String getOSArchitecture(); + + void addBroker(BrokerConfig broker); + + void removeBroker(BrokerConfig broker); + + long getCreateTime(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java new file mode 100644 index 0000000000..09ebb07105 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java @@ -0,0 +1,136 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.UUID; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class SystemConfigImpl implements SystemConfig +{ + private static final String OS_NAME = System.getProperty("os.name"); + private static final String OS_ARCH = System.getProperty("os.arch"); + private static final String OS_VERSION = System.getProperty("os.version"); + + private final UUID _id; + private String _name; + + private final String _host; + + private final Map _brokers = new ConcurrentHashMap(); + + private final long _createTime = System.currentTimeMillis(); + private final ConfigStore _store; + + public SystemConfigImpl(ConfigStore store) + { + this(store.createId(), store); + } + + public SystemConfigImpl(UUID id, ConfigStore store) + { + _id = id; + _store = store; + String host; + try + { + InetAddress addr = InetAddress.getLocalHost(); + host = addr.getHostName(); + } + catch (UnknownHostException e) + { + host="localhost"; + } + _host = host; + } + + public String getName() + { + return _name; + } + + public String getOperatingSystemName() + { + return OS_NAME; + } + + public String getNodeName() + { + return _host; + } + + public String getOSRelease() + { + return OS_VERSION; + } + + public String getOSVersion() + { + return ""; + } + + public String getOSArchitecture() + { + return OS_ARCH; + } + + public UUID getId() + { + return _id; + } + + public SystemConfigType getConfigType() + { + return SystemConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return null; + } + + public boolean isDurable() + { + return false; + } + + public void addBroker(final BrokerConfig broker) + { + broker.setSystem(this); + _store.addConfiguredObject(broker); + _brokers.put(broker.getId(), broker); + } + + public void removeBroker(final BrokerConfig broker) + { + _brokers.remove(broker.getId()); + _store.removeConfiguredObject(broker); + } + + public long getCreateTime() + { + return _createTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java new file mode 100644 index 0000000000..f5aabd2345 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java @@ -0,0 +1,128 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.*; + +public final class SystemConfigType extends ConfigObjectType +{ + private static final List> SYSTEM_PROPERTIES = new ArrayList>(); + + public static interface SystemProperty extends ConfigProperty + { + } + + private abstract static class SystemReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements SystemProperty + { + public SystemReadWriteProperty(String name) + { + super(name); + SYSTEM_PROPERTIES.add(this); + } + } + + private abstract static class SystemReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements SystemProperty + { + public SystemReadOnlyProperty(String name) + { + super(name); + SYSTEM_PROPERTIES.add(this); + } + } + + public static final SystemReadOnlyProperty NAME_PROPERTY = new SystemReadOnlyProperty("name") + { + public String getValue(SystemConfig object) + { + return object.getName(); + } + }; + + public static final SystemReadOnlyProperty ID_PROPERTY = new SystemReadOnlyProperty("id") + { + public UUID getValue(SystemConfig object) + { + return object.getId(); + } + }; + + public static final SystemReadOnlyProperty OS_NAME_PROPERTY = new SystemReadOnlyProperty("osName") + { + public String getValue(SystemConfig object) + { + return object.getOperatingSystemName(); + } + }; + + public static final SystemReadOnlyProperty NODE_NAME_PROPERTY = new SystemReadOnlyProperty("nodeName") + { + public String getValue(SystemConfig object) + { + return object.getNodeName(); + } + }; + + public static final SystemReadOnlyProperty RELEASE_PROPERTY = new SystemReadOnlyProperty("release") + { + public String getValue(SystemConfig object) + { + return object.getOSRelease(); + } + }; + + public static final SystemReadOnlyProperty VERSION_PROPERTY = new SystemReadOnlyProperty("version") + { + public String getValue(SystemConfig object) + { + return object.getOSVersion(); + } + }; + + public static final SystemReadOnlyProperty MACHINE_PROPERTY = new SystemReadOnlyProperty("machine") + { + public String getValue(SystemConfig object) + { + return object.getOSArchitecture(); + } + }; + + private static final SystemConfigType INSTANCE = new SystemConfigType(); + + private SystemConfigType() + { + } + + public Collection> getProperties() + { + return Collections.unmodifiableList(SYSTEM_PROPERTIES); + } + + + + public static SystemConfigType getInstance() + { + return INSTANCE; + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java new file mode 100644 index 0000000000..9431e5175f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +public interface VirtualHostConfig extends ConfiguredObject +{ + String getName(); + + BrokerConfig getBroker(); + + String getFederationTag(); + + void setBroker(BrokerConfig brokerConfig); + + long getCreateTime(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java new file mode 100644 index 0000000000..96682335bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java @@ -0,0 +1,96 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.configuration; + +import java.util.*; + +public class VirtualHostConfigType extends ConfigObjectType +{ + private static final List> VIRTUAL_HOST_PROPERTIES = new ArrayList>(); + private static final VirtualHostConfigType INSTANCE = new VirtualHostConfigType(); +public static interface VirtualHostProperty extends ConfigProperty + { + } + + private abstract static class VirtualHostReadWriteProperty extends ConfigProperty.ReadWriteConfigProperty implements VirtualHostProperty + { + public VirtualHostReadWriteProperty(String name) + { + super(name); + VIRTUAL_HOST_PROPERTIES.add(this); + } + } + + private abstract static class VirtualHostReadOnlyProperty extends ConfigProperty.ReadOnlyConfigProperty implements VirtualHostProperty + { + public VirtualHostReadOnlyProperty(String name) + { + super(name); + VIRTUAL_HOST_PROPERTIES.add(this); + } + } + + + public static final VirtualHostReadOnlyProperty NAME_PROPERTY = new VirtualHostReadOnlyProperty("name") + { + public String getValue(VirtualHostConfig object) + { + return object.getName(); + } + }; + + + public static final VirtualHostReadOnlyProperty BROKER_PROPERTY = new VirtualHostReadOnlyProperty("broker") + { + public BrokerConfig getValue(VirtualHostConfig object) + { + return object.getBroker(); + } + }; + + public static final VirtualHostReadOnlyProperty FEDERATION_TAG_PROPERTY = new VirtualHostReadOnlyProperty("federationTag") + { + public String getValue(VirtualHostConfig object) + { + return object.getFederationTag(); + } + }; + + + + public Collection> getProperties() + { + return Collections.unmodifiableList(VIRTUAL_HOST_PROPERTIES); + } + + + private VirtualHostConfigType() + { + } + + public static VirtualHostConfigType getInstance() + { + return INSTANCE; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 07f33b4a8f..32b95ff742 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -20,51 +20,57 @@ */ package org.apache.qpid.server.exchange; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.JMException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.ArrayType; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ExchangeConfigType; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ExchangeMessages; +import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.ExchangeMessages; -import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.log4j.Logger; +import javax.management.JMException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; public abstract class AbstractExchange implements Exchange, Managable { + + private AMQShortString _name; + private final AtomicBoolean _closed = new AtomicBoolean(); private Exchange _alternateExchange; protected boolean _durable; - protected String _exchangeType; protected int _ticket; private VirtualHost _virtualHost; - protected ExchangeMBean _exchangeMbean; + private final List _closeTaskList = new CopyOnWriteArrayList(); + + + protected AbstractExchangeMBean _exchangeMbean; /** * Whether the exchange is automatically deleted once all queues have detached from it @@ -75,95 +81,49 @@ public abstract class AbstractExchange implements Exchange, Managable private LogSubject _logSubject; private Map _referrers = new ConcurrentHashMap(); - /** - * 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 - { - // open mbean data types for representing exchange bindings - protected OpenType[] _bindingItemTypes; - protected CompositeType _bindingDataType; - protected TabularType _bindinglistDataType; - protected TabularDataSupport _bindingList; + private final CopyOnWriteArrayList _bindings = new CopyOnWriteArrayList(); + private final ExchangeType _type; + private UUID _id; + private final AtomicInteger _bindingCountHigh = new AtomicInteger(); + private final AtomicLong _receivedMessageCount = new AtomicLong(); + private final AtomicLong _receivedMessageSize = new AtomicLong(); + private final AtomicLong _routedMessageCount = new AtomicLong(); + private final AtomicLong _routedMessageSize = new AtomicLong(); + private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); +/* +======= public ExchangeMBean() throws NotCompliantMBeanException { super(ManagedExchange.class, ManagedExchange.TYPE); } +>>>>>>> .r902547 +*/ - protected void init() throws OpenDataException - { - _bindingItemTypes = new OpenType[2]; - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, TABULAR_UNIQUE_INDEX); - } - - public ManagedObject getParentObject() - { - return _virtualHost.getManagedObject(); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public String getExchangeType() - { - return _exchangeType; - } - - public Integer getTicketNo() - { - return _ticket; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - // Added exchangetype in the object name lets maangement apps to do any customization required - public ObjectName getObjectName() throws MalformedObjectNameException - { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + _exchangeType; - return new ObjectName(objNameString); - } + // TODO + private long _createTime = System.currentTimeMillis(); - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - } // End of MBean class + public AbstractExchange(final ExchangeType type) + { + _type = type; + } - public AMQShortString getName() + public AMQShortString getNameShortString() { return _name; } + public final AMQShortString getTypeShortString() + { + return _type.getName(); + } + /** * 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 JMException; + protected abstract AbstractExchangeMBean createMBean() throws JMException; public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException @@ -173,6 +133,11 @@ public abstract class AbstractExchange implements Exchange, Managable _durable = durable; _autoDelete = autoDelete; _ticket = ticket; + + // TODO - fix + _id = getConfigStore().createId(); + + getConfigStore().addConfiguredObject(this); try { _exchangeMbean = createMBean(); @@ -185,7 +150,12 @@ public abstract class AbstractExchange implements Exchange, Managable _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation - CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getType()), String.valueOf(name), durable)); + CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getTypeShortString()), String.valueOf(name), durable)); + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); } public abstract Logger getLogger(); @@ -207,21 +177,32 @@ public abstract class AbstractExchange implements Exchange, Managable public void close() throws AMQException { - if (_exchangeMbean != null) - { - _exchangeMbean.unregister(); - } - if(_alternateExchange != null) + + if(_closed.compareAndSet(false,true)) { - _alternateExchange.removeReference(this); + if (_exchangeMbean != null) + { + _exchangeMbean.unregister(); + } + getConfigStore().removeConfiguredObject(this); + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + + CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); + + for(Task task : _closeTaskList) + { + task.onClose(this); + } + _closeTaskList.clear(); } - - CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); } public String toString() { - return getClass().getSimpleName() + "[" + getName() +"]"; + return getClass().getSimpleName() + "[" + getNameShortString() +"]"; } public ManagedObject getManagedObject() @@ -288,4 +269,143 @@ public abstract class AbstractExchange implements Exchange, Managable { return !_referrers.isEmpty(); } + + public void addCloseTask(final Task task) + { + _closeTaskList.add(task); + } + + public void removeCloseTask(final Task task) + { + _closeTaskList.remove(task); + } + + public final void addBinding(final Binding binding) + { + _bindings.add(binding); + int bindingCountSize = _bindings.size(); + int maxBindingsSize; + while((maxBindingsSize = _bindingCountHigh.get()) < bindingCountSize) + { + _bindingCountHigh.compareAndSet(maxBindingsSize, bindingCountSize); + } + for(BindingListener listener : _listeners) + { + listener.bindingAdded(this, binding); + } + onBind(binding); + } + + public long getBindingCountHigh() + { + return _bindingCountHigh.get(); + } + + public final void removeBinding(final Binding binding) + { + onUnbind(binding); + for(BindingListener listener : _listeners) + { + listener.bindingRemoved(this, binding); + } + _bindings.remove(binding); + } + + public final Collection getBindings() + { + return Collections.unmodifiableList(_bindings); + } + + protected abstract void onBind(final Binding binding); + + protected abstract void onUnbind(final Binding binding); + + + public String getName() + { + return _name.toString(); + } + + public ExchangeType getType() + { + return _type; + } + + public Map getArguments() + { + // TODO - Fix + return Collections.EMPTY_MAP; + } + + public UUID getId() + { + return _id; + } + + public ExchangeConfigType getConfigType() + { + return ExchangeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public long getBindingCount() + { + return getBindings().size(); + } + + + + public final ArrayList route(final InboundMessage message) + { + _receivedMessageCount.incrementAndGet(); + _receivedMessageSize.addAndGet(message.getSize()); + final ArrayList queues = doRoute(message); + if(queues != null && !queues.isEmpty()) + { + _routedMessageCount.incrementAndGet(); + _routedMessageSize.addAndGet(message.getSize()); + } + return queues; + } + + protected abstract ArrayList doRoute(final InboundMessage message); + + public long getMsgReceives() + { + return _receivedMessageCount.get(); + } + + public long getMsgRoutes() + { + return _routedMessageCount.get(); + } + + public long getByteReceives() + { + return _receivedMessageSize.get(); + } + + public long getByteRoutes() + { + return _routedMessageSize.get(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void addBindingListener(final BindingListener listener) + { + _listeners.add(listener); + } + + public void removeBindingListener(final BindingListener listener) + { + _listeners.remove(listener); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java new file mode 100644 index 0000000000..ece8bc90fe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.framing.AMQShortString; + +import javax.management.openmbean.*; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; +import javax.management.JMException; + +/** + * Abstract MBean class. This has some of the methods implemented from + * management intrerface for exchanges. Any implementaion of an + * Exchange MBean should extend this class. + */ +public abstract class AbstractExchangeMBean extends AMQManagedObject implements ManagedExchange +{ + // open mbean data types for representing exchange bindings + protected OpenType[] _bindingItemTypes; + protected CompositeType _bindingDataType; + protected TabularType _bindinglistDataType; + + + private T _exchange; + + public AbstractExchangeMBean(final T abstractExchange) throws NotCompliantMBeanException + { + super(ManagedExchange.class, ManagedExchange.TYPE); + _exchange = abstractExchange; + } + + protected void init() throws OpenDataException + { + _bindingItemTypes = new OpenType[2]; + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, TABULAR_UNIQUE_INDEX); + } + + public ManagedObject getParentObject() + { + return _exchange.getVirtualHost().getManagedObject(); + } + + public T getExchange() + { + return _exchange; + } + + + public String getObjectInstanceName() + { + return _exchange.getNameShortString().toString(); + } + + public String getName() + { + return _exchange.getNameShortString().toString(); + } + + public String getExchangeType() + { + return _exchange.getTypeShortString().toString(); + } + + public Integer getTicketNo() + { + return _exchange._ticket; + } + + public boolean isDurable() + { + return _exchange._durable; + } + + public boolean isAutoDelete() + { + return _exchange._autoDelete; + } + + // Added exchangetype in the object name lets maangement apps to do any customization required + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + getExchangeType(); + return new ObjectName(objNameString); + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + VirtualHost vhost = getExchange().getVirtualHost(); + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); + vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + CurrentActor.remove(); + } +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 6b0cf89b95..1c4c341c14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -20,19 +20,20 @@ */ package org.apache.qpid.server.exchange; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.qmf.ManagementExchange; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + public class DefaultExchangeFactory implements ExchangeFactory { private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); @@ -47,6 +48,7 @@ public class DefaultExchangeFactory implements ExchangeFactory registerExchangeType(TopicExchange.TYPE); registerExchangeType(HeadersExchange.TYPE); registerExchangeType(FanoutExchange.TYPE); + registerExchangeType(ManagementExchange.TYPE); } public void registerExchangeType(ExchangeType type) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 7b21ad6b91..84444450c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -66,8 +66,8 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) throws AMQException { - _exchangeMap.put(exchange.getName(), exchange); - _exchangeMapStr.put(exchange.getName().toString(), exchange); + _exchangeMap.put(exchange.getNameShortString(), exchange); + _exchangeMapStr.put(exchange.getNameShortString().toString(), exchange); } public void setDefaultExchange(Exchange exchange) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 3c3902c545..cb0d8ecf8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -20,40 +20,29 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; + +import javax.management.JMException; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; public class DirectExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(DirectExchange.class); - /** - * Maps from queue name to queue instances - */ - private final Index _index = new Index(); + private final ConcurrentHashMap> _bindingsByKey = + new ConcurrentHashMap>(); public static final ExchangeType TYPE = new ExchangeType() { @@ -85,73 +74,15 @@ public class DirectExchange extends AbstractExchange } }; - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DirectExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DirectExchangeMBean() throws JMException - { - super(); - _exchangeType = "direct"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - Map> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : bindings.entrySet()) - { - AMQShortString key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(DirectExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - }// End of MBean class + public DirectExchange() + { + super(TYPE); + } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new DirectExchangeMBean(); + return new DirectExchangeMBean(this); } public Logger getLogger() @@ -159,68 +90,36 @@ public class DirectExchange extends AbstractExchange return _logger; } - public AMQShortString getType() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - public void registerQueue(String routingKey, AMQQueue queue, Map args) throws AMQException + public ArrayList doRoute(InboundMessage payload) { - registerQueue(new AMQShortString(routingKey), queue); - } - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - registerQueue(routingKey, queue); - } + final String routingKey = payload.getRoutingKey(); - private void registerQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException - { - assert queue != null; - assert routingKey != null; - if (!_index.add(routingKey, queue)) + CopyOnWriteArraySet bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey); + + if(bindings != null) { - if (_logger.isDebugEnabled()) + final ArrayList queues = new ArrayList(bindings.size()); + + for(Binding binding : bindings) { - _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey); + queues.add(binding.getQueue()); + binding.incrementMatches(); } - } - else - { + if (_logger.isDebugEnabled()) { - _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this); + _logger.debug("Publishing message to queue " + queues); } - } - } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that _routing key"); + return queues; } - } - - public ArrayList route(InboundMessage payload) - { - - final String routingKey = payload.getRoutingKey(); - - - final ArrayList queues = (routingKey == null) ? _index.get("") : _index.get(routingKey); - - if (_logger.isDebugEnabled()) + else { - _logger.debug("Publishing message to queue " + queues); + return new ArrayList(0); } - return queues; - } @@ -232,24 +131,40 @@ public class DirectExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) { - final List queues = _index.get(routingKey); - return queues != null && queues.contains(queue); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); + if(bindings != null) + { + for(Binding binding : bindings) + { + if(binding.getQueue().equals(queue)) + { + return true; + } + } + } + return false; + } public boolean isBound(AMQShortString routingKey) { - final List queues = _index.get(routingKey); - return queues != null && !queues.isEmpty(); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); + return bindings != null && !bindings.isEmpty(); } public boolean isBound(AMQQueue queue) { - Map> bindings = _index.getBindingsMap(); - for (List queues : bindings.values()) + + for (CopyOnWriteArraySet bindings : _bindingsByKey.values()) { - if (queues.contains(queue)) + for(Binding binding : bindings) { - return true; + if(binding.getQueue().equals(queue)) + { + return true; + } } } return false; @@ -257,11 +172,45 @@ public class DirectExchange extends AbstractExchange public boolean hasBindings() { - return !_index.getBindingsMap().isEmpty(); + return !getBindings().isEmpty(); } - public Map> getBindings() + protected void onBind(final Binding binding) { - return _index.getBindingsMap(); + String bindingKey = binding.getBindingKey(); + AMQQueue queue = binding.getQueue(); + AMQShortString routingKey = AMQShortString.valueOf(bindingKey); + + assert queue != null; + assert routingKey != null; + + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); + + if(bindings == null) + { + bindings = new CopyOnWriteArraySet(); + CopyOnWriteArraySet newBindings; + if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null) + { + bindings = newBindings; + } + } + + bindings.add(binding); + + } + + protected void onUnbind(final Binding binding) + { + assert binding != null; + + CopyOnWriteArraySet bindings = _bindingsByKey.get(binding.getBindingKey()); + if(bindings != null) + { + bindings.remove(binding); + } + } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java new file mode 100644 index 0000000000..086832c045 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * MBean class implementing the management interfaces. + */ +@MBeanDescription("Management Bean for Direct Exchange") +final class DirectExchangeMBean extends AbstractExchangeMBean +{ + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DirectExchangeMBean(final DirectExchange exchange) throws JMException + { + super(exchange); + + init(); + } + + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + + Map> bindingMap = new HashMap>(); + + for (Binding binding : getExchange().getBindings()) + { + String key = binding.getBindingKey(); + List queueList = bindingMap.get(key); + if(queueList == null) + { + queueList = new ArrayList(); + bindingMap.put(key, queueList); + } + queueList.add(binding.getQueue().getNameShortString().toString()); + + } + + for(Map.Entry> entry : bindingMap.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + } + + + +}// End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 4bbdeaef1c..8a31b1bab1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -25,17 +25,31 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ExchangeConfig; import javax.management.JMException; import java.util.ArrayList; +import java.util.List; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; -public interface Exchange extends ExchangeReferrer +public interface Exchange extends ExchangeReferrer, ExchangeConfig { - AMQShortString getName(); - AMQShortString getType(); + public interface BindingListener + { + void bindingAdded(Exchange exchange, Binding binding); + void bindingRemoved(Exchange exchange, Binding binding); + } + + AMQShortString getNameShortString(); + + AMQShortString getTypeShortString(); void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException, JMException; @@ -51,13 +65,8 @@ public interface Exchange extends ExchangeReferrer void close() throws AMQException; - void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - - void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - ArrayList route(InboundMessage message); + ArrayList route(InboundMessage message); /** @@ -101,6 +110,11 @@ public interface Exchange extends ExchangeReferrer boolean isBound(String bindingKey); + void addCloseTask(Task task); + + void removeCloseTask(Task task); + + Exchange getAlternateExchange(); void setAlternateExchange(Exchange exchange); @@ -110,4 +124,20 @@ public interface Exchange extends ExchangeReferrer void addReference(ExchangeReferrer exchange); boolean hasReferrers(); + + void addBinding(Binding binding); + + void removeBinding(Binding binding); + + Collection getBindings(); + + public void addBindingListener(BindingListener listener); + + public void removeBindingListener(BindingListener listener); + + + public static interface Task + { + public void onClose(Exchange exchange); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 00f8ebd856..bd75f7bc51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -21,109 +21,35 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ConcurrentHashMap; public class FanoutExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + private static final Integer ONE = Integer.valueOf(1); + /** * Maps from queue name to queue instances */ - private final CopyOnWriteArraySet _queues = new CopyOnWriteArraySet(); + private final ConcurrentHashMap _queues = new ConcurrentHashMap(); - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Fanout Exchange") - private final class FanoutExchangeMBean extends ExchangeMBean + protected AbstractExchangeMBean createMBean() throws JMException { - private static final String BINDING_KEY_SUBSTITUTE = "*"; - - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException - { - super(); - _exchangeType = "fanout"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - - _bindingList = new TabularDataSupport(_bindinglistDataType); - - if(_queues.isEmpty()) - { - return _bindingList; - } - - ArrayList queueNames = new ArrayList(); - - for (AMQQueue queue : _queues) - { - String queueName = queue.getName().toString(); - queueNames.add(queueName); - } - - Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(FanoutExchange.this, new AMQShortString(BINDING_KEY_SUBSTITUTE), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - } // End of MBean class - - protected ExchangeMBean createMBean() throws JMException - { - return new FanoutExchange.FanoutExchangeMBean(); + return new FanoutExchangeMBean(this); } public Logger getLogger() @@ -161,51 +87,26 @@ public class FanoutExchange extends AbstractExchange } }; - public Map> getBindings() + public FanoutExchange() { - return null; + super(TYPE); } - public AMQShortString getType() + public ArrayList doRoute(InboundMessage payload) { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - if (_queues.contains(queue)) - { - _logger.debug("Queue " + queue + " is already registered"); - } - else - { - _queues.add(queue); - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); - } - } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (!_queues.remove(queue)) + if (_logger.isDebugEnabled()) { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); + _logger.debug("Publishing message to queue " + _queues); } - } - public ArrayList route(InboundMessage payload) - { - - - if (_logger.isDebugEnabled()) + for(Binding b : getBindings()) { - _logger.debug("Publishing message to queue " + _queues); + b.incrementMatches(); } - return new ArrayList(_queues); + return new ArrayList(_queues.keySet()); } @@ -235,4 +136,71 @@ public class FanoutExchange extends AbstractExchange { return !_queues.isEmpty(); } + + protected void onBind(final Binding binding) + { + AMQQueue queue = binding.getQueue(); + assert queue != null; + + Integer oldVal; + + if((oldVal = _queues.putIfAbsent(queue, ONE)) != null) + { + Integer newVal = oldVal+1; + while(!_queues.replace(queue, oldVal, newVal)) + { + oldVal = _queues.get(queue); + if(oldVal == null) + { + oldVal = _queues.putIfAbsent(queue, ONE); + if(oldVal == null) + { + break; + } + } + newVal = oldVal + 1; + } + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Binding queue " + queue + + " with routing key " + new AMQShortString(binding.getBindingKey()) + " to exchange " + this); + } + } + + protected void onUnbind(final Binding binding) + { + AMQQueue queue = binding.getQueue(); + Integer oldValue = _queues.get(queue); + + boolean done = false; + + while(!(done || oldValue == null)) + { + while(!(done || oldValue == null) && oldValue.intValue() == 1) + { + if(!_queues.remove(queue, oldValue)) + { + oldValue = _queues.get(queue); + } + else + { + done = true; + } + } + while(!(done || oldValue == null) && oldValue.intValue() != 1) + { + Integer newValue = oldValue - 1; + if(!_queues.replace(queue, oldValue, newValue)) + { + oldValue = _queues.get(queue); + } + else + { + done = true; + } + } + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java new file mode 100644 index 0000000000..d5734f76a5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.ArrayList; + +/** + * MBean class implementing the management interfaces. + */ +@MBeanDescription("Management Bean for Fanout Exchange") +final class FanoutExchangeMBean extends AbstractExchangeMBean +{ + private static final String BINDING_KEY_SUBSTITUTE = "*"; + + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") + public FanoutExchangeMBean(final FanoutExchange exchange) throws JMException + { + super(exchange); + init(); + } + + public TabularData bindings() throws OpenDataException + { + + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + + + ArrayList queueNames = new ArrayList(); + + for (Binding binding : getExchange().getBindings()) + { + String queueName = binding.getQueue().getNameShortString().toString(); + queueNames.add(queueName); + } + + Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + + return bindingList; + } + + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 5677cc4510..ce0b14932f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -22,33 +22,20 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.binding.Binding; import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -119,151 +106,40 @@ public class HeadersExchange extends AbstractExchange private final List _bindings = new CopyOnWriteArrayList(); private Map _bindingByKey = new ConcurrentHashMap(); - /** - * HeadersExchangeMBean class implements the management interface for the - * Header Exchanges. - */ - @MBeanDescription("Management Bean for Headers Exchange") - private final class HeadersExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException - { - super(); - _exchangeType = "headers"; - init(); - } - - /** - * initialises the OpenType objects. - */ - protected void init() throws OpenDataException - { - - _bindingItemTypes = new OpenType[3]; - _bindingItemTypes[0] = SimpleType.INTEGER; - _bindingItemTypes[1] = SimpleType.STRING; - _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); - } - - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - int count = 1; - for (Iterator itr = _bindings.iterator(); itr.hasNext();) - { - Registration registration = itr.next(); - String queueName = registration.queue.getName().toString(); - - HeadersBinding headers = registration.binding; - FieldTable headerMappings = headers.getMappings(); - final List mappingList = new ArrayList(); - - headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - mappingList.add(propertyName + "=" + value.getValue()); - return true; - } - - public Object getResult() - { - return mappingList; - } - }); - - Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - /** - * Creates bindings. Binding pattern is as follows- - * =,=,... - * @param queueName - * @param binding - * @throws javax.management.JMException - */ - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - String[] bindings = binding.split(","); - FieldTable bindingMap = new FieldTable(); - for (int i = 0; i < bindings.length; i++) - { - String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2) - { - throw new JMException("Format for headers binding should be \"=,=\" "); - } - - if(keyAndValue.length ==1) - { - //no value was given, only a key. Use an empty value - //to signal match on key presence alone - bindingMap.setString(keyAndValue[0], ""); - } - else - { - bindingMap.setString(keyAndValue[0], keyAndValue[1]); - } - } - - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue, new AMQShortString(binding))); - } - - } // End of MBean class + public HeadersExchange() + { + super(TYPE); + } - public AMQShortString getType() + public void registerQueue(String routingKey, AMQQueue queue, Map args) { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + registerQueue(new AMQShortString(routingKey), queue, FieldTable.convertToFieldTable(args)); } - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) { - _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); + _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() + " with " + args); Registration registration = new Registration(new HeadersBinding(args), queue, routingKey); _bindings.add(registration); } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void deregisterQueue(String routingKey, AMQQueue queue, Map args) { - _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - - if(!_bindings.remove(new Registration(args == null ? null : new HeadersBinding(args), queue, routingKey))) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with headers args " + args); - } + _bindings.remove(new Registration(args == null ? null : new HeadersBinding(FieldTable.convertToFieldTable(args)), queue, new AMQShortString(routingKey))); } - public ArrayList route(InboundMessage payload) + public ArrayList doRoute(InboundMessage payload) { AMQMessageHeader header = payload.getMessageHeader(); if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": routing message with headers " + header); + _logger.debug("Exchange " + getNameShortString() + ": routing message with headers " + header); } boolean routed = false; - ArrayList queues = new ArrayList(); + ArrayList queues = new ArrayList(); for (Registration e : _bindings) { @@ -271,8 +147,8 @@ public class HeadersExchange extends AbstractExchange { if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": delivering message with headers " + - header + " to " + e.queue.getName()); + _logger.debug("Exchange " + getNameShortString() + ": delivering message with headers " + + header + " to " + e.queue.getNameShortString()); } queues.add(e.queue); @@ -315,6 +191,8 @@ public class HeadersExchange extends AbstractExchange return !_bindings.isEmpty(); } + + protected FieldTable getHeaders(ContentHeaderBody contentHeaderFrame) { //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers, @@ -322,14 +200,9 @@ public class HeadersExchange extends AbstractExchange return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new HeadersExchangeMBean(); - } - - public Map> getBindings() - { - return null; + return new HeadersExchangeMBean(this); } public Logger getLogger() @@ -338,7 +211,7 @@ public class HeadersExchange extends AbstractExchange } - private static class Registration + static class Registration { private final HeadersBinding binding; private final AMQQueue queue; @@ -365,5 +238,31 @@ public class HeadersExchange extends AbstractExchange && (routingKey == null ? ((Registration)o).routingKey == null : routingKey.equals(((Registration)o).routingKey)); } + + public HeadersBinding getBinding() + { + return binding; + } + + public AMQQueue getQueue() + { + return queue; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } } + + protected void onBind(final Binding binding) + { + registerQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); + } + + protected void onUnbind(final Binding binding) + { + deregisterQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java new file mode 100644 index 0000000000..2c7985b480 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java @@ -0,0 +1,96 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +/** + * HeadersExchangeMBean class implements the management interface for the + * Header Exchanges. + */ +@MBeanDescription("Management Bean for Headers Exchange") +final class HeadersExchangeMBean extends AbstractExchangeMBean +{ + + @MBeanConstructor("Creates an MBean for AMQ Headers exchange") + public HeadersExchangeMBean(final HeadersExchange headersExchange) throws JMException + { + super(headersExchange); + init(); + } + + /** + * initialises the OpenType objects. + */ + protected void init() throws OpenDataException + { + + _bindingItemTypes = new OpenType[3]; + _bindingItemTypes[0] = SimpleType.INTEGER; + _bindingItemTypes[1] = SimpleType.STRING; + _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", + HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); + } + + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + int count = 1; + for (Binding binding : getExchange().getBindings()) + { + + String queueName = binding.getQueue().getNameShortString().toString(); + + + Map headerMappings = binding.getArguments(); + final List mappingList = new ArrayList(); + + if(headerMappings != null) + { + for(Map.Entry entry : headerMappings.entrySet()) + { + + mappingList.add(entry.getKey() + "=" + entry.getValue()); + } + } + + + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + } + + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java deleted file mode 100644 index 90d04c814a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * An index of queues against routing key. Allows multiple queues to be stored - * against the same key. Used in the DirectExchange. - */ -class Index -{ - private ConcurrentMap> _index - = new ConcurrentHashMap>(); - private ConcurrentMap> _stringIndex - = new ConcurrentHashMap>(); - - - synchronized boolean add(AMQShortString key, AMQQueue queue) - { - ArrayList queues = _index.get(key); - if(queues == null) - { - queues = new ArrayList(); - } - else - { - queues = new ArrayList(queues); - } - - //next call is atomic, so there is no race to create the list - _index.put(key, queues); - _stringIndex.put(key.toString(), queues); - - if(queues.contains(queue)) - { - return false; - } - else - { - return queues.add(queue); - } - } - - - - synchronized boolean remove(AMQShortString key, AMQQueue queue) - { - ArrayList queues = _index.get(key); - if (queues != null) - { - queues = new ArrayList(queues); - boolean removed = queues.remove(queue); - if(removed) - { - if (queues.size() == 0) - { - _index.remove(key); - _stringIndex.remove(key.toString()); - } - else - { - _index.put(key, queues); - _stringIndex.put(key.toString(), queues); - } - } - return removed; - } - return false; - } - - ArrayList get(AMQShortString key) - { - return _index.get(key); - } - - ArrayList get(String key) - { - return _stringIndex.get(key); - } - - - Map> getBindingsMap() - { - return new HashMap>(_index); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index d5ca5a8a81..14f15dd92c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -21,32 +21,21 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortStringTokenizer; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.topic.TopicParser; -import org.apache.qpid.server.exchange.topic.TopicMatcherResult; -import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.exchange.topic.*; import org.apache.qpid.server.filter.JMSSelectorFilter; import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.lang.ref.WeakReference; @@ -87,314 +76,45 @@ public class TopicExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(TopicExchange.class); -/* - private final ConcurrentHashMap> _bindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _simpleBindingKey2queues = - new ConcurrentHashMap>(); - private final ConcurrentHashMap> _wildCardBindingKey2queues = - new ConcurrentHashMap>(); -*/ - // private ConcurrentHashMap _routingKey2queue = new ConcurrentHashMap(); - private static final byte TOPIC_SEPARATOR = (byte)'.'; - private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); - private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); - private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); - - private static final byte HASH_BYTE = (byte)'#'; - private static final byte STAR_BYTE = (byte)'*'; + private final TopicParser _parser = new TopicParser(); private final Map _topicExchangeResults = new ConcurrentHashMap(); - private final Map _bindings = new HashMap(); + private final Map _bindings = new HashMap(); private final Map> _selectorCache = new WeakHashMap>(); - public static class Binding + public TopicExchange() { - private final AMQShortString _bindingKey; - private final AMQQueue _queue; - private final FieldTable _args; - - public Binding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) - { - _bindingKey = bindingKey; - _queue = queue; - _args = args; - } - - public AMQShortString getBindingKey() - { - return _bindingKey; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public int hashCode() - { - return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); - } - - public boolean equals(Object o) - { - if(this == o) - { - return true; - } - if(o instanceof Binding) - { - Binding other = (Binding) o; - return (_queue == other._queue) - && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); - } - return false; - } - } - - - - private final class TopicExchangeResult implements TopicMatcherResult - { - private final Map _unfilteredQueues = new ConcurrentHashMap(); - private final ConcurrentHashMap> _filteredQueues = new ConcurrentHashMap>(); - - public void addUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == null) - { - _unfilteredQueues.put(queue, 1); - } - else - { - _unfilteredQueues.put(queue, instances + 1); - } - } - - public void removeUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == 1) - { - _unfilteredQueues.remove(queue); - } - else - { - _unfilteredQueues.put(queue,instances - 1); - } - - } - - - public void addFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map filters = _filteredQueues.get(queue); - if(filters == null) - { - filters = new ConcurrentHashMap(); - _filteredQueues.put(queue, filters); - } - Integer instances = filters.get(filter); - if(instances == null) - { - filters.put(filter,1); - } - else - { - filters.put(filter, instances + 1); - } - - } - - public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map filters = _filteredQueues.get(queue); - if(filters != null) - { - Integer instances = filters.get(filter); - if(instances != null) - { - if(instances == 1) - { - filters.remove(filter); - if(filters.isEmpty()) - { - _filteredQueues.remove(queue); - } - } - else - { - filters.put(filter, instances - 1); - } - } - - } - - } - - public void replaceQueueFilter(AMQQueue queue, - MessageFilter oldFilter, - MessageFilter newFilter) - { - Map filters = _filteredQueues.get(queue); - Map newFilters = new ConcurrentHashMap(filters); - Integer oldFilterInstances = filters.get(oldFilter); - if(oldFilterInstances == 1) - { - newFilters.remove(oldFilter); - } - else - { - newFilters.put(oldFilter, oldFilterInstances-1); - } - Integer newFilterInstances = filters.get(newFilter); - if(newFilterInstances == null) - { - newFilters.put(newFilter, 1); - } - else - { - newFilters.put(newFilter, newFilterInstances+1); - } - _filteredQueues.put(queue,newFilters); - } - - public Collection processMessage(InboundMessage msg, Collection queues) - { - if(queues == null) - { - if(_filteredQueues.isEmpty()) - { - return new ArrayList(_unfilteredQueues.keySet()); - } - else - { - queues = new HashSet(); - } - } - else if(!(queues instanceof Set)) - { - queues = new HashSet(queues); - } - - queues.addAll(_unfilteredQueues.keySet()); - if(!_filteredQueues.isEmpty()) - { - for(Map.Entry> entry : _filteredQueues.entrySet()) - { - if(!queues.contains(entry.getKey())) - { - for(MessageFilter filter : entry.getValue().keySet()) - { - if(filter.matches(msg)) - { - queues.add(entry.getKey()); - } - } - } - } - } - return queues; - } - + super(TYPE); } - - /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class TopicExchangeMBean extends ExchangeMBean + public synchronized void registerQueue(String rKey, AMQQueue queue, Map args) { - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public TopicExchangeMBean() throws JMException + try { - super(); - _exchangeType = "topic"; - init(); + registerQueue(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args)); } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException + catch (AMQInvalidArgumentException e) { - _bindingList = new TabularDataSupport(_bindinglistDataType); - Map> bindingData = new HashMap>(); - for (Binding binding : _bindings.keySet()) - { - String key = binding.getBindingKey().toString(); - List queueNames = bindingData.get(key); - if(queueNames == null) - { - queueNames = new ArrayList(); - bindingData.put(key, queueNames); - } - queueNames.add(binding.getQueue().getName().toString()); - - } - for(Map.Entry> entry : bindingData.entrySet()) - { - Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingCompositeData); - } - - return _bindingList; + throw new RuntimeException(e); } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(TopicExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; } - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQInvalidArgumentException { assert queue != null; assert rKey != null; - _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); + _logger.debug("Registering queue " + queue.getNameShortString() + " with routing key " + rKey); - AMQShortString routingKey; + AMQShortString routingKey = TopicNormalizer.normalize(rKey); - if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) - { - routingKey = normalize(rKey); - } - else - { - routingKey = rKey; - } - - Binding binding = new Binding(rKey, queue, args); + TopicBinding binding = new TopicBinding(rKey, queue, args); if(_bindings.containsKey(binding)) { @@ -463,8 +183,7 @@ public class TopicExchange extends AbstractExchange } - private JMSSelectorFilter createSelectorFilter(final FieldTable args) - throws AMQException + private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQInvalidArgumentException { final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); @@ -484,58 +203,7 @@ public class TopicExchange extends AbstractExchange return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0; } - private AMQShortString normalize(AMQShortString routingKey) - { - if(routingKey == null) - { - routingKey = AMQShortString.EMPTY_STRING; - } - - AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); - - List subscriptionList = new ArrayList(); - - while (routingTokens.hasMoreTokens()) - { - subscriptionList.add(routingTokens.nextToken()); - } - - int size = subscriptionList.size(); - - for (int index = 0; index < size; index++) - { - // if there are more levels - if ((index + 1) < size) - { - if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) - { - if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) - { - // we don't need #.# delete this one - subscriptionList.remove(index); - size--; - // redo this normalisation - index--; - } - - if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) - { - // we don't want #.* swap to *.# - // remove it and put it in at index + 1 - subscriptionList.add(index + 1, subscriptionList.remove(index)); - } - } - } // if we have more levels - } - - - - AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); - - return normalizedString; - } - - public ArrayList route(InboundMessage payload) + public ArrayList doRoute(InboundMessage payload) { final AMQShortString routingKey = payload.getRoutingKey() == null @@ -544,7 +212,7 @@ public class TopicExchange extends AbstractExchange // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues - ArrayList queues = new ArrayList(); + ArrayList queues = new ArrayList(); queues.addAll(getMatchedQueues(payload, routingKey)); if(queues == null || queues.isEmpty()) @@ -558,7 +226,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) { - Binding binding = new Binding(routingKey, queue, arguments); + TopicBinding binding = new TopicBinding(routingKey, queue, arguments); if (arguments == null) { return _bindings.containsKey(binding); @@ -585,7 +253,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey) { - for(Binding b : _bindings.keySet()) + for(TopicBinding b : _bindings.keySet()) { if(b.getBindingKey().equals(routingKey)) { @@ -598,7 +266,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQQueue queue) { - for(Binding b : _bindings.keySet()) + for(TopicBinding b : _bindings.keySet()) { if(b.getQueue().equals(queue)) { @@ -614,37 +282,45 @@ public class TopicExchange extends AbstractExchange return !_bindings.isEmpty(); } - public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - Binding binding = new Binding(rKey, queue, args); - - if (!_bindings.containsKey(binding)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName() - + " with routing key " + rKey + "."); - } + public void deregisterQueue(String rKey, AMQQueue queue, Map args) + { + removeBinding(new TopicBinding(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args))); + } - FieldTable bindingArgs = _bindings.remove(binding); - AMQShortString bindingKey = normalize(rKey); - TopicExchangeResult result = _topicExchangeResults.get(bindingKey); - if(argumentsContainSelector(bindingArgs)) + private boolean removeBinding(final TopicBinding binding) + { + if(_bindings.containsKey(binding)) { - result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs)); + FieldTable bindingArgs = _bindings.remove(binding); + AMQShortString bindingKey = TopicNormalizer.normalize(binding.getBindingKey()); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + if(argumentsContainSelector(bindingArgs)) + { + try + { + result.removeFilteredQueue(binding.getQueue(), createSelectorFilter(bindingArgs)); + } + catch (AMQInvalidArgumentException e) + { + return false; + } + } + else + { + result.removeUnfilteredQueue(binding.getQueue()); + } + return true; } else { - result.removeUnfilteredQueue(queue); + return false; } - } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new TopicExchangeMBean(); + return new TopicExchangeMBean(this); } public Logger getLogger() @@ -673,4 +349,15 @@ public class TopicExchange extends AbstractExchange } + + protected void onBind(final org.apache.qpid.server.binding.Binding binding) + { + registerQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + } + + protected void onUnbind(final org.apache.qpid.server.binding.Binding binding) + { + deregisterQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java new file mode 100644 index 0000000000..de39822ff7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java @@ -0,0 +1,74 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + +/** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ +@MBeanDescription("Management Bean for Topic Exchange") +final class TopicExchangeMBean extends AbstractExchangeMBean +{ + private TopicExchange _topicExchange; + + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public TopicExchangeMBean(final TopicExchange topicExchange) throws JMException + { + super(topicExchange); + init(); + } + + /** returns exchange bindings in tabular form */ + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + Map> bindingData = new HashMap>(); + for (Binding binding : getExchange().getBindings()) + { + String key = binding.getBindingKey(); + List queueNames = bindingData.get(key); + if(queueNames == null) + { + queueNames = new ArrayList(); + bindingData.put(key, queueNames); + } + queueNames.add(binding.getQueue().getNameShortString().toString()); + + } + for(Map.Entry> entry : bindingData.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; + CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingCompositeData); + } + + return bindingList; + } + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java new file mode 100644 index 0000000000..c6383a886e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java @@ -0,0 +1,70 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.TopicExchange; + +public class TopicBinding +{ + private final AMQShortString _bindingKey; + private final AMQQueue _queue; + private final FieldTable _args; + + public TopicBinding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) + { + _bindingKey = bindingKey; + _queue = queue; + _args = args; + } + + public AMQShortString getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public int hashCode() + { + return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); + } + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(o instanceof TopicBinding) + { + TopicBinding other = (TopicBinding) o; + return (_queue == other._queue) + && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); + } + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java new file mode 100644 index 0000000000..d9a779802f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java @@ -0,0 +1,179 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.message.InboundMessage; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public final class TopicExchangeResult implements TopicMatcherResult +{ + private final Map _unfilteredQueues = new ConcurrentHashMap(); + private final ConcurrentHashMap> _filteredQueues = new ConcurrentHashMap>(); + + public void addUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == null) + { + _unfilteredQueues.put(queue, 1); + } + else + { + _unfilteredQueues.put(queue, instances + 1); + } + } + + public void removeUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == 1) + { + _unfilteredQueues.remove(queue); + } + else + { + _unfilteredQueues.put(queue,instances - 1); + } + + } + + public Collection getUnfilteredQueues() + { + return _unfilteredQueues.keySet(); + } + + + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map filters = _filteredQueues.get(queue); + if(filters == null) + { + filters = new ConcurrentHashMap(); + _filteredQueues.put(queue, filters); + } + Integer instances = filters.get(filter); + if(instances == null) + { + filters.put(filter,1); + } + else + { + filters.put(filter, instances + 1); + } + + } + + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map filters = _filteredQueues.get(queue); + if(filters != null) + { + Integer instances = filters.get(filter); + if(instances != null) + { + if(instances == 1) + { + filters.remove(filter); + if(filters.isEmpty()) + { + _filteredQueues.remove(queue); + } + } + else + { + filters.put(filter, instances - 1); + } + } + + } + + } + + public void replaceQueueFilter(AMQQueue queue, + MessageFilter oldFilter, + MessageFilter newFilter) + { + Map filters = _filteredQueues.get(queue); + Map newFilters = new ConcurrentHashMap(filters); + Integer oldFilterInstances = filters.get(oldFilter); + if(oldFilterInstances == 1) + { + newFilters.remove(oldFilter); + } + else + { + newFilters.put(oldFilter, oldFilterInstances-1); + } + Integer newFilterInstances = filters.get(newFilter); + if(newFilterInstances == null) + { + newFilters.put(newFilter, 1); + } + else + { + newFilters.put(newFilter, newFilterInstances+1); + } + _filteredQueues.put(queue,newFilters); + } + + public Collection processMessage(InboundMessage msg, Collection queues) + { + if(queues == null) + { + if(_filteredQueues.isEmpty()) + { + return new ArrayList(_unfilteredQueues.keySet()); + } + else + { + queues = new HashSet(); + } + } + else if(!(queues instanceof Set)) + { + queues = new HashSet(queues); + } + + queues.addAll(_unfilteredQueues.keySet()); + if(!_filteredQueues.isEmpty()) + { + for(Map.Entry> entry : _filteredQueues.entrySet()) + { + if(!queues.contains(entry.getKey())) + { + for(MessageFilter filter : entry.getValue().keySet()) + { + if(filter.matches(msg)) + { + queues.add(entry.getKey()); + } + } + } + } + } + return queues; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java new file mode 100644 index 0000000000..7e7cb6c0ae --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java @@ -0,0 +1,96 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; +import org.apache.qpid.server.exchange.TopicExchange; + +import java.util.List; +import java.util.ArrayList; + +public class TopicNormalizer +{ + private static final byte TOPIC_SEPARATOR = (byte)'.'; + private static final byte HASH_BYTE = (byte)'#'; + private static final byte STAR_BYTE = (byte)'*'; + + private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); + private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); + private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); + + public static AMQShortString normalize(AMQShortString routingKey) + { + if(routingKey == null) + { + return AMQShortString.EMPTY_STRING; + } + else if(!(routingKey.contains(HASH_BYTE) || routingKey.contains(STAR_BYTE))) + { + return routingKey; + } + else + { + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + List subscriptionList = new ArrayList(); + + while (routingTokens.hasMoreTokens()) + { + subscriptionList.add(routingTokens.nextToken()); + } + + int size = subscriptionList.size(); + + for (int index = 0; index < size; index++) + { + // if there are more levels + if ((index + 1) < size) + { + if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) + { + if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) + { + // we don't need #.# delete this one + subscriptionList.remove(index); + size--; + // redo this normalisation + index--; + } + + if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + subscriptionList.add(index + 1, subscriptionList.remove(index)); + } + } + } // if we have more levels + } + + + + AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); + + return normalizedString; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java new file mode 100644 index 0000000000..c97d71dc39 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -0,0 +1,807 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.federation; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.BridgeConfig; +import org.apache.qpid.server.configuration.BridgeConfigType; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCreditUnit; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageReject; +import org.apache.qpid.transport.MessageRejectCode; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Option; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionException; +import org.apache.qpid.transport.SessionListener; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class Bridge implements BridgeConfig +{ + private final boolean _durable; + private final boolean _dynamic; + private final boolean _queueBridge; + private final boolean _localSource; + private final String _source; + private final String _destination; + private final String _key; + private final String _tag; + private final String _excludes; + private final BrokerLink _link; + private UUID _id; + private long _createTime = System.currentTimeMillis(); + + private Session _session; + + private BridgeImpl _delegate; + + private final int _bridgeNo; + private AutoCommitTransaction _transaction; + + public Bridge(final BrokerLink brokerLink, + final int bridgeNo, + final boolean durable, + final boolean dynamic, + final boolean srcIsQueue, + final boolean srcIsLocal, + final String src, + final String dest, + final String key, + final String tag, + final String excludes) + { + _link = brokerLink; + _bridgeNo = bridgeNo; + _durable = durable; + _dynamic = dynamic; + _queueBridge = srcIsQueue; + _localSource = srcIsLocal; + _source = src; + _destination = dest; + _key = key; + _tag = tag; + _excludes = excludes; + _id = brokerLink.getConfigStore().createId(); + + _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore()); + + if(dynamic) + { + if(srcIsLocal) + { + // TODO + } + else + { + if(srcIsQueue) + { + // TODO + } + else + { + _delegate = new DynamicExchangeBridge(); + } + } + } + else + { + if(srcIsLocal) + { + if(srcIsQueue) + { + _delegate = new StaticQueuePushBridge(); + } + else + { + _delegate = new StaticExchangePushBridge(); + } + } + else + { + if(srcIsQueue) + { + _delegate = new StaticQueuePullBridge(); + } + else + { + _delegate = new StaticExchangePullBridge(); + } + } + } + } + + public UUID getId() + { + return _id; + } + + public BridgeConfigType getConfigType() + { + return BridgeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getLink(); + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isDynamic() + { + return _dynamic; + } + + public boolean isQueueBridge() + { + return _queueBridge; + } + + public boolean isLocalSource() + { + return _localSource; + } + + public String getSource() + { + return _source; + } + + public String getDestination() + { + return _destination; + } + + public String getKey() + { + return _key; + } + + public String getTag() + { + return _tag; + } + + public String getExcludes() + { + return _excludes; + } + + public BrokerLink getLink() + { + return _link; + } + + public Integer getChannelId() + { + return (_session == null) ? 0 : _session.getChannel(); + } + + public int getAckBatching() + { + return 0; + } + + public long getCreateTime() + { + return _createTime; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + final Bridge bridge = (Bridge) o; + + if (_durable != bridge._durable) + { + return false; + } + if (_dynamic != bridge._dynamic) + { + return false; + } + if (_localSource != bridge._localSource) + { + return false; + } + if (_queueBridge != bridge._queueBridge) + { + return false; + } + if (_destination != null ? !_destination.equals(bridge._destination) : bridge._destination != null) + { + return false; + } + if (_excludes != null ? !_excludes.equals(bridge._excludes) : bridge._excludes != null) + { + return false; + } + if (_key != null ? !_key.equals(bridge._key) : bridge._key != null) + { + return false; + } + if (_source != null ? !_source.equals(bridge._source) : bridge._source != null) + { + return false; + } + if (_tag != null ? !_tag.equals(bridge._tag) : bridge._tag != null) + { + return false; + } + + return true; + } + + @Override + public int hashCode() + { + int result = (_durable ? 1 : 0); + result = 31 * result + (_dynamic ? 1 : 0); + result = 31 * result + (_queueBridge ? 1 : 0); + result = 31 * result + (_localSource ? 1 : 0); + result = 31 * result + (_source != null ? _source.hashCode() : 0); + result = 31 * result + (_destination != null ? _destination.hashCode() : 0); + result = 31 * result + (_key != null ? _key.hashCode() : 0); + result = 31 * result + (_tag != null ? _tag.hashCode() : 0); + result = 31 * result + (_excludes != null ? _excludes.hashCode() : 0); + return result; + } + + public void setSession(final Session session) + { + _session = session; + _delegate.setSession(session); + } + + private long getMessageWindowSize() + { + return 10l; + } + + + VirtualHost getVirtualHost() + { + return _link.getVirtualHost(); + } + + public void close() + { + // TODO + _delegate.close(); + _session = null; + } + + + private interface BridgeImpl + { + void setSession(Session session); + + void close(); + } + + private abstract class AbstractPullBridge implements BridgeImpl, SessionListener + { + public final void setSession(final Session session) + { + session.setSessionListener(this); + onSession(); + + } + + abstract void onSession(); + + + + public void message(final Session ssn, final MessageTransfer xfr) + { + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_destination); + + // TODO - deal with exchange not existing + + DeliveryProperties delvProps = null; + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + { + delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); + } + + MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); + final MessageStore store = getVirtualHost().getMessageStore(); + StoredMessage storeMessage = store.addMessage(messageMetaData); + storeMessage.addContent(0,xfr.getBody()); + storeMessage.flushToStore(); + MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)_session).getReference()); + + ArrayList queues = exchange.route(message); + + + + if(queues != null && queues.size() != 0) + { + enqueue(message, queues); + } + else + { + if(delvProps == null || !delvProps.hasDiscardUnroutable() || !delvProps.getDiscardUnroutable()) + { + if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) + { + RangeSet rejects = new RangeSet(); + rejects.add(xfr.getId()); + MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); + ssn.invoke(reject); + } + else + { + Exchange alternate = exchange.getAlternateExchange(); + if(alternate != null) + { + queues = alternate.route(message); + if(queues != null && queues.size() != 0) + { + enqueue(message, queues); + } + else + { + //TODO - log the message discard + } + } + else + { + //TODO - log the message discard + } + + + } + } + + + } + + ssn.processed(xfr); + + } + + + private void enqueue(final ServerMessage message, final ArrayList queues) + { + _transaction.enqueue(queues,message, new ServerTransaction.Action() + { + + BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); + + public void postCommit() + { + for(int i = 0; i < _queues.length; i++) + { + try + { + _queues[i].enqueue(message); + } + catch (AMQException e) + { + // TODO + + throw new RuntimeException(e); + } + } + } + + public void onRollback() + { + // NO-OP + } + }); + + } + + public void exception(final Session session, final SessionException exception) + { + // TODO - Handle exceptions + } + + public void closed(final Session session) + { + // TODO - handle close + } + + public void opened(final Session session) + { + // this method never called + } + + public void resumed(final Session session) + { + // will never resume these sessions + } + + + + } + + private final class StaticExchangePullBridge extends AbstractPullBridge + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag();; + + public void onSession() + { + + final HashMap options = new HashMap(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + _session.queueDeclare(_tmpQueueName,null, options, Option.AUTO_DELETE, Option.EXCLUSIVE); + _session.sync(); + // todo check exception + final Map bindingArgs = new HashMap(); + _session.exchangeBind(_tmpQueueName, _source, _key, bindingArgs); + _session.sync(); + // todo check exception + + final Map subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_tmpQueueName, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + + } + + public void close() + { + // TODO + } + } + + private final class StaticQueuePullBridge extends AbstractPullBridge + { + + public void onSession() + { + + final Map subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_source, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + + } + + public void close() + { + // TODO + } + } + + private final class DynamicExchangeBridge extends AbstractPullBridge implements Exchange.BindingListener + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag(); + + private final ConcurrentMap _bindings = new ConcurrentHashMap(); + + + void onSession() + { + + + final HashMap options = new HashMap(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + _session.queueDeclare(_tmpQueueName,null, options, Option.AUTO_DELETE, Option.EXCLUSIVE); + _session.sync(); + // todo - check exception + + final Map subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_tmpQueueName, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + _session.sync(); + // todo check exception + + + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_destination); + + // TODO - check null + + exchange.addBindingListener(this); + + Collection bindings = exchange.getBindings(); + for(Binding binding : bindings) + { + propogateBinding(binding); + } + + } + + private void propogateBinding(final Binding binding) + { + if(_bindings.putIfAbsent(binding,binding)== null) + { + Map arguments = new HashMap(binding.getArguments()); + + if(arguments.get("qpid.fed.origin") == null) + { + arguments.put("qpid.fed.op",""); + arguments.put("qpid.fed.origin",_link.getFederationTag()); + arguments.put("qpid.fed.tags",_link.getFederationTag()); + } + else + { + String tags = (String) arguments.get("qpid.fed.tags"); + if(tags == null) + { + tags = _link.getFederationTag(); + } + else + { + if(Arrays.asList(tags.split(",")).contains(_link.getFederationTag())) + { + return; + } + tags += "," + _link.getFederationTag(); + } + arguments.put("qpid.fed.tags", tags); + } + + _session.exchangeBind(_tmpQueueName, _source, binding.getBindingKey(), arguments); + _session.sync(); + // TODO - check exception? + + } + } + + private void propogateBindingRemoval(final Binding binding) + { + if(_bindings.remove(binding) != null) + { + // TODO - this is wrong!!!! + _session.exchangeUnbind(_tmpQueueName, _source, binding.getBindingKey()); + } + } + + + public void bindingAdded(final Exchange exchange, final Binding binding) + { + propogateBinding(binding); + } + + public void bindingRemoved(final Exchange exchange, final Binding binding) + { + propogateBindingRemoval(binding); + } + + public void close() + { + // TODO + } + } + + private class StaticExchangePushBridge implements BridgeImpl, SessionListener + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag(); + private AMQQueue _queue; + + public void setSession(final Session session) + { + session.setSessionListener(this); + + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_source); + + // TODO - Check null + + final HashMap options = new HashMap(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + + _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, + isDurable(), + _link.getFederationTag(), + false, + getVirtualHost(), + options); + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + _destination, + MessageAcceptMode.NONE, + MessageAcquireMode.PRE_ACQUIRED, + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(_destination, sub); + + try + { + _queue.registerSubscription(sub, true); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.EMPTY_MAP); + } + + public void close() + { + // TODO + } + + public void opened(final Session session) + { + // this method never called + } + + public void resumed(final Session session) + { + // this session will never be resumed + } + + public void message(final Session ssn, final MessageTransfer xfr) + { + // messages should not be sent ... should probably log error + } + + public void exception(final Session session, final SessionException exception) + { + // TODO + } + + public void closed(final Session session) + { + // TODO + } + } + + private class StaticQueuePushBridge implements BridgeImpl, SessionListener + { + private AMQQueue _queue; + + public void setSession(final Session session) + { + session.setSessionListener(this); + + QueueRegistry queueRegistry = getVirtualHost().getQueueRegistry(); + + _queue = queueRegistry.getQueue(_source); + + // TODO - null check + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + _destination, + MessageAcceptMode.NONE, + MessageAcquireMode.PRE_ACQUIRED, + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(_destination, sub); + + try + { + _queue.registerSubscription(sub, false); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + } + + public void close() + { + // TODO + } + + public void opened(final Session session) + { + // never called + } + + public void resumed(final Session session) + { + // session will not resume + } + + public void message(final Session ssn, final MessageTransfer xfr) + { + // should never be called ... should probably log error + } + + public void exception(final Session session, final SessionException exception) + { + // TODO + } + + public void closed(final Session session) + { + // TODO + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java new file mode 100644 index 0000000000..bb6fb9dcc3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java @@ -0,0 +1,497 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.federation; + +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.ConnectionConfigType; +import org.apache.qpid.server.configuration.LinkConfig; +import org.apache.qpid.server.configuration.LinkConfigType; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Binary; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionException; +import org.apache.qpid.transport.ConnectionListener; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import org.apache.qpid.transport.TransportException; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public class BrokerLink implements LinkConfig, ConnectionListener +{ + + private static final int CORE_POOL_SIZE = 4; + + private static final ScheduledThreadPoolExecutor _threadPool = + new ScheduledThreadPoolExecutor(CORE_POOL_SIZE); + + + private final String _transport; + private final String _host; + private final int _port; + private final String _remoteVhost; + private final boolean _durable; + private final String _authMechanism; + private final String _username; + private final String _password; + private final VirtualHost _virtualHost; + private UUID _id; + private AtomicBoolean _closing = new AtomicBoolean(); + private final long _createTime = System.currentTimeMillis(); + private Connection _qpidConnection; + private AtomicReference _executor = new AtomicReference(); + private AtomicInteger _bridgeId = new AtomicInteger(); + + private final ConcurrentHashMap _bridges = new ConcurrentHashMap(); + private final ConcurrentHashMap _activeBridges = new ConcurrentHashMap(); + private final ConcurrentLinkedQueue _pendingBridges = new ConcurrentLinkedQueue(); + private String _remoteFederationTag; + + private ConnectionConfig _connectionConfig; + private ConnectionException _exception; + private String _lastErrorMessage; + private int _retryDelay = 1; + private final Runnable _makeConnectionTask = new Runnable() + { + public void run() + { + doMakeConnection(); + } + };; + ; + + public static enum State + { + OPERATIONAL, + DOWN, + ESTABLISHING, + DELETED + } + + + private volatile State _state = State.DOWN; + + private static final AtomicReferenceFieldUpdater _stateUpdater = + AtomicReferenceFieldUpdater.newUpdater(BrokerLink.class, State.class, "_state"); + + private class ConnectionConfigAdapter implements ConnectionConfig + { + + private UUID _id = BrokerLink.this.getConfigStore().createId(); + + public VirtualHost getVirtualHost() + { + return BrokerLink.this.getVirtualHost(); + } + + public String getAddress() + { + return _host+":"+_port; + } + + public Boolean isIncoming() + { + return false; + } + + public Boolean isSystemConnection() + { + return true; + } + + public Boolean isFederationLink() + { + return true; + } + + public String getAuthId() + { + return _username; + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemotePID() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public UUID getId() + { + return _id; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + } + + private class SessionFactory implements Connection.SessionFactory + { + + public Session newSession(final Connection conn, final Binary name, final long expiry) + { + return new ServerSession(conn, new SessionDelegate(), name, expiry, _connectionConfig); + } + }; + + + public BrokerLink(final VirtualHost virtualHost, + final String transport, + final String host, + final int port, + final String remoteVhost, + final boolean durable, + final String authMechanism, final String username, final String password) + { + _virtualHost = virtualHost; + _transport = transport; + _host = host; + _port = port; + _remoteVhost = remoteVhost; + _durable = durable; + _authMechanism = authMechanism; + _username = username; + _password = password; + _id = virtualHost.getConfigStore().createId(); + _qpidConnection = new Connection(); + _connectionConfig = new ConnectionConfigAdapter(); + _qpidConnection.addConnectionListener(this); + + + makeConnection(); + } + + private final boolean updateState(State expected, State newState) + { + return _stateUpdater.compareAndSet(this,expected,newState); + } + + private void makeConnection() + { + _threadPool.execute(_makeConnectionTask); + } + + + + private void doMakeConnection() + { + if(updateState(State.DOWN, State.ESTABLISHING)) + { + try + { + _qpidConnection.connect(_host, _port, _remoteVhost, _username, _password, "ssl".equals(_transport), _authMechanism); + + final Map serverProps = _qpidConnection.getServerProperties(); + _remoteFederationTag = (String) serverProps.get("qpid.federation_tag"); + if(_remoteFederationTag == null) + { + _remoteFederationTag = UUID.fromString(_transport+":"+_host+":"+_port).toString(); + } + _qpidConnection.setSessionFactory(new SessionFactory()); + _qpidConnection.setAuthorizationID(_username == null ? "" : _username); + + updateState(State.ESTABLISHING, State.OPERATIONAL); + + _retryDelay = 1; + + for(Bridge bridge : _bridges.values()) + { + if(_state != State.OPERATIONAL) + { + break; + } + addBridge(bridge); + } + + + } + catch (TransportException e) + { + _lastErrorMessage = e.getMessage(); + if(_retryDelay < 60) + { + _retryDelay <<= 1; + } + + updateState(State.ESTABLISHING, State.DOWN); + _activeBridges.clear(); + scheduleConnectionRetry(); + } + } + } + + private void scheduleConnectionRetry() + { + if(_state != State.DELETED) + { + _threadPool.schedule(_makeConnectionTask, _retryDelay, TimeUnit.SECONDS); + } + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public String getTransport() + { + return _transport; + } + + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } + + public String getRemoteVhost() + { + return _remoteVhost; + } + + public UUID getId() + { + return _id; + } + + public LinkConfigType getConfigType() + { + return LinkConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return _durable; + } + + public String getAuthMechanism() + { + return _authMechanism; + } + + public String getUsername() + { + return _username; + } + + public String getPassword() + { + return _password; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + final BrokerLink that = (BrokerLink) o; + + if (_port != that._port) + { + return false; + } + if (_host != null ? !_host.equals(that._host) : that._host != null) + { + return false; + } + if (_remoteVhost != null ? !_remoteVhost.equals(that._remoteVhost) : that._remoteVhost != null) + { + return false; + } + if (_transport != null ? !_transport.equals(that._transport) : that._transport != null) + { + return false; + } + + return true; + } + + @Override + public int hashCode() + { + int result = _transport != null ? _transport.hashCode() : 0; + result = 31 * result + (_host != null ? _host.hashCode() : 0); + result = 31 * result + _port; + result = 31 * result + (_remoteVhost != null ? _remoteVhost.hashCode() : 0); + return result; + } + + public void close() + { + if(_closing.compareAndSet(false,true)) + { + // TODO - close connection + for(Bridge bridge : _bridges.values()) + { + bridge.close(); + } + _bridges.clear(); + + _virtualHost.removeBrokerConnection(this); + } + } + + public long getCreateTime() + { + return _createTime; + } + + public void createBridge(final boolean durable, + final boolean dynamic, + final boolean srcIsQueue, + final boolean srcIsLocal, + final String src, + final String dest, + final String key, + final String tag, + final String excludes) + { + if(!_closing.get()) + { + Bridge bridge = new Bridge(this, _bridgeId.incrementAndGet(), durable,dynamic,srcIsQueue,srcIsLocal,src,dest,key,tag,excludes); + if(_bridges.putIfAbsent(bridge, bridge) == null) + { + + addBridge(bridge); + } + } + + + } + + private void addBridge(final Bridge bridge) + { + getConfigStore().addConfiguredObject(bridge); + + if(_state == State.OPERATIONAL && (_activeBridges.putIfAbsent(bridge,bridge) == null)) + { + + + Session session = _qpidConnection.createSession("Bridge(" + + (bridge.isDurable() ? "durable" : "transient") + + "," + (bridge.isDynamic() ? "dynamic" : "static") + + "," + (bridge.isQueueBridge() ? "queue" : "exchange") + + "," + (bridge.isLocalSource() ? "local-src" : "remote-src") + + ",[Source: '" + bridge.getSource() + "']" + + ",[Destination: '" + bridge.getDestination() + "']" + + ",[Key: '" + bridge.getKey() + "']" + + ",[Tag: '" + bridge.getTag() + "']" + + ".[Excludes: '" + bridge.getExcludes() + "'])"); + bridge.setSession(session); + + + if(_closing.get()) + { + bridge.close(); + } + } + + } + + public void opened(final Connection connection) + { + // this method not called + } + + public void exception(final Connection connection, final ConnectionException exception) + { + _exception = exception; + _lastErrorMessage = exception.getMessage(); + + } + + public void closed(final Connection connection) + { + State currentState = _state; + if(currentState != State.DOWN && currentState != State.DELETED && updateState(currentState, State.DOWN)) + { + scheduleConnectionRetry(); + } + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public String getFederationTag() + { + return getVirtualHost().getFederationTag(); + } + + public String getRemoteFederationTag() + { + return _remoteFederationTag; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index dacd047fea..f32de03841 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.server.filter.jms.selector.SelectorParser; import org.apache.qpid.server.queue.Filterable; @@ -33,7 +34,7 @@ public class JMSSelectorFilter implements MessageFilter private String _selector; private BooleanExpression _matcher; - public JMSSelectorFilter(String selector) throws AMQException + public JMSSelectorFilter(String selector) throws AMQInvalidArgumentException { _selector = selector; _matcher = new SelectorParser().parse(selector); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 0343457a73..d806f9426a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -27,7 +27,6 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -102,11 +101,11 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { private static final Logger _log = Logger.getLogger(QueueBindHandler.class); @@ -80,7 +86,7 @@ public class QueueBindHandler implements StateAwareMethodListener if (body.getRoutingKey() == null) { - routingKey = queue.getName(); + routingKey = queue.getNameShortString(); } else { @@ -116,18 +122,26 @@ public class QueueBindHandler implements StateAwareMethodListener else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } if (!exch.isBound(routingKey, body.getArguments(), queue)) { - queue.bind(exch, routingKey, body.getArguments()); + String bindingKey = String.valueOf(routingKey); + Map arguments = FieldTable.convertToMap(body.getArguments()); + + if(!virtualHost.getBindingFactory().addBinding(bindingKey, queue, exch, arguments)) + { + Binding oldBinding = virtualHost.getBindingFactory().getBinding(bindingKey, queue, exch, arguments); + + Map oldArgs = oldBinding.getArguments(); + if((oldArgs == null && !arguments.isEmpty()) || (oldArgs != null && !oldArgs.equals(arguments))) + { + virtualHost.getBindingFactory().replaceBinding(bindingKey, queue, exch, arguments); + } + } } } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); - } catch (AMQException e) { throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index bb57fdbc36..5d5bd761c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.handler; import java.util.UUID; +import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; @@ -150,21 +151,21 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -75,7 +73,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener names); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java index 4a1f8dd191..194835ac02 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -85,6 +85,19 @@ public class ContentHeaderBodyAdapter implements AMQMessageHeader return getProperties().getReplyToAsString(); } + public String getReplyToExchange() + { + // TODO + return getReplyTo(); + } + + public String getReplyToRoutingKey() + { + // TODO + return getReplyTo(); + + } + public Object getHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java index b34a8fc470..2f8c2e09a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -278,6 +278,18 @@ public class MessageMetaData implements StorableMessageMetaData return getProperties().getReplyToAsString(); } + public String getReplyToExchange() + { + // TODO + return getReplyTo(); + } + + public String getReplyToRoutingKey() + { + // TODO + return getReplyTo(); + } + public Object getHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index 7fac7ab164..a15e16a64f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -105,6 +105,30 @@ class MessageTransferHeader implements AMQMessageHeader } } + public String getReplyToExchange() + { + if (_messageProps != null && _messageProps.getReplyTo() != null) + { + return _messageProps.getReplyTo().getExchange(); + } + else + { + return null; + } + } + + public String getReplyToRoutingKey() + { + if (_messageProps != null && _messageProps.getReplyTo() != null) + { + return _messageProps.getReplyTo().getRoutingKey(); + } + else + { + return null; + } + } + public Object getHeader(String name) { Map appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java index e866ad5078..baa5dce14f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -119,7 +119,7 @@ public class MessageTransferMessage implements InboundMessage, ServerMessage public ByteBuffer getBody() { ByteBuffer body = getMetaData().getBody(); - if(body == null) + if(body == null && getSize() != 0l) { final int size = (int) getSize(); int pos = 0; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index ea8fbbd68f..ec74f79ace 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -20,50 +20,16 @@ */ package org.apache.qpid.server.protocol; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicMarkableReference; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; - import org.apache.log4j.Logger; import org.apache.mina.transport.vmpipe.VmPipeAddress; + import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQProtocolHeaderException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodDispatcher; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.*; import org.apache.qpid.pool.Job; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.protocol.AMQConstant; @@ -71,6 +37,10 @@ import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.ConnectionConfigType; import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; @@ -85,12 +55,31 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; -public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession +import javax.management.JMException; +import javax.security.sasl.SaslServer; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig { private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); @@ -161,6 +150,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); private long _maxFrameSize; private final AtomicBoolean _closing = new AtomicBoolean(false); + private final UUID _id; + private final ConfigStore _configStore; public ManagedObject getManagedObject() { @@ -181,6 +172,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _logSubject = new ConnectionLogSubject(this); + _configStore = virtualHostRegistry.getConfigStore(); + _id = _configStore.createId(); + + _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false)); } @@ -765,6 +760,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void closeProtocolSession() { + getConfigStore().removeConfiguredObject(this); + _networkDriver.close(); try { @@ -902,6 +899,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _virtualHost = virtualHost; _virtualHost.getConnectionRegistry().registerConnection(this); + + _configStore.addConfiguredObject(this); try { @@ -1067,4 +1066,69 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } + public Boolean isIncoming() + { + return true; + } + + public Boolean isSystemConnection() + { + return false; + } + + public Boolean isFederationLink() + { + return false; + } + + public String getAuthId() + { + return getAuthorizedID().getName(); + } + + public Integer getRemotePID() + { + return null; + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return _configStore; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + public UUID getId() + { + return _id; + } + + public String getAddress() + { + return String.valueOf(getRemoteAddress()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 0562d04b7b..8d832a6a79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,8 +37,19 @@ */ package org.apache.qpid.server.protocol; -import java.util.Date; -import java.util.List; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; import javax.management.JMException; import javax.management.MBeanException; @@ -55,22 +66,8 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; +import java.util.Date; +import java.util.List; /** * This MBean class implements the management interface. In order to make more attributes, operations and notifications @@ -255,7 +252,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed Object[] itemValues = { channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getNameShortString().asString() : null, channel.getUnacknowledgedMessageMap().size(), channel.getBlocking() }; @@ -291,7 +288,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed // then the CurrentActor could be set in our JMX Proxy object. // As it is we need to set the CurrentActor on all MBean methods // Ideally we would not have a single method that can be called from - // two contexts. + // two contexts. boolean removeActor = false; if (CurrentActor.get() == null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java index 9a1c6c9418..b3cb90fc6e 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.protocol; +import org.apache.log4j.Logger; + import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.transport.NetworkDriver; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionDelegate; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; +import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.transport.ServerConnection; -import org.apache.log4j.Logger; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.transport.NetworkDriver; import java.net.SocketAddress; import java.nio.ByteBuffer; @@ -239,10 +239,10 @@ private static final byte[] AMQP_0_9_1_HEADER = final ConnectionDelegate connDelegate = new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn); - Connection conn = new ServerConnection(); + ServerConnection conn = new ServerConnection(); conn.setConnectionDelegate(connDelegate); - return new ProtocolEngine_0_10( conn, _networkDriver); + return new ProtocolEngine_0_10( conn, _networkDriver, _appRegistry); } }; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java deleted file mode 100755 index 7c3adf8b7d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.protocol.ProtocolEngineFactory; -import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.transport.NetworkDriver; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionDelegate; -import org.apache.qpid.server.transport.ServerConnection; -import org.apache.qpid.server.protocol.ProtocolEngine_0_10; - -public class ProtocolEngineFactory_0_10 implements ProtocolEngineFactory -{ - private ConnectionDelegate _delegate; - - public ProtocolEngineFactory_0_10(ConnectionDelegate delegate) - { - _delegate = delegate; - } - - public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) - { - Connection conn = new ServerConnection(); - conn.setConnectionDelegate(_delegate); - return new ProtocolEngine_0_10(conn, networkDriver); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java index e3cd3acd98..473f68028d 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -26,23 +26,34 @@ import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.network.InputHandler; import org.apache.qpid.transport.network.Assembler; import org.apache.qpid.transport.network.Disassembler; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.registry.IApplicationRegistry; import java.net.SocketAddress; +import java.util.UUID; -public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine +public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine, ConnectionConfig { public static final int MAX_FRAME_SIZE = 64 * 1024 - 1; private NetworkDriver _networkDriver; private long _readBytes; private long _writtenBytes; - private Connection _connection; + private ServerConnection _connection; + private final UUID _id; + private final IApplicationRegistry _appRegistry; - public ProtocolEngine_0_10(Connection conn, NetworkDriver networkDriver) + public ProtocolEngine_0_10(ServerConnection conn, + NetworkDriver networkDriver, + final IApplicationRegistry appRegistry) { super(new Assembler(conn)); _connection = conn; + _connection.setConnectionConfig(this); _networkDriver = networkDriver; + _id = appRegistry.getConfigStore().createId(); + _appRegistry = appRegistry; } public void setNetworkDriver(NetworkDriver driver) @@ -50,6 +61,14 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine _networkDriver = driver; Disassembler dis = new Disassembler(driver, MAX_FRAME_SIZE); _connection.setSender(dis); + _connection.onOpen(new Runnable() + { + public void run() + { + getConfigStore().addConfiguredObject(ProtocolEngine_0_10.this); + } + }); + } public SocketAddress getRemoteAddress() @@ -81,4 +100,81 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine { //Todo } + + public VirtualHostConfig getVirtualHost() + { + return _connection.getVirtualHost(); + } + + public String getAddress() + { + return getRemoteAddress().toString(); + } + + public Boolean isIncoming() + { + return true; + } + + public Boolean isSystemConnection() + { + return false; + } + + public Boolean isFederationLink() + { + return false; + } + + public String getAuthId() + { + return _connection.getAuthorizationID(); + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemotePID() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return _appRegistry.getConfigStore(); + } + + public UUID getId() + { + return _id; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + @Override + public void closed() + { + super.closed(); + getConfigStore().removeConfiguredObject(this); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index 51fbff76f4..d8986ec303 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -21,9 +21,11 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Map; public class AMQPriorityQueue extends SimpleAMQQueue { @@ -32,18 +34,18 @@ public class AMQPriorityQueue extends SimpleAMQQueue final AMQShortString owner, final boolean autoDelete, final VirtualHost virtualHost, - int priorities) + int priorities, Map arguments) { - super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); + super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities),arguments); } public AMQPriorityQueue(String queueName, boolean durable, String owner, boolean autoDelete, - VirtualHost virtualHost, int priorities) + VirtualHost virtualHost, int priorities, Map arguments) { - this(new AMQShortString(queueName), durable, new AMQShortString(owner),autoDelete,virtualHost,priorities); + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,priorities, arguments); } public int getPriorities() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 028f7e15a4..81ea2083e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,44 +20,48 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.QueueConfig; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.List; -import java.util.Set; import java.util.Map; +import java.util.Set; -public interface AMQQueue extends Managable, Comparable, ExchangeReferrer, TransactionLogResource +public interface AMQQueue extends Managable, Comparable, ExchangeReferrer, TransactionLogResource, BaseQueue, + QueueConfig { boolean getDeleteOnNoConsumers(); void setDeleteOnNoConsumers(boolean b); + void addBinding(Binding binding); + + void removeBinding(Binding binding); + + List getBindings(); + + int getBindingCount(); public interface Context { QueueEntry getLastSeenEntry(); } - AMQShortString getName(); - void setNoLocal(boolean b); - boolean isDurable(); - boolean isAutoDelete(); AMQShortString getOwner(); @@ -69,14 +73,6 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer VirtualHost getVirtualHost(); - - void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - List getExchangeBindings(); - - void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; void unregisterSubscription(final Subscription subscription) throws AMQException; @@ -86,6 +82,8 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer int getActiveConsumerCount(); + boolean hasExclusiveSubscriber(); + boolean isUnused(); boolean isEmpty(); @@ -107,8 +105,6 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer int delete() throws AMQException; - QueueEntry enqueue(ServerMessage message) throws AMQException; - void requeue(QueueEntry entry); void requeue(QueueEntryImpl storeContext, Subscription subscription); @@ -122,6 +118,8 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer void addQueueDeleteTask(final Task task); + void removeQueueDeleteTask(final Task task); + List getMessagesOnTheQueue(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index d4a5b3258b..fd7dd4cc60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -23,16 +23,21 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.QueueConfiguration; import java.util.Map; +import java.util.HashMap; public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + private static final String QPID_LVQ_KEY = "qpid.LVQ_key"; + private static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; + private static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key"; + private abstract static class QueueProperty { @@ -130,21 +135,60 @@ public class AMQQueueFactory boolean autoDelete, VirtualHost virtualHost, final FieldTable arguments) { - final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + return createAMQQueueImpl(name == null ? null : name.toString(), + durable, + owner == null ? null : owner.toString(), + autoDelete, + virtualHost, + FieldTable.convertToMap(arguments)); + } - AMQQueue q = null; - if(priorities > 1) + + public static AMQQueue createAMQQueueImpl(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, Map arguments) + { + int priorities = 1; + String conflationKey = null; + if(arguments != null) { - q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); + if(arguments.containsKey(QPID_LAST_VALUE_QUEUE) || arguments.containsKey(QPID_LAST_VALUE_QUEUE_KEY)) + { + conflationKey = (String) arguments.get(QPID_LAST_VALUE_QUEUE_KEY); + if(conflationKey == null) + { + conflationKey = QPID_LVQ_KEY; + } + } + else if(arguments.containsKey(X_QPID_PRIORITIES)) + { + Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); + if(prioritiesObj instanceof Number) + { + priorities = ((Number)prioritiesObj).intValue(); + } + } + } + + AMQQueue q; + if(conflationKey != null) + { + q = new ConflationQueue(queueName, durable, owner, autoDelete, virtualHost, arguments, conflationKey); + } + else if(priorities > 1) + { + q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities, arguments); } else { - q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost, arguments); } //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); - q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString())); + q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); if(arguments != null) { @@ -158,29 +202,43 @@ public class AMQQueueFactory } return q; + } + public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException { - AMQShortString queueName = new AMQShortString(config.getName()); + String queueName = config.getName(); boolean durable = config.getDurable(); boolean autodelete = config.getAutoDelete(); - AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null; - FieldTable arguments = null; - boolean priority = config.getPriority(); - int priorities = config.getPriorities(); - if(priority || priorities > 0) + String owner = config.getOwner(); + Map arguments = null; + if(config.isLVQ() || config.getLVQKey() != null) { if(arguments == null) { - arguments = new FieldTable(); + arguments = new HashMap(); } - if (priorities < 0) + arguments.put(QPID_LAST_VALUE_QUEUE, 1); + arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey()); + } + else + { + boolean priority = config.getPriority(); + int priorities = config.getPriorities(); + if(priority || priorities > 0) { - priorities = 10; + if(arguments == null) + { + arguments = new HashMap(); + } + if (priorities < 0) + { + priorities = 10; + } + arguments.put("x-qpid-priorities", priorities); } - arguments.put(new AMQShortString("x-qpid-priorities"), priorities); } AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); @@ -188,38 +246,4 @@ public class AMQQueueFactory return q; } - public static AMQQueue createAMQQueueImpl(String queueName, - boolean durable, - String owner, - boolean autoDelete, - VirtualHost virtualHost, Map arguments) - throws AMQException - { - int priorities = 1; - if(arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) - { - Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); - if(prioritiesObj instanceof Number) - { - priorities = ((Number)prioritiesObj).intValue(); - } - } - - - AMQQueue q = null; - if(priorities > 1) - { - q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities); - } - else - { - q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost); - } - - //Register the new queue - virtualHost.getQueueRegistry().registerQueue(q); - q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); - return q; - - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index c21d73cc41..6102e525e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -95,7 +95,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; - _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); + _queueName = jmxEncode(new StringBuffer(queue.getNameShortString()), 0).toString(); } public ManagedObject getParentObject() @@ -252,7 +252,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { throw new IllegalArgumentException("Capacity must not be less than FlowResumeCapacity"); } - + _queue.setCapacity(capacity); } @@ -267,10 +267,10 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { throw new IllegalArgumentException("FlowResumeCapacity must not exceed Capacity"); } - + _queue.setFlowResumeCapacity(flowResumeCapacity); } - + public boolean isFlowOverfull() { return _queue.isOverfull(); @@ -309,7 +309,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) { // important : add log to the log file - monitoring tools may be looking for this - _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); + _logger.info(notification.name() + " On Queue " + queue.getNameShortString() + " - " + notificationMsg); notificationMsg = notification.name() + " " + notificationMsg; _lastNotification = @@ -509,7 +509,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private String[] getMessageTransferMessageHeaderProps(MessageTransferMessage msg) { List list = new ArrayList(); - + AMQMessageHeader header = msg.getMessageHeader(); MessageProperties msgProps = msg.getHeader().get(MessageProperties.class); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java new file mode 100644 index 0000000000..05e0efd9a6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; + +public interface BaseQueue extends TransactionLogResource +{ + public static interface PostEnqueueAction + { + public void onEnqueue(QueueEntry entry); + } + + void enqueue(ServerMessage message) throws AMQException; + void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException; + + boolean isDurable(); + + AMQShortString getNameShortString(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java new file mode 100644 index 0000000000..26c0d7cf26 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Map; + +public class ConflationQueue extends SimpleAMQQueue +{ + protected ConflationQueue(String name, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, + Map args, + String conflationKey) + { + super(name, durable, owner, autoDelete, virtualHost, new ConflationQueueList.Factory(conflationKey), args); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java new file mode 100644 index 0000000000..9a6e5c884a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java @@ -0,0 +1,168 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.message.ServerMessage; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; + +public class ConflationQueueList extends SimpleQueueEntryList +{ + + private final String _conflationKey; + private final ConcurrentHashMap> _latestValuesMap = + new ConcurrentHashMap>(); + + public ConflationQueueList(AMQQueue queue, String conflationKey) + { + super(queue); + _conflationKey = conflationKey; + } + + @Override + protected ConflationQueueEntry createQueueEntry(ServerMessage message) + { + return new ConflationQueueEntry(this, message); + } + + + @Override + public QueueEntry add(final ServerMessage message) + { + ConflationQueueEntry entry = (ConflationQueueEntry) (super.add(message)); + AtomicReference latestValueReference = null; + + Object value = message.getMessageHeader().getHeader(_conflationKey); + if(value != null) + { + latestValueReference = _latestValuesMap.get(value); + if(latestValueReference == null) + { + _latestValuesMap.putIfAbsent(value, new AtomicReference(entry)); + latestValueReference = _latestValuesMap.get(value); + } + QueueEntry oldEntry; + + do + { + oldEntry = latestValueReference.get(); + } + while(oldEntry.compareTo(entry) < 0 && !latestValueReference.compareAndSet(oldEntry, entry)); + + if(oldEntry.compareTo(entry) < 0) + { + // We replaced some other entry to become the newest value + if(oldEntry.acquire()) + { + discardEntry(oldEntry); + } + } + else if (oldEntry.compareTo(entry) > 0) + { + // A newer entry came along + discardEntry(entry); + + } + } + + entry.setLatestValueReference(latestValueReference); + return entry; + } + + private void discardEntry(final QueueEntry entry) + { + if(entry.acquire()) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + txn.dequeue(entry.getQueue(),entry.getMessage(), + new ServerTransaction.Action() + { + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + + } + }); + } + } + + private final class ConflationQueueEntry extends QueueEntryImpl + { + + + private AtomicReference _latestValueReference; + + public ConflationQueueEntry(SimpleQueueEntryList queueEntryList, ServerMessage message) + { + super(queueEntryList, message); + } + + + public void release() + { + super.release(); + + if(_latestValueReference != null) + { + if(_latestValueReference.get() != this) + { + discardEntry(this); + } + } + + } + + public void setLatestValueReference(final AtomicReference latestValueReference) + { + _latestValueReference = latestValueReference; + } + } + + static class Factory implements QueueEntryListFactory + { + private final String _conflationKey; + + Factory(String conflationKey) + { + _conflationKey = conflationKey; + } + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new ConflationQueueList(queue, _conflationKey); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index aea485e749..d76487073d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -46,7 +45,7 @@ public class DefaultQueueRegistry implements QueueRegistry public void registerQueue(AMQQueue queue) { - _queueMap.put(queue.getName(), queue); + _queueMap.put(queue.getNameShortString(), queue); } public void unregisterQueue(AMQShortString name) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java deleted file mode 100644 index 2fd8e32fcd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.BindingMessages; -import org.apache.qpid.server.logging.subjects.BindingLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; - -public class ExchangeBinding -{ - private final Exchange _exchange; - private final AMQShortString _routingKey; - private final FieldTable _arguments; - - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); - private LogSubject _logSubject; - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, AMQQueue queue, FieldTable arguments) - { - _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; - _exchange = exchange; - _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; - _logSubject = new BindingLogSubject(routingKey,exchange,queue); - - CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(_arguments), arguments != null)); - } - - - - void unbind(AMQQueue queue) throws AMQException - { - _exchange.deregisterQueue(_routingKey, queue, _arguments); - - CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); - } - - public Exchange getExchange() - { - return _exchange; - } - - public AMQShortString getRoutingKey() - { - return _routingKey; - } - - public FieldTable getArguments() - { - return _arguments; - } - - public int hashCode() - { - return (_exchange == null ? 0 : _exchange.hashCode()) - + (_routingKey == null ? 0 : _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); - } -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java deleted file mode 100644 index 89262aee59..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; - -/** - * 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 -{ - 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(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - _bindings.add(new ExchangeBinding(routingKey, exchange, _queue, arguments)); - } - - - public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - return _bindings.remove(new ExchangeBinding(routingKey, exchange, _queue, arguments)); - } - - - /** - * 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/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index da4173d5d3..2d2fb3a214 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -63,7 +63,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done * by the message handle. */ - private ArrayList _destinationQueues; + private ArrayList _destinationQueues; private long _expiration; @@ -131,7 +131,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } - public ArrayList getDestinationQueues() + public ArrayList getDestinationQueues() { return _destinationQueues; } @@ -225,7 +225,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } - public void enqueue(final ArrayList queues) + public void enqueue(final ArrayList queues) { _destinationQueues = queues; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index a50e2b561d..edd1e0bdc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -28,6 +28,7 @@ public interface QueueEntry extends Comparable, Filterable { + public static enum State { AVAILABLE, @@ -163,6 +164,8 @@ public interface QueueEntry extends Comparable, Filterable boolean expired() throws AMQException; + boolean isAvailable(); + boolean isAcquired(); boolean acquire(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 5873e8f566..ada7726fc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -20,20 +20,23 @@ */ package org.apache.qpid.server.queue; +import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.log4j.Logger; -import java.util.*; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class QueueEntryImpl implements QueueEntry @@ -154,6 +157,11 @@ public class QueueEntryImpl implements QueueEntry } + public boolean isAvailable() + { + return _state == AVAILABLE_STATE; + } + public boolean isAcquired() { return _state.getState() == State.ACQUIRED; @@ -408,7 +416,7 @@ public class QueueEntryImpl implements QueueEntry if(alternateExchange != null) { - final List rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); + final List rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); final ServerMessage message = getMessage(); if(rerouteQueues != null && rerouteQueues.size() != 0) { @@ -419,9 +427,9 @@ public class QueueEntryImpl implements QueueEntry { try { - for(AMQQueue queue : rerouteQueues) + for(BaseQueue queue : rerouteQueues) { - QueueEntry entry = queue.enqueue(message); + queue.enqueue(message); } } catch (AMQException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 825aa9795e..d25d73b383 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,39 +1,51 @@ package org.apache.qpid.server.queue; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import javax.management.JMException; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.QueueConfigType; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.QueueActor; +import org.apache.qpid.server.logging.messages.QueueMessages; +import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.QueueActor; -import org.apache.qpid.server.logging.subjects.QueueLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.messages.QueueMessages; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; /* * @@ -81,7 +93,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private Exchange _alternateExchange; /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ - private final ExchangeBindings _bindings = new ExchangeBindings(this); + protected final QueueEntryList _entries; @@ -102,8 +114,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _totalMessagesReceived = new AtomicLong(); + private final AtomicLong _dequeueCount = new AtomicLong(); + private final AtomicLong _dequeueSize = new AtomicLong(); + private final AtomicLong _enqueueSize = new AtomicLong(); + private final AtomicLong _persistentMessageEnqueueSize = new AtomicLong(); + private final AtomicLong _persistentMessageDequeueSize = new AtomicLong(); + private final AtomicLong _persistentMessageEnqueueCount = new AtomicLong();; + private final AtomicLong _persistentMessageDequeueCount = new AtomicLong(); - + private final AtomicInteger _bindingCountHigh = new AtomicInteger(); /** max allowed size(KB) of a single message */ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); @@ -151,18 +170,38 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicBoolean _overfull = new AtomicBoolean(false); private boolean _deleteOnNoConsumers; + private final CopyOnWriteArrayList _bindings = new CopyOnWriteArrayList(); + private UUID _id; + private final Map _arguments; + + //TODO + private long _createTime = System.currentTimeMillis(); + - protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, Map arguments) { - this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); + this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory(),arguments); } + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, Map arguments) + { + this(queueName, durable, owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory(),arguments); + } + + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) + { + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,entryListFactory, arguments); + } + + + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, - QueueEntryListFactory entryListFactory) + QueueEntryListFactory entryListFactory, + Map arguments) { if (name == null) @@ -182,6 +221,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _autoDelete = autoDelete; _virtualHost = virtualHost; _entries = entryListFactory.createQueueEntryList(this); + _arguments = arguments; + + _id = virtualHost.getConfigStore().createId(); _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); @@ -208,6 +250,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener durable, !durable, priorities > 0)); + getConfigStore().addConfiguredObject(this); + try { _managedObject = new AMQQueueMBean(this); @@ -222,12 +266,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException - { - this(new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost); - } - public void resetNotifications() { // This ensure that the notification checks for the configured alerts are created. @@ -244,7 +282,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery.execute(runnable); } - public AMQShortString getName() + public AMQShortString getNameShortString() { return _name; } @@ -254,6 +292,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _nolocal = nolocal; } + public UUID getId() + { + return _id; + } + + public QueueConfigType getConfigType() + { + return QueueConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + public boolean isDurable() { return _durable; @@ -284,7 +337,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public Map getArguments() { - return null; + return _arguments; } public boolean isAutoDelete() @@ -313,56 +366,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _virtualHost; } - // ------ bind and unbind - - public void bind(Exchange exchange, String bindingKey, Map arguments) throws AMQException - { - - FieldTable fieldTable = FieldTable.convertToFieldTable(arguments); - AMQShortString routingKey = new AMQShortString(bindingKey); - - exchange.registerQueue(routingKey, this, fieldTable); - - if (isDurable() && exchange.isDurable()) - { - - _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, fieldTable); - } - - _bindings.addBinding(routingKey, fieldTable, exchange); - } - - - public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException - { - - exchange.registerQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, arguments); - } - - _bindings.addBinding(routingKey, arguments, exchange); - } - - public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + public String getName() { - exchange.deregisterQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getDurableConfigurationStore().unbindQueue(exchange, routingKey, this, arguments); - } - - boolean removed = _bindings.remove(routingKey, arguments, exchange); - if (!removed) - { - _logger.error("Mismatch between queue bindings and exchange record of bindings"); - } - } - - public List getExchangeBindings() - { - return new ArrayList(_bindings.getExchangeBindings()); + return getNameShortString().toString(); } // ------ Manage Subscriptions @@ -370,7 +376,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException { - if (isExclusiveSubscriber()) + if (hasExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); } @@ -459,17 +465,54 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteOnNoConsumers = b; } + public void addBinding(final Binding binding) + { + _bindings.add(binding); + int bindingCount = _bindings.size(); + int bindingCountHigh; + while(bindingCount > (bindingCountHigh = _bindingCountHigh.get())) + { + if(_bindingCountHigh.compareAndSet(bindingCountHigh, bindingCount)) + { + break; + } + } + } + + public int getBindingCountHigh() + { + return _bindingCountHigh.get(); + } + + public void removeBinding(final Binding binding) + { + _bindings.remove(binding); + } + + public List getBindings() + { + return Collections.unmodifiableList(_bindings); + } + + public int getBindingCount() + { + return getBindings().size(); + } // ------ Enqueue / Dequeue + public void enqueue(ServerMessage message) throws AMQException + { + enqueue(message, null); + } - public QueueEntry enqueue(ServerMessage message) throws AMQException + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { incrementQueueCount(); incrementQueueSize(message); - _totalMessagesReceived.incrementAndGet(); + QueueEntry entry; Subscription exclusiveSub = _exclusiveSubscriber; @@ -554,7 +597,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _managedObject.checkForNotification(entry.getMessage()); } - return entry; + if(action != null) + { + action.onEnqueue(entry); + } + } private void deliverToSubscription(final Subscription sub, final QueueEntry entry) @@ -596,7 +643,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void incrementQueueSize(final ServerMessage message) { - getAtomicQueueSize().addAndGet(message.getSize()); + long size = message.getSize(); + getAtomicQueueSize().addAndGet(size); + _enqueueSize.addAndGet(size); + if(message.isPersistent() && isDurable()) + { + _persistentMessageEnqueueSize.addAndGet(size); + _persistentMessageEnqueueCount.incrementAndGet(); + } } private void incrementQueueCount() @@ -654,7 +708,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards - while (subscriberIter.advance()) + while (subscriberIter.advance() && entry.isAvailable()) { Subscription sub = subscriberIter.getNode().getSubscription(); @@ -702,12 +756,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void decrementQueueSize(final QueueEntry entry) { - getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); + final ServerMessage message = entry.getMessage(); + long size = message.getSize(); + getAtomicQueueSize().addAndGet(-size); + _dequeueSize.addAndGet(size); + if(message.isPersistent() && isDurable()) + { + _persistentMessageDequeueSize.addAndGet(size); + _persistentMessageDequeueCount.incrementAndGet(); + } } void decrementQueueCount() { getAtomicQueueCount().decrementAndGet(); + _dequeueCount.incrementAndGet(); } public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException @@ -834,7 +897,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public int compareTo(final AMQQueue o) { - return _name.compareTo(o.getName()); + return _name.compareTo(o.getNameShortString()); } public AtomicInteger getAtomicQueueCount() @@ -847,7 +910,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _atomicQueueSize; } - private boolean isExclusiveSubscriber() + public boolean hasExclusiveSubscriber() { return _exclusiveSubscriber != null; } @@ -1099,6 +1162,45 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public void purge(final long request) + { + if(request == 0l) + { + clearQueue(); + } + else if(request > 0l) + { + + QueueEntryIterator queueListIterator = _entries.iterator(); + long count = 0; + + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && node.acquire()) + { + dequeueEntry(node, txn); + if(++count == request) + { + break; + } + } + + } + + txn.commit(); + + + } + } + + public long getCreateTime() + { + return _createTime; + } + // ------ Management functions public void deleteMessageFromTop() @@ -1172,11 +1274,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.add(task); } + public void removeQueueDeleteTask(final Task task) + { + _deleteTaskList.remove(task); + } + public int delete() throws AMQException { if (!_deleted.getAndSet(true)) { + for(Binding b : getBindings()) + { + _virtualHost.getBindingFactory().removeBinding(b); + } + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); while (subscriptionIter.advance()) @@ -1188,8 +1300,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); + getConfigStore().removeConfiguredObject(this); List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -1214,7 +1326,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for(final QueueEntry entry : entries) { adapter.setEntry(entry); - final List rerouteQueues = _alternateExchange.route(adapter); + final List rerouteQueues = _alternateExchange.route(adapter); final ServerMessage message = entry.getMessage(); if(rerouteQueues != null & rerouteQueues.size() != 0) { @@ -1226,9 +1338,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { try { - for(AMQQueue queue : rerouteQueues) + for(BaseQueue queue : rerouteQueues) { - QueueEntry entry = queue.enqueue(message); + queue.enqueue(message); } } catch (AMQException e) @@ -1479,7 +1591,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc // which would give us memory "leak". - if (!isExclusiveSubscriber()) + if (!hasExclusiveSubscriber()) { advanceAllSubscriptions(); } @@ -1820,7 +1932,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setFlowResumeCapacity(long flowResumeCapacity) { _flowResumeCapacity = flowResumeCapacity; - + checkCapacity(); } @@ -1919,9 +2031,50 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public long getMessageDequeueCount() + { + return _dequeueCount.get(); + } + + public long getTotalEnqueueSize() + { + return _enqueueSize.get(); + } + + public long getTotalDequeueSize() + { + return _dequeueSize.get(); + } + + public long getPersistentByteEnqueues() + { + return _persistentMessageEnqueueSize.get(); + } + + public long getPersistentByteDequeues() + { + return _persistentMessageDequeueSize.get(); + } + + public long getPersistentMsgEnqueues() + { + return _persistentMessageEnqueueCount.get(); + } + + public long getPersistentMsgDequeues() + { + return _persistentMessageDequeueCount.get(); + } + + @Override public String toString() { - return String.valueOf(getName()); + return String.valueOf(getNameShortString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index d27a5ed234..8721da0f78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -61,11 +61,9 @@ public class SimpleQueueEntryList implements QueueEntryList { _deletes.incrementAndGet(); QueueEntryImpl head = _head.nextNode(); - boolean deleted = head.isDeleted(); while(head._next != null && head.isDeleted()) { - deleted = true; final QueueEntryImpl newhead = head.nextNode(); if(newhead != null) { @@ -77,11 +75,6 @@ public class SimpleQueueEntryList implements QueueEntryList head = _head.nextNode(); } - if(!deleted) - { - deleted = true; - } - if(_deletes.get() > 1000L) { _deletes.set(0L); @@ -135,7 +128,7 @@ public class SimpleQueueEntryList implements QueueEntryList public QueueEntry add(ServerMessage message) { - QueueEntryImpl node = new QueueEntryImpl(this, message); + QueueEntryImpl node = createQueueEntry(message); for (;;) { QueueEntryImpl tail = _tail; @@ -160,6 +153,11 @@ public class SimpleQueueEntryList implements QueueEntryList } } + protected QueueEntryImpl createQueueEntry(ServerMessage message) + { + return new QueueEntryImpl(this, message); + } + public QueueEntry next(QueueEntry node) { return ((QueueEntryImpl)node).getNext(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 5cb379f10d..2c4c0a0570 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,24 +20,33 @@ */ package org.apache.qpid.server.registry; -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; - import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + +import org.apache.qpid.qmf.QMFService; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.SystemConfig; +import org.apache.qpid.server.configuration.SystemConfigImpl; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.transport.QpidAcceptor; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * An abstract application registry that provides access to configuration information and handles the @@ -75,6 +84,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected RootMessageLogger _rootMessageLogger; + protected UUID _brokerId = UUID.randomUUID(); + + protected QMFService _qmfService; + + private BrokerConfig _broker; + + private ConfigStore _configStore; + static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -100,6 +117,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.info("Initialising Application Registry:" + instanceID); _instanceMap.put(instanceID, instance); + final ConfigStore store = ConfigStore.newInstance(); + store.setRoot(new SystemConfigImpl(store)); + instance.setConfigStore(store); + + BrokerConfig broker = new BrokerConfigAdapter(instance, instanceID); + + SystemConfig system = (SystemConfig) store.getRoot(); + system.addBroker(broker); + instance.setBroker(broker); + try { instance.initialise(instanceID); @@ -107,7 +134,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry catch (Exception e) { _instanceMap.remove(instanceID); - throw e; + try + { + system.removeBroker(broker); + } + finally + { + throw e; + } } } else @@ -116,6 +150,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + public ConfigStore getConfigStore() + { + return _configStore; + } + + public void setConfigStore(final ConfigStore configStore) + { + _configStore = configStore; + } + public static boolean isConfigured() { return isConfigured(DEFAULT_INSTANCE); @@ -151,6 +195,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); } instance.close(); + instance.getBroker().getSystem().removeBroker(instance.getBroker()); } } catch (Exception e) @@ -316,5 +361,32 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { return _rootMessageLogger; } - + + public UUID getBrokerId() + { + return _brokerId; + } + + public QMFService getQMFService() + { + return _qmfService; + } + + public BrokerConfig getBroker() + { + return _broker; + } + + public void setBroker(final BrokerConfig broker) + { + _broker = broker; + } + + public VirtualHost createVirtualHost(final VirtualHostConfiguration vhostConfig) throws Exception + { + VirtualHostImpl virtualHost = new VirtualHostImpl(this, vhostConfig); + _virtualHostRegistry.registerVirtualHost(virtualHost); + getBroker().addVirtualHost(virtualHost); + return virtualHost; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java new file mode 100644 index 0000000000..c3d1945550 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java @@ -0,0 +1,163 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.common.QpidProperties; + +import java.util.UUID; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BrokerConfigAdapter implements BrokerConfig +{ + private final IApplicationRegistry _instance; + private final int _instanceId; + private SystemConfig _system; + + private final Map _vhosts = new ConcurrentHashMap(); + private final long _createTime = System.currentTimeMillis(); + private UUID _id; + private String _federationTag; + + public BrokerConfigAdapter(final IApplicationRegistry instance, final int instanceID) + { + _instance = instance; + _instanceId = instanceID; + _id = instance.getConfigStore().createId(); + _federationTag = UUID.randomUUID().toString(); + } + + public void setSystem(final SystemConfig system) + { + _system = system; + } + + public SystemConfig getSystem() + { + return _system; + } + + public Integer getPort() + { + List ports = _instance.getConfiguration().getPorts(); + if(ports.size() > 0) + { + return Integer.valueOf(ports.get(0).toString()); + } + else + { + return 0; + } + } + + public Integer getWorkerThreads() + { + return _instance.getConfiguration().getProcessors(); + } + + public Integer getMaxConnections() + { + return 0; + } + + public Integer getConnectionBacklogLimit() + { + return 0; + } + + public Long getStagingThreshold() + { + return 0L; + } + + public Integer getManagementPublishInterval() + { + return 10; + } + + public String getVersion() + { + return QpidProperties.getReleaseVersion() + " [Build: " + QpidProperties.getBuildVersion() + "]"; + } + + public String getDataDirectory() + { + return _instance.getConfiguration().getQpidWork(); + } + + public void addVirtualHost(final VirtualHostConfig virtualHost) + { + virtualHost.setBroker(this); + _vhosts.put(virtualHost.getId(), virtualHost); + getConfigStore().addConfiguredObject(virtualHost); + + } + + private ConfigStore getConfigStore() + { + return _instance.getConfigStore(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void createBrokerConnection(final String transport, + final String host, + final int port, + final boolean durable, + final String authMechanism, + final String username, + final String password) + { + VirtualHost vhost = _instance.getVirtualHostRegistry().getDefaultVirtualHost(); + vhost.createBrokerConnection(transport, host, port, "", durable, authMechanism, username, password); + } + + public UUID getId() + { + return _id; + } + + public BrokerConfigType getConfigType() + { + return BrokerConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _system; + } + + public boolean isDurable() + { + return false; + } + + public String getFederationTag() + { + return _federationTag; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index f325b53dfb..e1cc1bf1dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -21,13 +21,15 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; + import org.apache.qpid.AMQException; import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.logging.RootMessageLoggerImpl; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; @@ -36,7 +38,6 @@ import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import java.io.File; @@ -51,6 +52,9 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise(int instanceID) throws Exception { + _qmfService = new QMFService(getConfigStore(), this); + + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); @@ -75,6 +79,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _databaseManager.initialiseManagement(_configuration); + _managedObjectRegistry.start(); initialiseVirtualHosts(); @@ -91,6 +96,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry try { super.close(); + _qmfService.close(); } finally { @@ -102,7 +108,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { for (String name : _configuration.getVirtualHosts()) { - _virtualHostRegistry.registerVirtualHost(new VirtualHostImpl(_configuration.getVirtualHostConfig(name))); + createVirtualHost(_configuration.getVirtualHostConfig(name)); } getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 92accb3499..f0226c7982 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -20,22 +20,25 @@ */ package org.apache.qpid.server.registry; -import java.util.Collection; -import java.net.InetSocketAddress; - -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; + +import org.apache.qpid.qmf.QMFService; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.transport.QpidAcceptor; -import org.apache.mina.common.IoAcceptor; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +import java.net.InetSocketAddress; +import java.util.UUID; public interface IApplicationRegistry { @@ -81,4 +84,17 @@ public interface IApplicationRegistry */ void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor); + public UUID getBrokerId(); + + QMFService getQMFService(); + + void setBroker(BrokerConfig broker); + + BrokerConfig getBroker(); + + VirtualHost createVirtualHost(VirtualHostConfiguration vhostConfig) throws Exception; + + ConfigStore getConfigStore(); + + void setConfigStore(ConfigStore store); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index a299907e42..e7fc8effaf 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -42,7 +42,7 @@ public class PrincipalPermissions private static final Object CREATE_QUEUES_KEY = new Object(); private static final Object CREATE_EXCHANGES_KEY = new Object(); - + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); @@ -64,9 +64,9 @@ public class PrincipalPermissions } /** - * + * * @param permission the type of permission to check - * + * * @param parameters vararg depending on what permission was passed in * ACCESS: none * BIND: none @@ -113,7 +113,7 @@ public class PrincipalPermissions { _fullVHostAccess = true; } - + private void grantPublish(Permission permission, Object... parameters) { Map publishRights = (Map) _permissions.get(permission); @@ -344,9 +344,9 @@ public class PrincipalPermissions } /** - * + * * @param permission the type of permission to check - * + * * @param parameters vararg depending on what permission was passed in * ACCESS: none * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey @@ -363,7 +363,7 @@ public class PrincipalPermissions switch (permission) { - case ACCESS://No Parameters + case ACCESS://No Parameters return AuthzResult.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey return authoriseBind(parameters); @@ -444,7 +444,7 @@ public class PrincipalPermissions { if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) { - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } else { @@ -453,7 +453,7 @@ public class PrincipalPermissions } // If we are - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } @@ -486,7 +486,7 @@ public class PrincipalPermissions // Otherwise exchange must be listed in the white list // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) + if (!exchanges.containsKey(((Exchange) parameters[0]).getNameShortString())) { return AuthzResult.DENIED; } @@ -494,7 +494,7 @@ public class PrincipalPermissions { // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); + HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getNameShortString()); // Having no routingKeys in the map then all are allowed. if (routingKeys == null) @@ -544,7 +544,7 @@ public class PrincipalPermissions // check the valid exchanges if (rights == null || rights.containsKey(exchangeName)) { - return AuthzResult.ALLOWED; + return AuthzResult.ALLOWED; } else { @@ -587,13 +587,13 @@ public class PrincipalPermissions // If there is a white list then check if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) { - return AuthzResult.ALLOWED; + return AuthzResult.ALLOWED; } else { return AuthzResult.DENIED; } - + } } @@ -604,7 +604,7 @@ public class PrincipalPermissions //user has been granted full access to the vhost return AuthzResult.ALLOWED; } - + Exchange exchange = (Exchange) parameters[1]; AMQQueue bind_queueName = (AMQQueue) parameters[2]; @@ -631,7 +631,7 @@ public class PrincipalPermissions } // Check to see if we have a white list of routingkeys to check - Map rkeys = (Map) exchangeDetails.get(exchange.getName()); + Map rkeys = (Map) exchangeDetails.get(exchange.getNameShortString()); // if keys is null then any rkey is allowed on this exchange if (rkeys == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java new file mode 100644 index 0000000000..4a66b74783 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.anonymous; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainSaslServerFactory; + +public class AnonymousInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "ANONYMOUS"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return AnonymousSaslServerFactory.class; + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java new file mode 100644 index 0000000000..b4cce15d88 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java @@ -0,0 +1,88 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.anonymous; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +public class AnonymousSaslServer implements SaslServer +{ + public static final String MECHANISM = "ANONYMOUS"; + + private boolean _complete = false; + + public AnonymousSaslServer() + { + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + _complete = true; + return null; + } + + public boolean isComplete() + { + return _complete; + } + + public String getAuthorizationID() + { + return null; + } + + 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 + { + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java new file mode 100644 index 0000000000..6032255870 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.anonymous; + +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainSaslServer; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class AnonymousSaslServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (AnonymousSaslServer.MECHANISM.equals(mechanism)) + { + return new AnonymousSaslServer(); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE) || + props.containsKey(Sasl.POLICY_NOANONYMOUS)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + else + { + return new String[]{AnonymousSaslServer.MECHANISM}; + } + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 5ca75aa9ae..31211d6b9e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -20,22 +20,24 @@ */ package org.apache.qpid.server.store; +import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.TransactionLogMessages; -import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.commons.configuration.Configuration; - import java.io.ByteArrayInputStream; import java.io.File; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; import java.sql.Blob; import java.sql.Connection; import java.sql.Driver; @@ -49,8 +51,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; public class DerbyMessageStore implements MessageStore @@ -590,7 +590,10 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString()); + stmt.execute(); + stmt.close(); + conn.commit(); ResultSet rs = stmt.executeQuery(); @@ -617,7 +620,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing Exchange with name " + exchange.getName() + " to database: " + e, e); + throw new AMQException("Error writing Exchange with name " + exchange.getNameShortString() + " to database: " + e, e); } } @@ -631,11 +634,11 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString()); int results = stmt.executeUpdate(); if(results == 0) { - throw new AMQException("Exchange " + exchange.getName() + " not found"); + throw new AMQException("Exchange " + exchange.getNameShortString() + " not found"); } else { @@ -645,7 +648,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing deleting with name " + exchange.getName() + " from database: " + e, e); + throw new AMQException("Error writing deleting with name " + exchange.getNameShortString() + " from database: " + e, e); } finally { @@ -677,8 +680,8 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); ResultSet rs = stmt.executeQuery(); @@ -687,8 +690,8 @@ public class DerbyMessageStore implements MessageStore if (!rs.next()) { stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(args != null) { @@ -713,8 +716,8 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " to database: " + e, e); + throw new AMQException("Error writing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " to database: " + e, e); } finally { @@ -748,23 +751,23 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(stmt.executeUpdate() != 1) { - throw new AMQException("Queue binding for queue with name " + queue.getName() + " to exchange " - + exchange.getName() + " not found"); + throw new AMQException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " not found"); } conn.commit(); stmt.close(); } catch (SQLException e) { - throw new AMQException("Error removing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " in database: " + e, e); + throw new AMQException("Error removing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " in database: " + e, e); } finally { @@ -801,7 +804,7 @@ public class DerbyMessageStore implements MessageStore Connection conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); - stmt.setString(1, queue.getName().toString()); + stmt.setString(1, queue.getNameShortString().toString()); ResultSet rs = stmt.executeQuery(); @@ -816,7 +819,7 @@ public class DerbyMessageStore implements MessageStore ? null : queue.getPrincipalHolder().getPrincipal().getName(); - stmt.setString(1, queue.getName().toString()); + stmt.setString(1, queue.getNameShortString().toString()); stmt.setString(2, owner); stmt.execute(); @@ -830,7 +833,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing AMQQueue with name " + queue.getName() + " to database: " + e, e); + throw new AMQException("Error writing AMQQueue with name " + queue.getNameShortString() + " to database: " + e, e); } } } @@ -843,7 +846,7 @@ public class DerbyMessageStore implements MessageStore public void removeQueue(final AMQQueue queue) throws AMQException { - AMQShortString name = queue.getName(); + AMQShortString name = queue.getNameShortString(); _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); Connection conn = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java index cfbacd28c8..a50e8e99b4 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -31,6 +31,11 @@ import org.apache.commons.configuration.Configuration; public interface DurableConfigurationStore { + public static interface Source + { + DurableConfigurationStore getDurableConfigurationStore(); + } + /** * Called after instantiation in order to configure the message store. A particular implementation can define * whatever parameters it wants. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 684d3c2e74..b0ea0ef506 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -20,41 +20,49 @@ */ package org.apache.qpid.server.subscription; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.ConcurrentHashMap; -import java.util.Map; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfigType; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.filter.FilterManager; -import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * 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 abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener +public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener, + SubscriptionConfig { private StateListener _stateListener = new StateListener() @@ -85,6 +93,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final long _subscriptionID = idGenerator.getAndIncrement(); private LogSubject _logSubject; private LogActor _logActor; + private UUID _id; static final class BrowserSubscription extends SubscriptionImpl @@ -152,6 +161,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return false; } + @Override + public boolean isExplicitAcknowledge() + { + return false; + } + /** * This method can be called by each of the publisher threads. As a result all changes to the channel object must be * thread safe. @@ -318,9 +333,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _autoClose = false; } - } + public ConfigStore getConfigStore() + { + return getQueue().getConfigStore(); + } public synchronized void setQueue(AMQQueue queue, boolean exclusive) @@ -331,6 +349,9 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } _queue = queue; + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); + _logSubject = new SubscriptionLogSubject(this); _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); @@ -414,7 +435,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public boolean hasInterest(QueueEntry entry) { - + //check that the message hasn't been rejected @@ -505,7 +526,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage { _stateChangeLock.unlock(); } - + getConfigStore().removeConfiguredObject(this); //Log Subscription closed CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_CLOSE()); @@ -689,4 +710,60 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } abstract boolean isBrowser(); + + public String getCreditMode() + { + return "WINDOW"; + } + + public SessionConfig getSessionConfig() + { + return getChannel(); + } + + public boolean isBrowsing() + { + return isBrowser(); + } + + public boolean isExplicitAcknowledge() + { + return true; + } + + public UUID getId() + { + return _id; + } + + public boolean isDurable() + { + return false; + } + + public SubscriptionConfigType getConfigType() + { + return SubscriptionConfigType.getInstance(); + } + + public boolean isExclusive() + { + return getQueue().hasExclusiveSubscriber(); + } + + public ConfiguredObject getParent() + { + return getSessionConfig(); + } + + public String getName() + { + return String.valueOf(_consumerTag); + } + + public Map getArguments() + { + return null; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 5b3668ab64..54c294c76d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -36,11 +36,12 @@ import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderProperties; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.AMQException; import org.apache.qpid.transport.*; @@ -50,12 +51,10 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.ConcurrentHashMap; -import java.util.ArrayList; -import java.util.Map; -import java.util.HashMap; +import java.util.*; import java.nio.ByteBuffer; -public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener +public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig { private static final AtomicLong idGenerator = new AtomicLong(0); @@ -98,6 +97,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private LogSubject _logSubject; private LogActor _logActor; private Map _properties = new ConcurrentHashMap(); + private UUID _id; + private String _traceExclude; + private String _trace; public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, @@ -116,7 +118,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _creditManager.addStateListener(this); _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED); - } public void setNoLocal(boolean noLocal) @@ -146,6 +147,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); } _queue = queue; + Map arguments = queue.getArguments() == null ? Collections.EMPTY_MAP : queue.getArguments(); + _traceExclude = (String) arguments.get("qpid.trace.exclude"); + _trace = (String) arguments.get("qpid.trace.id"); + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); _logSubject = new SubscriptionLogSubject(this); _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); @@ -235,6 +241,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } } _creditManager.removeListener(this); + getConfigStore().removeConfiguredObject(this); } finally { @@ -245,6 +252,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } + public ConfigStore getConfigStore() + { + return getQueue().getConfigStore(); + } + public void creditStateChanged(boolean hasCredit) { @@ -290,6 +302,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr MessageTransfer xfr; + DeliveryProperties deliveryProps; + MessageProperties messageProps = null; + if(serverMsg instanceof MessageTransferMessage) { @@ -316,11 +331,15 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } else { + if(header instanceof MessageProperties) + { + messageProps = (MessageProperties) header; + } newHeaders.add(header); } } - DeliveryProperties deliveryProps = new DeliveryProperties(); + deliveryProps = new DeliveryProperties(); if(origDeliveryProps != null) { if(origDeliveryProps.hasDeliveryMode()) @@ -343,21 +362,33 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { deliveryProps.setRoutingKey(origDeliveryProps.getRoutingKey()); } + if(origDeliveryProps.hasTimestamp()) + { + deliveryProps.setTimestamp(origDeliveryProps.getTimestamp()); + } + } deliveryProps.setRedelivered(entry.isRedelivered()); newHeaders.add(deliveryProps); + + if(_trace != null && messageProps == null) + { + messageProps = new MessageProperties(); + newHeaders.add(messageProps); + } + Header header = new Header(newHeaders); xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); } - else + else if(serverMsg instanceof AMQMessage) { AMQMessage message_0_8 = (AMQMessage) serverMsg; - DeliveryProperties deliveryProps = new DeliveryProperties(); - MessageProperties messageProps = new MessageProperties(); + deliveryProps = new DeliveryProperties(); + messageProps = new MessageProperties(); int size = (int) message_0_8.getSize(); ByteBuffer body = ByteBuffer.allocate(size); @@ -399,9 +430,52 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setUserId(properties.getUserId().getBytes()); } + FieldTable fieldTable = properties.getHeaders(); + + final Map appHeaders = FieldTable.convertToMap(fieldTable); + + + messageProps.setApplicationHeaders(appHeaders); + + Header header = new Header(headers); + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + } + else + { + + deliveryProps = new DeliveryProperties(); + messageProps = new MessageProperties(); + + int size = (int) serverMsg.getSize(); + ByteBuffer body = ByteBuffer.allocate(size); + serverMsg.getContent(body, 0); + body.flip(); + + Struct[] headers = new Struct[] { deliveryProps, messageProps }; + + + deliveryProps.setExpiration(serverMsg.getExpiration()); + deliveryProps.setImmediate(serverMsg.isImmediate()); + deliveryProps.setPriority(MessageDeliveryPriority.get(serverMsg.getMessageHeader().getPriority())); + deliveryProps.setRedelivered(entry.isRedelivered()); + deliveryProps.setRoutingKey(serverMsg.getRoutingKey()); + deliveryProps.setTimestamp(serverMsg.getMessageHeader().getTimestamp()); + + messageProps.setContentEncoding(serverMsg.getMessageHeader().getEncoding()); + messageProps.setContentLength(size); + messageProps.setContentType(serverMsg.getMessageHeader().getMimeType()); + if(serverMsg.getMessageHeader().getCorrelationId() != null) + { + messageProps.setCorrelationId(serverMsg.getMessageHeader().getCorrelationId().getBytes()); + } + + + // TODO - ReplyTo + + final Map appHeaders = new HashMap(); - properties.getHeaders().processOverElements( + /*properties.getHeaders().processOverElements( new FieldTable.FieldTableElementProcessor() { @@ -424,39 +498,98 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setApplicationHeaders(appHeaders); - +*/ Header header = new Header(headers); xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); } - if(_acceptMode == MessageAcceptMode.NONE) + boolean excludeDueToFederation = false; + + if(_trace != null) { - xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + if(!messageProps.hasApplicationHeaders()) + { + messageProps.setApplicationHeaders(new HashMap()); + } + Map appHeaders = messageProps.getApplicationHeaders(); + String trace = (String) appHeaders.get("x-qpid.trace"); + if(trace == null) + { + trace = _trace; + } + else + { + if(_traceExclude != null) + { + excludeDueToFederation = Arrays.asList(trace.split(",")).contains(_traceExclude); + } + trace+=","+_trace; + } + appHeaders.put("x-qpid.trace",trace); } - else if(_flowMode == MessageFlowMode.WINDOW) + + if(!excludeDueToFederation) { - xfr.setCompletionListener(new Method.CompletionListener() - { - public void onComplete(Method method) + if(_acceptMode == MessageAcceptMode.NONE) + { + xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + } + else if(_flowMode == MessageFlowMode.WINDOW) + { + xfr.setCompletionListener(new Method.CompletionListener() { - restoreCredit(entry); - } - }); - } + public void onComplete(Method method) + { + restoreCredit(entry); + } + }); + } - _postIdSettingAction._xfr = xfr; - if(_acceptMode == MessageAcceptMode.EXPLICIT) - { - _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + _postIdSettingAction._xfr = xfr; + if(_acceptMode == MessageAcceptMode.EXPLICIT) + { + _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + } + else + { + _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + } + + _session.sendMessage(xfr, _postIdSettingAction); + + if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED) + { + forceDequeue(entry, false); + } } else { - _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + forceDequeue(entry, _flowMode == MessageFlowMode.WINDOW); + } + } + + private void forceDequeue(final QueueEntry entry, final boolean restoreCredit) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + txn.dequeue(entry.getQueue(),entry.getMessage(), + new ServerTransaction.Action() + { + public void postCommit() + { + if(restoreCredit) + { + restoreCredit(entry); + } + entry.discard(); + } - _session.sendMessage(xfr, _postIdSettingAction); + public void onRollback() + { + } + }); } void reject(QueueEntry entry) @@ -660,4 +793,59 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } + public SessionConfig getSessionConfig() + { + return getSession(); + } + + public boolean isBrowsing() + { + return _acquireMode == MessageAcquireMode.NOT_ACQUIRED; + } + + public boolean isExclusive() + { + return getQueue().hasExclusiveSubscriber(); + } + + public ConfiguredObject getParent() + { + return getSessionConfig(); + } + + public boolean isDurable() + { + return false; + } + + public SubscriptionConfigType getConfigType() + { + return SubscriptionConfigType.getInstance(); + } + + public boolean isExplicitAcknowledge() + { + return _acceptMode == MessageAcceptMode.EXPLICIT; + } + + public String getCreditMode() + { + return _flowMode.toString(); + } + + public UUID getId() + { + return _id; + } + + public String getName() + { + return _destination; + } + + public Map getArguments() + { + //TODO + return Collections.EMPTY_MAP; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 2a8b99ddac..1aff1eec86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -20,12 +20,20 @@ */ package org.apache.qpid.server.transport; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.Method; -import org.apache.qpid.server.virtualhost.VirtualHost; public class ServerConnection extends Connection { + private ConnectionConfig _config; + private Runnable _onOpenTask; + + public ServerConnection() + { + } + @Override protected void invoke(Method method) { @@ -36,6 +44,10 @@ public class ServerConnection extends Connection protected void setState(State state) { super.setState(state); + if(state == State.OPEN && _onOpenTask != null) + { + _onOpenTask.run(); + } } @Override @@ -61,4 +73,19 @@ public class ServerConnection extends Connection { _virtualHost = virtualHost; } + + public void setConnectionConfig(final ConnectionConfig config) + { + _config = config; + } + + public ConnectionConfig getConfig() + { + return _config; + } + + public void onOpen(final Runnable task) + { + _onOpenTask = task; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index cfc5bb3a72..4cfcafa533 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -40,7 +40,7 @@ public class ServerConnectionDelegate extends ServerDelegate public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN) { - this(Collections.EMPTY_MAP, Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); + this(new HashMap(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 77dfbc0376..3e48ac2619 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -20,32 +20,55 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.transport.*; +import com.sun.security.auth.UserPrincipal; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SessionConfigType; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.subscription.Subscription_0_10; -import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Binary; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.Range; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import static org.apache.qpid.util.Serial.gt; -import java.util.*; +import java.lang.ref.WeakReference; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.security.Principal; -import java.lang.ref.WeakReference; -import static org.apache.qpid.util.Serial.*; -import com.sun.security.auth.UserPrincipal; - -public class ServerSession extends Session implements PrincipalHolder +public class ServerSession extends Session implements PrincipalHolder, SessionConfig { private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); + private final UUID _id; + private ConnectionConfig _connectionConfig; + public static interface MessageDispositionChangeListener { public void onAccept(); @@ -78,37 +101,41 @@ public class ServerSession extends Session implements PrincipalHolder private final WeakReference _reference; - - ServerSession(Connection connection, Binary name, long expiry) + ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) { - super(connection, name, expiry); - - _transaction = new AutoCommitTransaction(this.getMessageStore()); - _principal = new UserPrincipal(connection.getAuthorizationID()); - _reference = new WeakReference(this); + this(connection, delegate, name, expiry, ((ServerConnection)connection).getConfig()); } - ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) + public ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry, ConnectionConfig connConfig) { super(connection, delegate, name, expiry); + _connectionConfig = connConfig; _transaction = new AutoCommitTransaction(this.getMessageStore()); _principal = new UserPrincipal(connection.getAuthorizationID()); _reference = new WeakReference(this); + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); + } + + private ConfigStore getConfigStore() + { + return getConnectionConfig().getConfigStore(); } + @Override protected boolean isFull(int id) { return isCommandsFull(id); } - public void enqueue(final ServerMessage message, final ArrayList queues) + public void enqueue(final ServerMessage message, final ArrayList queues) { _transaction.enqueue(queues,message, new ServerTransaction.Action() { - AMQQueue[] _queues = queues.toArray(new AMQQueue[queues.size()]); + BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); public void postCommit() { @@ -243,7 +270,7 @@ public class ServerSession extends Session implements PrincipalHolder Iterator unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); Iterator rangeIter = ranges.iterator(); - if(rangeIter.hasNext()) + if(rangeIter.hasNext()) { Range range = rangeIter.next(); @@ -290,6 +317,8 @@ public class ServerSession extends Session implements PrincipalHolder } _messageDispositionListenerMap.clear(); + getConfigStore().removeConfiguredObject(this); + for (Task task : _taskList) { task.doTask(this); @@ -391,8 +420,61 @@ public class ServerSession extends Session implements PrincipalHolder public MessageStore getMessageStore() { - return ((ServerConnection)getConnection()).getVirtualHost().getMessageStore(); + return getVirtualHost().getMessageStore(); } + public VirtualHost getVirtualHost() + { + return (VirtualHost) _connectionConfig.getVirtualHost(); + } + + public UUID getId() + { + return _id; + } + + public SessionConfigType getConfigType() + { + return SessionConfigType.getInstance(); + } + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + public boolean isAttached() + { + return true; + } + + public long getDetachedLifespan() + { + return 0; + } + + public Long getExpiryTime() + { + return null; + } + + public Long getMaxClientRate() + { + return null; + } + + public ConnectionConfig getConnectionConfig() + { + return _connectionConfig; + } + + public String getSessionName() + { + return getName().toString(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 4ade799c59..3b0f990377 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -28,6 +28,7 @@ import org.apache.qpid.server.exchange.*; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.message.MessageMetaData_0_10; import org.apache.qpid.server.subscription.Subscription_0_10; @@ -42,6 +43,7 @@ import org.apache.qpid.framing.*; import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import java.nio.ByteBuffer; public class ServerSessionDelegate extends SessionDelegate { @@ -218,11 +220,15 @@ public class ServerSessionDelegate extends SessionDelegate MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); final MessageStore store = getVirtualHost(ssn).getMessageStore(); StoredMessage storeMessage = store.addMessage(messageMetaData); - storeMessage.addContent(0,xfr.getBody()); + ByteBuffer body = xfr.getBody(); + if(body != null) + { + storeMessage.addContent(0, body); + } storeMessage.flushToStore(); MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference()); - ArrayList queues = exchange.route(message); + ArrayList queues = exchange.route(message); @@ -355,7 +361,7 @@ public class ServerSessionDelegate extends SessionDelegate else { // TODO - check exchange has same properties - if(!exchange.getType().toString().equals(method.getType())) + if(!exchange.getTypeShortString().toString().equals(method.getType())) { exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); } @@ -419,7 +425,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - if(!exchange.getType().toString().equals(method.getType())) + if(!exchange.getTypeShortString().toString().equals(method.getType())) { exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); } @@ -525,7 +531,7 @@ public class ServerSessionDelegate extends SessionDelegate if(exchange != null) { result.setDurable(exchange.isDurable()); - result.setType(exchange.getType().toString()); + result.setType(exchange.getTypeShortString().toString()); result.setNotFound(false); } else @@ -582,30 +588,23 @@ public class ServerSessionDelegate extends SessionDelegate + "' to Queue: '" + method.getQueue() + "' not allowed"); } - else if(exchange.getType().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) + else if(exchange.getTypeShortString().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) { exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); } else { - try - { - AMQShortString routingKey = new AMQShortString(method.getBindingKey()); - FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); + AMQShortString routingKey = new AMQShortString(method.getBindingKey()); + FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); - if (!exchange.isBound(routingKey, fieldTable, queue)) - { - queue.bind(exchange, routingKey, fieldTable); + if (!exchange.isBound(routingKey, fieldTable, queue)) + { + virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); - } - else - { - // todo - } } - catch (AMQException e) + else { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + // todo } } @@ -649,14 +648,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - try - { - queue.unBind(exchange, new AMQShortString(method.getBindingKey()), null); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } + virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); } } @@ -827,7 +819,7 @@ public class ServerSessionDelegate extends SessionDelegate { queue.setDeleteOnNoConsumers(true); } - + final String alternateExchangeName = method.getAlternateExchange(); if(alternateExchangeName != null && alternateExchangeName.length() != 0) { @@ -870,11 +862,12 @@ public class ServerSessionDelegate extends SessionDelegate if (autoRegister) { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); - queue.bind(defaultExchange, new AMQShortString(queueName), null); + virtualHost.getBindingFactory().addBinding(queueName, queue, defaultExchange, null); } @@ -1114,7 +1107,7 @@ public class ServerSessionDelegate extends SessionDelegate if(queue != null) { - result.setQueue(queue.getName().toString()); + result.setQueue(queue.getNameShortString().toString()); result.setDurable(queue.isDurable()); result.setExclusive(queue.isExclusive()); result.setAutoDelete(queue.isAutoDelete()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java index 7b29106ba6..f674741057 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.TransactionLog; @@ -46,7 +47,7 @@ public class AutoCommitTransaction implements ServerTransaction postCommitAction.postCommit(); } - public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { try @@ -105,7 +106,7 @@ public class AutoCommitTransaction implements ServerTransaction } - public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { try { @@ -128,7 +129,7 @@ public class AutoCommitTransaction implements ServerTransaction } - public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) { try { @@ -137,7 +138,7 @@ public class AutoCommitTransaction implements ServerTransaction { TransactionLog.Transaction txn = _transactionLog.newTransaction(); Long id = message.getMessageNumber(); - for(AMQQueue q : queues) + for(BaseQueue q : queues) { if(q.isDurable()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index 9997fbe767..1124b0e812 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -2,6 +2,7 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.TransactionLog; @@ -28,7 +29,7 @@ public class LocalTransaction implements ServerTransaction _postCommitActions.add(postCommitAction); } - public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { if(message.isPersistent() && queue.isDurable()) { @@ -113,7 +114,7 @@ public class LocalTransaction implements ServerTransaction } } - public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { if(message.isPersistent() && queue.isDurable()) { @@ -132,7 +133,7 @@ public class LocalTransaction implements ServerTransaction } - public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) { @@ -140,7 +141,7 @@ public class LocalTransaction implements ServerTransaction { if(_transaction == null) { - for(AMQQueue queue : queues) + for(BaseQueue queue : queues) { if(queue.isDurable()) { @@ -155,7 +156,7 @@ public class LocalTransaction implements ServerTransaction try { - for(AMQQueue queue : queues) + for(BaseQueue queue : queues) { if(queue.isDurable()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java index 88bdc363c4..f3ef6569f3 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -20,15 +20,12 @@ */ package org.apache.qpid.server.txn; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.EnqueableMessage; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueEntry; -import java.util.List; -import java.util.SortedSet; import java.util.Collection; +import java.util.List; public interface ServerTransaction { @@ -45,13 +42,13 @@ public interface ServerTransaction public void onRollback(); } - void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); void dequeue(Collection ackedMessages, Action postCommitAction); - void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); - void enqueue(List queues, EnqueableMessage message, Action postCommitAction); + void enqueue(List queues, EnqueableMessage message, Action postCommitAction); void commit(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e4a382d275..c140e4a144 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -21,7 +21,10 @@ package org.apache.qpid.server.virtualhost; import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; @@ -31,8 +34,13 @@ import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.binding.BindingFactory; -public interface VirtualHost +import java.util.UUID; +import java.util.TimerTask; + +public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig { IConnectionRegistry getConnectionRegistry(); @@ -59,4 +67,24 @@ public interface VirtualHost void close() throws Exception; ManagedObject getManagedObject(); + + UUID getBrokerId(); + + void scheduleTask(long period, TimerTask task); + + + IApplicationRegistry getApplicationRegistry(); + + BindingFactory getBindingFactory(); + + void createBrokerConnection(String transport, + String host, + int port, + String vhost, + boolean durable, + String authMechanism, String username, String password); + + ConfigStore getConfigStore(); + + void removeBrokerConnection(BrokerLink brokerLink); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index c543531210..221ec0b639 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -34,10 +34,10 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.TransactionLogMessages; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; @@ -215,7 +215,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (queue == null) { _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getName()); + + exchange.getNameShortString()); } else { @@ -227,10 +227,18 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa argumentsFT = new FieldTable(org.apache.mina.common.ByteBuffer.wrap(buf),buf.limit()); } - _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName - + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + BindingFactory bf = _virtualHost.getBindingFactory(); - queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + Map argumentMap = FieldTable.convertToMap(argumentsFT); + + if(bf.getBinding(bindingKey, queue, exchange, argumentMap) == null) + { + + _logger.info("Restoring binding: (Exchange: " + exchange.getNameShortString() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + + bf.restoreBinding(bindingKey, queue, exchange, argumentMap); + } } } @@ -271,7 +279,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (_logger.isDebugEnabled()) { - _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getName()); + _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getNameShortString()); } Integer count = _queueRecoveries.get(queueName); @@ -286,7 +294,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa } else { - _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getName() + " is unknwon, entry will be discarded"); + _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getNameShortString() + " is unknwon, entry will be discarded"); TransactionLog.Transaction txn = _transactionLog.newTransaction(); txn.dequeueMessage(queue, messageId); txn.commitTranAsync(); @@ -333,7 +341,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey())); CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true)); - } + } CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 2f1528eb43..b208872a5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -20,19 +20,21 @@ */ package org.apache.qpid.server.virtualhost; -import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.VirtualHostMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; -import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.ExchangeConfiguration; import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfigType; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; @@ -41,6 +43,11 @@ import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.federation.BrokerLink; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; @@ -48,14 +55,15 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import javax.management.NotCompliantMBeanException; import java.util.Collections; @@ -63,6 +71,9 @@ import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + public class VirtualHostImpl implements Accessable, VirtualHost { @@ -88,9 +99,17 @@ public class VirtualHostImpl implements Accessable, VirtualHost private ACLManager _accessManager; - private final Timer _houseKeepingTimer; + private final Timer _timer; + private final IApplicationRegistry _appRegistry; private VirtualHostConfiguration _configuration; private DurableConfigurationStore _durableConfigurationStore; + private BindingFactory _bindingFactory; + private BrokerConfig _broker; + private UUID _id; + + + private final long _createTime = System.currentTimeMillis(); + private final ConcurrentHashMap _links = new ConcurrentHashMap(); public void setAccessableName(String name) { @@ -113,6 +132,26 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _configuration; } + public UUID getId() + { + return _id; //To change body of implemented methods use File | Settings | File Templates. + } + + public VirtualHostConfigType getConfigType() + { + return VirtualHostConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getBroker(); + } + + public boolean isDurable() + { + return false; + } + /** * 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. @@ -141,23 +180,28 @@ public class VirtualHostImpl implements Accessable, VirtualHost } // End of MBean class - /** - * Normal Constructor - * - * @param hostConfig - * - * @throws Exception - */ - public VirtualHostImpl(VirtualHostConfiguration hostConfig) throws Exception + + + public VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig) throws Exception { - this(hostConfig, null); + this(appRegistry, hostConfig, null); } + public VirtualHostImpl(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception { + this(ApplicationRegistry.getInstance(),hostConfig,store); + } + + private VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig, MessageStore store) throws Exception + { + _appRegistry = appRegistry; + _broker = appRegistry.getBroker(); _configuration = hostConfig; _name = hostConfig.getName(); + _id = appRegistry.getConfigStore().createId(); + CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); if (_name == null || _name.length() == 0) @@ -169,7 +213,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _connectionRegistry = new ConnectionRegistry(this); - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + _timer = new Timer("TimerThread-" + _name + ":", true); _queueRegistry = new DefaultQueueRegistry(this); @@ -178,6 +222,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _exchangeRegistry = new DefaultExchangeRegistry(this); + //Create a temporary RT to store the durable entries from the config file // so we can replay them in to the real _RT after it has been loaded. /// This should be removed after the _RT has been fully split from the the TL @@ -189,6 +234,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost // This needs to be after the RT has been defined as it creates the default durable exchanges. _exchangeRegistry.initialise(); + _bindingFactory = new BindingFactory(this); + initialiseModel(hostConfig); if (store != null) @@ -205,9 +252,11 @@ public class VirtualHostImpl implements Accessable, VirtualHost initialiseMessageStore(hostConfig); } + + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config // file and write them in to the new routing Table. - for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) +/* for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) { getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); } @@ -220,7 +269,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) { getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - } + }*/ _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); @@ -250,7 +299,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost } catch (Exception e) { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + _logger.error("Exception in housekeeping for queue: " + q.getNameShortString().toString(), e); //Don't throw exceptions as this will stop the // house keeping task from running. } @@ -258,9 +307,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); + final TimerTask expiredMessagesTask = new RemoveExpiredMessagesTask(); + scheduleTask(period, expiredMessagesTask); class ForceChannelClosuresTask extends TimerTask { @@ -272,6 +320,12 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } + public void scheduleTask(final long period, final TimerTask task) + { + _timer.scheduleAtFixedRate(task, period / 2, period); + } + + private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception { String messageStoreClass = hostConfig.getMessageStoreClass(); @@ -377,7 +431,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost List routingKeys = queueConfiguration.getRoutingKeys(); if (routingKeys == null || routingKeys.isEmpty()) { - routingKeys = Collections.singletonList(queue.getName()); + routingKeys = Collections.singletonList(queue.getNameShortString()); } for (Object routingKeyNameObj : routingKeys) @@ -387,12 +441,12 @@ public class VirtualHostImpl implements Accessable, VirtualHost { _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); } - queue.bind(exchange, routingKey, null); + _bindingFactory.addBinding(routingKey.toString(), queue, exchange, null); } if (exchange != _exchangeRegistry.getDefaultExchange()) { - queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + _bindingFactory.addBinding(queue.getNameShortString().toString(), queue, exchange, null); } } @@ -401,6 +455,26 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _name; } + public BrokerConfig getBroker() + { + return _broker; + } + + public String getFederationTag() + { + return _broker.getFederationTag(); + } + + public void setBroker(final BrokerConfig broker) + { + _broker = broker; + } + + public long getCreateTime() + { + return _createTime; + } + public QueueRegistry getQueueRegistry() { return _queueRegistry; @@ -457,9 +531,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost } //Stop Housekeeping - if (_houseKeepingTimer != null) + if (_timer != null) { - _houseKeepingTimer.cancel(); + _timer.cancel(); } //Close MessageStore @@ -481,6 +555,59 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _virtualHostMBean; } + public UUID getBrokerId() + { + return _appRegistry.getBrokerId(); + } + + public IApplicationRegistry getApplicationRegistry() + { + return _appRegistry; + } + + public BindingFactory getBindingFactory() + { + return _bindingFactory; + } + + public void createBrokerConnection(final String transport, + final String host, + final int port, + final String vhost, + final boolean durable, + final String authMechanism, + final String username, + final String password) + { + BrokerLink blink = new BrokerLink(this, transport, host, port, vhost, durable, authMechanism, username, password); + _links.putIfAbsent(blink,blink); + getConfigStore().addConfiguredObject(blink); + } + + public void removeBrokerConnection(final String transport, + final String host, + final int port, + final String vhost) + { + removeBrokerConnection(new BrokerLink(this, transport, host, port, vhost, false, null,null,null)); + + } + + public void removeBrokerConnection(BrokerLink blink) + { + blink = _links.get(blink); + if(blink != null) + { + blink.close(); + getConfigStore().removeConfiguredObject(blink); + } + } + + public ConfigStore getConfigStore() + { + return getApplicationRegistry().getConfigStore(); + } + /** * Temporary Startup RT class to record the creation of persistent queues / exchanges. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index b86e0d0baf..5975eeec3d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.virtualhost; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.configuration.ConfigStore; import java.util.ArrayList; import java.util.Collection; @@ -52,7 +53,7 @@ public class VirtualHostRegistry public VirtualHost getVirtualHost(String name) { - if(name == null || name.trim().length() == 0 ) + if(name == null || name.trim().length() == 0 || "/".equals(name.trim())) { name = getDefaultVirtualHostName(); } @@ -60,6 +61,11 @@ public class VirtualHostRegistry return _registry.get(name); } + public VirtualHost getDefaultVirtualHost() + { + return getVirtualHost(getDefaultVirtualHostName()); + } + private String getDefaultVirtualHostName() { return _defaultVirtualHostName; @@ -80,4 +86,9 @@ public class VirtualHostRegistry { return _applicationRegistry; } + + public ConfigStore getConfigStore() + { + return _applicationRegistry.getConfigStore(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java index faa7b85d58..f26611f0bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -219,7 +219,7 @@ public class MessageStoreTool _console.println(""); - _console.println(BOILER_PLATE); + _console.println(BOILER_PLATE); runCLI(); } @@ -495,13 +495,13 @@ public class MessageStoreTool if (_exchange != null) { status.append("["); - status.append(_exchange.getName()); + status.append(_exchange.getNameShortString()); status.append("]"); if (_queue != null) { status.append("->'"); - status.append(_queue.getName()); + status.append(_queue.getNameShortString()); status.append("'"); if (_msgids != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java index ef3599bdc8..348c95572d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -52,7 +52,7 @@ public class Copy extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), txn); + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getNameShortString().toString(), txn); txn.commit(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java index ab8e781df5..3c4a0c8fac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -292,12 +292,12 @@ public class List extends AbstractCommand { if (exchange.isBound(queue)) { - data.add(queue.getName().toString()); + data.add(queue.getNameShortString().toString()); } } else { - data.add(queue.getName().toString()); + data.add(queue.getNameShortString().toString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index 6a5e2a6025..615f6ec1c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -196,7 +196,7 @@ public class Move extends AbstractCommand protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) { ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), txn); + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getNameShortString().toString(), txn); txn.commit(); } } -- cgit v1.2.1 From 0defb143a4ef03f77436efe81f1f7902e828b6b4 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 31 Jan 2010 00:53:20 +0000 Subject: QPID-2379 : Updates to deal with changes to management spec git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@904940 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 6a1c24b5a7..a3d6ce0885 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1056,6 +1056,16 @@ public class QMFService implements ConfigStore.ConfigEventListener return factory.createResponseCommand(); } + public BrokerSchema.QueueClass.RerouteMethodResponseCommand reroute(final BrokerSchema.QueueClass.RerouteMethodResponseCommandFactory factory, + final Long request, + final Boolean useAltExchange, + final String exchange) + { + //TODO + return factory.createResponseCommand(); + } + + public Map getArguments() { return _obj.getArguments(); -- cgit v1.2.1 From 9a2820488699edbf64cd48d5ce69700a0963d925 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 5 Feb 2010 10:13:21 +0000 Subject: QPID-2370 : Committing patch to improve broker logging. This will not cleanly apply to trunk due to IO changes. QPID-1084 : Committed change to prevent flow control threads being created/sent if the channel/session is closed or the state has acutally changed in the mean time. Wrapped .debug statements as per review feedback Merged and adapted these changes from 0.5.x r905592,905596,905605 The AMQMinaProtocolSession Changes were moved to the AMQProtocolEngine git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@906890 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 4 +++- .../src/main/java/org/apache/qpid/server/state/AMQStateManager.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index ec74f79ace..6d2826b55e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -407,11 +407,13 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR, AMQConstant.CHANNEL_ERROR.getName().toString()); + _logger.info(e.getMessage() + " whilst processing:" + methodBody); closeConnection(channelId, ce, false); } } catch (AMQConnectionException e) { + _logger.info(e.getMessage() + " whilst processing:" + methodBody); closeConnection(channelId, e, false); } } @@ -744,7 +746,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { if (_logger.isInfoEnabled()) { - _logger.info("Closing connection due to: " + e.getMessage()); + _logger.info("Closing connection due to: " + e); } markChannelAwaitingCloseOk(channelId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index c5b3099f58..6850724b10 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -196,7 +196,7 @@ public class AMQStateManager implements AMQMethodListener || (body instanceof ChannelCloseOkBody) || (body instanceof ChannelCloseBody))) { - throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "channel is closed"); + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "channel is closed won't process:" + body); } } -- cgit v1.2.1 From ebb7a3b8337377a1717b43ca5c56187c00d4c382 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Mon, 8 Feb 2010 21:16:38 +0000 Subject: Added unimplimented method to get the trunk compiling git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@907801 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index a3d6ce0885..d289d3c34b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1235,6 +1235,13 @@ public class QMFService implements ConfigStore.ConfigEventListener // TODO return 0; } + + @Override + public Boolean getShadow() + { + // TODO Auto-generated method stub + return null; + } } private class SessionDelegate implements BrokerSchema.SessionDelegate -- cgit v1.2.1 From 8618b7e45ba6b0f74b27c68d2bcf94cd57f15758 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Fri, 12 Feb 2010 22:30:38 +0000 Subject: I have added the license header to the files included in this commit. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@909641 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/protocol/AMQProtocolEngineFactory.java | 21 +++++++++++++++++++++ .../apache/qpid/server/queue/SubFlushRunner.java | 21 +++++++++++++++++++++ .../security/access/AuthorizationManager.java | 21 +++++++++++++++++++++ .../apache/qpid/server/txn/LocalTransaction.java | 21 +++++++++++++++++++++ 4 files changed, 84 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java index ff0c007a60..0e4444725e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.protocol; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.protocol.ProtocolEngineFactory; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java index 547365f647..1309e05978 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.queue; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.server.subscription.Subscription; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java index 9527120f30..895ed52222 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.security.access; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + public class AuthorizationManager { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index 1124b0e812..7c9276dbdc 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -1,4 +1,25 @@ package org.apache.qpid.server.txn; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; -- cgit v1.2.1 From d92c23f24b1c3609ed006f31281b1358a8b8d4a6 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 15 Feb 2010 12:18:50 +0000 Subject: QPID-2379: change unimplemented property method to return false instead of null git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@910210 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index d289d3c34b..33847683bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1240,7 +1240,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Boolean getShadow() { // TODO Auto-generated method stub - return null; + return false; } } -- cgit v1.2.1 From 11d0830854190774df9d46f0745142e26ec1feb5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:17:32 +0000 Subject: QPID-2379: add ConsumerCountHigh to Queue delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918938 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/qmf/QMFService.java | 3 +-- .../apache/qpid/server/configuration/QueueConfig.java | 2 ++ .../org/apache/qpid/server/queue/SimpleAMQQueue.java | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 33847683bb..3e155e104c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -981,8 +981,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getConsumerCountHigh() { - // TODO - return 0l; + return (long) _obj.getConsumerCountHigh(); } public Long getConsumerCountLow() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index a451091fee..8a5559c155 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -45,6 +45,8 @@ public interface QueueConfig extends ConfiguredObject Date: Thu, 4 Mar 2010 11:17:48 +0000 Subject: QPID-2379: add TxnStarts, TxnCommits, TxnRejects, TxnCount on Session delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918939 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 12 ++--- .../java/org/apache/qpid/server/AMQChannel.java | 50 ++++++++++++++++++++- .../qpid/server/configuration/SessionConfig.java | 8 ++++ .../qpid/server/transport/ServerSession.java | 51 +++++++++++++++++++++- 4 files changed, 111 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 3e155e104c..b6c06f7f34 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1300,26 +1300,22 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getTxnStarts() { - // TODO - return 0l; + return _obj.getTxnStarts(); } public Long getTxnCommits() { - // TODO - return 0l; + return _obj.getTxnCommits(); } public Long getTxnRejects() { - // TODO - return 0l; + return _obj.getTxnRejects(); } public Long getTxnCount() { - // TODO - return 0l; + return _obj.getTxnCount(); } public Long getClientCredit() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1b03ee2334..15ac52305f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -84,6 +84,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; public class AMQChannel implements SessionConfig { @@ -132,6 +133,11 @@ public class AMQChannel implements SessionConfig private final AtomicBoolean _suspended = new AtomicBoolean(false); private ServerTransaction _transaction; + + private final AtomicLong _txnStarts = new AtomicLong(0); + private final AtomicLong _txnCommits = new AtomicLong(0); + private final AtomicLong _txnRejects = new AtomicLong(0); + private final AtomicLong _txnCount = new AtomicLong(0); // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; @@ -180,6 +186,7 @@ public class AMQChannel implements SessionConfig public void setLocalTransactional() { _transaction = new LocalTransaction(_messageStore); + _txnStarts.incrementAndGet(); } public boolean isTransactional() @@ -189,6 +196,40 @@ public class AMQChannel implements SessionConfig // theory return !(_transaction instanceof AutoCommitTransaction); } + + private void incrementOutstandingTxnsIfNecessary() + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 1 if 0. + _txnCount.compareAndSet(0,1); + } + + private void decrementOutstandingTxnsIfNecessary() + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 0 if 1. + _txnCount.compareAndSet(1,0); + } + + public Long getTxnStarts() + { + return _txnStarts.get(); + } + + public Long getTxnCommits() + { + return _txnCommits.get(); + } + + public Long getTxnRejects() + { + return _txnRejects.get(); + } + + public Long getTxnCount() + { + return _txnCount.get(); + } public int getChannelId() { @@ -278,7 +319,7 @@ public class AMQChannel implements SessionConfig else { _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues)); - + incrementOutstandingTxnsIfNecessary(); } } } @@ -845,6 +886,9 @@ public class AMQChannel implements SessionConfig _transaction.commit(); + _txnCommits.incrementAndGet(); + _txnStarts.incrementAndGet(); + decrementOutstandingTxnsIfNecessary(); } public void rollback() throws AMQException @@ -877,6 +921,10 @@ public class AMQChannel implements SessionConfig finally { _rollingBack = false; + + _txnRejects.incrementAndGet(); + _txnStarts.incrementAndGet(); + decrementOutstandingTxnsIfNecessary(); } postRollbackTask.run(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java index ae01ab25ea..e46e951588 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java @@ -38,4 +38,12 @@ public interface SessionConfig extends ConfiguredObject(); private ServerTransaction _transaction; + + private final AtomicLong _txnStarts = new AtomicLong(0); + private final AtomicLong _txnCommits = new AtomicLong(0); + private final AtomicLong _txnRejects = new AtomicLong(0); + private final AtomicLong _txnCount = new AtomicLong(0); private Principal _principal; @@ -160,7 +166,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo } }); - + incrementOutstandingTxnsIfNecessary(); } @@ -391,13 +397,56 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public void commit() { _transaction.commit(); + + _txnCommits.incrementAndGet(); + _txnStarts.incrementAndGet(); + decrementOutstandingTxnsIfNecessary(); } public void rollback() { _transaction.rollback(); + + _txnRejects.incrementAndGet(); + _txnStarts.incrementAndGet(); + decrementOutstandingTxnsIfNecessary(); + } + + + private void incrementOutstandingTxnsIfNecessary() + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 1 if 0. + _txnCount.compareAndSet(0,1); + } + + private void decrementOutstandingTxnsIfNecessary() + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 0 if 1. + _txnCount.compareAndSet(1,0); + } + + public Long getTxnStarts() + { + return _txnStarts.get(); } + public Long getTxnCommits() + { + return _txnCommits.get(); + } + + public Long getTxnRejects() + { + return _txnRejects.get(); + } + + public Long getTxnCount() + { + return _txnCount.get(); + } + public Principal getPrincipal() { return _principal; -- cgit v1.2.1 From 7c9e337a5a364d5946c1fdfc3bb65677b61ec2df Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:18:02 +0000 Subject: QPID-2379: increase the QMF management update interval from 10ms to 10sec git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918940 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java index c3d1945550..c8f5181416 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java @@ -93,7 +93,7 @@ public class BrokerConfigAdapter implements BrokerConfig public Integer getManagementPublishInterval() { - return 10; + return 10000; } public String getVersion() -- cgit v1.2.1 From 6f7e476ee694881cecccbe73ae7011c1cdba7ee0 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:18:30 +0000 Subject: QPID-2379: add BytesTxnEnqueues and MsgTxnEnqueues on Queue delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918941 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFMessage.java | 6 +++++ .../main/java/org/apache/qpid/qmf/QMFService.java | 6 ++--- .../java/org/apache/qpid/server/AMQChannel.java | 13 ++++++----- .../qpid/server/configuration/QueueConfig.java | 6 ++++- .../qpid/server/configuration/SessionConfig.java | 2 ++ .../org/apache/qpid/server/message/AMQMessage.java | 17 ++++++++++++++ .../server/message/MessageTransferMessage.java | 9 +++++--- .../apache/qpid/server/message/ServerMessage.java | 3 +++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 26 +++++++++++++++++++++- .../qpid/server/transport/ServerSession.java | 8 +++++++ 10 files changed, 82 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java index c250b2c011..de9bf1e9cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.message.*; import org.apache.qpid.transport.codec.BBEncoder; @@ -202,4 +203,9 @@ public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHead } } + public SessionConfig getSessionConfig() + { + return null; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index b6c06f7f34..3f1f354585 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -912,8 +912,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getMsgTxnEnqueues() { - // TODO - return 0l; + return _obj.getMsgTxnEnqueues(); } public Long getMsgTxnDequeues() @@ -954,8 +953,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getByteTxnEnqueues() { - // TODO - return 0l; + return _obj.getByteTxnEnqueues(); } public Long getByteTxnDequeues() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 15ac52305f..ec1b22270f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -312,13 +312,13 @@ public class AMQChannel implements SessionConfig } else { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage)); + _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage,isTransactional())); } } else { - _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues)); + _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues, isTransactional())); incrementOutstandingTxnsIfNecessary(); } } @@ -1030,7 +1030,7 @@ public class AMQChannel implements SessionConfig } - private AMQMessage createAMQMessage(IncomingMessage incomingMessage) + private AMQMessage createAMQMessage(IncomingMessage incomingMessage, boolean transactional) throws AMQException { @@ -1054,12 +1054,15 @@ public class AMQChannel implements SessionConfig private class MessageDeliveryAction implements ServerTransaction.Action { + private boolean _transactional; private IncomingMessage _incommingMessage; private ArrayList _destinationQueues; public MessageDeliveryAction(IncomingMessage currentMessage, - ArrayList destinationQueues) + ArrayList destinationQueues, + boolean transactional) { + _transactional = transactional; _incommingMessage = currentMessage; _destinationQueues = destinationQueues; } @@ -1070,7 +1073,7 @@ public class AMQChannel implements SessionConfig { final boolean immediate = _incommingMessage.isImmediate(); - final AMQMessage amqMessage = createAMQMessage(_incommingMessage); + final AMQMessage amqMessage = createAMQMessage(_incommingMessage, _transactional); MessageReference ref = amqMessage.newReference(); for(final BaseQueue queue : _destinationQueues) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index 8a5559c155..0b5df9b8fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -49,6 +49,8 @@ public interface QueueConfig extends ConfiguredObject _handle; + WeakReference _channelRef; + public AMQMessage(StoredMessage handle) + { + this(handle, null); + } + + public AMQMessage(StoredMessage handle, WeakReference channelRef) { _handle = handle; final MessageMetaData metaData = handle.getMetaData(); @@ -75,6 +85,8 @@ public class AMQMessage implements ServerMessage { _flags |= IMMEDIATE; } + + _channelRef = channelRef; } @@ -326,4 +338,9 @@ public class AMQMessage implements ServerMessage { return _handle; } + + public SessionConfig getSessionConfig() + { + return _channelRef == null ? null : ((SessionConfig) _channelRef.get()); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java index baa5dce14f..08006435f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -21,9 +21,10 @@ package org.apache.qpid.server.message; import org.apache.qpid.transport.*; +import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.transport.ServerSession; -import java.util.concurrent.atomic.AtomicLong; import java.nio.ByteBuffer; import java.lang.ref.WeakReference; @@ -37,13 +38,11 @@ public class MessageTransferMessage implements InboundMessage, ServerMessage private WeakReference _sessionRef; - public MessageTransferMessage(StoredMessage storeMessage, WeakReference sessionRef) { _storeMessage = storeMessage; _sessionRef = sessionRef; - } private MessageMetaData_0_10 getMetaData() @@ -142,5 +141,9 @@ public class MessageTransferMessage implements InboundMessage, ServerMessage return _sessionRef == null ? null : _sessionRef.get(); } + public SessionConfig getSessionConfig() + { + return _sessionRef == null ? null : (ServerSession) _sessionRef.get(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java index 1ac538c15b..2f2d39115f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.message; import java.nio.ByteBuffer; +import org.apache.qpid.server.configuration.SessionConfig; + public interface ServerMessage extends EnqueableMessage, MessageContentSource { String getRoutingKey(); @@ -44,4 +46,5 @@ public interface ServerMessage extends EnqueableMessage, MessageContentSource public int getContent(ByteBuffer buf, int offset); + SessionConfig getSessionConfig(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index c64b9047de..d99b551936 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -12,6 +12,7 @@ import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.QueueConfigType; import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; @@ -122,6 +123,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _persistentMessageEnqueueCount = new AtomicLong(); private final AtomicLong _persistentMessageDequeueCount = new AtomicLong(); private final AtomicInteger _counsumerCountHigh = new AtomicInteger(0); + private final AtomicLong _msgTxnEnqueues = new AtomicLong(0); + private final AtomicLong _byteTxnEnqueues = new AtomicLong(0); private final AtomicInteger _bindingCountHigh = new AtomicInteger(); @@ -516,7 +519,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { - + incrementTxnEnqueueStats(message); incrementQueueCount(); incrementQueueSize(message); _totalMessagesReceived.incrementAndGet(); @@ -666,6 +669,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { getAtomicQueueCount().incrementAndGet(); } + + private void incrementTxnEnqueueStats(final ServerMessage message) + { + SessionConfig session = message.getSessionConfig(); + + if(session !=null && session.isTransactional()) + { + _msgTxnEnqueues.incrementAndGet(); + _byteTxnEnqueues.addAndGet(message.getSize()); + } + } private void deliverMessage(final Subscription sub, final QueueEntry entry) throws AMQException @@ -2064,6 +2078,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { return _dequeueSize.get(); } + + public long getByteTxnEnqueues() + { + return _byteTxnEnqueues.get(); + } + + public long getMsgTxnEnqueues() + { + return _msgTxnEnqueues.get(); + } public long getPersistentByteEnqueues() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index a65f3938a6..99c3572a2f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -388,6 +388,14 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo sub.releaseSendLock(); } } + + public boolean isTransactional() + { + // this does not look great but there should only be one "non-transactional" + // transactional context, while there could be several transactional ones in + // theory + return !(_transaction instanceof AutoCommitTransaction); + } public void selectTx() { -- cgit v1.2.1 From 7d21eac1b9295f0a9d1472eb3805b76c8c22da5a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:19:00 +0000 Subject: QPID-2379: add BytesTxnDequeues and MsgTxnDequeues on Queue delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918942 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 6 ++---- .../qpid/server/configuration/QueueConfig.java | 4 ++++ .../org/apache/qpid/server/queue/AMQQueue.java | 2 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 5 +++-- .../apache/qpid/server/queue/SimpleAMQQueue.java | 25 +++++++++++++++++++++- .../qpid/server/subscription/Subscription.java | 1 + .../qpid/server/subscription/SubscriptionImpl.java | 4 ++++ .../server/subscription/Subscription_0_10.java | 5 +++++ 8 files changed, 44 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 3f1f354585..69d9ccb431 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -917,8 +917,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getMsgTxnDequeues() { - // TODO - return 0l; + return _obj.getMsgTxnDequeues(); } public Long getMsgPersistEnqueues() @@ -958,8 +957,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getByteTxnDequeues() { - // TODO - return 0l; + return _obj.getByteTxnDequeues(); } public Long getBytePersistEnqueues() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index 0b5df9b8fa..c3593561bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -62,7 +62,11 @@ public interface QueueConfig extends ConfiguredObject, ExchangeRefer void requeue(QueueEntryImpl storeContext, Subscription subscription); - void dequeue(QueueEntry entry); + void dequeue(QueueEntry entry, Subscription sub); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index ada7726fc0..bf4015eb7a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -366,13 +366,14 @@ public class QueueEntryImpl implements QueueEntry if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) { + Subscription s = null; if (state instanceof SubscriptionAcquiredState) { - Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); + s = ((SubscriptionAcquiredState) state).getSubscription(); s.onDequeue(this); } - getQueue().dequeue(this); + getQueue().dequeue(this,s); if(_stateChangeListeners != null) { notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d99b551936..df2aec2534 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -125,6 +125,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicInteger _counsumerCountHigh = new AtomicInteger(0); private final AtomicLong _msgTxnEnqueues = new AtomicLong(0); private final AtomicLong _byteTxnEnqueues = new AtomicLong(0); + private final AtomicLong _msgTxnDequeues = new AtomicLong(0); + private final AtomicLong _byteTxnDequeues = new AtomicLong(0); private final AtomicInteger _bindingCountHigh = new AtomicInteger(); @@ -680,6 +682,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _byteTxnEnqueues.addAndGet(message.getSize()); } } + + private void incrementTxnDequeueStats(QueueEntry entry) + { + _msgTxnDequeues.incrementAndGet(); + _byteTxnDequeues.addAndGet(entry.getSize()); + } private void deliverMessage(final Subscription sub, final QueueEntry entry) throws AMQException @@ -764,7 +772,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener deliverAsync(); } - public void dequeue(QueueEntry entry) + public void dequeue(QueueEntry entry, Subscription sub) { decrementQueueCount(); decrementQueueSize(entry); @@ -772,6 +780,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _deliveredMessages.decrementAndGet(); } + + if(sub != null && sub.isSessionTransactional()) + { + incrementTxnDequeueStats(entry); + } checkCapacity(); @@ -2084,10 +2097,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _byteTxnEnqueues.get(); } + public long getByteTxnDequeues() + { + return _byteTxnDequeues.get(); + } + public long getMsgTxnEnqueues() { return _msgTxnEnqueues.get(); } + + public long getMsgTxnDequeues() + { + return _msgTxnDequeues.get(); + } public long getPersistentByteEnqueues() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 9e9d2da579..0a3576ff42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -105,4 +105,5 @@ public interface Subscription public Object get(String key); + boolean isSessionTransactional(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index b0ea0ef506..156b05d15c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -766,4 +766,8 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return null; } + public boolean isSessionTransactional() + { + return _channel.isTransactional(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 54c294c76d..4bad81ec17 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -848,4 +848,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr //TODO return Collections.EMPTY_MAP; } + + public boolean isSessionTransactional() + { + return _session.isTransactional(); + } } -- cgit v1.2.1 From 7374b4a58d4bb37ca384627696dce9124ad79eeb Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:19:28 +0000 Subject: QPID-2379: move getCreateTime() up to the ConfiguredObject supertype, add implementation to remaining *Config implementors and their associated QMFService delegates git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918943 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/qmf/ManagementExchange.java | 2 +- .../broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 9 +++------ .../broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 6 ++++++ .../main/java/org/apache/qpid/server/binding/BindingFactory.java | 2 +- .../java/org/apache/qpid/server/configuration/BindingConfig.java | 2 -- .../java/org/apache/qpid/server/configuration/BridgeConfig.java | 2 -- .../java/org/apache/qpid/server/configuration/BrokerConfig.java | 2 -- .../org/apache/qpid/server/configuration/ConfiguredObject.java | 1 + .../org/apache/qpid/server/configuration/ExchangeConfig.java | 2 -- .../java/org/apache/qpid/server/configuration/LinkConfig.java | 2 -- .../java/org/apache/qpid/server/configuration/QueueConfig.java | 2 -- .../java/org/apache/qpid/server/configuration/SystemConfig.java | 2 -- .../org/apache/qpid/server/configuration/VirtualHostConfig.java | 2 -- .../java/org/apache/qpid/server/exchange/AbstractExchange.java | 2 +- .../main/java/org/apache/qpid/server/federation/BrokerLink.java | 7 ++++++- .../java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 6 ++++++ .../org/apache/qpid/server/protocol/ProtocolEngine_0_10.java | 6 ++++++ .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 2 +- .../org/apache/qpid/server/subscription/SubscriptionImpl.java | 6 ++++++ .../org/apache/qpid/server/subscription/Subscription_0_10.java | 6 ++++++ .../java/org/apache/qpid/server/transport/ServerSession.java | 6 ++++++ 21 files changed, 50 insertions(+), 27 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index b639cb9fc1..aa18b5a136 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -80,7 +80,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); - // TODO + //TODO : persist creation time private long _createTime = System.currentTimeMillis(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 69d9ccb431..8a59178b77 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1227,8 +1227,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public long getCreateTime() { - // TODO - return 0; + return _obj.getCreateTime(); } @Override @@ -1351,8 +1350,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public long getCreateTime() { - // TODO - return 0; //To change body of implemented methods use File | Settings | File Templates. + return _obj.getCreateTime(); } } @@ -1419,8 +1417,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public long getCreateTime() { - // TODO - return 0; //To change body of implemented methods use File | Settings | File Templates. + return _obj.getCreateTime(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index ec1b22270f..3b17da5af7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -157,6 +157,7 @@ public class AMQChannel implements SessionConfig private static final AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible."); private final UUID _id; + private long _createTime = System.currentTimeMillis(); public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -1367,4 +1368,9 @@ public class AMQChannel implements SessionConfig { return getConnectionConfig().getAddress() + "/" + getChannelId(); } + + public long getCreateTime() + { + return _createTime; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index e11af5d553..5423f02107 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -78,7 +78,7 @@ public class BindingFactory private final class BindingImpl extends Binding implements AMQQueue.Task, Exchange.Task, BindingConfig { private final BindingLogSubject _logSubject; - //TODO + //TODO : persist creation time private long _createTime = System.currentTimeMillis(); private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java index 9414edcec4..233134abc5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java @@ -37,7 +37,5 @@ public interface BindingConfig extends ConfiguredObject, C extends Con public boolean isDurable(); + long getCreateTime(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java index 40dc88c28c..41c51d9684 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java @@ -52,6 +52,4 @@ public interface ExchangeConfig extends ConfiguredObject void close(); - long getCreateTime(); - void createBridge(boolean durable, boolean dynamic, boolean srcIsQueue, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index c3593561bb..95e2aa516b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -77,6 +77,4 @@ public interface QueueConfig extends ConfiguredObject>>>>>> .r902547 */ - // TODO + //TODO : persist creation time private long _createTime = System.currentTimeMillis(); public AbstractExchange(final ExchangeType type) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java index bb6fb9dcc3..dc7f2654e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java @@ -106,7 +106,7 @@ public class BrokerLink implements LinkConfig, ConnectionListener private class ConnectionConfigAdapter implements ConnectionConfig { - + private long _adapterCreateTime = System.currentTimeMillis(); private UUID _id = BrokerLink.this.getConfigStore().createId(); public VirtualHost getVirtualHost() @@ -178,6 +178,11 @@ public class BrokerLink implements LinkConfig, ConnectionListener { return false; } + + public long getCreateTime() + { + return _adapterCreateTime; + } } private class SessionFactory implements Connection.SessionFactory diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 6d2826b55e..3ee4d5529e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -152,6 +152,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private final AtomicBoolean _closing = new AtomicBoolean(false); private final UUID _id; private final ConfigStore _configStore; + private long _createTime = System.currentTimeMillis(); public ManagedObject getManagedObject() { @@ -1133,4 +1134,9 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return String.valueOf(getRemoteAddress()); } + public long getCreateTime() + { + return _createTime; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java index 473f68028d..89ba665e72 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -43,6 +43,7 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine private ServerConnection _connection; private final UUID _id; private final IApplicationRegistry _appRegistry; + private long _createTime = System.currentTimeMillis(); public ProtocolEngine_0_10(ServerConnection conn, NetworkDriver networkDriver, @@ -177,4 +178,9 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine super.closed(); getConfigStore().removeConfiguredObject(this); } + + public long getCreateTime() + { + return _createTime; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index df2aec2534..b5d1290e98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -180,7 +180,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private UUID _id; private final Map _arguments; - //TODO + //TODO : persist creation time private long _createTime = System.currentTimeMillis(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 156b05d15c..c548f3ccad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -94,6 +94,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private LogSubject _logSubject; private LogActor _logActor; private UUID _id; + private long _createTime = System.currentTimeMillis(); static final class BrowserSubscription extends SubscriptionImpl @@ -770,4 +771,9 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage { return _channel.isTransactional(); } + + public long getCreateTime() + { + return _createTime; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 4bad81ec17..4cc7e6fce2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -100,6 +100,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private UUID _id; private String _traceExclude; private String _trace; + private long _createTime = System.currentTimeMillis(); public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, @@ -853,4 +854,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { return _session.isTransactional(); } + + public long getCreateTime() + { + return _createTime; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 99c3572a2f..63d540be6b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -69,6 +69,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo private final UUID _id; private ConnectionConfig _connectionConfig; + private long _createTime = System.currentTimeMillis(); public static interface MessageDispositionChangeListener { @@ -534,4 +535,9 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo { return getName().toString(); } + + public long getCreateTime() + { + return _createTime; + } } -- cgit v1.2.1 From 9e29f07bbb18a4892ae1a4141df907932877cabf Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 4 Mar 2010 11:19:46 +0000 Subject: QPID-2379: defer getShadow property to ConnectionConfig objects instead of hardcoding in the delegate git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918944 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 4 +--- .../java/org/apache/qpid/server/configuration/ConnectionConfig.java | 2 ++ .../src/main/java/org/apache/qpid/server/federation/BrokerLink.java | 5 +++++ .../main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 5 +++++ .../java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java | 5 +++++ 5 files changed, 18 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 8a59178b77..6d360b2084 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1230,11 +1230,9 @@ public class QMFService implements ConfigStore.ConfigEventListener return _obj.getCreateTime(); } - @Override public Boolean getShadow() { - // TODO Auto-generated method stub - return false; + return _obj.isShadow(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java index 95fb7d39a1..ad451f44a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java @@ -42,4 +42,6 @@ public interface ConnectionConfig extends ConfiguredObject Date: Wed, 10 Mar 2010 14:37:53 +0000 Subject: QPID-2379: ensure SubFlushRunner runnable changes thread name back to previous value, use corrects Logger for the class git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@921368 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SubFlushRunner.java | 41 +++++++++++++--------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java index 1309e05978..46c1a6af9a 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java @@ -30,7 +30,7 @@ import org.apache.log4j.Logger; class SubFlushRunner implements ReadWriteRunnable { - private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + private static final Logger _logger = Logger.getLogger(SubFlushRunner.class); private final Subscription _sub; @@ -46,29 +46,36 @@ class SubFlushRunner implements ReadWriteRunnable public void run() { - - Thread.currentThread().setName(_name); - - boolean complete = false; + String originalName = Thread.currentThread().getName(); try { - CurrentActor.set(_sub.getLogActor()); - complete = getQueue().flushSubscription(_sub, ITERATIONS); + Thread.currentThread().setName(_name); + + boolean complete = false; + try + { + CurrentActor.set(_sub.getLogActor()); + complete = getQueue().flushSubscription(_sub, ITERATIONS); + + } + catch (AMQException e) + { + _logger.error(e); + } + finally + { + CurrentActor.remove(); + } + if (!complete && !_sub.isSuspended()) + { + getQueue().execute(this); + } } - catch (AMQException e) - { - _logger.error(e); - } finally { - CurrentActor.remove(); + Thread.currentThread().setName(originalName); } - if (!complete && !_sub.isSuspended()) - { - getQueue().execute(this); - } - } -- cgit v1.2.1 From e9319047d4f057d5b83e1c9a6492cc872855b589 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 10 Mar 2010 14:38:07 +0000 Subject: QPID-2430: when the AcceptMode=NONE, dont add the MessageAcceptCompletionListener if AcquireMode is not PRE_ACQUIRED, fallback to just using the restorecredit listener if using WINDOW flow mode git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@921369 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/subscription/Subscription_0_10.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 4cc7e6fce2..9d2f3506cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -531,7 +531,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr if(!excludeDueToFederation) { - if(_acceptMode == MessageAcceptMode.NONE) + if(_acceptMode == MessageAcceptMode.NONE && _acquireMode != MessageAcquireMode.PRE_ACQUIRED) { xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); } -- cgit v1.2.1 From a66906f8d45fae417f288cdd51a417af2ccd5e5a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 10 Mar 2010 14:38:11 +0000 Subject: QPID-2379: add getDelivered() to Subscription git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@921370 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 3 +-- .../org/apache/qpid/server/configuration/SubscriptionConfig.java | 2 +- .../org/apache/qpid/server/subscription/SubscriptionImpl.java | 8 +++++++- .../org/apache/qpid/server/subscription/Subscription_0_10.java | 8 +++++++- 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 6d360b2084..54f1db845e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1404,8 +1404,7 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getDelivered() { - // TODO - return 0l; + return _obj.getDelivered(); } public UUID getId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java index 985ecb2be9..b101d70553 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java @@ -43,5 +43,5 @@ public interface SubscriptionConfig extends ConfiguredObject Date: Wed, 10 Mar 2010 14:38:39 +0000 Subject: QPID-2379: only inc/dec the outstanding txn count if the channel/session is transactional, obviously. Inc txnStart on ServerSession when selectTX is invoked. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@921371 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/AMQChannel.java | 18 ++++++++++++------ .../apache/qpid/server/transport/ServerSession.java | 19 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 3b17da5af7..54a05da84d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -200,16 +200,22 @@ public class AMQChannel implements SessionConfig private void incrementOutstandingTxnsIfNecessary() { - //There can currently only be at most one outstanding transaction - //due to only having LocalTransaction support. Set value to 1 if 0. - _txnCount.compareAndSet(0,1); + if(isTransactional()) + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 1 if 0. + _txnCount.compareAndSet(0,1); + } } private void decrementOutstandingTxnsIfNecessary() { - //There can currently only be at most one outstanding transaction - //due to only having LocalTransaction support. Set value to 0 if 1. - _txnCount.compareAndSet(1,0); + if(isTransactional()) + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 0 if 1. + _txnCount.compareAndSet(1,0); + } } public Long getTxnStarts() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 63d540be6b..b5d5d7bba9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -401,6 +401,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public void selectTx() { _transaction = new LocalTransaction(this.getMessageStore()); + _txnStarts.incrementAndGet(); } public void commit() @@ -424,16 +425,22 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo private void incrementOutstandingTxnsIfNecessary() { - //There can currently only be at most one outstanding transaction - //due to only having LocalTransaction support. Set value to 1 if 0. - _txnCount.compareAndSet(0,1); + if(isTransactional()) + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 1 if 0. + _txnCount.compareAndSet(0,1); + } } private void decrementOutstandingTxnsIfNecessary() { - //There can currently only be at most one outstanding transaction - //due to only having LocalTransaction support. Set value to 0 if 1. - _txnCount.compareAndSet(1,0); + if(isTransactional()) + { + //There can currently only be at most one outstanding transaction + //due to only having LocalTransaction support. Set value to 0 if 1. + _txnCount.compareAndSet(1,0); + } } public Long getTxnStarts() -- cgit v1.2.1 From 8e1e53dd5b7c261fd810b7833ccf876dbdecdd39 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 18 Mar 2010 16:23:56 +0000 Subject: QPID-2379: add Binding.msgMatched() support to the HeadersExchange git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@924879 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/binding/Binding.java | 2 +- .../qpid/server/exchange/HeadersBinding.java | 109 +++++++------ .../qpid/server/exchange/HeadersExchange.java | 172 ++++++++++----------- 3 files changed, 140 insertions(+), 143 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java index 0b689c16a7..0b6035f32d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java @@ -37,7 +37,7 @@ public class Binding private final UUID _id; private final AtomicLong _matches = new AtomicLong(); - Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) + public Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) { _id = id; _bindingKey = bindingKey; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index 35c4a8f9b2..f58a6513a9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.message.AMQMessageHeader; /** @@ -38,69 +39,35 @@ class HeadersBinding private static final Logger _logger = Logger.getLogger(HeadersBinding.class); private final FieldTable _mappings; + private final Binding _binding; private final Set required = new HashSet(); private final Map matches = new HashMap(); private boolean matchAny; - private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor - { - private Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName))) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor - { - Boolean _result = Boolean.FALSE; - - public boolean processElement(String propertyName, AMQTypedValue value) - { - if(required.contains(propertyName)) - { - _result = Boolean.TRUE; - return false; - } - return true; - } - - public Object getResult() - { - return _result; - } - } - - - /** - * Creates a binding for a set of mappings. Those mappings whose value is + * Creates a header 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 + * + * @param binding the binding to create a header binding using */ - - HeadersBinding(FieldTable mappings) + public HeadersBinding(Binding binding) { - _mappings = mappings; - initMappings(); + _binding = binding; + if(_binding !=null) + { + _mappings = FieldTable.convertToFieldTable(_binding.getArguments()); + initMappings(); + } + else + { + _mappings = null; + } } - + private void initMappings() { - _mappings.processOverElements(new FieldTable.FieldTableElementProcessor() { @@ -133,6 +100,11 @@ class HeadersBinding { return _mappings; } + + public Binding getBinding() + { + return _binding; + } /** * Checks whether the supplied headers match the requirements of this binding @@ -250,4 +222,39 @@ class HeadersBinding { return key.startsWith("X-") || key.startsWith("x-"); } -} + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + + if (o == null) + { + return false; + } + + if (!(o instanceof HeadersBinding)) + { + return false; + } + + final HeadersBinding hb = (HeadersBinding) o; + + if(_binding == null) + { + if(hb.getBinding() != null) + { + return false; + } + } + else if (!_binding.equals(hb.getBinding())) + { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index ce0b14932f..e98a603d12 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -24,8 +24,6 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; @@ -36,10 +34,11 @@ import org.apache.qpid.server.binding.Binding; import javax.management.JMException; import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; /** * An exchange that binds queues based on a set of required headers and header values @@ -72,7 +71,14 @@ public class HeadersExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - + + private final ConcurrentHashMap> _bindingsByKey = + new ConcurrentHashMap>(); + + private final CopyOnWriteArrayList _bindingHeaderMatchers = + new CopyOnWriteArrayList(); + + public static final ExchangeType TYPE = new ExchangeType() { @@ -102,34 +108,12 @@ public class HeadersExchange extends AbstractExchange } }; - - private final List _bindings = new CopyOnWriteArrayList(); - private Map _bindingByKey = new ConcurrentHashMap(); - - public HeadersExchange() { super(TYPE); } + - public void registerQueue(String routingKey, AMQQueue queue, Map args) - { - registerQueue(new AMQShortString(routingKey), queue, FieldTable.convertToFieldTable(args)); - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) - { - _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() + " with " + args); - - Registration registration = new Registration(new HeadersBinding(args), queue, routingKey); - _bindings.add(registration); - - } - - public void deregisterQueue(String routingKey, AMQQueue queue, Map args) - { - _bindings.remove(new Registration(args == null ? null : new HeadersBinding(FieldTable.convertToFieldTable(args)), queue, new AMQShortString(routingKey))); - } public ArrayList doRoute(InboundMessage payload) { @@ -138,24 +122,27 @@ public class HeadersExchange extends AbstractExchange { _logger.debug("Exchange " + getNameShortString() + ": routing message with headers " + header); } - boolean routed = false; - ArrayList queues = new ArrayList(); - for (Registration e : _bindings) + + LinkedHashSet queues = new LinkedHashSet(); + + for (HeadersBinding hb : _bindingHeaderMatchers) { - - if (e.binding.matches(header)) + if (hb.matches(header)) { + Binding b = hb.getBinding(); + + b.incrementMatches(); + if (_logger.isDebugEnabled()) { _logger.debug("Exchange " + getNameShortString() + ": delivering message with headers " + - header + " to " + e.queue.getNameShortString()); + header + " to " + b.getQueue().getNameShortString()); } - queues.add(e.queue); - - routed = true; + queues.add(b.getQueue()); } } - return queues; + + return new ArrayList(queues); } public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) @@ -166,38 +153,49 @@ public class HeadersExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) { - return isBound(queue); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); + + if(bindings != null) + { + for(Binding binding : bindings) + { + if(binding.getQueue().equals(queue)) + { + return true; + } + } + } + + return false; } public boolean isBound(AMQShortString routingKey) { - return hasBindings(); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); + return bindings != null && !bindings.isEmpty(); } public boolean isBound(AMQQueue queue) { - for (Registration r : _bindings) + for (CopyOnWriteArraySet bindings : _bindingsByKey.values()) { - if (r.queue.equals(queue)) + for(Binding binding : bindings) { - return true; + if(binding.getQueue().equals(queue)) + { + return true; + } } } + return false; } public boolean hasBindings() { - return !_bindings.isEmpty(); - } - - - - protected FieldTable 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(); + return !getBindings().isEmpty(); } protected AbstractExchangeMBean createMBean() throws JMException @@ -210,59 +208,51 @@ public class HeadersExchange extends AbstractExchange return _logger; } - - static class Registration + protected void onBind(final Binding binding) { - private final HeadersBinding binding; - private final AMQQueue queue; - private final AMQShortString routingKey; + String bindingKey = binding.getBindingKey(); + AMQQueue queue = binding.getQueue(); + AMQShortString routingKey = AMQShortString.valueOf(bindingKey); + Map args = binding.getArguments(); - Registration(HeadersBinding binding, AMQQueue queue, AMQShortString routingKey) - { - this.binding = binding; - this.queue = queue; - this.routingKey = routingKey; - } + assert queue != null; + assert routingKey != null; - public int hashCode() - { - int queueHash = queue.hashCode(); - int routingHash = routingKey == null ? 0 : routingKey.hashCode(); - return queueHash + routingHash; - } + CopyOnWriteArraySet bindings = _bindingsByKey.get(bindingKey); - public boolean equals(Object o) + if(bindings == null) { - return o instanceof Registration - && ((Registration) o).queue.equals(queue) - && (routingKey == null ? ((Registration)o).routingKey == null - : routingKey.equals(((Registration)o).routingKey)); - } - - public HeadersBinding getBinding() - { - return binding; + bindings = new CopyOnWriteArraySet(); + CopyOnWriteArraySet newBindings; + if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null) + { + bindings = newBindings; + } } - - public AMQQueue getQueue() + + if(_logger.isDebugEnabled()) { - return queue; + _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() + + " with binding key '" +bindingKey + "' and args: " + args); } - public AMQShortString getRoutingKey() - { - return routingKey; - } - } + _bindingHeaderMatchers.add(new HeadersBinding(binding)); + bindings.add(binding); - protected void onBind(final Binding binding) - { - registerQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); } protected void onUnbind(final Binding binding) { - deregisterQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); + assert binding != null; + + CopyOnWriteArraySet bindings = _bindingsByKey.get(binding.getBindingKey()); + if(bindings != null) + { + bindings.remove(binding); + } + + _logger.debug("==============="); + _logger.debug("Removing Binding: " + _bindingHeaderMatchers.remove(new HeadersBinding(binding))); } } -- cgit v1.2.1 From ddf51178562aeb7c990461234b8c3e7e02ca7719 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 18 Mar 2010 16:24:10 +0000 Subject: QPID-2379: remove some unused parameters git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@924880 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 54a05da84d..fe5da20fa5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -319,7 +319,7 @@ public class AMQChannel implements SessionConfig } else { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage,isTransactional())); + _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage)); } } @@ -1037,7 +1037,7 @@ public class AMQChannel implements SessionConfig } - private AMQMessage createAMQMessage(IncomingMessage incomingMessage, boolean transactional) + private AMQMessage createAMQMessage(IncomingMessage incomingMessage) throws AMQException { @@ -1061,7 +1061,6 @@ public class AMQChannel implements SessionConfig private class MessageDeliveryAction implements ServerTransaction.Action { - private boolean _transactional; private IncomingMessage _incommingMessage; private ArrayList _destinationQueues; @@ -1069,7 +1068,6 @@ public class AMQChannel implements SessionConfig ArrayList destinationQueues, boolean transactional) { - _transactional = transactional; _incommingMessage = currentMessage; _destinationQueues = destinationQueues; } @@ -1080,7 +1078,7 @@ public class AMQChannel implements SessionConfig { final boolean immediate = _incommingMessage.isImmediate(); - final AMQMessage amqMessage = createAMQMessage(_incommingMessage, _transactional); + final AMQMessage amqMessage = createAMQMessage(_incommingMessage); MessageReference ref = amqMessage.newReference(); for(final BaseQueue queue : _destinationQueues) -- cgit v1.2.1 From 70dc435fc8db3456c5d504bc0cc20de2f4f2ec5a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 18 Mar 2010 16:24:36 +0000 Subject: QPID-2397: add Binding.msgMatched() support to the TopicExchange, and remove its internal usage of the TopicBinding class git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@924881 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/binding/Binding.java | 29 ++++---- .../apache/qpid/server/exchange/TopicExchange.java | 78 +++++++++++++--------- .../server/exchange/topic/TopicExchangeResult.java | 24 ++++++- 3 files changed, 84 insertions(+), 47 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java index 0b6035f32d..60c9a86b76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java @@ -89,29 +89,30 @@ public class Binding @Override public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + { + return true; + } + + if (o == null || !(o instanceof Binding)) + { + return false; + } final Binding binding = (Binding) o; - if (!_bindingKey.equals(binding._bindingKey)) return false; - if (!_exchange.equals(binding._exchange)) return false; - if (!_queue.equals(binding._queue)) return false; - - return true; + return (_bindingKey == null ? binding.getBindingKey() == null : _bindingKey.equals(binding.getBindingKey())) + && (_exchange == null ? binding.getExchange() == null : _exchange.equals(binding.getExchange())) + && (_queue == null ? binding.getQueue() == null : _queue.equals(binding.getQueue())); } @Override public int hashCode() { - int result = _bindingKey.hashCode(); - result = 31 * result + _queue.hashCode(); - result = 31 * result + _exchange.hashCode(); + int result = _bindingKey == null ? 1 : _bindingKey.hashCode(); + result = 31 * result + (_queue == null ? 3 : _queue.hashCode()); + result = 31 * result + (_exchange == null ? 5 : _exchange.hashCode()); return result; } - - - - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 14f15dd92c..6e60d95700 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -31,6 +31,7 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.exchange.topic.*; import org.apache.qpid.server.filter.JMSSelectorFilter; import org.apache.qpid.server.message.InboundMessage; @@ -83,7 +84,7 @@ public class TopicExchange extends AbstractExchange private final Map _topicExchangeResults = new ConcurrentHashMap(); - private final Map _bindings = new HashMap(); + private final Map _bindings = new HashMap(); private final Map> _selectorCache = new WeakHashMap>(); @@ -92,20 +93,12 @@ public class TopicExchange extends AbstractExchange super(TYPE); } - public synchronized void registerQueue(String rKey, AMQQueue queue, Map args) - { - try - { - registerQueue(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args)); - } - catch (AMQInvalidArgumentException e) - { - throw new RuntimeException(e); - } - } - - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQInvalidArgumentException + protected synchronized void registerQueue(final Binding binding) throws AMQInvalidArgumentException { + AMQShortString rKey = new AMQShortString(binding.getBindingKey()) ; + AMQQueue queue = binding.getQueue(); + FieldTable args = FieldTable.convertToFieldTable(binding.getArguments()); + assert queue != null; assert rKey != null; @@ -114,8 +107,6 @@ public class TopicExchange extends AbstractExchange AMQShortString routingKey = TopicNormalizer.normalize(rKey); - TopicBinding binding = new TopicBinding(rKey, queue, args); - if(_bindings.containsKey(binding)) { FieldTable oldArgs = _bindings.get(binding); @@ -146,6 +137,8 @@ public class TopicExchange extends AbstractExchange return; } } + + result.addBinding(binding); } else @@ -177,6 +170,8 @@ public class TopicExchange extends AbstractExchange result.addUnfilteredQueue(queue); } } + + result.addBinding(binding); _bindings.put(binding, args); } @@ -210,11 +205,19 @@ public class TopicExchange extends AbstractExchange ? AMQShortString.EMPTY_STRING : new AMQShortString(payload.getRoutingKey()); + _logger.info("Message routing key: " + routingKey ); + // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues ArrayList queues = new ArrayList(); queues.addAll(getMatchedQueues(payload, routingKey)); + for(BaseQueue q : queues) + { + _logger.info("Matched Queue: " + q.getNameShortString() ); + } + + if(queues == null || queues.isEmpty()) { _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); @@ -226,7 +229,8 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) { - TopicBinding binding = new TopicBinding(routingKey, queue, arguments); + Binding binding = new Binding(null, routingKey.toString(), queue, this, FieldTable.convertToMap(arguments)); + if (arguments == null) { return _bindings.containsKey(binding); @@ -253,7 +257,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey) { - for(TopicBinding b : _bindings.keySet()) + for(Binding b : _bindings.keySet()) { if(b.getBindingKey().equals(routingKey)) { @@ -266,7 +270,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQQueue queue) { - for(TopicBinding b : _bindings.keySet()) + for(Binding b : _bindings.keySet()) { if(b.getQueue().equals(queue)) { @@ -282,19 +286,16 @@ public class TopicExchange extends AbstractExchange return !_bindings.isEmpty(); } - - public void deregisterQueue(String rKey, AMQQueue queue, Map args) - { - removeBinding(new TopicBinding(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args))); - } - - private boolean removeBinding(final TopicBinding binding) + private boolean deregisterQueue(final Binding binding) { if(_bindings.containsKey(binding)) { FieldTable bindingArgs = _bindings.remove(binding); - AMQShortString bindingKey = TopicNormalizer.normalize(binding.getBindingKey()); + AMQShortString bindingKey = TopicNormalizer.normalize(new AMQShortString(binding.getBindingKey())); TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + + result.removeBinding(binding); + if(argumentsContainSelector(bindingArgs)) { try @@ -341,8 +342,14 @@ public class TopicExchange extends AbstractExchange Collection queues = results.size() == 1 ? null : new HashSet(); for(TopicMatcherResult result : results) { + TopicExchangeResult res = (TopicExchangeResult)result; - queues = ((TopicExchangeResult)result).processMessage(message, queues); + for(Binding b : res.getBindings()) + { + b.incrementMatches(); + } + + queues = res.processMessage(message, queues); } return queues; } @@ -350,14 +357,21 @@ public class TopicExchange extends AbstractExchange } - protected void onBind(final org.apache.qpid.server.binding.Binding binding) + protected void onBind(final Binding binding) { - registerQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + try + { + registerQueue(binding); + } + catch (AMQInvalidArgumentException e) + { + throw new RuntimeException(e); + } } - protected void onUnbind(final org.apache.qpid.server.binding.Binding binding) + protected void onUnbind(final Binding binding) { - deregisterQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + deregisterQueue(binding); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java index d9a779802f..41dc0d749a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java @@ -21,14 +21,22 @@ package org.apache.qpid.server.exchange.topic; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.message.InboundMessage; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; public final class TopicExchangeResult implements TopicMatcherResult { + private final List _bindings = new CopyOnWriteArrayList(); private final Map _unfilteredQueues = new ConcurrentHashMap(); private final ConcurrentHashMap> _filteredQueues = new ConcurrentHashMap>(); @@ -64,6 +72,20 @@ public final class TopicExchangeResult implements TopicMatcherResult return _unfilteredQueues.keySet(); } + public void addBinding(Binding binding) + { + _bindings.add(binding); + } + + public void removeBinding(Binding binding) + { + _bindings.remove(binding); + } + + public List getBindings() + { + return new ArrayList(_bindings); + } public void addFilteredQueue(AMQQueue queue, MessageFilter filter) { -- cgit v1.2.1 From 109cc40107c02adc0a1c05b4f2c0f3e7d58bc448 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 18 Mar 2010 16:24:53 +0000 Subject: QPID-2379: add Binding.msgMatched() support to the ManagementExchange. Remove the ManagementExchange from the list of creatable exchange types returned for use by the JMX management console. Remove the use of TopicBinding's and then remove the now-unused class entirely. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@924882 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/qmf/ManagementExchange.java | 50 ++++++++-------- .../apache/qpid/server/AMQBrokerManagerMBean.java | 2 +- .../server/exchange/DefaultExchangeFactory.java | 25 ++++++-- .../qpid/server/exchange/ExchangeFactory.java | 2 + .../qpid/server/exchange/topic/TopicBinding.java | 70 ---------------------- 5 files changed, 47 insertions(+), 102 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index aa18b5a136..e552596058 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -31,7 +31,6 @@ import org.apache.qpid.server.configuration.ExchangeConfigType; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.exchange.ExchangeType; -import org.apache.qpid.server.exchange.topic.TopicBinding; import org.apache.qpid.server.exchange.topic.TopicExchangeResult; import org.apache.qpid.server.exchange.topic.TopicMatcherResult; import org.apache.qpid.server.exchange.topic.TopicNormalizer; @@ -47,7 +46,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -55,6 +53,7 @@ import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicLong; public class ManagementExchange implements Exchange, QMFService.Listener @@ -69,8 +68,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener private final Map _topicExchangeResults = new ConcurrentHashMap(); - private final Map _topicBindings = new HashMap(); - private final Set _bindingSet = new HashSet(); + private final Set _bindingSet = new CopyOnWriteArraySet(); private UUID _id; private static final String AGENT_BANK = "0"; @@ -254,21 +252,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener public synchronized void addBinding(final Binding b) { - _bindingSet.add(b); - - for(BindingListener listener : _listeners) - { - listener.bindingAdded(this, b); - } - - if(_bindingSet.size() > _bindingCountHigh) - { - _bindingCountHigh = _bindingSet.size(); - } - - TopicBinding binding = new TopicBinding(new AMQShortString(b.getBindingKey()), b.getQueue(), null); - - if(!_topicBindings.containsKey(binding)) + if(_bindingSet.add(b)) { AMQShortString routingKey = TopicNormalizer.normalize(new AMQShortString(b.getBindingKey())); @@ -284,10 +268,20 @@ public class ManagementExchange implements Exchange, QMFService.Listener { result.addUnfilteredQueue(b.getQueue()); } - _topicBindings.put(binding, null); + result.addBinding(b); + } + + for(BindingListener listener : _listeners) + { + listener.bindingAdded(this, b); + } + if(_bindingSet.size() > _bindingCountHigh) + { + _bindingCountHigh = _bindingSet.size(); } + String bindingKey = b.getBindingKey(); if(bindingKey.startsWith("schema.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#.")) @@ -355,6 +349,13 @@ public class ManagementExchange implements Exchange, QMFService.Listener HashSet queues = new HashSet(); for(TopicMatcherResult result : results) { + TopicExchangeResult res = (TopicExchangeResult)result; + + for(Binding b : res.getBindings()) + { + b.incrementMatches(); + } + queues.addAll(((TopicExchangeResult)result).getUnfilteredQueues()); } for(AMQQueue queue : queues) @@ -378,14 +379,11 @@ public class ManagementExchange implements Exchange, QMFService.Listener public synchronized void removeBinding(final Binding binding) { - _bindingSet.remove(binding); - - TopicBinding topicBinding = new TopicBinding(new AMQShortString(binding.getBindingKey()), binding.getQueue(), null); - - if(_topicBindings.containsKey(topicBinding)) + if(_bindingSet.remove(binding)) { - AMQShortString bindingKey = TopicNormalizer.normalize(topicBinding.getBindingKey()); + AMQShortString bindingKey = TopicNormalizer.normalize(new AMQShortString(binding.getBindingKey())); TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + result.removeBinding(binding); result.removeUnfilteredQueue(binding.getQueue()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 41ae52e9b8..be4e8f8ec1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -110,7 +110,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr public String[] getExchangeTypes() throws IOException { ArrayList exchangeTypes = new ArrayList(); - for(ExchangeType ex : _exchangeFactory.getRegisteredTypes()) + for(ExchangeType ex : _exchangeFactory.getPublicCreatableTypes()) { exchangeTypes.add(ex.getName().toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 1c4c341c14..9be8bddd28 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -20,8 +20,12 @@ */ package org.apache.qpid.server.exchange; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; @@ -30,10 +34,6 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - public class DefaultExchangeFactory implements ExchangeFactory { private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); @@ -60,6 +60,21 @@ public class DefaultExchangeFactory implements ExchangeFactory { return _exchangeClassMap.values(); } + + public Collection> getPublicCreatableTypes() + { + Collection> publicTypes = + new ArrayList>(); + publicTypes.addAll(_exchangeClassMap.values()); + + //Remove the ManagementExchange type if present, as these + //are private and cannot be created by external means + publicTypes.remove(ManagementExchange.TYPE); + + return publicTypes; + } + + public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index b91bf559f1..aa4cc1ec24 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -38,6 +38,8 @@ public interface ExchangeFactory void initialise(VirtualHostConfiguration hostConfig); Collection> getRegisteredTypes(); + + Collection> getPublicCreatableTypes(); Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java deleted file mode 100644 index c6383a886e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange.topic; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.TopicExchange; - -public class TopicBinding -{ - private final AMQShortString _bindingKey; - private final AMQQueue _queue; - private final FieldTable _args; - - public TopicBinding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) - { - _bindingKey = bindingKey; - _queue = queue; - _args = args; - } - - public AMQShortString getBindingKey() - { - return _bindingKey; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public int hashCode() - { - return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); - } - - public boolean equals(Object o) - { - if(this == o) - { - return true; - } - if(o instanceof TopicBinding) - { - TopicBinding other = (TopicBinding) o; - return (_queue == other._queue) - && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); - } - return false; - } -} -- cgit v1.2.1 From 5e33292a317033a6b9db95010a6d198ee27bdfa5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 18 Mar 2010 18:20:51 +0000 Subject: QPID-2379: remove mistakingly commited temporary logging additions git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@924934 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/exchange/TopicExchange.java | 8 -------- 1 file changed, 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 6e60d95700..1245efdafa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -205,19 +205,11 @@ public class TopicExchange extends AbstractExchange ? AMQShortString.EMPTY_STRING : new AMQShortString(payload.getRoutingKey()); - _logger.info("Message routing key: " + routingKey ); - // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues ArrayList queues = new ArrayList(); queues.addAll(getMatchedQueues(payload, routingKey)); - for(BaseQueue q : queues) - { - _logger.info("Matched Queue: " + q.getNameShortString() ); - } - - if(queues == null || queues.isEmpty()) { _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); -- cgit v1.2.1 From 84139c0b683da48f272fc999fd13606a235ff189 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 23 Mar 2010 11:54:48 +0000 Subject: QPID-2379: add the queue UnackedMessage counts git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@926530 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 6 ++-- .../qpid/server/configuration/QueueConfig.java | 4 +++ .../org/apache/qpid/server/queue/AMQQueue.java | 1 + .../apache/qpid/server/queue/QueueEntryImpl.java | 30 ++++++++++++-------- .../apache/qpid/server/queue/SimpleAMQQueue.java | 33 ++++++++++++++++++++++ 5 files changed, 59 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 54f1db845e..381c376f56 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1004,14 +1004,12 @@ public class QMFService implements ConfigStore.ConfigEventListener public Long getUnackedMessages() { - // TODO - return 0l; + return _obj.getUnackedMessageCount(); } public Long getUnackedMessagesHigh() { - // TODO - return 0l; + return _obj.getUnackedMessageCountHigh(); } public Long getUnackedMessagesLow() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index 95e2aa516b..4c9ec6619e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -75,6 +75,10 @@ public interface QueueConfig extends ConfiguredObject, ExchangeRefer void dequeue(QueueEntry entry, Subscription sub); + void decrementUnackedMsgCount(); boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index bf4015eb7a..1ba4f4d89b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -226,22 +226,29 @@ public class QueueEntryImpl implements QueueEntry public void release() { - _stateUpdater.set(this,AVAILABLE_STATE); - if(!getQueue().isDeleted()) + EntryState state = _state; + + if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, AVAILABLE_STATE)) { - getQueue().requeue(this); - if(_stateChangeListeners != null) + if(state instanceof SubscriptionAcquiredState) { - notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + getQueue().decrementUnackedMsgCount(); } + + if(!getQueue().isDeleted()) + { + getQueue().requeue(this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } + } + else if(acquire()) + { + routeToAlternate(); + } } - else if(acquire()) - { - routeToAlternate(); - } - - } public boolean releaseButRetain() @@ -369,6 +376,7 @@ public class QueueEntryImpl implements QueueEntry Subscription s = null; if (state instanceof SubscriptionAcquiredState) { + getQueue().decrementUnackedMsgCount(); s = ((SubscriptionAcquiredState) state).getSubscription(); s.onDequeue(this); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b5d1290e98..cf2f637697 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -127,6 +127,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _byteTxnEnqueues = new AtomicLong(0); private final AtomicLong _msgTxnDequeues = new AtomicLong(0); private final AtomicLong _byteTxnDequeues = new AtomicLong(0); + private final AtomicLong _unackedMsgCount = new AtomicLong(0); + private final AtomicLong _unackedMsgCountHigh = new AtomicLong(0); private final AtomicInteger _bindingCountHigh = new AtomicInteger(); @@ -693,6 +695,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throws AMQException { _deliveredMessages.incrementAndGet(); + incrementUnackedMsgCount(); + sub.send(entry); setLastSeenEntry(sub,entry); @@ -2138,4 +2142,33 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { return String.valueOf(getNameShortString()); } + + public long getUnackedMessageCountHigh() + { + return _unackedMsgCountHigh.get(); + } + + public long getUnackedMessageCount() + { + return _unackedMsgCount.get(); + } + + public void decrementUnackedMsgCount() + { + _unackedMsgCount.decrementAndGet(); + } + + private void incrementUnackedMsgCount() + { + long unackedMsgCount = _unackedMsgCount.incrementAndGet(); + + long unackedMsgCountHigh; + while(unackedMsgCount > (unackedMsgCountHigh = _unackedMsgCountHigh.get())) + { + if(_unackedMsgCountHigh.compareAndSet(unackedMsgCountHigh, unackedMsgCount)) + { + break; + } + } + } } -- cgit v1.2.1 From 1a477d5ba3b4e594b96f178855f237e5c579327e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 30 Mar 2010 13:45:18 +0000 Subject: QPID-2630, QPID-2631: Restore the virtualhosts.xml file. When a virtualhosts.xml file is specified load it as its own Configuration object to ensure the property heirarchy is not lost. Enforce that virtualhost config can only be specified in either the main config.xml file or the virtualhosts.xml file, but not both. Allow the virtualhosts.xml file to be a combined configuration and use to provide override abilities for testing. Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@929136 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 116 ++++++++++++++------- 1 file changed, 76 insertions(+), 40 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 879eb7c9e6..edf88f9b5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -21,18 +21,19 @@ package org.apache.qpid.server.configuration; import java.io.File; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Locale; -import java.util.Collections; +import java.util.Map; import java.util.Map.Entry; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationFactory; +import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; @@ -52,18 +53,17 @@ public class ServerConfiguration implements SignalHandler private Configuration _config; // Default Configuration values - //todo make these all public, to make validation of configuration easier. public static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; public static final String DEFAULT_STATUS_UPDATES = "on"; public static final String SECURITY_CONFIG_RELOADED = "SECURITY CONFIGURATION RELOADED"; - private static final int DEFAULT_FRAME_SIZE = 65536; - private static final int DEFAULT_PORT = 5672; - private static final int DEFAUL_SSL_PORT = 8672; - private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; - private static final int DEFAULT_JMXPORT = 8999; + public static final int DEFAULT_FRAME_SIZE = 65536; + public static final int DEFAULT_PORT = 5672; + public static final int DEFAULT_SSL_PORT = 8672; + public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; + public static final int DEFAULT_JMXPORT = 8999; private static int _jmxPort = DEFAULT_JMXPORT; @@ -71,6 +71,7 @@ public class ServerConfiguration implements SignalHandler private SecurityConfiguration _securityConfiguration = null; private File _configFile; + private File _vhostsFile; private Logger _log = LoggerFactory.getLogger(this.getClass()); @@ -134,8 +135,6 @@ public class ServerConfiguration implements SignalHandler { setConfig(conf); - substituteEnvironmentVariables(); - _jmxPort = getConfig().getInt("management.jmxport", 8999); _securityConfiguration = new SecurityConfiguration(conf.subset("security")); @@ -143,61 +142,86 @@ public class ServerConfiguration implements SignalHandler } - private void setupVirtualHosts(Configuration conf) throws ConfigurationException + /* + * Modified to enforce virtualhosts configuration in external file or main file, but not + * both, as a fix for QPID-2360 and QPID-2361. + */ + @SuppressWarnings("unchecked") + private void setupVirtualHosts(Configuration conf) throws ConfigurationException { - List vhosts = conf.getList("virtualhosts"); - Iterator i = vhosts.iterator(); - while (i.hasNext()) + List vhostFiles = conf.getList("virtualhosts"); + Configuration vhostConfig = conf.subset("virtualhosts"); + + // Only one configuration mechanism allowed + if (!vhostFiles.isEmpty() && !vhostConfig.subset("virtualhost").isEmpty()) { - Object thing = i.next(); - if (thing instanceof String) - { - //Open the Virtualhost.xml file and copy values in to main config - XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing); - Iterator keys = vhostConfiguration.getKeys(); - while (keys.hasNext()) - { - String key = (String) keys.next(); - conf.setProperty("virtualhosts." + key, vhostConfiguration.getProperty(key)); - } - } + throw new ConfigurationException("Only one of external or embedded virtualhosts configuration allowed."); + } + + // We can only have one vhosts XML file included + if (vhostFiles.size() > 1) + { + throw new ConfigurationException("Only one external virtualhosts configuration file allowed, multiple filenames found."); + } + + // Virtualhost configuration object + Configuration vhostConfiguration = new HierarchicalConfiguration(); + + // Load from embedded configuration if possible + if (!vhostConfig.subset("virtualhost").isEmpty()) + { + vhostConfiguration = vhostConfig; } - - List hosts = conf.getList("virtualhosts.virtualhost.name"); + else + { + // Load from the external configuration if possible + for (String fileName : vhostFiles) + { + // Open the vhosts XML file and copy values from it to our config + _vhostsFile = new File(fileName); + vhostConfiguration = parseConfig(new File(fileName)); + } + } + + // Now extract the virtual host names from the configuration object + List hosts = vhostConfiguration.getList("virtualhost.name"); for (int j = 0; j < hosts.size(); j++) { String name = (String) hosts.get(j); - // Add the keys of the virtual host to the main config then bail out - - VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost." + name)); - _virtualHosts.put(vhostConfig.getName(), vhostConfig); + + // Add the virtual hosts to the server configuration + VirtualHostConfiguration virtualhost = new VirtualHostConfiguration(name, vhostConfiguration.subset("virtualhost." + name)); + _virtualHosts.put(virtualhost.getName(), virtualhost); } - } - private void substituteEnvironmentVariables() + private static void substituteEnvironmentVariables(Configuration conf) { for (Entry var : envVarMap.entrySet()) { String val = System.getenv(var.getKey()); if (val != null) { - getConfig().setProperty(var.getValue(), val); + conf.setProperty(var.getValue(), val); } } } - private final static Configuration parseConfig(File file) throws ConfigurationException + private static Configuration parseConfig(File file) throws ConfigurationException { ConfigurationFactory factory = new ConfigurationFactory(); factory.setConfigurationFileName(file.getAbsolutePath()); Configuration conf = factory.getConfiguration(); - Iterator keys = conf.getKeys(); + + Iterator keys = conf.getKeys(); if (!keys.hasNext()) { keys = null; conf = flatConfig(file); } + + substituteEnvironmentVariables(conf); + return conf; } @@ -311,13 +335,25 @@ public class ServerConfiguration implements SignalHandler if (_configFile != null) { Configuration newConfig = parseConfig(_configFile); + _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); - + + // Reload virtualhosts from correct location + Configuration newVhosts; + if (_vhostsFile == null) + { + newVhosts = newConfig.subset("virtualhosts"); + } + else + { + newVhosts = parseConfig(_vhostsFile); + } + VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); for (String hostname : _virtualHosts.keySet()) { VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); - SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security")); + SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newVhosts.subset("virtualhost."+hostname+".security")); vhost.getAccessManager().configureGlobalPlugins(_securityConfiguration); vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); } @@ -601,7 +637,7 @@ public class ServerConfiguration implements SignalHandler public int getSSLPort() { - return getConfig().getInt("connector.ssl.port", DEFAUL_SSL_PORT); + return getConfig().getInt("connector.ssl.port", DEFAULT_SSL_PORT); } public String getKeystorePath() -- cgit v1.2.1 From e8901f7f2feb150969b449867eef246de196a7c1 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 5 Apr 2010 15:17:11 +0000 Subject: QPID-2361: Fix to correctly set default virtualhost name in external configuration file Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@930877 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index edf88f9b5a..307a697a95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -180,6 +180,10 @@ public class ServerConfiguration implements SignalHandler // Open the vhosts XML file and copy values from it to our config _vhostsFile = new File(fileName); vhostConfiguration = parseConfig(new File(fileName)); + + // save the default virtualhost name + String defaultVirtualHost = vhostConfiguration.getString("default"); + _config.setProperty("virtualhosts.default", defaultVirtualHost); } } -- cgit v1.2.1 From 1209b7fc315cd3c84bbf959b7ffeac5eb01fa41c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 9 Apr 2010 14:16:08 +0000 Subject: QPID-2379: add Connection.close() method implementation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@932428 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 5 ++- .../server/configuration/ConnectionConfig.java | 2 + .../apache/qpid/server/federation/BrokerLink.java | 5 +++ .../qpid/server/protocol/AMQProtocolEngine.java | 50 +++++++++++++++++++++- .../qpid/server/protocol/ProtocolEngine_0_10.java | 5 +++ 5 files changed, 63 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 381c376f56..c32fcfd73a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1214,8 +1214,9 @@ public class QMFService implements ConfigStore.ConfigEventListener public BrokerSchema.ConnectionClass.CloseMethodResponseCommand close(final BrokerSchema.ConnectionClass.CloseMethodResponseCommandFactory factory) { - //todo - throw new UnsupportedOperationException(); + _obj.mgmtClose(); + + return factory.createResponseCommand(); } public UUID getId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java index ad451f44a7..0dd36fe1fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java @@ -44,4 +44,6 @@ public interface ConnectionConfig extends ConfiguredObject Date: Fri, 9 Apr 2010 14:16:26 +0000 Subject: QPID-2379: add Session.close() method implementation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@932429 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 14 ++++++-- .../java/org/apache/qpid/server/AMQChannel.java | 26 ++++++++------ .../qpid/server/configuration/SessionConfig.java | 4 +++ .../qpid/server/protocol/AMQProtocolEngine.java | 41 ++++++++++++++++++++++ .../qpid/server/protocol/AMQProtocolSession.java | 1 + .../qpid/server/transport/ServerSession.java | 5 +++ 6 files changed, 78 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index c32fcfd73a..4491f3f7d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.qpid.AMQException; import org.apache.qpid.qmf.schema.BrokerSchema; import org.apache.qpid.server.configuration.*; import org.apache.qpid.server.registry.IApplicationRegistry; @@ -1336,8 +1337,17 @@ public class QMFService implements ConfigStore.ConfigEventListener public BrokerSchema.SessionClass.CloseMethodResponseCommand close(final BrokerSchema.SessionClass.CloseMethodResponseCommandFactory factory) { - //todo - throw new UnsupportedOperationException(); + try + { + _obj.mgmtClose(); + } + catch (AMQException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return factory.createResponseCommand(); } public UUID getId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index fe5da20fa5..454b731e5f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -141,7 +141,7 @@ public class AMQChannel implements SessionConfig // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; - private boolean _closing; + private AtomicBoolean _closing = new AtomicBoolean(false); private final ConcurrentMap _blockingQueues = new ConcurrentHashMap(); @@ -480,7 +480,13 @@ public class AMQChannel implements SessionConfig */ public void close() throws AMQException { - setClosing(true); + if(!_closing.compareAndSet(false, true)) + { + //Channel is already closing + return; + } + + CurrentActor.get().message(_logSubject, ChannelMessages.CHN_CLOSE()); unsubscribeAllConsumers(); _transaction.rollback(); @@ -498,13 +504,6 @@ public class AMQChannel implements SessionConfig } - private void setClosing(boolean closing) - { - _closing = closing; - - CurrentActor.get().message(_logSubject, ChannelMessages.CHN_CLOSE()); - } - private void unsubscribeAllConsumers() throws AMQException { if (_logger.isInfoEnabled()) @@ -881,7 +880,7 @@ public class AMQChannel implements SessionConfig public boolean isSuspended() { - return _suspended.get() || _closing || _session.isClosing(); + return _suspended.get() || _closing.get() || _session.isClosing(); } public void commit() throws AMQException @@ -981,7 +980,7 @@ public class AMQChannel implements SessionConfig public boolean isClosing() { - return _closing; + return _closing.get(); } public AMQProtocolSession getProtocolSession() @@ -1377,4 +1376,9 @@ public class AMQChannel implements SessionConfig { return _createTime; } + + public void mgmtClose() throws AMQException + { + _session.mgmtCloseChannel(_channelId); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java index 5e5dd10e57..8fef642eff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java @@ -21,6 +21,8 @@ package org.apache.qpid.server.configuration; +import org.apache.qpid.AMQException; + public interface SessionConfig extends ConfiguredObject { VirtualHostConfig getVirtualHost(); @@ -48,4 +50,6 @@ public interface SessionConfig extends ConfiguredObject Date: Fri, 9 Apr 2010 14:16:42 +0000 Subject: QPID-2379: add ability to respond to method requests with non-zero status codes, use to signal unimplemented methods. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@932430 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/qmf/QMFMethodResponseCommand.java | 43 +++++++++++++++++++--- .../main/java/org/apache/qpid/qmf/QMFService.java | 21 +++++------ 2 files changed, 48 insertions(+), 16 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java index 529b04ebdb..5fea014ad8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java @@ -20,24 +20,57 @@ */ package org.apache.qpid.qmf; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.transport.codec.BBEncoder; public class QMFMethodResponseCommand extends QMFCommand { - public QMFMethodResponseCommand(final QMFMethodRequestCommand cmd) + private CompletionCode _status = null; + private String _msg = null; + + public QMFMethodResponseCommand(final QMFMethodRequestCommand cmd, + CompletionCode status, + String msg) { super( new QMFCommandHeader(cmd.getHeader().getVersion(), cmd.getHeader().getSeq(), QMFOperation.METHOD_RESPONSE)); + + if(status == null) + { + _status = CompletionCode.OK; + } + else + { + _status = status; + } + + _msg = msg; + } + + public CompletionCode getStatus() + { + return _status; + } + + public String getStatusText() + { + return _msg; } @Override public void encode(final BBEncoder encoder) { super.encode(encoder); - encoder.writeUint32(0); - encoder.writeStr16("OK"); + + encoder.writeUint32(_status.ordinal()); + + if(_msg == null) + { + encoder.writeStr16(_status.toString()); + } + else + { + encoder.writeStr16(_msg); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 4491f3f7d5..1a9766c5b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -679,8 +679,8 @@ public class QMFService implements ConfigStore.ConfigEventListener final String destQueue, final Long qty) { - // todo - throw new UnsupportedOperationException(); + // TODO + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } public UUID getId() @@ -1056,7 +1056,7 @@ public class QMFService implements ConfigStore.ConfigEventListener final String exchange) { //TODO - return factory.createResponseCommand(); + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } @@ -1319,20 +1319,20 @@ public class QMFService implements ConfigStore.ConfigEventListener public BrokerSchema.SessionClass.SolicitAckMethodResponseCommand solicitAck(final BrokerSchema.SessionClass.SolicitAckMethodResponseCommandFactory factory) { - //todo - throw new UnsupportedOperationException(); + //TODO + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } public BrokerSchema.SessionClass.DetachMethodResponseCommand detach(final BrokerSchema.SessionClass.DetachMethodResponseCommandFactory factory) { - //todo - throw new UnsupportedOperationException(); + //TODO + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } public BrokerSchema.SessionClass.ResetLifespanMethodResponseCommand resetLifespan(final BrokerSchema.SessionClass.ResetLifespanMethodResponseCommandFactory factory) { - //todo - throw new UnsupportedOperationException(); + //TODO + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } public BrokerSchema.SessionClass.CloseMethodResponseCommand close(final BrokerSchema.SessionClass.CloseMethodResponseCommandFactory factory) @@ -1343,8 +1343,7 @@ public class QMFService implements ConfigStore.ConfigEventListener } catch (AMQException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + return factory.createResponseCommand(CompletionCode.EXCEPTION, e.getMessage()); } return factory.createResponseCommand(); -- cgit v1.2.1 From 1f07acf5f421b44506b10f0633cc9ade07385cd9 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 19 Apr 2010 08:34:36 +0000 Subject: QPID-2379 / QPID-2400: Unregister event listeners during QMFService shutdown to prevent fielding object removal events that cant be actioned anymore. Add null check to the QMFClass retrieval during the unmanage process. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@935474 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 1a9766c5b2..b3be6d77e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -359,6 +359,12 @@ public class QMFService implements ConfigStore.ConfigEventListener public void close() { + for(ConfigObjectType v : _qmfClassMapping.values()) + { + _configStore.removeConfigEventListener(v, this); + } + _listeners.clear(); + _managedObjects.clear(); _managedObjectsById.clear(); _classMap.clear(); @@ -414,6 +420,11 @@ public class QMFService implements ConfigStore.ConfigEventListener private void unmanageObject(final ConfiguredObject object) { final QMFClass qmfClass = _classMap.get(object.getConfigType()); + + if(qmfClass == null) + { + return; + } ConcurrentHashMap classObjects = _managedObjects.get(qmfClass); if(classObjects != null) -- cgit v1.2.1 From e7b0eefa91ebb4c4ff4f8dcff6b369cceeee4318 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 20 Apr 2010 14:03:56 +0000 Subject: QPID-2097: Use the standard RMIServerSocketFactory for InVM testing to workaround the alternating pass-fail issue encountered when running back to back tests using JMX with the InVM broker. Enable the ModelTest. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@935928 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 11 ++++ .../management/JMXManagedObjectRegistry.java | 65 +++++++++++++++++----- 2 files changed, 61 insertions(+), 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 307a697a95..2a956c6dff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -86,6 +86,7 @@ public class ServerConfiguration implements SignalHandler public static final String CONNECTOR_PROTECTIO_ENABLED = "connector.protectio.enabled"; public static final String CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE = "connector.protectio.readBufferLimitSize"; public static final String CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE = "connector.protectio.writeBufferLimitSize"; + public static final String MGMT_CUSTOM_REGISTRY_SOCKET = "management.custom-registry-socket"; public static final String STATUS_UPDATES = "status-updates"; public static final String ADVANCED_LOCALE = "advanced.locale"; @@ -390,6 +391,16 @@ public class ServerConfiguration implements SignalHandler { return _jmxPort; } + + public boolean getUseCustomRMISocketFactory() + { + return getConfig().getBoolean(MGMT_CUSTOM_REGISTRY_SOCKET, true); + } + + public void setUseCustomRMISocketFactory(boolean bool) + { + getConfig().setProperty(MGMT_CUSTOM_REGISTRY_SOCKET, bool); + } public boolean getPlatformMbeanserver() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 048551010e..7ce0f6022b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -56,7 +56,8 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.rmi.AlreadyBoundException; -import java.rmi.RemoteException; +import java.rmi.NoSuchObjectException; +import java.rmi.NotBoundException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; @@ -81,7 +82,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry private final MBeanServer _mbeanServer; private JMXConnectorServer _cs; private Registry _rmiRegistry; - + private boolean _useCustomSocketFactory; public JMXManagedObjectRegistry() throws AMQException { @@ -89,6 +90,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); // Retrieve the config parameters + _useCustomSocketFactory = appRegistry.getConfiguration().getUseCustomRMISocketFactory(); boolean platformServer = appRegistry.getConfiguration().getPlatformMbeanserver(); _mbeanServer = @@ -226,7 +228,14 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * As a result, only binds made using the object reference will succeed, thus securing it from external change. */ System.setProperty("java.rmi.server.randomIDs", "true"); - _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); + if(_useCustomSocketFactory) + { + _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory()); + } + else + { + _rmiRegistry = LocateRegistry.createRegistry(port, null, null); + } /* * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls @@ -274,8 +283,27 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //now do the normal tasks super.start(); - } + } + @Override + public synchronized void stop() throws IOException + { + try + { + if (_rmiRegistry != null) + { + _rmiRegistry.unbind("jmxrmi"); + } + } + catch (NotBoundException nbe) + { + //ignore + } + + //now do the normal tasks + super.stop(); + } + @Override public JMXServiceURL getAddress() { @@ -374,27 +402,34 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry return false; } - // stops the RMIRegistry and unregisters the MBeans from the MBeanServer - public void close() throws RemoteException + //Stops the JMXConnectorServer and RMIRegistry, then unregisters any remaining MBeans from the MBeanServer + public void close() { - if (_rmiRegistry != null) - { - // Stopping the RMI registry - UnicastRemoteObject.unexportObject(_rmiRegistry, true); - } - if (_cs != null) { // Stopping the JMX ConnectorServer try { - _cs.stop(); - CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort())); + _cs.stop(); } catch (IOException e) { - _log.warn("Error while closing the JMX ConnectorServer: " + e.getMessage()); + _log.error("Exception while closing the JMX ConnectorServer: " + e.getMessage()); + } + } + + if (_rmiRegistry != null) + { + // Stopping the RMI registry + CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); + try + { + UnicastRemoteObject.unexportObject(_rmiRegistry, false); + } + catch (NoSuchObjectException e) + { + _log.error("Exception while closing the RMI Registry: " + e.getMessage()); } } -- cgit v1.2.1 From 408fdc7478b1cc24014f86fa0a7af930764bbd80 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 21 Apr 2010 11:31:18 +0000 Subject: QPID-2479: Add info/debug level logging to allow tracking the virtualhost housekeeping process Applied patch from Sorin Suciu Merged from 0.5.x-dev r930288 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@936259 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/virtualhost/VirtualHostImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index b208872a5a..4ae1ea6e08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -286,28 +286,32 @@ public class VirtualHostImpl implements Accessable, VirtualHost /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ if (period != 0L) { - class RemoveExpiredMessagesTask extends TimerTask + class HouseKeepingTask extends TimerTask { + Logger _hkLogger = Logger.getLogger(HouseKeepingTask.class); + public void run() { + _hkLogger.info("Starting the houseKeeping job"); for (AMQQueue q : _queueRegistry.getQueues()) { - + _hkLogger.debug("Checking message status for queue: "+q.getName().toString()); try { q.checkMessageStatus(); } catch (Exception e) { - _logger.error("Exception in housekeeping for queue: " + q.getNameShortString().toString(), e); + _hkLogger.error("Exception in housekeeping for queue: " + q.getNameShortString().toString(), e); //Don't throw exceptions as this will stop the // house keeping task from running. } } + _hkLogger.info("HouseKeeping job completed."); } } - final TimerTask expiredMessagesTask = new RemoveExpiredMessagesTask(); + final TimerTask expiredMessagesTask = new HouseKeepingTask(); scheduleTask(period, expiredMessagesTask); class ForceChannelClosuresTask extends TimerTask -- cgit v1.2.1 From dd37c9106485a6c4b933fd5000912b4b8ea35a28 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 23 Apr 2010 15:44:39 +0000 Subject: QPID-2513 : Applied patch from Sorin Suciu to enable OSGi Service plugins git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@937343 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/plugins/Activator.java | 4 ++ .../apache/qpid/server/plugins/PluginManager.java | 57 +++++++++++++--------- 2 files changed, 39 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java index b0ebf197f9..89d9c1de74 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java @@ -19,6 +19,8 @@ package org.apache.qpid.server.plugins; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -30,6 +32,8 @@ public class Activator implements BundleActivator public void start(BundleContext ctx) throws Exception { _context = ctx; + ctx.registerService(ServerConfiguration.class.getName(), ApplicationRegistry.getInstance().getConfiguration(), null); + } public void stop(BundleContext ctx) throws Exception diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index dbfcefb6ab..682c66239b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -44,13 +44,12 @@ import org.osgi.util.tracker.ServiceTracker; /** * * @author aidan - * + * * Provides access to pluggable elements, such as exchanges */ public class PluginManager { - private Felix _felix = null; private ServiceTracker _exchangeTracker = null; private ServiceTracker _securityTracker = null; @@ -70,16 +69,28 @@ public class PluginManager + "org.osgi.service.packageadmin; version=1.2.0," + "org.osgi.service.startlevel; version=1.0.0," + "org.osgi.service.url; version=1.0.0," + - "org.apache.qpid.framing; version=0.2.1," + - "org.apache.qpid.server.exchange; version=0.2.1," + - "org.apache.qpid.server.management; version=0.2.1,"+ - "org.apache.qpid.protocol; version=0.2.1,"+ - "org.apache.qpid.server.virtualhost; version=0.2.1," + - "org.apache.qpid; version=0.2.1," + - "org.apache.qpid.server.queue; version=0.2.1," + + "org.osgi.util.tracker; version=1.0.0,"+ + "org.apache.qpid; version=0.7," + + "org.apache.qpid.framing; version=0.7," + + "org.apache.qpid.server.exchange; version=0.7," + + "org.apache.qpid.server.management; version=0.7,"+ + "org.apache.qpid.server.protocol; version=0.7,"+ + "org.apache.qpid.server.virtualhost; version=0.7," + + "org.apache.qpid.server.registry; version=0.7," + + "org.apache.qpid.server.queue; version=0.7," + + "org.apache.qpid.server.binding; version=0.7," + + "org.apache.qpid.server.configuration; version=0.7," + + "org.apache.qpid.server.configuration.management; version=0.7," + + "org.apache.qpid.server.persistent; version=0.7," + + "org.apache.qpid.server.plugins; version=0.7," + + "org.apache.qpid.server.queue; version=0.7," + + "org.apache.qpid.server.security; version=0.7," + + "org.apache.qpid.framing.AMQShortString; version=0.7," + + "org.apache.qpid.server.queue.AMQQueue; version=0.7," + + "org.apache.qpid.server.security.access; version=0.7,"+ + "org.apache.commons.configuration; version=0.7," + "javax.management.openmbean; version=1.0.0,"+ - "javax.management; version=1.0.0,"+ - "org.apache.qpid.junit.extensions.util; version=0.6.1," + "javax.management; version=1.0.0," ); if (plugindir == null) @@ -91,10 +102,11 @@ public class PluginManager // Set the list of bundles to load File dir = new File(plugindir); if (!dir.exists()) - { + { _empty = true; return; - } + } + StringBuffer pluginJars = new StringBuffer(); if (dir.isDirectory()) @@ -107,6 +119,7 @@ public class PluginManager } } } + if (pluginJars.length() == 0) { _empty = true; @@ -124,13 +137,13 @@ public class PluginManager try { _felix.start(); - + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); _exchangeTracker.open(); _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); - _exchangeTracker.open(); - + _securityTracker.open(); + } catch (BundleException e) { @@ -138,19 +151,19 @@ public class PluginManager } } - private Map getServices(ServiceTracker tracker) + private Map getServices(ServiceTracker tracker) { - Mapexchanges = new HashMap(); + Mapservices = new HashMap(); - if (tracker != null) + if ((tracker != null) && (tracker.getServices() != null)) { for (Object service : tracker.getServices()) { - exchanges.put(service.getClass().getName(), (type) service); + services.put(service.getClass().getName(), (T) service); } - } + } - return exchanges; + return services; } public Map> getExchanges() -- cgit v1.2.1 From 313c8b1f67f7b9ddca911d6227e947aed6e01db6 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Fri, 23 Apr 2010 19:02:31 +0000 Subject: QPID-2517 - Broker schema changes to support cluster management. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@937470 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index b3be6d77e3..ef7426c814 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -619,6 +619,11 @@ public class QMFService implements ConfigStore.ConfigEventListener return (BrokerSchema.SystemObject) adapt(_obj.getSystem()); } + public String getName() + { + return "amqp-broker"; + } + public Integer getPort() { return _obj.getPort(); -- cgit v1.2.1 From 706da7c98d161aa79bf789dc17dc74460c911baf Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 24 Apr 2010 00:49:02 +0000 Subject: QPID-2534: export the necessary additional packages. Reenable the PluginTest now that the required package is available to the plugin git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@937566 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 682c66239b..0911c73fe7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -70,8 +70,10 @@ public class PluginManager "org.osgi.service.startlevel; version=1.0.0," + "org.osgi.service.url; version=1.0.0," + "org.osgi.util.tracker; version=1.0.0,"+ + "org.apache.qpid.junit.extensions.util; version=0.7," + "org.apache.qpid; version=0.7," + "org.apache.qpid.framing; version=0.7," + + "org.apache.qpid.protocol; version=0.7," + "org.apache.qpid.server.exchange; version=0.7," + "org.apache.qpid.server.management; version=0.7,"+ "org.apache.qpid.server.protocol; version=0.7,"+ -- cgit v1.2.1 From f143411bc8475b8c2288b7c271247ad77e6b3a82 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:09:42 +0000 Subject: QPID-2575 : Create Connection and Session models to correctly expose the Owning Session. Addressed issue where getPrincipal was used in error to identify queue owner. Session model now allows access to this in a protocol independent way. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942101 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 14 +++++- .../server/handler/BasicConsumeMethodHandler.java | 31 +++++++------ .../qpid/server/handler/BasicGetMethodHandler.java | 25 ++++++---- .../qpid/server/handler/QueueBindHandler.java | 23 +++++---- .../qpid/server/handler/QueueDeclareHandler.java | 54 +++++++++++++--------- .../qpid/server/handler/QueueDeleteHandler.java | 16 ++++--- .../qpid/server/handler/QueuePurgeHandler.java | 20 ++++---- .../qpid/server/protocol/AMQConnectionModel.java | 38 +++++++++++++++ .../qpid/server/protocol/AMQProtocolEngine.java | 19 +++++++- .../qpid/server/protocol/AMQProtocolSession.java | 4 +- .../qpid/server/protocol/AMQSessionModel.java | 28 +++++++++++ .../org/apache/qpid/server/queue/AMQQueue.java | 6 ++- .../apache/qpid/server/queue/SimpleAMQQueue.java | 8 ++-- .../qpid/server/transport/ServerConnection.java | 26 ++++++++++- .../qpid/server/transport/ServerSession.java | 17 ++++++- .../server/transport/ServerSessionDelegate.java | 3 +- 16 files changed, 247 insertions(+), 85 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 454b731e5f..573fa9d966 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -56,6 +56,8 @@ import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.protocol.AMQProtocolEngine; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.IncomingMessage; @@ -86,7 +88,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -public class AMQChannel implements SessionConfig +public class AMQChannel implements SessionConfig, AMQSessionModel { public static final int DEFAULT_PREFETCH = 5000; @@ -1058,6 +1060,16 @@ public class AMQChannel implements SessionConfig } + public Object getID() + { + return _channelId; + } + + public AMQConnectionModel getConnectionModel() + { + return _session; + } + private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index d806f9426a..50019090d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -26,6 +26,7 @@ import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; @@ -48,14 +49,14 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener public void methodReceived(AMQStateManager stateManager, QueueBindBody body, int channelId) throws AMQException { - AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); + AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); + VirtualHost virtualHost = protocolConnection.getVirtualHost(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); @@ -70,7 +71,7 @@ public class QueueBindHandler implements StateAwareMethodListener if (body.getQueue() == null) { - AMQChannel channel = session.getChannel(channelId); + AMQChannel channel = protocolConnection.getChannel(channelId); if (channel == null) { @@ -114,15 +115,19 @@ public class QueueBindHandler implements StateAwareMethodListener { //Perform ACLs - if (!virtualHost.getAccessManager().authoriseBind(session, exch, + if (!virtualHost.getAccessManager().authoriseBind(protocolConnection, exch, queue, routingKey)) { throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); } - else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) + else if (queue.isExclusive() && !queue.isDurable()) { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); + AMQSessionModel session = queue.getExclusiveOwningSession(); + if (session == null || session.getConnectionModel() != protocolConnection) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); + } } if (!exch.isBound(routingKey, body.getArguments(), queue)) @@ -153,9 +158,9 @@ public class QueueBindHandler implements StateAwareMethodListener } if (!body.getNowait()) { - MethodRegistry methodRegistry = session.getMethodRegistry(); + MethodRegistry methodRegistry = protocolConnection.getMethodRegistry(); AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); + protocolConnection.writeFrame(responseBody.generateFrame(channelId)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 5d5bd761c7..961a165877 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -35,6 +35,7 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.QueueRegistry; @@ -61,8 +62,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener, ExchangeRefer PrincipalHolder getPrincipalHolder(); void setPrincipalHolder(PrincipalHolder principalHolder); - void setExclusiveOwner(Object owner); - Object getExclusiveOwner(); + void setExclusiveOwningSession(AMQSessionModel owner); + AMQSessionModel getExclusiveOwningSession(); VirtualHost getVirtualHost(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index cf2f637697..b7f3f59c4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -7,6 +7,8 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; @@ -83,7 +85,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private PrincipalHolder _prinicpalHolder; - private Object _exclusiveOwner; + private AMQSessionModel _exclusiveOwner; private final boolean _durable; @@ -2045,12 +2047,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return ids; } - public Object getExclusiveOwner() + public AMQSessionModel getExclusiveOwningSession() { return _exclusiveOwner; } - public void setExclusiveOwner(Object exclusiveOwner) + public void setExclusiveOwningSession(AMQSessionModel exclusiveOwner) { _exclusiveOwner = exclusiveOwner; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 1aff1eec86..58dbc95224 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -22,10 +22,23 @@ package org.apache.qpid.server.transport; import org.apache.qpid.server.configuration.ConnectionConfig; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.ConnectionCloseCode; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDetachCode; +import org.apache.qpid.transport.SessionDetach; +import org.apache.qpid.transport.Binary; +import org.apache.qpid.transport.SessionDetached; +import org.apache.qpid.transport.SessionException; +import org.apache.qpid.transport.ExecutionException; +import org.apache.qpid.transport.ExecutionErrorCode; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.AMQException; -public class ServerConnection extends Connection +public class ServerConnection extends Connection implements AMQConnectionModel { private ConnectionConfig _config; private Runnable _onOpenTask; @@ -88,4 +101,15 @@ public class ServerConnection extends Connection { _onOpenTask = task; } + + public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException + { + ExecutionException ex = new ExecutionException(); + ex.setErrorCode(ExecutionErrorCode.RESOURCE_LIMIT_EXCEEDED); + ex.setDescription(message); + ((ServerSession)session).invoke(ex); + + ((ServerSession)session).close(); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 2195cc4154..52b253c075 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -39,6 +39,8 @@ import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.transport.Binary; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.MessageTransfer; @@ -63,7 +65,7 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; -public class ServerSession extends Session implements PrincipalHolder, SessionConfig +public class ServerSession extends Session implements PrincipalHolder, SessionConfig, AMQSessionModel { private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); @@ -310,7 +312,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo } } - public void removeDispositionListener(Method method) + public void removeDispositionListener(Method method) { _messageDispositionListenerMap.remove(method.getId()); } @@ -552,4 +554,15 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo { close(); } + + public Object getID() + { + return getName(); + } + + public AMQConnectionModel getConnectionModel() + { + return (ServerConnection) getConnection(); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 3b0f990377..7dcb268290 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -36,6 +36,7 @@ import org.apache.qpid.server.flow.*; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.*; @@ -813,7 +814,7 @@ public class ServerSessionDelegate extends SessionDelegate if(method.getExclusive()) { queue.setPrincipalHolder((ServerSession)session); - queue.setExclusiveOwner(session); + queue.setExclusiveOwningSession((AMQSessionModel) session); } else if(method.getAutoDelete()) { -- cgit v1.2.1 From c88bf1a09b9d38675a30518053de049b3bebe9aa Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:10:08 +0000 Subject: QPID-2575 : Add getClientID to SessionModel and standardise use accross 0-8/0-10, 0-10 does not appear to provide a client ID so maintaining use of Principal Name. This means migration between 0-8 and 0-10 will not behave as expected. Correct erroneous usages of session.getPrincipal when comparing with queue.getOwner is requried. Queue owners are the client id not the authenticated user. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942102 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/AMQChannel.java | 6 +++++- .../org/apache/qpid/server/handler/QueueDeclareHandler.java | 12 ++++++------ .../org/apache/qpid/server/protocol/AMQProtocolEngine.java | 4 ++++ .../apache/qpid/server/protocol/AMQProtocolSessionMBean.java | 2 +- .../org/apache/qpid/server/protocol/AMQSessionModel.java | 2 ++ .../java/org/apache/qpid/server/queue/AMQQueueMBean.java | 6 +----- .../java/org/apache/qpid/server/store/DerbyMessageStore.java | 6 +----- .../java/org/apache/qpid/server/transport/ServerSession.java | 7 +++++++ .../apache/qpid/server/transport/ServerSessionDelegate.java | 2 +- 9 files changed, 28 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 573fa9d966..e2f6b5cfce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -141,7 +141,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel private final AtomicLong _txnRejects = new AtomicLong(0); private final AtomicLong _txnCount = new AtomicLong(0); - // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; private AtomicBoolean _closing = new AtomicBoolean(false); @@ -1070,6 +1069,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return _session; } + public String getClientID() + { + return String.valueOf(_session.getContextKey()); + } + private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 961a165877..444505f5bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -63,6 +63,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener Date: Fri, 7 May 2010 15:12:22 +0000 Subject: QPID-2581 : Add ConfigurationManager and split config creation from config processing git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942109 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ConfigurationManager.java | 59 +++++++ .../server/configuration/QueueConfiguration.java | 33 +++- .../server/configuration/ServerConfiguration.java | 188 ++++++++++++-------- .../configuration/VirtualHostConfiguration.java | 192 ++++++++++++--------- .../configuration/plugin/ConfigurationPlugin.java | 147 ++++++++++++++++ .../plugin/ConfigurationPluginFactory.java | 41 +++++ .../org/apache/qpid/server/queue/AMQQueue.java | 2 + .../apache/qpid/server/queue/SimpleAMQQueue.java | 10 +- .../qpid/server/registry/ApplicationRegistry.java | 182 +++++++++++++++---- .../ConfigurationFileApplicationRegistry.java | 61 +------ .../qpid/server/registry/IApplicationRegistry.java | 3 + 11 files changed, 679 insertions(+), 239 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java new file mode 100644 index 0000000000..3f2966b4a2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import java.util.Map; + +public class ConfigurationManager +{ + Logger _logger = Logger.getLogger(ConfigurationManager.class); + + public ConfigurationPlugin getConfigurationPlugin(String configurationElement, Configuration configuration) throws ConfigurationException + { + Map configPlugins = + ApplicationRegistry.getInstance().getPluginManager().getConfigurationPlugins(); + + ConfigurationPluginFactory factory = configPlugins.get(configurationElement); + + if (_logger.isInfoEnabled()) + { + _logger.info("Got Factory:" + factory + ": for :" + configurationElement); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Loaded Plugins:"); + for (String key : configPlugins.keySet()) + { + _logger.debug(key + ":" + configPlugins.get(key)); + } + } + + return factory != null ? factory.newInstance(configurationElement, configuration) : null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 44759bb4b8..5c3e0911f5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -21,21 +21,48 @@ package org.apache.qpid.server.configuration; import java.util.List; +import java.util.Map; +import java.util.HashMap; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; -public class QueueConfiguration +public class QueueConfiguration extends ConfigurationPlugin { - + private Configuration _config; private String _name; private VirtualHostConfiguration _vHostConfig; - public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) + public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) throws ConfigurationException { _vHostConfig = virtualHostConfiguration; _config = config; _name = name; + + setConfiguration("virtualhosts.virtualhost.queues.queue", config); + } + + public String[] getElementsProcessed() + { + return new String[]{"maximumMessageSize", + "maximumQueueDepth", + "maximumMessageCount", + "maximumMessageAge", + "minimumAlertRepeatGap", + "durable", + "exchange", + "queue", + "autodelete", + "priority", + "priorities", + "routingKey", + "capacity", + "flowResumeCapacity", + "lvq", + "lvqKey" + }; } public VirtualHostConfiguration getVirtualHostConfiguration() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 2a956c6dff..27ec80b1f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -20,15 +20,6 @@ package org.apache.qpid.server.configuration; -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; - import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -37,38 +28,42 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; -import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.transport.NetworkDriverConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sun.misc.Signal; import sun.misc.SignalHandler; -public class ServerConfiguration implements SignalHandler -{ - - private Configuration _config; +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +public class ServerConfiguration extends ConfigurationPlugin implements SignalHandler +{ // Default Configuration values public static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144; public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144; public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false; public static final String DEFAULT_STATUS_UPDATES = "on"; public static final String SECURITY_CONFIG_RELOADED = "SECURITY CONFIGURATION RELOADED"; - + public static final int DEFAULT_FRAME_SIZE = 65536; public static final int DEFAULT_PORT = 5672; public static final int DEFAULT_SSL_PORT = 8672; public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public static final int DEFAULT_JMXPORT = 8999; - private static int _jmxPort = DEFAULT_JMXPORT; - private Map _virtualHosts = new HashMap(); - private SecurityConfiguration _securityConfiguration = null; private File _configFile; private File _vhostsFile; @@ -117,6 +112,23 @@ public class ServerConfiguration implements SignalHandler envVarMap.put("QPID_STATUS-UPDATES", "status-updates"); } + /** + * Loads the given file and sets up the HUP signal handler. + * + * This will load the file and present the root level properties but will + * not perform any virtualhost configuration. + * + * To perform this configure() must be called. + * + * This has been made a two step process to allow the Plugin Manager and + * Configuration Manager to be initialised in the Application Registry. + * + * If using this ServerConfiguration via an ApplicationRegistry there is no + * need to explictly call configure() as this is done via the AR.initialise() + * + * @param configurationURL + * @throws org.apache.commons.configuration.ConfigurationException + */ public ServerConfiguration(File configurationURL) throws ConfigurationException { this(parseConfig(configurationURL)); @@ -132,15 +144,52 @@ public class ServerConfiguration implements SignalHandler } } - public ServerConfiguration(Configuration conf) throws ConfigurationException + /** + * Wraps the given Commons Configuration as a ServerConfiguration. + * + * Mainly used during testing and in locations where configuration is not + * desired but the interface requires configuration. + * + * If the given configuration has VirtualHost configuration then configure() + * must be called to perform the required setup. + * + * This has been made a two step process to allow the Plugin Manager and + * Configuration Manager to be initialised in the Application Registry. + * + * If using this ServerConfiguration via an ApplicationRegistry there is no + * need to explictly call configure() as this is done via the AR.initialise() + * + * @param conf + */ + public ServerConfiguration(Configuration conf) { - setConfig(conf); + _configuration = conf; + } - _jmxPort = getConfig().getInt("management.jmxport", 8999); - _securityConfiguration = new SecurityConfiguration(conf.subset("security")); + /** + * Processes this configuration and setups any VirtualHosts defined in the + * configuration. + * + * This has been separated from the constructor to allow the PluginManager + * time to be created and provide plugins to the ConfigurationManager for + * processing here. + * + * Called by ApplicationRegistry.initialise(); + * + * NOTE: A DEFAULT ApplicationRegistry must exist when using this method + * or a new ApplicationRegistry will be created. + * + * @throws ConfigurationException + */ + public void configure() throws ConfigurationException + { - setupVirtualHosts(conf); + setupVirtualHosts(_configuration); + } + public String[] getElementsProcessed() + { + return new String[]{""}; } /* @@ -148,30 +197,30 @@ public class ServerConfiguration implements SignalHandler * both, as a fix for QPID-2360 and QPID-2361. */ @SuppressWarnings("unchecked") - private void setupVirtualHosts(Configuration conf) throws ConfigurationException + private void setupVirtualHosts(Configuration conf) throws ConfigurationException { List vhostFiles = conf.getList("virtualhosts"); Configuration vhostConfig = conf.subset("virtualhosts"); - // Only one configuration mechanism allowed + // Only one configuration mechanism allowed if (!vhostFiles.isEmpty() && !vhostConfig.subset("virtualhost").isEmpty()) { - throw new ConfigurationException("Only one of external or embedded virtualhosts configuration allowed."); - } - + throw new ConfigurationException("Only one of external or embedded virtualhosts configuration allowed."); + } + // We can only have one vhosts XML file included - if (vhostFiles.size() > 1) - { - throw new ConfigurationException("Only one external virtualhosts configuration file allowed, multiple filenames found."); - } - + if (vhostFiles.size() > 1) + { + throw new ConfigurationException("Only one external virtualhosts configuration file allowed, multiple filenames found."); + } + // Virtualhost configuration object Configuration vhostConfiguration = new HierarchicalConfiguration(); - - // Load from embedded configuration if possible + + // Load from embedded configuration if possible if (!vhostConfig.subset("virtualhost").isEmpty()) { - vhostConfiguration = vhostConfig; + vhostConfiguration = vhostConfig; } else { @@ -181,19 +230,19 @@ public class ServerConfiguration implements SignalHandler // Open the vhosts XML file and copy values from it to our config _vhostsFile = new File(fileName); vhostConfiguration = parseConfig(new File(fileName)); - + // save the default virtualhost name String defaultVirtualHost = vhostConfiguration.getString("default"); - _config.setProperty("virtualhosts.default", defaultVirtualHost); - } + _configuration.setProperty("virtualhosts.default", defaultVirtualHost); + } } - + // Now extract the virtual host names from the configuration object - List hosts = vhostConfiguration.getList("virtualhost.name"); + List hosts = vhostConfiguration.getList("virtualhost.name"); for (int j = 0; j < hosts.size(); j++) { String name = (String) hosts.get(j); - + // Add the virtual hosts to the server configuration VirtualHostConfiguration virtualhost = new VirtualHostConfiguration(name, vhostConfiguration.subset("virtualhost." + name)); _virtualHosts.put(virtualhost.getName(), virtualhost); @@ -217,7 +266,7 @@ public class ServerConfiguration implements SignalHandler ConfigurationFactory factory = new ConfigurationFactory(); factory.setConfigurationFileName(file.getAbsolutePath()); Configuration conf = factory.getConfiguration(); - + Iterator keys = conf.getKeys(); if (!keys.hasNext()) { @@ -232,6 +281,7 @@ public class ServerConfiguration implements SignalHandler /** * Check the configuration file to see if status updates are enabled. + * * @return true if status updates are enabled */ public boolean getStatusUpdatesEnabled() @@ -244,6 +294,7 @@ public class ServerConfiguration implements SignalHandler /** * The currently defined {@see Locale} for this broker + * * @return the configuration defined locale */ public Locale getLocale() @@ -331,7 +382,7 @@ public class ServerConfiguration implements SignalHandler } catch (ConfigurationException e) { - _log.error("Could not reload configuration file security sections", e); + _log.error("Could not reload configuration file security sections", e); } } @@ -340,9 +391,9 @@ public class ServerConfiguration implements SignalHandler if (_configFile != null) { Configuration newConfig = parseConfig(_configFile); - - _securityConfiguration = new SecurityConfiguration(newConfig.subset("security")); - + + setConfiguration("", newConfig); + // Reload virtualhosts from correct location Configuration newVhosts; if (_vhostsFile == null) @@ -353,30 +404,20 @@ public class ServerConfiguration implements SignalHandler { newVhosts = parseConfig(_vhostsFile); } - + VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); for (String hostname : _virtualHosts.keySet()) { VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newVhosts.subset("virtualhost."+hostname+".security")); - vhost.getAccessManager().configureGlobalPlugins(_securityConfiguration); + vhost.getAccessManager().configureGlobalPlugins(getSecurityConfiguration()); vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); } - + _log.warn(SECURITY_CONFIG_RELOADED); } } - public void setConfig(Configuration _config) - { - this._config = _config; - } - - public Configuration getConfig() - { - return _config; - } - public String getQpidWork() { return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); @@ -384,19 +425,19 @@ public class ServerConfiguration implements SignalHandler public void setJMXManagementPort(int mport) { - _jmxPort = mport; + getConfig().setProperty("management.jmxport", mport); } public int getJMXManagementPort() { - return _jmxPort; + return getConfig().getInt("management.jmxport", DEFAULT_JMXPORT); } - + public boolean getUseCustomRMISocketFactory() { return getConfig().getBoolean(MGMT_CUSTOM_REGISTRY_SOCKET, true); } - + public void setUseCustomRMISocketFactory(boolean bool) { getConfig().setProperty(MGMT_CUSTOM_REGISTRY_SOCKET, bool); @@ -422,6 +463,11 @@ public class ServerConfiguration implements SignalHandler return _virtualHosts.get(name); } + public void setVirtualHostConfig(VirtualHostConfiguration config) + { + _virtualHosts.put(config.getName(), config); + } + public List getPrincipalDatabaseNames() { return getConfig().getList("security.principal-databases.principal-database.name"); @@ -506,7 +552,7 @@ public class ServerConfiguration implements SignalHandler public SecurityConfiguration getSecurityConfiguration() { - return _securityConfiguration; + return new SecurityConfiguration(_configuration.subset("security")); } public boolean getQueueAutoRegister() @@ -604,7 +650,6 @@ public class ServerConfiguration implements SignalHandler return getConfig().getList("connector.non08port", Collections.EMPTY_LIST); } - public String getBind() { return getConfig().getString("connector.bind", "wildcard"); @@ -685,6 +730,11 @@ public class ServerConfiguration implements SignalHandler return getConfig().getString("virtualhosts.default"); } + public void setDefaultVirtualHost(String vhost) + { + getConfig().setProperty("virtualhosts.default", vhost); + } + public void setHousekeepingExpiredMessageCheckPeriod(long value) { getConfig().setProperty("housekeeping.expiredMessageCheckPeriod", value); @@ -693,8 +743,8 @@ public class ServerConfiguration implements SignalHandler public long getHousekeepingCheckPeriod() { return getConfig().getLong("housekeeping.checkPeriod", - getConfig().getLong("housekeeping.expiredMessageCheckPeriod", - DEFAULT_HOUSEKEEPING_PERIOD)); + getConfig().getLong("housekeeping.expiredMessageCheckPeriod", + DEFAULT_HOUSEKEEPING_PERIOD)); } public NetworkDriverConfiguration getNetworkConfiguration() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 6c72025ec2..696a82b8f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -20,97 +20,118 @@ */ package org.apache.qpid.server.configuration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; -public class VirtualHostConfiguration +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; + +public class VirtualHostConfiguration extends ConfigurationPlugin { - private Configuration _config; - private String _name; - private Map _queues = new HashMap(); - private Map _exchanges = new HashMap(); - - public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException - { - _config = config; - _name = name; - Iterator i = _config.getList("queues.queue.name").iterator(); - - while (i.hasNext()) - { - String queueName = (String) i.next(); - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); - mungedConf.addConfiguration(_config.subset("queues")); - _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); - } + private Configuration _config; + private String _name; + private Map _queues = new HashMap(); + private Map _exchanges = new HashMap(); + + public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException + { + _config = config; + _name = name; + setConfiguration(config); + } + + /** + * Apply the given configuration to this VirtualHostConfiguration + * + * @param config the config to apply + * @throws ConfigurationException if a problem occurs with configuration + */ + public void setConfiguration(Configuration config) throws ConfigurationException + { + super.setConfiguration("virtualhosts.virtualhost",config); + + Iterator i = _config.getList("queues.queue.name").iterator(); - i = _config.getList("exchanges.exchange.name").iterator(); - int count = 0; - while (i.hasNext()) + while (i.hasNext()) { - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); - mungedConf.addConfiguration(_config.subset("exchanges")); - String exchName = (String) i.next(); - _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); + String queueName = (String) i.next(); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); + mungedConf.addConfiguration(_config.subset("queues")); + _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); } + i = _config.getList("exchanges.exchange.name").iterator(); + int count = 0; + while (i.hasNext()) + { + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); + mungedConf.addConfiguration(_config.subset("exchanges")); + String exchName = (String) i.next(); + _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); + } } - public String getName() - { + public String getName() + { return _name; } - public long getHousekeepingExpiredMessageCheckPeriod() - { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod()); - } - - public String getAuthenticationDatabase() - { - return _config.getString("security.authentication.name"); - } - - public List getCustomExchanges() - { - return _config.getList("custom-exchanges.class-name"); - } - - public SecurityConfiguration getSecurityConfiguration() - { - return new SecurityConfiguration(_config.subset("security")); - } - - public Configuration getStoreConfiguration() - { - return _config.subset("store"); - } - - public String getMessageStoreClass() - { - return _config.getString("store.class", MemoryMessageStore.class.getName()); - } - - public List getExchanges() - { - return _config.getList("exchanges.exchange.name"); - } - - public String[] getQueueNames() - { - return _queues.keySet().toArray(new String[_queues.size()]); - } + public long getHousekeepingExpiredMessageCheckPeriod() + { + return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod()); + } + + public String getAuthenticationDatabase() + { + return _config.getString("security.authentication.name"); + } + + public List getCustomExchanges() + { + return _config.getList("custom-exchanges.class-name"); + } + + public SecurityConfiguration getSecurityConfiguration() + { + return new SecurityConfiguration(_config.subset("security")); + } + + public Configuration getStoreConfiguration() + { + return _config.subset("store"); + } + + public String getMessageStoreClass() + { + return _config.getString("store.class", MemoryMessageStore.class.getName()); + } + + public void setMessageStoreClass(String storeClass) + { + _config.setProperty("store.class", storeClass); + } + + public List getExchanges() + { + return _config.getList("exchanges.exchange.name"); + } + + public String[] getQueueNames() + { + return _queues.keySet().toArray(new String[_queues.size()]); + } public ExchangeConfiguration getExchangeConfiguration(String exchangeName) { @@ -121,13 +142,21 @@ public class VirtualHostConfiguration { // We might be asked for the config for a queue we don't know about, // such as one that's been dynamically created. Those get the defaults by default. - if (_queues.containsKey(queueName)) + if (_queues.containsKey(queueName)) { return _queues.get(queueName); - } + } else { - return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); + try + { + return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); + } + catch (ConfigurationException e) + { + // The configuration is empty so there can't be an error. + return null; + } } } @@ -140,7 +169,7 @@ public class VirtualHostConfiguration { return _config.getLong("queues.minimumMemoryUsage", 0); } - + public int getMaximumMessageAge() { return _config.getInt("queues.maximumMessageAge", 0); @@ -166,7 +195,6 @@ public class VirtualHostConfiguration return _config.getLong("queues.minimumAlertRepeatGap", 0); } - public long getCapacity() { return _config.getLong("queues.capacity", 0l); @@ -177,4 +205,10 @@ public class VirtualHostConfiguration return _config.getLong("queues.flowResumeCapacity", getCapacity()); } + public String[] getElementsProcessed() + { + return new String[]{"queues", "exchanges", "custom-exchanges", + "security", "store", "housekeeping"}; + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java new file mode 100644 index 0000000000..0822d6debf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java @@ -0,0 +1,147 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugin; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ConfigurationManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public abstract class ConfigurationPlugin +{ + protected Logger _logger = Logger.getLogger(this.getClass()); + + private Map, ConfigurationPlugin> + _pluginConfiguration = new HashMap, ConfigurationPlugin>(); + + protected Configuration _configuration; + + /** + * The Elements that this Plugin can process. + * i.e. + * For a Queues plugin that would be a list containing: + * queue - the queue entries + * the alerting values for defaults + * exchange - the default exchange + * durable - set the default durablity + * etc + * + * @return + */ + abstract public String[] getElementsProcessed(); + + public Configuration getConfig() + { + return _configuration; + } + + public C getConfiguration(Class plugin) + { + return (C) _pluginConfiguration.get(plugin); + } + + /** + * Sets the configuration for this plugin + * + * @param path + * @param configuration the configuration for this plugin. + */ + + public void setConfiguration(String path, Configuration configuration) throws ConfigurationException + { + _configuration = configuration; + + // Extract a list of elements for processing + Iterator keys = configuration.getKeys(); + + Set elements = new HashSet(); + while (keys.hasNext()) + { + String key = (String) keys.next(); + + int elementNameIndex = key.indexOf("."); + + String element = key.trim(); + if (elementNameIndex != -1) + { + element = key.substring(0, elementNameIndex).trim(); + } + + //Trim any element properties + elementNameIndex = element.indexOf("["); + if (elementNameIndex != -1) + { + element = element.substring(0,elementNameIndex).trim(); + } + + elements.add(element); + } + + + //Remove the items we already expect in the configuration + for (String tag : getElementsProcessed()) + { + elements.remove(tag); + } + + if (_logger.isInfoEnabled()) + { + if (!elements.isEmpty()) + { + _logger.info("Elements to lookup:" + path); + for (String tag : elements) + { + _logger.info(tag); + } + } + } + + // Process the elements in the configuration + for (String element : elements.toArray(new String[elements.size()])) + { + ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); + + String configurationElement = path +"."+ element; + ConfigurationPlugin elementHandler = configurationManager. + getConfigurationPlugin(configurationElement, + configuration.subset(element)); + + + if (elementHandler == null) + { + _logger.warn("Unused configuration element:" + configurationElement); + } + else + { + _pluginConfiguration.put(elementHandler.getClass(), elementHandler); + } + } + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java new file mode 100644 index 0000000000..1286669f22 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugin; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +public interface ConfigurationPluginFactory +{ + + /** + * The Parent paths of the configuration that this plugin supports. + * i.e. + * For Queue Elements the parent path is + * virtualhosts.virtualhost + * @return + */ + abstract public String[] getParentPaths(); + + + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index c557c876f1..366abd3f7c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -272,5 +272,7 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer void configure(QueueConfiguration config); + QueueConfiguration getConfiguration(); + ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b7f3f59c4b..b819538544 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -186,7 +186,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener //TODO : persist creation time private long _createTime = System.currentTimeMillis(); - + private QueueConfiguration _queueConfiguration; protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, Map arguments) { @@ -2069,9 +2069,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); _capacity = config.getCapacity(); _flowResumeCapacity = config.getFlowResumeCapacity(); + + _queueConfiguration = config; } } + + public QueueConfiguration getConfiguration() + { + return _queueConfiguration; + } + public String getResourceName() { return _resourceName; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 2c4c0a0570..5b8f8f0bb8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -22,22 +22,30 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; - +import org.apache.qpid.AMQException; +import org.apache.qpid.common.QpidProperties; import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfigurationManager; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.SystemConfig; import org.apache.qpid.server.configuration.SystemConfigImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostImpl; @@ -82,6 +90,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected PluginManager _pluginManager; + protected ConfigurationManager _configurationManager; + protected RootMessageLogger _rootMessageLogger; protected UUID _brokerId = UUID.randomUUID(); @@ -92,6 +102,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private ConfigStore _configStore; + protected String _registryName; + static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -114,7 +126,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { if (instance != null) { - _logger.info("Initialising Application Registry:" + instanceID); + _logger.info("Initialising Application Registry(" + instance + "):" + instanceID); _instanceMap.put(instanceID, instance); final ConfigStore store = ConfigStore.newInstance(); @@ -170,9 +182,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _instanceMap.containsKey(instanceID); } - /** - * Method to cleanly shutdown the default registry running in this JVM - */ + /** Method to cleanly shutdown the default registry running in this JVM */ public static void remove() { remove(DEFAULT_INSTANCE); @@ -223,6 +233,82 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _configuration = configuration; } + public void configure() throws ConfigurationException + { + _logger.error("Configure AR"); + + _configurationManager = new ConfigurationManager(); + + try + { + _pluginManager = new PluginManager(_configuration.getPluginDirectory()); + } + catch (Exception e) + { + throw new ConfigurationException(e); + } + + _configuration.configure(); + } + + public void initialise(int instanceID) throws Exception + { + _logger.error("Creating RML:" + this); + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, + new Log4jMessageLogger()); + _logger.error("Created RML:" + _rootMessageLogger + ":" + this); + _registryName = String.valueOf(instanceID); + + // Set the Actor for current log messages + CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); + + _logger.error("Init AR:" + this); + configure(); + _logger.error("Configured AR:" + this); + + _qmfService = new QMFService(getConfigStore(), this); + + CurrentActor.get().message(BrokerMessages.BRK_STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); + + initialiseManagedObjectRegistry(); + + _virtualHostRegistry = new VirtualHostRegistry(this); + + _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); + + createDatabaseManager(_configuration); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + + _databaseManager.initialiseManagement(_configuration); + + _managedObjectRegistry.start(); + + initialiseVirtualHosts(); + + // Startup complete pop the current actor + CurrentActor.remove(); + } + + protected void createDatabaseManager(ServerConfiguration configuration) throws Exception + { + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); + } + + protected void initialiseVirtualHosts() throws Exception + { + for (String name : _configuration.getVirtualHosts()) + { + createVirtualHost(_configuration.getVirtualHostConfig(name)); + } + getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); + } + + protected void initialiseManagedObjectRegistry() throws AMQException + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + } + public static IApplicationRegistry getInstance() { return getInstance(DEFAULT_INSTANCE); @@ -239,6 +325,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { _logger.info("Creating DEFAULT_APPLICATION_REGISTRY: " + _APPLICATION_REGISTRY + " : Instance:" + instanceID); + new Exception().printStackTrace(System.out); + new Exception().printStackTrace(System.err); IApplicationRegistry registry = (IApplicationRegistry) Class.forName(_APPLICATION_REGISTRY).getConstructor((Class[]) null).newInstance((Object[]) null); ApplicationRegistry.initialise(registry, instanceID); _logger.info("Initialised Application Registry:" + instanceID); @@ -262,38 +350,69 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { if (_logger.isInfoEnabled()) { - _logger.info("Shutting down ApplicationRegistry:"+this); + _logger.info("Shutting down ApplicationRegistry:" + this); } - //Stop incomming connections - unbind(); - - //Shutdown virtualhosts - for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) + try { - virtualHost.close(); + //Stop incoming connections + unbind(); } + finally + { + try + { +// Replace with this +// _virtualHostRegistry.close(); - // Replace above with this -// _virtualHostRegistry.close(); - -// _accessManager.close(); - -// _databaseManager.close(); - - _authenticationManager.close(); + //Shutdown virtualhosts + for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) + { + virtualHost.close(); + } + } + finally + { +// _accessManager.close(); +// +// _databaseManager.close(); -// _databaseManager.close(); + try + { + _authenticationManager.close(); + } + finally + { + try + { + // close the rmi registry(if any) started for management + if (_managedObjectRegistry != null) + { + _managedObjectRegistry.close(); + } + } + finally + { + try + { + _qmfService.close(); + } + finally + { + try + { + _pluginManager.close(); + } + finally + { + CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); + } + } + } - // close the rmi registry(if any) started for management - if (_managedObjectRegistry != null) - { - _managedObjectRegistry.close(); + } + } } - -// _pluginManager.close(); - - CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); } private void unbind() @@ -357,6 +476,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _pluginManager; } + public ConfigurationManager getConfigurationManager() + { + return _configurationManager; + } + public RootMessageLogger getRootMessageLogger() { return _rootMessageLogger; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index e1cc1bf1dd..5dd7520b8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -23,70 +23,21 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.AMQException; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.logging.RootMessageLoggerImpl; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import java.io.File; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { - private String _registryName; - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException { super(new ServerConfiguration(configurationURL)); } - public void initialise(int instanceID) throws Exception - { - _qmfService = new QMFService(getConfigStore(), this); - - - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, - new Log4jMessageLogger()); - - _registryName = String.valueOf(instanceID); - - // Set the Actor for current log messages - CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - - CurrentActor.get().message(BrokerMessages.BRK_STARTUP(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); - - initialiseManagedObjectRegistry(); - - _virtualHostRegistry = new VirtualHostRegistry(this); - - _pluginManager = new PluginManager(_configuration.getPluginDirectory()); - - _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); - - _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - - _databaseManager.initialiseManagement(_configuration); - - - _managedObjectRegistry.start(); - - initialiseVirtualHosts(); - - // Startup complete pop the current actor - CurrentActor.remove(); - } @Override public void close() throws Exception @@ -104,16 +55,9 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - private void initialiseVirtualHosts() throws Exception - { - for (String name : _configuration.getVirtualHosts()) - { - createVirtualHost(_configuration.getVirtualHostConfig(name)); - } - getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); - } - private void initialiseManagedObjectRegistry() throws AMQException + @Override + protected void initialiseManagedObjectRegistry() throws AMQException { if (_configuration.getManagementEnabled()) { @@ -124,4 +68,5 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _managedObjectRegistry = new NoopManagedObjectRegistry(); } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index f0226c7982..1fa16099c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -27,6 +27,7 @@ import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.ConfigurationManager; import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -75,6 +76,8 @@ public interface IApplicationRegistry PluginManager getPluginManager(); + ConfigurationManager getConfigurationManager(); + RootMessageLogger getRootMessageLogger(); /** -- cgit v1.2.1 From a1e6717bb07cd13a43511960e6ae4af88cb443c4 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:13:07 +0000 Subject: Corrected Broker Activator stop code git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942111 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/Activator.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java index 89d9c1de74..583e480970 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java @@ -32,13 +32,11 @@ public class Activator implements BundleActivator public void start(BundleContext ctx) throws Exception { _context = ctx; - ctx.registerService(ServerConfiguration.class.getName(), ApplicationRegistry.getInstance().getConfiguration(), null); - + ctx.registerService(ServerConfiguration.class.getName(), ApplicationRegistry.getInstance().getConfiguration(), null); } public void stop(BundleContext ctx) throws Exception - { - start(null); + { } public BundleContext getContext() -- cgit v1.2.1 From c05345ab26e6fba2d4a83fcdb7e2c04c8fbce3cc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:13:23 +0000 Subject: QPID-2584 : Updated VirtualHost to load VirtualHost Plugins and not hard code SCD git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942112 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginFactory.java | 26 +++++++++++ .../qpid/server/virtualhost/VirtualHostImpl.java | 54 +++++++++++++++++++++- .../virtualhost/plugin/VirtualHostPlugin.java | 40 ++++++++++++++++ .../plugin/VirtualHostPluginFactory.java | 28 +++++++++++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java new file mode 100644 index 0000000000..58dbe69fa1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.plugins; + +public interface PluginFactory +{ + public String getPluginName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 4ae1ea6e08..8d78415056 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -28,6 +28,8 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.virtualhost.plugin.VirtualHostPluginFactory; +import org.apache.qpid.server.virtualhost.plugin.VirtualHostPlugin; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; @@ -72,8 +74,10 @@ import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class VirtualHostImpl implements Accessable, VirtualHost { @@ -321,6 +325,54 @@ public class VirtualHostImpl implements Accessable, VirtualHost _connectionRegistry.expireClosedChannels(); } } + + Map plugins = + ApplicationRegistry.getInstance(). + getPluginManager().getVirtualHostPlugins(); + + if (plugins != null) + { + ScheduledThreadPoolExecutor vhostTasks = new ScheduledThreadPoolExecutor(plugins.size()); + + for (String pluginName : plugins.keySet()) + { + try + { + VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); + + TimeUnit units = TimeUnit.MILLISECONDS; + + if (plugin.getTimeUnit() != null) + { + try + { + units = TimeUnit.valueOf(plugin.getTimeUnit()); + } + catch (IllegalArgumentException iae) + { + _logger.warn("Plugin:" + pluginName + + " provided an illegal TimeUnit value:" + + plugin.getTimeUnit()); + // Warn and use default of millseconds + // Should not occur in a well behaved plugin + } + } + + vhostTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, + plugin.getDelay(), units); + + _logger.info("Loaded VirtualHostPlugin:" + plugin); + } + catch (IllegalArgumentException iae) + { + _logger.warn("VirtualHostPlugin:" + pluginName + " has not been configured for this virtualhost(" + getName() + ")"); + } + catch (Exception e) + { + _logger.error("Unable to load VirtualHostPlugin:" + pluginName + " due to:" + e.getMessage(), e); + } + } + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java new file mode 100644 index 0000000000..d3b97ff40c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugin; + +public interface VirtualHostPlugin extends Runnable +{ + public void run(); + + /** + * Long value representing the delay between repeats + * + * @return + */ + public long getDelay(); + + /** + * Option to specify what the delay value represents + * @see java.util.concurrent.TimeUnit for valid value. + * @return + */ + public String getTimeUnit(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java new file mode 100644 index 0000000000..bde60fc9ae --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugin; + +import org.apache.qpid.server.virtualhost.VirtualHost; + +public interface VirtualHostPluginFactory +{ + public VirtualHostPlugin newInstance(VirtualHost vhost); +} -- cgit v1.2.1 From 7c7d88195037c6a5cb82296433bd2e9c1d5a9c6a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:13:44 +0000 Subject: QPID-2585 : Upgrade to Felix 2.0.5 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942114 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 267 +++++++++++++++------ 1 file changed, 187 insertions(+), 80 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 0911c73fe7..171de7a701 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -19,16 +19,12 @@ package org.apache.qpid.server.plugins; -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import org.apache.commons.configuration.ConfigurationException; import org.apache.felix.framework.Felix; import org.apache.felix.framework.cache.BundleCache; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; +import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; @@ -37,155 +33,266 @@ import org.apache.qpid.server.security.access.plugins.DenyAll; import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; import org.apache.qpid.server.security.access.plugins.SimpleXML; import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; +import org.apache.qpid.server.virtualhost.plugin.VirtualHostPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.util.tracker.ServiceTracker; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** - * * @author aidan - * - * Provides access to pluggable elements, such as exchanges + * + * Provides access to pluggable elements, such as exchanges */ public class PluginManager { - private Felix _felix = null; private ServiceTracker _exchangeTracker = null; private ServiceTracker _securityTracker = null; - private Activator _activator = null; - private boolean _empty; + private ServiceTracker _configTracker = null; + private ServiceTracker _virtualHostTracker = null; + + private Felix _felix; + + Activator _activator; + private Map _securityPlugins; + private static final int FELIX_STOP_TIMEOUT = 30000; public PluginManager(String plugindir) throws Exception { StringMap configMap = new StringMap(false); - // Tell felix it's being embedded - configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); // Add the bundle provided service interface package and the core OSGi // packages to be exported from the class path via the system bundle. - configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, "org.osgi.framework; version=1.3.0," - + "org.osgi.service.packageadmin; version=1.2.0," + - "org.osgi.service.startlevel; version=1.0.0," + - "org.osgi.service.url; version=1.0.0," + - "org.osgi.util.tracker; version=1.0.0,"+ - "org.apache.qpid.junit.extensions.util; version=0.7," + - "org.apache.qpid; version=0.7," + - "org.apache.qpid.framing; version=0.7," + - "org.apache.qpid.protocol; version=0.7," + - "org.apache.qpid.server.exchange; version=0.7," + - "org.apache.qpid.server.management; version=0.7,"+ - "org.apache.qpid.server.protocol; version=0.7,"+ - "org.apache.qpid.server.virtualhost; version=0.7," + - "org.apache.qpid.server.registry; version=0.7," + - "org.apache.qpid.server.queue; version=0.7," + - "org.apache.qpid.server.binding; version=0.7," + - "org.apache.qpid.server.configuration; version=0.7," + - "org.apache.qpid.server.configuration.management; version=0.7," + - "org.apache.qpid.server.persistent; version=0.7," + - "org.apache.qpid.server.plugins; version=0.7," + - "org.apache.qpid.server.queue; version=0.7," + - "org.apache.qpid.server.security; version=0.7," + - "org.apache.qpid.framing.AMQShortString; version=0.7," + - "org.apache.qpid.server.queue.AMQQueue; version=0.7," + - "org.apache.qpid.server.security.access; version=0.7,"+ - "org.apache.commons.configuration; version=0.7," + - "javax.management.openmbean; version=1.0.0,"+ - "javax.management; version=1.0.0," - ); - + configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, + "org.osgi.framework; version=1.3.0," + + "org.osgi.service.packageadmin; version=1.2.0," + + "org.osgi.service.startlevel; version=1.0.0," + + "org.osgi.service.url; version=1.0.0," + + "org.osgi.util.tracker; version=1.0.0," + + "org.apache.qpid.junit.extensions.util; version=0.7," + + "org.apache.qpid; version=0.7," + + "org.apache.qpid.framing; version=0.7," + + "org.apache.qpid.protocol; version=0.7," + + "org.apache.qpid.server.exchange; version=0.7," + + "org.apache.qpid.server.management; version=0.7," + + "org.apache.qpid.server.protocol; version=0.7," + + "org.apache.qpid.server.virtualhost; version=0.7," + + "org.apache.qpid.server.virtualhost.plugin; version=0.7," + + "org.apache.qpid.server.registry; version=0.7," + + "org.apache.qpid.server.queue; version=0.7," + + "org.apache.qpid.server.binding; version=0.7," + + "org.apache.qpid.server.configuration; version=0.7," + + "org.apache.qpid.server.configuration.plugin; version=0.7," + + "org.apache.qpid.server.configuration.management; version=0.7," + + "org.apache.qpid.server.persistent; version=0.7," + + "org.apache.qpid.server.plugins; version=0.7," + + "org.apache.qpid.server.queue; version=0.7," + + "org.apache.qpid.server.security; version=0.7," + + "org.apache.qpid.framing.AMQShortString; version=0.7," + + "org.apache.qpid.server.queue.AMQQueue; version=0.7," + + "org.apache.qpid.server.security.access; version=0.7," + + "org.apache.commons.configuration; version=0.7," + + "org.apache.log4j; version=1.2.12," + + "javax.management.openmbean; version=1.0.0," + + "javax.management; version=1.0.0," + ); + if (plugindir == null) { - _empty = true; return; } - + // Set the list of bundles to load File dir = new File(plugindir); if (!dir.exists()) - { - _empty = true; + { return; - } - + } + StringBuffer pluginJars = new StringBuffer(); - + if (dir.isDirectory()) { for (String child : dir.list()) { if (child.endsWith("jar")) { - pluginJars.append(String.format(" file:%s%s%s", plugindir,File.separator,child)); + pluginJars.append(String.format(" file:%s%s%s", plugindir, File.separator, child)); } } } - + if (pluginJars.length() == 0) { - _empty = true; return; } - - configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); - configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); - + +// configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); +// configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); + + configMap.put("felix.auto.start.1", pluginJars.toString()); + configMap.put("felix.shutdown.hook","false"); + configMap.put(FelixConstants.FRAMEWORK_STORAGE, plugindir); + + List activators = new ArrayList(); _activator = new Activator(); activators.add(_activator); + configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activators); - _felix = new Felix(configMap, activators); + _felix = new Felix(configMap); try { + System.out.println("Starting Plugin manager"); + _felix.start(); - + + System.out.println("Started Plugin manager"); + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); _exchangeTracker.open(); - + _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); _securityTracker.open(); - + + _configTracker = new ServiceTracker(_activator.getContext(), ConfigurationPluginFactory.class.getName(), null); + _configTracker.open(); + + _virtualHostTracker = new ServiceTracker(_activator.getContext(), VirtualHostPluginFactory.class.getName(), null); + _virtualHostTracker.open(); + } catch (BundleException e) { - throw new Exception("Could not create bundle"); + throw new ConfigurationException("Could not start PluginManager:" + e.getMessage(), e); } } private Map getServices(ServiceTracker tracker) - { - Mapservices = new HashMap(); - + { + Map services = new HashMap(); + if ((tracker != null) && (tracker.getServices() != null)) { for (Object service : tracker.getServices()) { - services.put(service.getClass().getName(), (T) service); + if (service instanceof PluginFactory) + { + services.put(((PluginFactory) service).getPluginName(), (T) service); + } + else + { + services.put(service.getClass().getName(), (T) service); + } } - } - + } + return services; } - + public Map> getExchanges() { return getServices(_exchangeTracker); } - + public Map getSecurityPlugins() { - if (_securityPlugins == null) + _securityPlugins = getServices(_securityTracker); + // A little gross that we have to add them here, but not all the plugins are OSGIfied + _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); + _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); + _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); + _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); + _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); + + return _securityPlugins; + } + + public Map getConfigurationPlugins() + { + Map services = new HashMap(); + + if ((_configTracker != null) && (_configTracker.getServices() != null)) { - _securityPlugins = getServices(_securityTracker); - // A little gross that we have to add them here, but not all the plugins are OSGIfied - _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); - _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); - _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); - _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); - _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); + for (Object service : _configTracker.getServices()) + { + for (String parent : ((ConfigurationPluginFactory) service).getParentPaths()) + { + services.put(parent, ((ConfigurationPluginFactory) service)); + } + } + } + + return services; + + } + + public Map getVirtualHostPlugins() + { + return getServices(_virtualHostTracker); + } + + public

      Map getPlugins(Class

      plugin) + { + ServiceTracker tracker = new ServiceTracker(_activator.getContext(), plugin.getName(), null); + tracker.open(); + + try + { + return getServices(tracker); + } + finally + { + tracker.close(); + } + } + + public void close() + { + if (_felix != null) + { + try + { + _exchangeTracker.close(); + + _securityTracker.close(); + + _configTracker.close(); + + _virtualHostTracker.close(); + } + finally + { + System.out.println("Stopping Plugin manager"); + //fixme should be stopAndWait() but hangs VM, need upgrade in felix + try + { + _felix.stop(); + } + catch (BundleException e) + { + //ignore + } + + try + { + _felix.waitForStop(FELIX_STOP_TIMEOUT); + } + catch (InterruptedException e) + { + //ignore + } + + System.out.println("Stopped Plugin manager"); + } } - return _securityPlugins; } } -- cgit v1.2.1 From e88a1d3631922c05c18a0f5a1babc3d2ac32353d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 7 May 2010 15:14:24 +0000 Subject: QPID-2579 : Remove debug logging git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@942116 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ConfigurationManager.java | 4 +- .../server/configuration/QueueConfiguration.java | 2 +- .../server/configuration/ServerConfiguration.java | 4 +- .../configuration/VirtualHostConfiguration.java | 3 +- .../configuration/plugin/ConfigurationPlugin.java | 147 --------------------- .../plugin/ConfigurationPluginFactory.java | 41 ------ .../configuration/plugins/ConfigurationPlugin.java | 147 +++++++++++++++++++++ .../plugins/ConfigurationPluginFactory.java | 41 ++++++ .../apache/qpid/server/plugins/PluginManager.java | 8 +- .../qpid/server/registry/ApplicationRegistry.java | 9 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 4 +- .../virtualhost/plugin/VirtualHostPlugin.java | 40 ------ .../plugin/VirtualHostPluginFactory.java | 28 ---- .../virtualhost/plugins/VirtualHostPlugin.java | 40 ++++++ .../plugins/VirtualHostPluginFactory.java | 28 ++++ 15 files changed, 269 insertions(+), 277 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java index 3f2966b4a2..9529d1097d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java @@ -23,8 +23,8 @@ package org.apache.qpid.server.configuration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import java.util.Map; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 5c3e0911f5..9da36c9b08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -26,7 +26,7 @@ import java.util.HashMap; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public class QueueConfiguration extends ConfigurationPlugin { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 27ec80b1f8..96b2e26f3c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -28,8 +28,8 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; -import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 696a82b8f2..4e29a3e526 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -26,8 +26,7 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.configuration.plugin.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import java.util.HashMap; import java.util.Iterator; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java deleted file mode 100644 index 0822d6debf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPlugin.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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.plugin; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.ConfigurationManager; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.log4j.Logger; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -public abstract class ConfigurationPlugin -{ - protected Logger _logger = Logger.getLogger(this.getClass()); - - private Map, ConfigurationPlugin> - _pluginConfiguration = new HashMap, ConfigurationPlugin>(); - - protected Configuration _configuration; - - /** - * The Elements that this Plugin can process. - * i.e. - * For a Queues plugin that would be a list containing: - * queue - the queue entries - * the alerting values for defaults - * exchange - the default exchange - * durable - set the default durablity - * etc - * - * @return - */ - abstract public String[] getElementsProcessed(); - - public Configuration getConfig() - { - return _configuration; - } - - public C getConfiguration(Class plugin) - { - return (C) _pluginConfiguration.get(plugin); - } - - /** - * Sets the configuration for this plugin - * - * @param path - * @param configuration the configuration for this plugin. - */ - - public void setConfiguration(String path, Configuration configuration) throws ConfigurationException - { - _configuration = configuration; - - // Extract a list of elements for processing - Iterator keys = configuration.getKeys(); - - Set elements = new HashSet(); - while (keys.hasNext()) - { - String key = (String) keys.next(); - - int elementNameIndex = key.indexOf("."); - - String element = key.trim(); - if (elementNameIndex != -1) - { - element = key.substring(0, elementNameIndex).trim(); - } - - //Trim any element properties - elementNameIndex = element.indexOf("["); - if (elementNameIndex != -1) - { - element = element.substring(0,elementNameIndex).trim(); - } - - elements.add(element); - } - - - //Remove the items we already expect in the configuration - for (String tag : getElementsProcessed()) - { - elements.remove(tag); - } - - if (_logger.isInfoEnabled()) - { - if (!elements.isEmpty()) - { - _logger.info("Elements to lookup:" + path); - for (String tag : elements) - { - _logger.info(tag); - } - } - } - - // Process the elements in the configuration - for (String element : elements.toArray(new String[elements.size()])) - { - ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); - - String configurationElement = path +"."+ element; - ConfigurationPlugin elementHandler = configurationManager. - getConfigurationPlugin(configurationElement, - configuration.subset(element)); - - - if (elementHandler == null) - { - _logger.warn("Unused configuration element:" + configurationElement); - } - else - { - _pluginConfiguration.put(elementHandler.getClass(), elementHandler); - } - } - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java deleted file mode 100644 index 1286669f22..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/ConfigurationPluginFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.plugin; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -public interface ConfigurationPluginFactory -{ - - /** - * The Parent paths of the configuration that this plugin supports. - * i.e. - * For Queue Elements the parent path is - * virtualhosts.virtualhost - * @return - */ - abstract public String[] getParentPaths(); - - - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java new file mode 100644 index 0000000000..dc0410dba6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -0,0 +1,147 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ConfigurationManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public abstract class ConfigurationPlugin +{ + protected Logger _logger = Logger.getLogger(this.getClass()); + + private Map, ConfigurationPlugin> + _pluginConfiguration = new HashMap, ConfigurationPlugin>(); + + protected Configuration _configuration; + + /** + * The Elements that this Plugin can process. + * i.e. + * For a Queues plugin that would be a list containing: + * queue - the queue entries + * the alerting values for defaults + * exchange - the default exchange + * durable - set the default durablity + * etc + * + * @return + */ + abstract public String[] getElementsProcessed(); + + public Configuration getConfig() + { + return _configuration; + } + + public C getConfiguration(Class plugin) + { + return (C) _pluginConfiguration.get(plugin); + } + + /** + * Sets the configuration for this plugin + * + * @param path + * @param configuration the configuration for this plugin. + */ + + public void setConfiguration(String path, Configuration configuration) throws ConfigurationException + { + _configuration = configuration; + + // Extract a list of elements for processing + Iterator keys = configuration.getKeys(); + + Set elements = new HashSet(); + while (keys.hasNext()) + { + String key = (String) keys.next(); + + int elementNameIndex = key.indexOf("."); + + String element = key.trim(); + if (elementNameIndex != -1) + { + element = key.substring(0, elementNameIndex).trim(); + } + + //Trim any element properties + elementNameIndex = element.indexOf("["); + if (elementNameIndex != -1) + { + element = element.substring(0,elementNameIndex).trim(); + } + + elements.add(element); + } + + + //Remove the items we already expect in the configuration + for (String tag : getElementsProcessed()) + { + elements.remove(tag); + } + + if (_logger.isInfoEnabled()) + { + if (!elements.isEmpty()) + { + _logger.info("Elements to lookup:" + path); + for (String tag : elements) + { + _logger.info(tag); + } + } + } + + // Process the elements in the configuration + for (String element : elements.toArray(new String[elements.size()])) + { + ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); + + String configurationElement = path +"."+ element; + ConfigurationPlugin elementHandler = configurationManager. + getConfigurationPlugin(configurationElement, + configuration.subset(element)); + + + if (elementHandler == null) + { + _logger.warn("Unused configuration element:" + configurationElement); + } + else + { + _pluginConfiguration.put(elementHandler.getClass(), elementHandler); + } + } + } +} + + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java new file mode 100644 index 0000000000..1e928a1728 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; + +public interface ConfigurationPluginFactory +{ + + /** + * The Parent paths of the configuration that this plugin supports. + * i.e. + * For Queue Elements the parent path is + * virtualhosts.virtualhost + * @return + */ + abstract public String[] getParentPaths(); + + + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 171de7a701..293a9c5ebc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -24,7 +24,7 @@ import org.apache.felix.framework.Felix; import org.apache.felix.framework.cache.BundleCache; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; -import org.apache.qpid.server.configuration.plugin.ConfigurationPluginFactory; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; @@ -33,7 +33,7 @@ import org.apache.qpid.server.security.access.plugins.DenyAll; import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; import org.apache.qpid.server.security.access.plugins.SimpleXML; import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; -import org.apache.qpid.server.virtualhost.plugin.VirtualHostPluginFactory; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.util.tracker.ServiceTracker; @@ -84,12 +84,12 @@ public class PluginManager "org.apache.qpid.server.management; version=0.7," + "org.apache.qpid.server.protocol; version=0.7," + "org.apache.qpid.server.virtualhost; version=0.7," + - "org.apache.qpid.server.virtualhost.plugin; version=0.7," + + "org.apache.qpid.server.virtualhost.plugins; version=0.7," + "org.apache.qpid.server.registry; version=0.7," + "org.apache.qpid.server.queue; version=0.7," + "org.apache.qpid.server.binding; version=0.7," + "org.apache.qpid.server.configuration; version=0.7," + - "org.apache.qpid.server.configuration.plugin; version=0.7," + + "org.apache.qpid.server.configuration.plugins; version=0.7," + "org.apache.qpid.server.configuration.management; version=0.7," + "org.apache.qpid.server.persistent; version=0.7," + "org.apache.qpid.server.plugins; version=0.7," + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 5b8f8f0bb8..727e902a0c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -202,7 +202,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { if (_logger.isInfoEnabled()) { - _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); + _logger.info("Shutting down ApplicationRegistry(" + instanceID + "):" + instance); } instance.close(); instance.getBroker().getSystem().removeBroker(instance.getBroker()); @@ -235,7 +235,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void configure() throws ConfigurationException { - _logger.error("Configure AR"); _configurationManager = new ConfigurationManager(); @@ -253,18 +252,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void initialise(int instanceID) throws Exception { - _logger.error("Creating RML:" + this); _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); - _logger.error("Created RML:" + _rootMessageLogger + ":" + this); _registryName = String.valueOf(instanceID); // Set the Actor for current log messages CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - _logger.error("Init AR:" + this); configure(); - _logger.error("Configured AR:" + this); _qmfService = new QMFService(getConfigStore(), this); @@ -325,8 +320,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { _logger.info("Creating DEFAULT_APPLICATION_REGISTRY: " + _APPLICATION_REGISTRY + " : Instance:" + instanceID); - new Exception().printStackTrace(System.out); - new Exception().printStackTrace(System.err); IApplicationRegistry registry = (IApplicationRegistry) Class.forName(_APPLICATION_REGISTRY).getConstructor((Class[]) null).newInstance((Object[]) null); ApplicationRegistry.initialise(registry, instanceID); _logger.info("Initialised Application Registry:" + instanceID); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 8d78415056..4331bbf972 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -28,8 +28,8 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.virtualhost.plugin.VirtualHostPluginFactory; -import org.apache.qpid.server.virtualhost.plugin.VirtualHostPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java deleted file mode 100644 index d3b97ff40c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPlugin.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugin; - -public interface VirtualHostPlugin extends Runnable -{ - public void run(); - - /** - * Long value representing the delay between repeats - * - * @return - */ - public long getDelay(); - - /** - * Option to specify what the delay value represents - * @see java.util.concurrent.TimeUnit for valid value. - * @return - */ - public String getTimeUnit(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java deleted file mode 100644 index bde60fc9ae..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/VirtualHostPluginFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugin; - -import org.apache.qpid.server.virtualhost.VirtualHost; - -public interface VirtualHostPluginFactory -{ - public VirtualHostPlugin newInstance(VirtualHost vhost); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java new file mode 100644 index 0000000000..6c9526346c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins; + +public interface VirtualHostPlugin extends Runnable +{ + public void run(); + + /** + * Long value representing the delay between repeats + * + * @return + */ + public long getDelay(); + + /** + * Option to specify what the delay value represents + * @see java.util.concurrent.TimeUnit for valid value. + * @return + */ + public String getTimeUnit(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java new file mode 100644 index 0000000000..c32ff76f81 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins; + +import org.apache.qpid.server.virtualhost.VirtualHost; + +public interface VirtualHostPluginFactory +{ + public VirtualHostPlugin newInstance(VirtualHost vhost); +} -- cgit v1.2.1 From 1f094213e7d74d4b3c3dd81b47158acfea202210 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 17 May 2010 11:06:50 +0000 Subject: Make constructor public instead of package git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945079 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java index 867fb4f9c7..1f5b027b80 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java @@ -29,7 +29,7 @@ public class StoredMemoryMessage implements StoredMessage private final ByteBuffer _content; private final StorableMessageMetaData _metaData; - StoredMemoryMessage(long messageNumber, StorableMessageMetaData metaData) + public StoredMemoryMessage(long messageNumber, StorableMessageMetaData metaData) { _messageNumber = messageNumber; _metaData = metaData; -- cgit v1.2.1 From 617d82c7863006a9d789a9a3cb80eabc9eddd92c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 18 May 2010 08:22:09 +0000 Subject: QPID-2613: flush 0-8/0-9 message to store when delivery begins git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945536 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index e2f6b5cfce..7d0163510a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -303,7 +303,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { try { - + _currentMessage.getStoredMessage().flushToStore(); + final ArrayList destinationQueues = _currentMessage.getDestinationQueues(); if(!checkMessageUserId(_currentMessage.getContentHeader())) -- cgit v1.2.1 From 8e6e134a6726a1855f107871907b38260917cce6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:42:04 +0000 Subject: QPID-2584 : Update VirtualHostImp and VHPlugin to ensure that a RuntimeException occuring in a plugin will not cause the Plugin to stop running. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945676 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 5 ++++ .../qpid/server/virtualhost/VirtualHostImpl.java | 3 ++- .../virtualhost/plugins/VirtualHostPlugin.java | 30 +++++++++++++++++++--- 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 4e29a3e526..780f5f1159 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -210,4 +210,9 @@ public class VirtualHostConfiguration extends ConfigurationPlugin "security", "store", "housekeeping"}; } + + public int getHouseKeepingThreadCount() + { + return _config.getInt("housekeeping.threadCount", Runtime.getRuntime().availableProcessors()); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 4331bbf972..0252d265fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -332,7 +332,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost if (plugins != null) { - ScheduledThreadPoolExecutor vhostTasks = new ScheduledThreadPoolExecutor(plugins.size()); + ScheduledThreadPoolExecutor vhostTasks + = new ScheduledThreadPoolExecutor(_configuration.getHouseKeepingThreadCount()); for (String pluginName : plugins.keySet()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java index 6c9526346c..e30b5e1934 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -20,21 +20,43 @@ */ package org.apache.qpid.server.virtualhost.plugins; -public interface VirtualHostPlugin extends Runnable +import org.apache.log4j.Logger; + +public abstract class VirtualHostPlugin implements Runnable { - public void run(); + Logger _logger = Logger.getLogger(this.getClass()); + + final public void run() + { + try + { + execute(); + } + catch (Throwable e) + { + _logger.warn(this.getClass().getSimpleName()+" throw exception: " + e); + } + } + /** * Long value representing the delay between repeats * * @return */ - public long getDelay(); + public abstract long getDelay(); /** * Option to specify what the delay value represents * @see java.util.concurrent.TimeUnit for valid value. * @return */ - public String getTimeUnit(); + public abstract String getTimeUnit(); + + /** + * Execute the plugin. + */ + public abstract void execute(); + + } -- cgit v1.2.1 From 8dba7b7ab260e158765578c6fa3d65302b3e2abc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:42:51 +0000 Subject: QPID-2584 : Convert all TimerTasks to HouseKeepingTasks for running in the VHost thread pool. Update VirtualHost and Configuration to allow configuration and testing of VirtualHostHouseKeepingPlugins. Added system test to validate the loading of VHPlugins is performed correctly git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945678 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/qmf/ManagementExchange.java | 15 ++-- .../configuration/VirtualHostConfiguration.java | 2 +- .../qpid/server/virtualhost/HouseKeepingTask.java | 58 +++++++++++++++ .../qpid/server/virtualhost/VirtualHost.java | 13 +++- .../qpid/server/virtualhost/VirtualHostImpl.java | 86 ++++++++++++++++------ .../plugins/VirtualHostHouseKeepingPlugin.java | 49 ++++++++++++ .../virtualhost/plugins/VirtualHostPlugin.java | 62 ---------------- .../plugins/VirtualHostPluginFactory.java | 2 +- 8 files changed, 192 insertions(+), 95 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index e552596058..67620d384b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -40,6 +40,7 @@ import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.virtualhost.HouseKeepingTask; import org.apache.qpid.server.virtualhost.VirtualHost; import java.nio.ByteBuffer; @@ -189,7 +190,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener } _virtualHost = host; _id = host.getConfigStore().createId(); - _virtualHost.scheduleTask(_virtualHost.getBroker().getManagementPublishInterval(),_updateTask); + _virtualHost.scheduleHouseKeepingTask(_virtualHost.getBroker().getManagementPublishInterval(), new UpdateTask(_virtualHost)); getConfigStore().addConfiguredObject(this); getQMFService().addListener(this); } @@ -484,17 +485,17 @@ public class ManagementExchange implements Exchange, QMFService.Listener - private final TimerTask _updateTask = new UpdateTask(); - - - private class UpdateTask extends TimerTask + private class UpdateTask extends HouseKeepingTask { + public UpdateTask(VirtualHost vhost) + { + super(vhost); + } - public void run() + public void execute() { publishAllConsole(); publishAllSchema(); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 780f5f1159..09ae3bd920 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -213,6 +213,6 @@ public class VirtualHostConfiguration extends ConfigurationPlugin public int getHouseKeepingThreadCount() { - return _config.getInt("housekeeping.threadCount", Runtime.getRuntime().availableProcessors()); + return _config.getInt("housekeeping.poolSize", Runtime.getRuntime().availableProcessors()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java new file mode 100644 index 0000000000..1f4dd56eb1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.log4j.Logger; + +public abstract class HouseKeepingTask implements Runnable +{ + Logger _logger = Logger.getLogger(this.getClass()); + + protected VirtualHost _virtualhost; + + private String _name; + + public HouseKeepingTask(VirtualHost vhost) + { + _virtualhost = vhost; + _name = _virtualhost.getName() + ":" + this.getClass().getSimpleName(); + } + + final public void run() + { + // Don't need to undo this as this is a thread pool thread so will + // always go through here before we do any real work. + Thread.currentThread().setName(_name); + try + { + execute(); + } + catch (Throwable e) + { + _logger.warn(this.getClass().getSimpleName() + " throw exception: " + e); + } + } + + + /** Execute the plugin. */ + public abstract void execute(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index c140e4a144..a5d75d8574 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -37,8 +37,10 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.binding.BindingFactory; +import java.util.List; import java.util.UUID; import java.util.TimerTask; +import java.util.concurrent.FutureTask; public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig { @@ -70,8 +72,17 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo UUID getBrokerId(); - void scheduleTask(long period, TimerTask task); + void scheduleHouseKeepingTask(long period, HouseKeepingTask task); + long getHouseKeepingTaskCount(); + + public long getHouseKeepingCompletedTaskCount(); + + int getHouseKeepingPoolSize(); + + void setHouseKeepingPoolSize(int newSize); + + int getHouseKeepingActiveCount(); IApplicationRegistry getApplicationRegistry(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 0252d265fd..413ebe159e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -29,7 +29,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; @@ -71,11 +71,12 @@ import javax.management.NotCompliantMBeanException; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import java.util.Map; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.FutureTask; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -103,7 +104,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost private ACLManager _accessManager; - private final Timer _timer; + private final ScheduledThreadPoolExecutor _houseKeepingTasks; private final IApplicationRegistry _appRegistry; private VirtualHostConfiguration _configuration; private DurableConfigurationStore _durableConfigurationStore; @@ -114,6 +115,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost private final long _createTime = System.currentTimeMillis(); private final ConcurrentHashMap _links = new ConcurrentHashMap(); + private static final int HOUSEKEEPING_SHUTDOWN_TIMEOUT = 5; public void setAccessableName(String name) { @@ -217,7 +219,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _connectionRegistry = new ConnectionRegistry(this); - _timer = new Timer("TimerThread-" + _name + ":", true); + _houseKeepingTasks = new ScheduledThreadPoolExecutor(_configuration.getHouseKeepingThreadCount()); _queueRegistry = new DefaultQueueRegistry(this); @@ -290,33 +292,35 @@ public class VirtualHostImpl implements Accessable, VirtualHost /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ if (period != 0L) { - class HouseKeepingTask extends TimerTask + class ExpiredMessagesTask extends HouseKeepingTask { - Logger _hkLogger = Logger.getLogger(HouseKeepingTask.class); - - public void run() + public ExpiredMessagesTask(VirtualHost vhost) + { + super(vhost); + } + + public void execute() { - _hkLogger.info("Starting the houseKeeping job"); for (AMQQueue q : _queueRegistry.getQueues()) { - _hkLogger.debug("Checking message status for queue: "+q.getName().toString()); + _logger.debug("Checking message status for queue: " + + q.getName()); try { q.checkMessageStatus(); } catch (Exception e) { - _hkLogger.error("Exception in housekeeping for queue: " + q.getNameShortString().toString(), e); + _logger.error("Exception in housekeeping for queue: " + + q.getNameShortString().toString(), e); //Don't throw exceptions as this will stop the // house keeping task from running. } } - _hkLogger.info("HouseKeeping job completed."); } } - final TimerTask expiredMessagesTask = new HouseKeepingTask(); - scheduleTask(period, expiredMessagesTask); + scheduleHouseKeepingTask(period, new ExpiredMessagesTask(this)); class ForceChannelClosuresTask extends TimerTask { @@ -332,14 +336,12 @@ public class VirtualHostImpl implements Accessable, VirtualHost if (plugins != null) { - ScheduledThreadPoolExecutor vhostTasks - = new ScheduledThreadPoolExecutor(_configuration.getHouseKeepingThreadCount()); - for (String pluginName : plugins.keySet()) { try { - VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); + VirtualHostHouseKeepingPlugin plugin = + plugins.get(pluginName).newInstance(this); TimeUnit units = TimeUnit.MILLISECONDS; @@ -359,7 +361,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } - vhostTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, + _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, plugin.getDelay(), units); _logger.info("Loaded VirtualHostPlugin:" + plugin); @@ -377,9 +379,42 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } - public void scheduleTask(final long period, final TimerTask task) + /** + * Allow other broker components to register a HouseKeepingTask + * + * @param period How often this task should run, in ms. + * @param task The task to run. + */ + public void scheduleHouseKeepingTask(long period, HouseKeepingTask task) + { + _houseKeepingTasks.scheduleAtFixedRate(task, period / 2, period, + TimeUnit.MILLISECONDS); + } + + public long getHouseKeepingTaskCount() { - _timer.scheduleAtFixedRate(task, period / 2, period); + return _houseKeepingTasks.getTaskCount(); + } + + public long getHouseKeepingCompletedTaskCount() + { + return _houseKeepingTasks.getCompletedTaskCount(); + } + + public int getHouseKeepingPoolSize() + { + return _houseKeepingTasks.getCorePoolSize(); + } + + public void setHouseKeepingPoolSize(int newSize) + { + _houseKeepingTasks.setCorePoolSize(newSize); + } + + + public int getHouseKeepingActiveCount() + { + return _houseKeepingTasks.getActiveCount(); } @@ -588,9 +623,14 @@ public class VirtualHostImpl implements Accessable, VirtualHost } //Stop Housekeeping - if (_timer != null) + if (_houseKeepingTasks != null) { - _timer.cancel(); + _houseKeepingTasks.shutdown(); + + if (!_houseKeepingTasks.awaitTermination(HOUSEKEEPING_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) + { + _houseKeepingTasks.shutdownNow(); + } } //Close MessageStore diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java new file mode 100644 index 0000000000..e76844fa3a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins; + +import org.apache.qpid.server.virtualhost.HouseKeepingTask; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask +{ + public VirtualHostHouseKeepingPlugin(VirtualHost vhost) + { + super(vhost); + } + + /** + * Long value representing the delay between repeats + * + * @return + */ + public abstract long getDelay(); + + /** + * Option to specify what the delay value represents + * + * @return + * + * @see java.util.concurrent.TimeUnit for valid value. + */ + public abstract String getTimeUnit(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java deleted file mode 100644 index e30b5e1934..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugins; - -import org.apache.log4j.Logger; - -public abstract class VirtualHostPlugin implements Runnable -{ - Logger _logger = Logger.getLogger(this.getClass()); - - final public void run() - { - try - { - execute(); - } - catch (Throwable e) - { - _logger.warn(this.getClass().getSimpleName()+" throw exception: " + e); - } - } - - - /** - * Long value representing the delay between repeats - * - * @return - */ - public abstract long getDelay(); - - /** - * Option to specify what the delay value represents - * @see java.util.concurrent.TimeUnit for valid value. - * @return - */ - public abstract String getTimeUnit(); - - /** - * Execute the plugin. - */ - public abstract void execute(); - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java index c32ff76f81..c8bea18444 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java @@ -24,5 +24,5 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public interface VirtualHostPluginFactory { - public VirtualHostPlugin newInstance(VirtualHost vhost); + public VirtualHostHouseKeepingPlugin newInstance(VirtualHost vhost); } -- cgit v1.2.1 From 5cab7ece402ff44d0321706d4fb85b32706a77dd Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:43:22 +0000 Subject: QPID-2585 : Ensure plugins are correctly loaded, so can renenable PluginTest. (Patch provided by Andrew Kennedy) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945679 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/plugins/PluginManager.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 293a9c5ebc..924570f00d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -21,9 +21,9 @@ package org.apache.qpid.server.plugins; import org.apache.commons.configuration.ConfigurationException; import org.apache.felix.framework.Felix; -import org.apache.felix.framework.cache.BundleCache; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; +import org.apache.felix.main.AutoProcessor; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.access.ACLPlugin; @@ -120,11 +120,11 @@ public class PluginManager if (dir.isDirectory()) { - for (String child : dir.list()) + for (File child : dir.listFiles()) { - if (child.endsWith("jar")) + if (child.getName().endsWith("jar")) { - pluginJars.append(String.format(" file:%s%s%s", plugindir, File.separator, child)); + pluginJars.append(String.format(" file:%s%s%s", plugindir, File.separator, child.getName())); } } } @@ -137,8 +137,8 @@ public class PluginManager // configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); // configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); - configMap.put("felix.auto.start.1", pluginJars.toString()); - configMap.put("felix.shutdown.hook","false"); + configMap.put(AutoProcessor.AUTO_START_PROP + ".1", pluginJars.toString()); + configMap.put(FelixConstants.FRAMEWORK_STORAGE, plugindir); @@ -154,6 +154,9 @@ public class PluginManager _felix.start(); + + AutoProcessor.process(configMap, _felix.getBundleContext()); + System.out.println("Started Plugin manager"); _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); -- cgit v1.2.1 From fe6b4a3338ead258bbff3fd6c0998c7bcdf30e93 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:43:42 +0000 Subject: QPID-2614 : Update QueueConfiguration to take two parameters, moved Munging code from VHC to QC. Updated Test. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945680 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/QueueConfiguration.java | 11 ++++++++--- .../qpid/server/configuration/VirtualHostConfiguration.java | 7 ++----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 9da36c9b08..8e64aee174 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.HashMap; +import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; @@ -35,13 +36,17 @@ public class QueueConfiguration extends ConfigurationPlugin private String _name; private VirtualHostConfiguration _vHostConfig; - public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration) throws ConfigurationException + public QueueConfiguration(String name, VirtualHostConfiguration virtualHostConfiguration) throws ConfigurationException { _vHostConfig = virtualHostConfiguration; - _config = config; _name = name; - setConfiguration("virtualhosts.virtualhost.queues.queue", config); + CompositeConfiguration mungedConf = new CompositeConfiguration(); + mungedConf.addConfiguration(_vHostConfig.getConfig().subset("queues.queue." + name)); + mungedConf.addConfiguration(_vHostConfig.getConfig().subset("queues")); + _config = mungedConf; + + setConfiguration("virtualhosts.virtualhost.queues.queue", mungedConf); } public String[] getElementsProcessed() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 09ae3bd920..d3e5921e79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -64,10 +64,7 @@ public class VirtualHostConfiguration extends ConfigurationPlugin while (i.hasNext()) { String queueName = (String) i.next(); - CompositeConfiguration mungedConf = new CompositeConfiguration(); - mungedConf.addConfiguration(_config.subset("queues.queue." + queueName)); - mungedConf.addConfiguration(_config.subset("queues")); - _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this)); + _queues.put(queueName, new QueueConfiguration(queueName, this)); } i = _config.getList("exchanges.exchange.name").iterator(); @@ -149,7 +146,7 @@ public class VirtualHostConfiguration extends ConfigurationPlugin { try { - return new QueueConfiguration(queueName, new PropertiesConfiguration(), this); + return new QueueConfiguration(queueName, this); } catch (ConfigurationException e) { -- cgit v1.2.1 From 7d355716929f49d89ff69dbd9cb24af35b139b6b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:44:06 +0000 Subject: QPID-2581 : Update ConfigurationPlugin to correctly handle attributes in configuration. Added work around for the fact that we use a Composite Configuration that turns an XML attribute key of '[@attribute]' in to '@attribute]'. Added test for to this conversion. This makes the Plugin Configuration interface consistent so if we swap our configuration format. The key style of '[@attribute]' will work as expected. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945681 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/plugins/ConfigurationPlugin.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index dc0410dba6..bac6e5c4d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -94,7 +94,7 @@ public abstract class ConfigurationPlugin //Trim any element properties elementNameIndex = element.indexOf("["); - if (elementNameIndex != -1) + if (elementNameIndex > 0) { element = element.substring(0,elementNameIndex).trim(); } @@ -106,6 +106,18 @@ public abstract class ConfigurationPlugin //Remove the items we already expect in the configuration for (String tag : getElementsProcessed()) { + + // Work round the issue with Commons configuration. + // With an XMLConfiguration the key will be [@property] + // but with a CompositeConfiguration it will be @property]. + // Hide this issue from our users so when/if we change the + // configuration they don't have to. + int bracketIndex = tag.indexOf("["); + if (bracketIndex != -1) + { + tag = tag.substring(bracketIndex + 1, tag.length()); + } + elements.remove(tag); } @@ -116,7 +128,7 @@ public abstract class ConfigurationPlugin _logger.info("Elements to lookup:" + path); for (String tag : elements) { - _logger.info(tag); + _logger.info("Tag:'"+tag+"'"); } } } -- cgit v1.2.1 From 822e95fa4d350a2916d8b45160df37160c540560 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 18 May 2010 14:44:20 +0000 Subject: QPID-2584 : Add Logging Actor to HouseKeepingTasks git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@945682 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/virtualhost/HouseKeepingTask.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java index 1f4dd56eb1..45d4be9340 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.virtualhost; import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.AbstractActor; +import org.apache.qpid.server.logging.actors.CurrentActor; public abstract class HouseKeepingTask implements Runnable { @@ -30,10 +33,12 @@ public abstract class HouseKeepingTask implements Runnable private String _name; + private RootMessageLogger _rootLogger; public HouseKeepingTask(VirtualHost vhost) { _virtualhost = vhost; _name = _virtualhost.getName() + ":" + this.getClass().getSimpleName(); + _rootLogger = CurrentActor.get().getRootMessageLogger(); } final public void run() @@ -41,13 +46,22 @@ public abstract class HouseKeepingTask implements Runnable // Don't need to undo this as this is a thread pool thread so will // always go through here before we do any real work. Thread.currentThread().setName(_name); + CurrentActor.set(new AbstractActor(_rootLogger) + { + @Override + public String getLogMessage() + { + return _name; + } + }); + try { execute(); } catch (Throwable e) { - _logger.warn(this.getClass().getSimpleName() + " throw exception: " + e); + _logger.warn(this.getClass().getSimpleName() + " throw exception: " + e, e); } } -- cgit v1.2.1 From d07578cac7759bdae0a4ab05bdeb3b2358f80689 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 19 May 2010 14:15:42 +0000 Subject: QPID-2422: add a boolean exclusive property to queues, update the DerbyStore and virtualhost recovery process to allow restoring exclusivity. Also persist and restore queue arguments. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@946199 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 4 +-- .../server/configuration/QueueConfiguration.java | 6 ++++ .../org/apache/qpid/server/federation/Bridge.java | 4 +-- .../qpid/server/handler/QueueDeclareHandler.java | 4 +-- .../apache/qpid/server/queue/AMQPriorityQueue.java | 10 +++--- .../apache/qpid/server/queue/AMQQueueFactory.java | 17 +++++---- .../apache/qpid/server/queue/ConflationQueue.java | 3 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 22 +++++++----- .../server/store/ConfigurationRecoveryHandler.java | 2 +- .../qpid/server/store/DerbyMessageStore.java | 40 +++++++++++++++++++--- .../server/transport/ServerSessionDelegate.java | 5 +-- .../VirtualHostConfigRecoveryHandler.java | 6 ++-- 12 files changed, 86 insertions(+), 37 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index be4e8f8ec1..b2e43b4f0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -278,8 +278,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr ownerShortString = new AMQShortString(owner); } - queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost(), - null); + queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, + getVirtualHost(), null); if (queue.isDurable() && !queue.isAutoDelete()) { _durableConfig.createQueue(queue); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 8e64aee174..1812f657d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -58,6 +58,7 @@ public class QueueConfiguration extends ConfigurationPlugin "minimumAlertRepeatGap", "durable", "exchange", + "exclusive", "queue", "autodelete", "priority", @@ -79,6 +80,11 @@ public class QueueConfiguration extends ConfigurationPlugin { return _config.getBoolean("durable" ,false); } + + public boolean getExclusive() + { + return _config.getBoolean("exclusive" ,false); + } public boolean getAutoDelete() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index c97d71dc39..ae578eb196 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -678,8 +678,8 @@ public class Bridge implements BridgeConfig isDurable(), _link.getFederationTag(), false, - getVirtualHost(), - options); + false, + getVirtualHost(), options); FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 444505f5bb..4f7d275e71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -236,8 +236,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener arguments) { - super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities),arguments); + super(name, durable, owner, autoDelete, exclusive, virtualHost,new PriorityQueueList.Factory(priorities), arguments); } public AMQPriorityQueue(String queueName, boolean durable, String owner, boolean autoDelete, - VirtualHost virtualHost, int priorities, Map arguments) + boolean exclusive, VirtualHost virtualHost, int priorities, Map arguments) { - this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,priorities, arguments); + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner), + autoDelete, exclusive,virtualHost, priorities, arguments); } public int getPriorities() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index fd7dd4cc60..3340c1e20a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -133,13 +133,16 @@ public class AMQQueueFactory boolean durable, AMQShortString owner, boolean autoDelete, - VirtualHost virtualHost, final FieldTable arguments) + boolean exclusive, + VirtualHost virtualHost, + final FieldTable arguments) { return createAMQQueueImpl(name == null ? null : name.toString(), durable, owner == null ? null : owner.toString(), autoDelete, - virtualHost, + exclusive, + virtualHost, FieldTable.convertToMap(arguments)); } @@ -148,6 +151,7 @@ public class AMQQueueFactory boolean durable, String owner, boolean autoDelete, + boolean exclusive, VirtualHost virtualHost, Map arguments) { int priorities = 1; @@ -175,15 +179,15 @@ public class AMQQueueFactory AMQQueue q; if(conflationKey != null) { - q = new ConflationQueue(queueName, durable, owner, autoDelete, virtualHost, arguments, conflationKey); + q = new ConflationQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, conflationKey); } else if(priorities > 1) { - q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities, arguments); + q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, priorities, arguments); } else { - q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost, arguments); + q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments); } //Register the new queue @@ -212,6 +216,7 @@ public class AMQQueueFactory boolean durable = config.getDurable(); boolean autodelete = config.getAutoDelete(); + boolean exclusive = config.getExclusive(); String owner = config.getOwner(); Map arguments = null; if(config.isLVQ() || config.getLVQKey() != null) @@ -241,7 +246,7 @@ public class AMQQueueFactory } } - AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); + AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, exclusive, host, arguments); q.configure(config); return q; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java index 26c0d7cf26..400d9867ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java @@ -31,11 +31,12 @@ public class ConflationQueue extends SimpleAMQQueue boolean durable, String owner, boolean autoDelete, + boolean exclusive, VirtualHost virtualHost, Map args, String conflationKey) { - super(name, durable, owner, autoDelete, virtualHost, new ConflationQueueList.Factory(conflationKey), args); + super(name, durable, owner, autoDelete, exclusive, virtualHost, new ConflationQueueList.Factory(conflationKey), args); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b819538544..afc7fb6480 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -85,6 +85,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private PrincipalHolder _prinicpalHolder; + private boolean _exclusive = false; private AMQSessionModel _exclusiveOwner; @@ -188,27 +189,28 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private long _createTime = System.currentTimeMillis(); private QueueConfiguration _queueConfiguration; - protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, Map arguments) + + + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map arguments) { - this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory(),arguments); + this(name, durable, owner, autoDelete, exclusive, virtualHost,new SimpleQueueEntryList.Factory(), arguments); } - public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, Map arguments) + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map arguments) { - this(queueName, durable, owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory(),arguments); + this(queueName, durable, owner, autoDelete, exclusive, virtualHost, new SimpleQueueEntryList.Factory(), arguments); } - public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) { - this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,entryListFactory, arguments); + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner), autoDelete, exclusive, virtualHost, entryListFactory, arguments); } - - protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, + boolean exclusive, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) @@ -229,6 +231,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _durable = durable; _owner = owner; _autoDelete = autoDelete; + _exclusive = exclusive; _virtualHost = virtualHost; _entries = entryListFactory.createQueueEntryList(this); _arguments = arguments; @@ -324,7 +327,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean isExclusive() { - return _exclusiveOwner != null; + return _exclusive; } public Exchange getAlternateExchange() @@ -2054,6 +2057,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setExclusiveOwningSession(AMQSessionModel exclusiveOwner) { + _exclusive = true; _exclusiveOwner = exclusiveOwner; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java index c7606832d0..a883f656be 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java @@ -29,7 +29,7 @@ public interface ConfigurationRecoveryHandler public static interface QueueRecoveryHandler { - void queue(String queueName, String owner, FieldTable arguments); + void queue(String queueName, String owner, boolean exclusive, FieldTable arguments); ExchangeRecoveryHandler completeQueueRecovery(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index ccef66fd13..d38b318fdf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -73,7 +73,7 @@ public class DerbyMessageStore implements MessageStore private static final String META_DATA_TABLE_NAME = "QPID_META_DATA"; private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; - private static final int DB_VERSION = 1; + private static final int DB_VERSION = 3; @@ -90,9 +90,9 @@ public class DerbyMessageStore implements MessageStore private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; - private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; + private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), exclusive SMALLINT not null, arguments blob, PRIMARY KEY ( name ))"; private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; - private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; + private static final String SELECT_FROM_QUEUE = "SELECT name, owner, exclusive, arguments FROM " + QUEUE_TABLE_NAME; private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; private static final String SELECT_FROM_BINDINGS = @@ -104,7 +104,7 @@ public class DerbyMessageStore implements MessageStore private static final String FIND_EXCHANGE = "SELECT name FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; - private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; + private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner, exclusive, arguments) VALUES (?, ?, ?, ?)"; private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; @@ -405,7 +405,23 @@ public class DerbyMessageStore implements MessageStore { String queueName = rs.getString(1); String owner = rs.getString(2); - qrh.queue(queueName, owner, null); + boolean exclusive = rs.getBoolean(3); + Blob argumentsAsBlob = rs.getBlob(4); + + byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length()); + FieldTable arguments; + if(dataAsBytes.length > 0) + { + org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.wrap(dataAsBytes); + + arguments = new FieldTable(buffer,buffer.limit()); + } + else + { + arguments = null; + } + + qrh.queue(queueName, owner, exclusive, arguments); queues.add(queueName); } @@ -817,7 +833,21 @@ public class DerbyMessageStore implements MessageStore stmt.setString(1, queue.getNameShortString().toString()); stmt.setString(2, owner); + stmt.setBoolean(3,queue.isExclusive()); + final byte[] underlying; + if(arguments != null) + { + underlying = arguments.getDataAsBytes(); + } + else + { + underlying = new byte[0]; + } + + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(4,bis,underlying.length); + stmt.execute(); stmt.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 7479d801be..541810d2fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -914,6 +914,7 @@ public class ServerSessionDelegate extends SessionDelegate public void doTask(ServerSession session) { q.setPrincipalHolder(null); + q.setExclusiveOwningSession(null); } }; final ServerSession s = (ServerSession) session; @@ -962,8 +963,8 @@ public class ServerSessionDelegate extends SessionDelegate String owner = body.getExclusive() ? session.getClientID() : null; - final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost, - body.getArguments()); + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), + body.getExclusive(), virtualHost, body.getArguments()); if (body.getExclusive() && !body.getDurable()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 221ec0b639..ca999ceb0b 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -92,7 +92,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa return this; } - public void queue(String queueName, String owner, FieldTable arguments) + public void queue(String queueName, String owner, boolean exclusive, FieldTable arguments) { AMQShortString queueNameShortString = new AMQShortString(queueName); @@ -100,8 +100,8 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (q == null) { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, - arguments); + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, exclusive, + _virtualHost, arguments); _virtualHost.getQueueRegistry().registerQueue(q); } -- cgit v1.2.1 From e5c90eec9eb73444370f987d009cc79d8af943e8 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 19 May 2010 15:42:10 +0000 Subject: QPID-2466: swap WeakReference usage to keep handles to message content to SoftReference's. Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@946227 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/message/MessageMetaData_0_10.java | 8 ++++---- .../main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java index 5a5e2fe5b4..cf8ae2166c 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java @@ -32,7 +32,7 @@ import org.apache.qpid.transport.codec.BBEncoder; import org.apache.qpid.transport.codec.BBDecoder; import java.nio.ByteBuffer; -import java.lang.ref.WeakReference; +import java.lang.ref.SoftReference; public class MessageMetaData_0_10 implements StorableMessageMetaData { @@ -42,7 +42,7 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData private MessageTransferHeader _messageHeader; private long _arrivalTime; private int _bodySize; - private volatile WeakReference _body; + private volatile SoftReference _body; private static final int ENCODER_SIZE = 1 << 16; @@ -89,7 +89,7 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData ByteBuffer body = ByteBuffer.allocate(_bodySize); body.put(xfrBody); body.flip(); - _body = new WeakReference(body); + _body = new SoftReference(body); } @@ -212,7 +212,7 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData public void setBody(ByteBuffer body) { - _body = new WeakReference(body); + _body = new SoftReference(body); } private static class MetaDataFactory implements MessageMetaDataType.Factory diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index d38b318fdf..a87cd32e37 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -36,7 +36,7 @@ import org.apache.qpid.server.queue.AMQQueue; import java.io.ByteArrayInputStream; import java.io.File; -import java.lang.ref.WeakReference; +import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.sql.Blob; import java.sql.Connection; @@ -1408,7 +1408,7 @@ public class DerbyMessageStore implements MessageStore { private final long _messageId; - private volatile WeakReference _metaDataRef; + private volatile SoftReference _metaDataRef; private Connection _conn; StoredDerbyMessage(long messageId, StorableMessageMetaData metaData) @@ -1424,7 +1424,7 @@ public class DerbyMessageStore implements MessageStore { _messageId = messageId; - _metaDataRef = new WeakReference(metaData); + _metaDataRef = new SoftReference(metaData); if(persist) { _conn = newConnection(); @@ -1451,7 +1451,7 @@ public class DerbyMessageStore implements MessageStore { throw new RuntimeException(e); } - _metaDataRef = new WeakReference(metaData); + _metaDataRef = new SoftReference(metaData); } return metaData; -- cgit v1.2.1 From ec6fec97d87ff7f88cd9ef8fa77dcae26ba54ca7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 20 May 2010 15:17:14 +0000 Subject: QPID-1447 : Update TopicDeletePolicy to have it's own ConfigurationPlugin for handling the configuration section. Improved configuration section based on feedback from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@946664 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/plugins/ConfigurationPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index bac6e5c4d7..df4a7da4bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -146,7 +146,7 @@ public abstract class ConfigurationPlugin if (elementHandler == null) { - _logger.warn("Unused configuration element:" + configurationElement); + _logger.warn("Unused configuration element: '" + configurationElement+"'"); } else { -- cgit v1.2.1 From 1a1e020836ce829c53a35b48fec4b4ce3a920292 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 20 May 2010 15:18:59 +0000 Subject: QPID-2622 : Add Closeable interface and update Broker components to use it and add close method in ApplicationRegistry to safely perform the close. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@946667 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 3 +- .../qpid/server/connection/ConnectionRegistry.java | 31 +++--- .../server/management/ManagedObjectRegistry.java | 5 +- .../management/NoopManagedObjectRegistry.java | 2 +- .../apache/qpid/server/plugins/PluginManager.java | 3 +- .../qpid/server/registry/ApplicationRegistry.java | 107 +++++++++------------ .../ConfigurationFileApplicationRegistry.java | 3 +- .../qpid/server/registry/IApplicationRegistry.java | 3 +- .../auth/manager/AuthenticationManager.java | 5 +- .../qpid/server/virtualhost/VirtualHost.java | 5 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 27 ++++-- .../server/virtualhost/VirtualHostRegistry.java | 12 ++- 12 files changed, 111 insertions(+), 95 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index ef7426c814..8bb1a6b9fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -22,6 +22,7 @@ package org.apache.qpid.qmf; import org.apache.qpid.AMQException; +import org.apache.qpid.common.Closeable; import org.apache.qpid.qmf.schema.BrokerSchema; import org.apache.qpid.server.configuration.*; import org.apache.qpid.server.registry.IApplicationRegistry; @@ -34,7 +35,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -public class QMFService implements ConfigStore.ConfigEventListener +public class QMFService implements ConfigStore.ConfigEventListener, Closeable { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java index 7b50a2e3ad..69bdf94621 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -20,7 +20,8 @@ */ package org.apache.qpid.server.connection; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; +import org.apache.qpid.common.Closeable; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; @@ -29,16 +30,11 @@ import org.apache.qpid.protocol.AMQConstant; import java.util.concurrent.CopyOnWriteArrayList; import java.util.List; -public class ConnectionRegistry implements IConnectionRegistry +public class ConnectionRegistry implements IConnectionRegistry, Closeable { private List _registry = new CopyOnWriteArrayList(); - private VirtualHost _virtualHost; - - public ConnectionRegistry(VirtualHost virtualHost) - { - _virtualHost = virtualHost; - } + private Logger _logger = Logger.getLogger(ConnectionRegistry.class); public void initialise() { @@ -54,17 +50,24 @@ public class ConnectionRegistry implements IConnectionRegistry } /** Close all of the currently open connections. */ - public void close() throws AMQException + public void close() { while (!_registry.isEmpty()) { AMQProtocolSession connection = _registry.get(0); - connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", - 0, 0, - connection.getProtocolOutputConverter().getProtocolMajorVersion(), - connection.getProtocolOutputConverter().getProtocolMinorVersion(), - (Throwable) null), true); + try + { + connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", + 0, 0, + connection.getProtocolOutputConverter().getProtocolMajorVersion(), + connection.getProtocolOutputConverter().getProtocolMinorVersion(), + (Throwable) null), true); + } + catch (AMQException e) + { + _logger.warn("Error closing connection:" + e.getMessage()); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java index b58b17ba86..fda80ad0dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.management; import javax.management.JMException; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.common.Closeable; import java.rmi.RemoteException; import java.io.IOException; @@ -39,13 +40,11 @@ import java.io.IOException; * be the obvious choice for managed objects. * */ -public interface ManagedObjectRegistry +public interface ManagedObjectRegistry extends Closeable { void start() throws IOException, ConfigurationException; void registerObject(ManagedObject managedObject) throws JMException; void unregisterObject(ManagedObject managedObject) throws JMException; - - void close() throws RemoteException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java index b4fbed6948..a048e75b2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -53,7 +53,7 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry { } - public void close() throws RemoteException + public void close() { } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 924570f00d..c1eff5f8db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -24,6 +24,7 @@ import org.apache.felix.framework.Felix; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; import org.apache.felix.main.AutoProcessor; +import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.access.ACLPlugin; @@ -50,7 +51,7 @@ import java.util.Map; * Provides access to pluggable elements, such as exchanges */ -public class PluginManager +public class PluginManager implements Closeable { private ServiceTracker _exchangeTracker = null; private ServiceTracker _securityTracker = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 727e902a0c..d339304ab6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.common.Closeable; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.BrokerConfig; @@ -339,73 +340,52 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } - public void close() throws Exception + /** + * Close non-null Closeable items and log any errors + * @param close + */ + private void close(Closeable close) { - if (_logger.isInfoEnabled()) + try { - _logger.info("Shutting down ApplicationRegistry:" + this); + if (close != null) + { + close.close(); + } } - - try + catch (Throwable e) { - //Stop incoming connections - unbind(); + _logger.error("Error thrown whilst closing " + close.getClass().getSimpleName(), e); } - finally + } + + + public void close() + { + if (_logger.isInfoEnabled()) { - try - { -// Replace with this -// _virtualHostRegistry.close(); + _logger.info("Shutting down ApplicationRegistry:" + this); + } - //Shutdown virtualhosts - for (VirtualHost virtualHost : getVirtualHostRegistry().getVirtualHosts()) - { - virtualHost.close(); - } - } - finally - { -// _accessManager.close(); + //Stop incoming connections + unbind(); + + //Shutdown virtualhosts + close(_virtualHostRegistry); + +// close(_accessManager); // -// _databaseManager.close(); +// close(_databaseManager); - try - { - _authenticationManager.close(); - } - finally - { - try - { - // close the rmi registry(if any) started for management - if (_managedObjectRegistry != null) - { - _managedObjectRegistry.close(); - } - } - finally - { - try - { - _qmfService.close(); - } - finally - { - try - { - _pluginManager.close(); - } - finally - { - CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); - } - } - } + close(_authenticationManager); - } - } - } + close(_managedObjectRegistry); + + close(_qmfService); + + close(_pluginManager); + + CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); } private void unbind() @@ -415,8 +395,17 @@ public abstract class ApplicationRegistry implements IApplicationRegistry for (InetSocketAddress bindAddress : _acceptors.keySet()) { QpidAcceptor acceptor = _acceptors.get(bindAddress); - acceptor.getNetworkDriver().close(); - CurrentActor.get().message(BrokerMessages.BRK_SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); + + try + { + acceptor.getNetworkDriver().close(); + } + catch (Throwable e) + { + _logger.error("Unable to close network driver due to:" + e.getMessage()); + } + + CurrentActor.get().message(BrokerMessages.BRK_SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 5dd7520b8b..ae18cc0edb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -40,14 +40,13 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry @Override - public void close() throws Exception + public void close() { //Set the Actor for Broker Shutdown CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); try { super.close(); - _qmfService.close(); } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 1fa16099c8..62dddeda92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -53,9 +53,8 @@ public interface IApplicationRegistry /** * Shutdown this Registry - * @throws Exception - //fixme needs to be made more specific */ - void close() throws Exception; + void close(); /** * Get the low level configuration. For use cases where the configured object approach is not required diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index d1803124a7..d34d0c4d27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -20,19 +20,18 @@ */ package org.apache.qpid.server.security.auth.manager; +import org.apache.qpid.common.Closeable; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.security.auth.AuthenticationResult; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; -public interface AuthenticationManager +public interface AuthenticationManager extends Closeable { String getMechanisms(); SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; AuthenticationResult authenticate(SaslServer server, byte[] response); - - void close(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index a5d75d8574..9e1c07863c 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.virtualhost; +import org.apache.qpid.common.Closeable; import org.apache.qpid.server.connection.IConnectionRegistry; import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.configuration.VirtualHostConfiguration; @@ -42,7 +43,7 @@ import java.util.UUID; import java.util.TimerTask; import java.util.concurrent.FutureTask; -public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig +public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable { IConnectionRegistry getConnectionRegistry(); @@ -66,7 +67,7 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo ACLManager getAccessManager(); - void close() throws Exception; + void close(); ManagedObject getManagedObject(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 413ebe159e..4a2f796d2b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -217,7 +217,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _virtualHostMBean = new VirtualHostMBean(); - _connectionRegistry = new ConnectionRegistry(this); + _connectionRegistry = new ConnectionRegistry(); _houseKeepingTasks = new ScheduledThreadPoolExecutor(_configuration.getHouseKeepingThreadCount()); @@ -607,9 +607,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _accessManager; } - public void close() throws Exception + public void close() { - //Stop Connections _connectionRegistry.close(); @@ -627,16 +626,32 @@ public class VirtualHostImpl implements Accessable, VirtualHost { _houseKeepingTasks.shutdown(); - if (!_houseKeepingTasks.awaitTermination(HOUSEKEEPING_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) + try + { + if (!_houseKeepingTasks.awaitTermination(HOUSEKEEPING_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) + { + _houseKeepingTasks.shutdownNow(); + } + } + catch (InterruptedException e) { - _houseKeepingTasks.shutdownNow(); + _logger.warn("Interrupted during Housekeeping shutdown:" + e.getMessage()); + // Swallowing InterruptedException ok as we are shutting down. } } //Close MessageStore if (_messageStore != null) { - _messageStore.close(); + //Remove MessageStore Interface should not throw Exception + try + { + _messageStore.close(); + } + catch (Exception e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } } CurrentActor.get().message(VirtualHostMessages.VHT_CLOSED()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 5975eeec3d..4b140f1ca7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.virtualhost; +import org.apache.qpid.common.Closeable; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.configuration.ConfigStore; @@ -29,7 +30,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class VirtualHostRegistry +public class VirtualHostRegistry implements Closeable { private final Map _registry = new ConcurrentHashMap(); @@ -91,4 +92,13 @@ public class VirtualHostRegistry { return _applicationRegistry.getConfigStore(); } + + public void close() + { + for (VirtualHost virtualHost : getVirtualHosts()) + { + virtualHost.close(); + } + + } } -- cgit v1.2.1 From 271bb681b7efc63ae12ae409f21e95179496c042 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 20 May 2010 15:20:04 +0000 Subject: QPID-1447 : Modified VirtualHostHouseKeepingPlugin to return a TimeUnit and force plugin to perform validation. Potentially could be refactored to allow all VHHKPlugins to process TimeUnits in a consistent way. Add Config validation and UnitTest for SlowConsumerDetctionConfiguration. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@946669 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHostImpl.java | 19 +------------------ .../plugins/VirtualHostHouseKeepingPlugin.java | 4 +++- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 4a2f796d2b..2542e1e94d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -343,26 +343,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost VirtualHostHouseKeepingPlugin plugin = plugins.get(pluginName).newInstance(this); - TimeUnit units = TimeUnit.MILLISECONDS; - - if (plugin.getTimeUnit() != null) - { - try - { - units = TimeUnit.valueOf(plugin.getTimeUnit()); - } - catch (IllegalArgumentException iae) - { - _logger.warn("Plugin:" + pluginName + - " provided an illegal TimeUnit value:" - + plugin.getTimeUnit()); - // Warn and use default of millseconds - // Should not occur in a well behaved plugin - } - } _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, - plugin.getDelay(), units); + plugin.getDelay(), plugin.getTimeUnit()); _logger.info("Loaded VirtualHostPlugin:" + plugin); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java index e76844fa3a..d2fd4daaa5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.virtualhost.plugins; import org.apache.qpid.server.virtualhost.HouseKeepingTask; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.concurrent.TimeUnit; + public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask { public VirtualHostHouseKeepingPlugin(VirtualHost vhost) @@ -44,6 +46,6 @@ public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask * * @see java.util.concurrent.TimeUnit for valid value. */ - public abstract String getTimeUnit(); + public abstract TimeUnit getTimeUnit(); } -- cgit v1.2.1 From 3e882a6fdc6852f0023f2f8547413c252e270a03 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 21 May 2010 21:08:23 +0000 Subject: QPID-2585 : Prevent NPE if plugins are not enabled but requested git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@947174 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index c1eff5f8db..cba8dda425 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -245,6 +245,12 @@ public class PluginManager implements Closeable public

      Map getPlugins(Class

      plugin) { + // If plugins are not configured then return an empty set + if (_activator == null) + { + return new HashMap(); + } + ServiceTracker tracker = new ServiceTracker(_activator.getContext(), plugin.getName(), null); tracker.open(); -- cgit v1.2.1 From d59603494b0bc8a50853241d8ad1e5c479f9eced Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 21 May 2010 21:09:15 +0000 Subject: QPID-1447 : Complete SCDPolicyConfiguration Testing git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@947176 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/QueueConfiguration.java | 37 ++-- .../server/configuration/ServerConfiguration.java | 118 ++++++------ .../configuration/VirtualHostConfiguration.java | 44 +++-- .../configuration/plugins/ConfigurationPlugin.java | 207 +++++++++++++++++++-- 4 files changed, 289 insertions(+), 117 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 1812f657d5..ee68143a2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -31,8 +31,6 @@ import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public class QueueConfiguration extends ConfigurationPlugin { - - private Configuration _config; private String _name; private VirtualHostConfiguration _vHostConfig; @@ -44,7 +42,6 @@ public class QueueConfiguration extends ConfigurationPlugin CompositeConfiguration mungedConf = new CompositeConfiguration(); mungedConf.addConfiguration(_vHostConfig.getConfig().subset("queues.queue." + name)); mungedConf.addConfiguration(_vHostConfig.getConfig().subset("queues")); - _config = mungedConf; setConfiguration("virtualhosts.virtualhost.queues.queue", mungedConf); } @@ -78,42 +75,42 @@ public class QueueConfiguration extends ConfigurationPlugin public boolean getDurable() { - return _config.getBoolean("durable" ,false); + return getBooleanValue("durable"); } public boolean getExclusive() { - return _config.getBoolean("exclusive" ,false); + return getBooleanValue("exclusive"); } public boolean getAutoDelete() { - return _config.getBoolean("autodelete", false); + return getBooleanValue("autodelete"); } public String getOwner() { - return _config.getString("owner", null); + return getStringValue("owner", null); } public boolean getPriority() { - return _config.getBoolean("priority", false); + return getBooleanValue("priority"); } public int getPriorities() { - return _config.getInt("priorities", -1); + return getIntValue("priorities", -1); } public String getExchange() { - return _config.getString("exchange", null); + return getStringValue("exchange", null); } public List getRoutingKeys() { - return _config.getList("routingKey"); + return getListValue("routingKey"); } public String getName() @@ -123,46 +120,46 @@ public class QueueConfiguration extends ConfigurationPlugin public int getMaximumMessageAge() { - return _config.getInt("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); + return getIntValue("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); } public long getMaximumQueueDepth() { - return _config.getLong("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth()); + return getLongValue("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth()); } public long getMaximumMessageSize() { - return _config.getLong("maximumMessageSize", _vHostConfig.getMaximumMessageSize()); + return getLongValue("maximumMessageSize", _vHostConfig.getMaximumMessageSize()); } public long getMaximumMessageCount() { - return _config.getLong("maximumMessageCount", _vHostConfig.getMaximumMessageCount()); + return getLongValue("maximumMessageCount", _vHostConfig.getMaximumMessageCount()); } public long getMinimumAlertRepeatGap() { - return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); + return getLongValue("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap()); } public long getCapacity() { - return _config.getLong("capacity", _vHostConfig.getCapacity()); + return getLongValue("capacity", _vHostConfig.getCapacity()); } public long getFlowResumeCapacity() { - return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity()); + return getLongValue("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity()); } public boolean isLVQ() { - return _config.getBoolean("lvq", false); + return getBooleanValue("lvq"); } public String getLVQKey() { - return _config.getString("lvqKey", null); + return getStringValue("lvqKey", null); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 96b2e26f3c..fe399669fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -287,7 +287,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public boolean getStatusUpdatesEnabled() { // Retrieve the setting from configuration but default to on. - String value = getConfig().getString(STATUS_UPDATES, DEFAULT_STATUS_UPDATES); + String value = getStringValue(STATUS_UPDATES, DEFAULT_STATUS_UPDATES); return value.equalsIgnoreCase("on"); } @@ -300,7 +300,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public Locale getLocale() { - String localeString = getConfig().getString(ADVANCED_LOCALE); + String localeString = getStringValue(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant // If the configuration does not have a defined locale use the JVM default @@ -430,12 +430,12 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public int getJMXManagementPort() { - return getConfig().getInt("management.jmxport", DEFAULT_JMXPORT); + return getIntValue("management.jmxport", DEFAULT_JMXPORT); } public boolean getUseCustomRMISocketFactory() { - return getConfig().getBoolean(MGMT_CUSTOM_REGISTRY_SOCKET, true); + return getBooleanValue(MGMT_CUSTOM_REGISTRY_SOCKET, true); } public void setUseCustomRMISocketFactory(boolean bool) @@ -445,7 +445,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public boolean getPlatformMbeanserver() { - return getConfig().getBoolean("management.platform-mbeanserver", true); + return getBooleanValue("management.platform-mbeanserver", true); } public String[] getVirtualHosts() @@ -455,7 +455,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public String getPluginDirectory() { - return getConfig().getString("plugin-directory"); + return getStringValue("plugin-directory"); } public VirtualHostConfiguration getVirtualHostConfig(String name) @@ -470,84 +470,84 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public List getPrincipalDatabaseNames() { - return getConfig().getList("security.principal-databases.principal-database.name"); + return getListValue("security.principal-databases.principal-database.name"); } public List getPrincipalDatabaseClass() { - return getConfig().getList("security.principal-databases.principal-database.class"); + return getListValue("security.principal-databases.principal-database.class"); } public List getPrincipalDatabaseAttributeNames(int index) { String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name"; - return getConfig().getList(name); + return getListValue(name); } public List getPrincipalDatabaseAttributeValues(int index) { String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value"; - return getConfig().getList(name); + return getListValue(name); } public List getManagementPrincipalDBs() { - return getConfig().getList("security.jmx.principal-database"); + return getListValue("security.jmx.principal-database"); } public List getManagementAccessList() { - return getConfig().getList("security.jmx.access"); + return getListValue("security.jmx.access"); } public int getFrameSize() { - return getConfig().getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + return getIntValue("advanced.framesize", DEFAULT_FRAME_SIZE); } public boolean getProtectIOEnabled() { - return getConfig().getBoolean(CONNECTOR_PROTECTIO_ENABLED, DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED); + return getBooleanValue(CONNECTOR_PROTECTIO_ENABLED, DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED); } public int getBufferReadLimit() { - return getConfig().getInt(CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_READ_LIMIT_SIZE); + return getIntValue(CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_READ_LIMIT_SIZE); } public int getBufferWriteLimit() { - return getConfig().getInt(CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_WRITE_LIMIT_SIZE); + return getIntValue(CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_WRITE_LIMIT_SIZE); } public boolean getSynchedClocks() { - return getConfig().getBoolean("advanced.synced-clocks", false); + return getBooleanValue("advanced.synced-clocks"); } public boolean getMsgAuth() { - return getConfig().getBoolean("security.msg-auth", false); + return getBooleanValue("security.msg-auth"); } public String getJMXPrincipalDatabase() { - return getConfig().getString("security.jmx.principal-database"); + return getStringValue("security.jmx.principal-database"); } public String getManagementKeyStorePath() { - return getConfig().getString("management.ssl.keyStorePath", null); + return getStringValue("management.ssl.keyStorePath"); } public boolean getManagementSSLEnabled() { - return getConfig().getBoolean("management.ssl.enabled", true); + return getBooleanValue("management.ssl.enabled", true); } public String getManagementKeyStorePassword() { - return getConfig().getString("management.ssl.keyStorePassword"); + return getStringValue("management.ssl.keyStorePassword"); } public SecurityConfiguration getSecurityConfiguration() @@ -557,12 +557,12 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public boolean getQueueAutoRegister() { - return getConfig().getBoolean("queue.auto_register", true); + return getBooleanValue("queue.auto_register", true); } public boolean getManagementEnabled() { - return getConfig().getBoolean("management.enabled", true); + return getBooleanValue("management.enabled", true); } public void setManagementEnabled(boolean enabled) @@ -572,162 +572,162 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public int getHeartBeatDelay() { - return getConfig().getInt("heartbeat.delay", 5); + return getIntValue("heartbeat.delay", 5); } public double getHeartBeatTimeout() { - return getConfig().getDouble("heartbeat.timeoutFactor", 2.0); + return getDoubleValue("heartbeat.timeoutFactor", 2.0); } public int getDeliveryPoolSize() { - return getConfig().getInt("delivery.poolsize", 0); + return getIntValue("delivery.poolsize"); } public long getMaximumMessageAge() { - return getConfig().getLong("maximumMessageAge", 0); + return getLongValue("maximumMessageAge"); } public long getMaximumMessageCount() { - return getConfig().getLong("maximumMessageCount", 0); + return getLongValue("maximumMessageCount"); } public long getMaximumQueueDepth() { - return getConfig().getLong("maximumQueueDepth", 0); + return getLongValue("maximumQueueDepth"); } public long getMaximumMessageSize() { - return getConfig().getLong("maximumMessageSize", 0); + return getLongValue("maximumMessageSize"); } public long getMinimumAlertRepeatGap() { - return getConfig().getLong("minimumAlertRepeatGap", 0); + return getLongValue("minimumAlertRepeatGap"); } public long getCapacity() { - return getConfig().getLong("capacity", 0L); + return getLongValue("capacity"); } public long getFlowResumeCapacity() { - return getConfig().getLong("flowResumeCapacity", getCapacity()); + return getLongValue("flowResumeCapacity", getCapacity()); } public int getProcessors() { - return getConfig().getInt("connector.processors", 4); + return getIntValue("connector.processors", 4); } public List getPorts() { - return getConfig().getList("connector.port", Collections.singletonList(DEFAULT_PORT)); + return getListValue("connector.port", Collections.singletonList(DEFAULT_PORT)); } public List getPortExclude010() { - return getConfig().getList("connector.non010port", Collections.EMPTY_LIST); + return getListValue("connector.non010port"); } public List getPortExclude091() { - return getConfig().getList("connector.non091port", Collections.EMPTY_LIST); + return getListValue("connector.non091port"); } public List getPortExclude09() { - return getConfig().getList("connector.non09port", Collections.EMPTY_LIST); + return getListValue("connector.non09port"); } public List getPortExclude08() { - return getConfig().getList("connector.non08port", Collections.EMPTY_LIST); + return getListValue("connector.non08port"); } public String getBind() { - return getConfig().getString("connector.bind", "wildcard"); + return getStringValue("connector.bind", "wildcard"); } public int getReceiveBufferSize() { - return getConfig().getInt("connector.socketReceiveBuffer", 32767); + return getIntValue("connector.socketReceiveBuffer", 32767); } public int getWriteBufferSize() { - return getConfig().getInt("connector.socketWriteBuffer", 32767); + return getIntValue("connector.socketWriteBuffer", 32767); } public boolean getTcpNoDelay() { - return getConfig().getBoolean("connector.tcpNoDelay", true); + return getBooleanValue("connector.tcpNoDelay", true); } public boolean getEnableExecutorPool() { - return getConfig().getBoolean("advanced.filterchain[@enableExecutorPool]", false); + return getBooleanValue("advanced.filterchain[@enableExecutorPool]"); } public boolean getEnablePooledAllocator() { - return getConfig().getBoolean("advanced.enablePooledAllocator", false); + return getBooleanValue("advanced.enablePooledAllocator"); } public boolean getEnableDirectBuffers() { - return getConfig().getBoolean("advanced.enableDirectBuffers", false); + return getBooleanValue("advanced.enableDirectBuffers"); } public boolean getEnableSSL() { - return getConfig().getBoolean("connector.ssl.enabled", false); + return getBooleanValue("connector.ssl.enabled"); } public boolean getSSLOnly() { - return getConfig().getBoolean("connector.ssl.sslOnly", false); + return getBooleanValue("connector.ssl.sslOnly"); } public int getSSLPort() { - return getConfig().getInt("connector.ssl.port", DEFAULT_SSL_PORT); + return getIntValue("connector.ssl.port", DEFAULT_SSL_PORT); } public String getKeystorePath() { - return getConfig().getString("connector.ssl.keystorePath", "none"); + return getStringValue("connector.ssl.keystorePath", "none"); } public String getKeystorePassword() { - return getConfig().getString("connector.ssl.keystorePassword", "none"); + return getStringValue("connector.ssl.keystorePassword", "none"); } public String getCertType() { - return getConfig().getString("connector.ssl.certType", "SunX509"); + return getStringValue("connector.ssl.certType", "SunX509"); } public boolean getQpidNIO() { - return getConfig().getBoolean("connector.qpidnio", false); + return getBooleanValue("connector.qpidnio"); } public boolean getUseBiasedWrites() { - return getConfig().getBoolean("advanced.useWriteBiasedPool", false); + return getBooleanValue("advanced.useWriteBiasedPool"); } public String getDefaultVirtualHost() { - return getConfig().getString("virtualhosts.default"); + return getStringValue("virtualhosts.default"); } public void setDefaultVirtualHost(String vhost) @@ -742,8 +742,8 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public long getHousekeepingCheckPeriod() { - return getConfig().getLong("housekeeping.checkPeriod", - getConfig().getLong("housekeeping.expiredMessageCheckPeriod", + return getLongValue("housekeeping.checkPeriod", + getLongValue("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD)); } @@ -760,7 +760,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public Boolean getTcpNoDelay() { // Can't call parent getTcpNoDelay since it just calls this one - return getConfig().getBoolean("connector.tcpNoDelay", true); + return getBooleanValue("connector.tcpNoDelay", true); } public Integer getSoTimeout() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index d3e5921e79..ca1f25952e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -37,14 +37,12 @@ import java.util.HashSet; public class VirtualHostConfiguration extends ConfigurationPlugin { - private Configuration _config; private String _name; private Map _queues = new HashMap(); private Map _exchanges = new HashMap(); public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException { - _config = config; _name = name; setConfiguration(config); } @@ -59,7 +57,7 @@ public class VirtualHostConfiguration extends ConfigurationPlugin { super.setConfiguration("virtualhosts.virtualhost",config); - Iterator i = _config.getList("queues.queue.name").iterator(); + Iterator i = getListValue("queues.queue.name").iterator(); while (i.hasNext()) { @@ -67,13 +65,13 @@ public class VirtualHostConfiguration extends ConfigurationPlugin _queues.put(queueName, new QueueConfiguration(queueName, this)); } - i = _config.getList("exchanges.exchange.name").iterator(); + i = getListValue("exchanges.exchange.name").iterator(); int count = 0; while (i.hasNext()) { CompositeConfiguration mungedConf = new CompositeConfiguration(); mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")")); - mungedConf.addConfiguration(_config.subset("exchanges")); + mungedConf.addConfiguration(_configuration.subset("exchanges")); String exchName = (String) i.next(); _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf)); } @@ -86,42 +84,42 @@ public class VirtualHostConfiguration extends ConfigurationPlugin public long getHousekeepingExpiredMessageCheckPeriod() { - return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod()); + return getLongValue("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod()); } public String getAuthenticationDatabase() { - return _config.getString("security.authentication.name"); + return getStringValue("security.authentication.name"); } public List getCustomExchanges() { - return _config.getList("custom-exchanges.class-name"); + return getListValue("custom-exchanges.class-name"); } public SecurityConfiguration getSecurityConfiguration() { - return new SecurityConfiguration(_config.subset("security")); + return new SecurityConfiguration(_configuration.subset("security")); } public Configuration getStoreConfiguration() { - return _config.subset("store"); + return _configuration.subset("store"); } public String getMessageStoreClass() { - return _config.getString("store.class", MemoryMessageStore.class.getName()); + return getStringValue("store.class", MemoryMessageStore.class.getName()); } public void setMessageStoreClass(String storeClass) { - _config.setProperty("store.class", storeClass); + _configuration.setProperty("store.class", storeClass); } public List getExchanges() { - return _config.getList("exchanges.exchange.name"); + return getListValue("exchanges.exchange.name"); } public String[] getQueueNames() @@ -158,47 +156,47 @@ public class VirtualHostConfiguration extends ConfigurationPlugin public long getMemoryUsageMaximum() { - return _config.getLong("queues.maximumMemoryUsage", 0); + return getLongValue("queues.maximumMemoryUsage"); } public long getMemoryUsageMinimum() { - return _config.getLong("queues.minimumMemoryUsage", 0); + return getLongValue("queues.minimumMemoryUsage"); } public int getMaximumMessageAge() { - return _config.getInt("queues.maximumMessageAge", 0); + return getIntValue("queues.maximumMessageAge"); } public Long getMaximumQueueDepth() { - return _config.getLong("queues.maximumQueueDepth", 0); + return getLongValue("queues.maximumQueueDepth"); } public Long getMaximumMessageSize() { - return _config.getLong("queues.maximumMessageSize", 0); + return getLongValue("queues.maximumMessageSize"); } public Long getMaximumMessageCount() { - return _config.getLong("queues.maximumMessageCount", 0); + return getLongValue("queues.maximumMessageCount"); } public Long getMinimumAlertRepeatGap() { - return _config.getLong("queues.minimumAlertRepeatGap", 0); + return getLongValue("queues.minimumAlertRepeatGap"); } public long getCapacity() { - return _config.getLong("queues.capacity", 0l); + return getLongValue("queues.capacity"); } public long getFlowResumeCapacity() { - return _config.getLong("queues.flowResumeCapacity", getCapacity()); + return getLongValue("queues.flowResumeCapacity", getCapacity()); } public String[] getElementsProcessed() @@ -210,6 +208,6 @@ public class VirtualHostConfiguration extends ConfigurationPlugin public int getHouseKeepingThreadCount() { - return _config.getInt("housekeeping.poolSize", Runtime.getRuntime().availableProcessors()); + return getIntValue("housekeeping.poolSize", Runtime.getRuntime().availableProcessors()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index df4a7da4bf..e6306b70d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -22,14 +22,19 @@ package org.apache.qpid.server.configuration.plugins; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConversionException; +import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.ConfigurationManager; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; public abstract class ConfigurationPlugin @@ -44,14 +49,14 @@ public abstract class ConfigurationPlugin /** * The Elements that this Plugin can process. * i.e. - * For a Queues plugin that would be a list containing: - * queue - the queue entries - * the alerting values for defaults - * exchange - the default exchange - * durable - set the default durablity - * etc + * For a Queues plugin that would be a list containing: + * queue - the queue entries + * the alerting values for defaults + * exchange - the default exchange + * durable - set the default durablity + * etc * - * @return + * @return */ abstract public String[] getElementsProcessed(); @@ -96,13 +101,12 @@ public abstract class ConfigurationPlugin elementNameIndex = element.indexOf("["); if (elementNameIndex > 0) { - element = element.substring(0,elementNameIndex).trim(); + element = element.substring(0, elementNameIndex).trim(); } elements.add(element); } - //Remove the items we already expect in the configuration for (String tag : getElementsProcessed()) { @@ -114,7 +118,7 @@ public abstract class ConfigurationPlugin // configuration they don't have to. int bracketIndex = tag.indexOf("["); if (bracketIndex != -1) - { + { tag = tag.substring(bracketIndex + 1, tag.length()); } @@ -128,7 +132,7 @@ public abstract class ConfigurationPlugin _logger.info("Elements to lookup:" + path); for (String tag : elements) { - _logger.info("Tag:'"+tag+"'"); + _logger.info("Tag:'" + tag + "'"); } } } @@ -138,15 +142,14 @@ public abstract class ConfigurationPlugin { ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); - String configurationElement = path +"."+ element; + String configurationElement = path + "." + element; ConfigurationPlugin elementHandler = configurationManager. getConfigurationPlugin(configurationElement, configuration.subset(element)); - if (elementHandler == null) { - _logger.warn("Unused configuration element: '" + configurationElement+"'"); + _logger.warn("Unused configuration element: '" + configurationElement + "'"); } else { @@ -154,6 +157,180 @@ public abstract class ConfigurationPlugin } } } + + protected boolean hasConfiguration() + { + return _configuration != null; + } + + /// Getters + + protected double getDoubleValue(String property) + { + return getDoubleValue(property, 0.0); + } + + protected double getDoubleValue(String property, double defaultValue) + { + return _configuration.getDouble(property, defaultValue); + } + + + protected long getLongValue(String property) + { + return getLongValue(property, 0); + } + + protected long getLongValue(String property, long defaultValue) + { + return _configuration.getLong(property, defaultValue); + } + + protected int getIntValue(String property) + { + return getIntValue(property, 0); + } + + protected int getIntValue(String property, int defaultValue) + { + return _configuration.getInt(property, defaultValue); + } + + protected String getStringValue(String property) + { + return getStringValue(property, null); + } + + protected String getStringValue(String property, String defaultValue) + { + return _configuration.getString(property, defaultValue); + } + + protected boolean getBooleanValue(String property) + { + return getBooleanValue(property, false); + } + + protected boolean getBooleanValue(String property, boolean defaultValue) + { + return _configuration.getBoolean(property, defaultValue); + } + + protected List getListValue(String property) + { + return getListValue(property, Collections.EMPTY_LIST); + } + + protected List getListValue(String property, List defaultValue) + { + return _configuration.getList(property, defaultValue); + } + + + + /// Validation Helpers + + protected boolean contains(String property) + { + return _configuration.getProperty(property) != null; + } + + + /** + * Provide mechanism to validate Configuration contains a Postiive Long Value + * + * @param property + * + * @throws ConfigurationException + */ + protected void validatePositiveLong(String property) throws ConfigurationException + { + try + { + if (!containsPositiveLong(property)) + { + throw new ConfigurationException(this.getClass().getSimpleName() + + ": '" + property + + "' must be a Positive Long value."); + } + } + catch (Exception e) + { + Throwable last = e; + + // Find the first cause + if (e instanceof ConversionException) + { + Throwable t = e.getCause(); + while (t != null) + { + last = t; + t = last.getCause(); + } + } + + throw new ConfigurationException(this.getClass().getSimpleName() + + ": unable to configure invalid " + + property + ":" + + _configuration.getString(property), + last); + } + } + + protected boolean containsLong(String property) + { + try + { + _configuration.getLong(property); + return true; + } + catch (NoSuchElementException e) + { + return false; + } + } + + protected boolean containsPositiveLong(String property) + { + try + { + long value = _configuration.getLong(property); + return value > 0; + } + catch (NoSuchElementException e) + { + return false; + } + + } + + protected boolean containsInt(String property) + { + try + { + _configuration.getInt(property); + return true; + } + catch (NoSuchElementException e) + { + return false; + } + } + + protected boolean containsBoolean(String property) + { + try + { + _configuration.getBoolean(property); + return true; + } + catch (NoSuchElementException e) + { + return false; + } + } + + } -- cgit v1.2.1 From fce28bba8259967c9dbb14b9ce45412bd6da4361 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 21 May 2010 21:09:52 +0000 Subject: QPID-2581 : Update ConfigurationPlugin to provide a validateConfiguration() method simplifying the plugins git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@947177 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/QueueConfiguration.java | 6 ++++++ .../org/apache/qpid/server/configuration/ServerConfiguration.java | 6 ++++++ .../apache/qpid/server/configuration/VirtualHostConfiguration.java | 6 ++++++ .../qpid/server/configuration/plugins/ConfigurationPlugin.java | 4 ++++ 4 files changed, 22 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index ee68143a2d..adbb0059d8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -68,6 +68,12 @@ public class QueueConfiguration extends ConfigurationPlugin }; } + @Override + public void validateConfiguration() throws ConfigurationException + { + //Currently doesn't do validation + } + public VirtualHostConfiguration getVirtualHostConfiguration() { return _vHostConfig; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index fe399669fd..8f9bded82a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -192,6 +192,12 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return new String[]{""}; } + @Override + public void validateConfiguration() throws ConfigurationException + { + //Currently doesn't do validation + } + /* * Modified to enforce virtualhosts configuration in external file or main file, but not * both, as a fix for QPID-2360 and QPID-2361. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index ca1f25952e..00b109f33b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -206,6 +206,12 @@ public class VirtualHostConfiguration extends ConfigurationPlugin } + @Override + public void validateConfiguration() throws ConfigurationException + { + //Currently doesn't do validation + } + public int getHouseKeepingThreadCount() { return getIntValue("housekeeping.poolSize", Runtime.getRuntime().availableProcessors()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index e6306b70d5..cb21f07eaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -156,8 +156,12 @@ public abstract class ConfigurationPlugin _pluginConfiguration.put(elementHandler.getClass(), elementHandler); } } + + validateConfiguration(); } + abstract public void validateConfiguration() throws ConfigurationException; + protected boolean hasConfiguration() { return _configuration != null; -- cgit v1.2.1 From 9d71424242925a8d24bf3068e06ab609ce71b9cc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 25 May 2010 11:20:55 +0000 Subject: QPID-2626: Fix typo and unchecked assignment warning in ServerConnectionDelegate Applied patch from Emmanuel Bourg git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@948001 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerConnectionDelegate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index 4cfcafa533..a56951cf5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -106,13 +106,13 @@ public class ServerConnectionDelegate extends ServerDelegate { sconn.setVirtualHost(vhost); - sconn.invoke(new ConnectionOpenOk(Collections.EMPTY_LIST)); + sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); sconn.setState(Connection.State.OPEN); } else { - sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown vistrulhost '"+vhostName+"'")); + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '" + vhostName + "'")); sconn.setState(Connection.State.CLOSING); } -- cgit v1.2.1 From e28e79734d3b4fb51ebf9898f90bf65733bce07f Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 25 May 2010 14:11:56 +0000 Subject: Set property for native line endings on BasicGetMethodHandler git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@948051 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/BasicGetMethodHandler.java | 424 ++++++++++----------- 1 file changed, 212 insertions(+), 212 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index df5b8098ae..2ab0b04fb9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -1,212 +1,212 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicGetBody; -import org.apache.qpid.framing.BasicGetEmptyBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.flow.MessageOnlyCreditManager; -import org.apache.qpid.server.subscription.SubscriptionImpl; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class BasicGetMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); - - private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); - - public static BasicGetMethodHandler getInstance() - { - return _instance; - } - - private BasicGetMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException - { - AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); - - - VirtualHost vHost = protocolConnection.getVirtualHost(); - - AMQChannel channel = protocolConnection.getChannel(channelId); - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - else - { - AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); - if (queue == null) - { - _log.info("No queue for '" + body.getQueue() + "'"); - if(body.getQueue()!=null) - { - throw body.getConnectionException(AMQConstant.NOT_FOUND, - "No such queue, '" + body.getQueue()+ "'"); - } - else - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "No queue name provided, no default queue defined."); - } - } - else - { - - //Perform ACLs - if (!vHost.getAccessManager().authoriseConsume(protocolConnection, body.getNoAck(), queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive()) - { - AMQSessionModel session = queue.getExclusiveOwningSession(); - if (session == null || session.getConnectionModel() != protocolConnection) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue is exclusive, but not created on this Connection."); - } - } - - if (!performGet(queue,protocolConnection, channel, !body.getNoAck())) - { - MethodRegistry methodRegistry = protocolConnection.getMethodRegistry(); - // TODO - set clusterId - BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); - - - protocolConnection.writeFrame(responseBody.generateFrame(channelId)); - } - } - } - } - - public static boolean performGet(final AMQQueue queue, - final AMQProtocolSession session, - final AMQChannel channel, - final boolean acks) - throws AMQException - { - - final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); - - final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod() - { - - int _msg; - - public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) - throws AMQException - { - singleMessageCredit.useCreditForMessage(entry.getMessage()); - if(entry.getMessage() instanceof AMQMessage) - { - session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(), - deliveryTag, queue.getMessageCount()); - } - else - { - //TODO Convert AMQP 0-10 message - throw new RuntimeException("Not implemented conversion of 0-10 message"); - } - - } - }; - final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() - { - - public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) - { - channel.addUnacknowledgedMessage(entry, deliveryTag, null); - } - }; - - Subscription sub; - if(acks) - { - sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod); - } - else - { - sub = new GetNoAckSubscription(channel, - session, - null, - null, - false, - singleMessageCredit, - getDeliveryMethod, - getRecordMethod); - } - - queue.registerSubscription(sub,false); - queue.flushSubscription(sub); - queue.unregisterSubscription(sub); - return(!singleMessageCredit.hasCredit()); - - - } - - public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription - { - public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, - AMQShortString consumerTag, FieldTable filters, - boolean noLocal, FlowCreditManager creditManager, - ClientDeliveryMethod deliveryMethod, - RecordDeliveryMethod recordMethod) - throws AMQException - { - super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); - } - - public boolean isTransient() - { - return true; - } - - public boolean wouldSuspend(QueueEntry msg) - { - return !getCreditManager().useCreditForMessage(msg.getMessage()); - } - - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.BasicGetBody; +import org.apache.qpid.framing.BasicGetEmptyBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.MessageOnlyCreditManager; +import org.apache.qpid.server.subscription.SubscriptionImpl; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class BasicGetMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); + + private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler(); + + public static BasicGetMethodHandler getInstance() + { + return _instance; + } + + private BasicGetMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException + { + AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); + + + VirtualHost vHost = protocolConnection.getVirtualHost(); + + AMQChannel channel = protocolConnection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + else + { + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue()); + if (queue == null) + { + _log.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue()+ "'"); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined."); + } + } + else + { + + //Perform ACLs + if (!vHost.getAccessManager().authoriseConsume(protocolConnection, body.getNoAck(), queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + else if (queue.isExclusive()) + { + AMQSessionModel session = queue.getExclusiveOwningSession(); + if (session == null || session.getConnectionModel() != protocolConnection) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue is exclusive, but not created on this Connection."); + } + } + + if (!performGet(queue,protocolConnection, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = protocolConnection.getMethodRegistry(); + // TODO - set clusterId + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + protocolConnection.writeFrame(responseBody.generateFrame(channelId)); + } + } + } + } + + public static boolean performGet(final AMQQueue queue, + final AMQProtocolSession session, + final AMQChannel channel, + final boolean acks) + throws AMQException + { + + final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); + + final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod() + { + + int _msg; + + public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) + throws AMQException + { + singleMessageCredit.useCreditForMessage(entry.getMessage()); + if(entry.getMessage() instanceof AMQMessage) + { + session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(), + deliveryTag, queue.getMessageCount()); + } + else + { + //TODO Convert AMQP 0-10 message + throw new RuntimeException("Not implemented conversion of 0-10 message"); + } + + } + }; + final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, null); + } + }; + + Subscription sub; + if(acks) + { + sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod); + } + else + { + sub = new GetNoAckSubscription(channel, + session, + null, + null, + false, + singleMessageCredit, + getDeliveryMethod, + getRecordMethod); + } + + queue.registerSubscription(sub,false); + queue.flushSubscription(sub); + queue.unregisterSubscription(sub); + return(!singleMessageCredit.hasCredit()); + + + } + + public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription + { + public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession, + AMQShortString consumerTag, FieldTable filters, + boolean noLocal, FlowCreditManager creditManager, + ClientDeliveryMethod deliveryMethod, + RecordDeliveryMethod recordMethod) + throws AMQException + { + super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod); + } + + public boolean isTransient() + { + return true; + } + + public boolean wouldSuspend(QueueEntry msg) + { + return !getCreditManager().useCreditForMessage(msg.getMessage()); + } + + } +} -- cgit v1.2.1 From 66432f3c6d26f99828f2bafed4adf663f5d23645 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 25 May 2010 14:23:51 +0000 Subject: Set property for native line endings on QueuePurgeHandler git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@948059 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/handler/QueuePurgeHandler.java | 256 ++++++++++----------- 1 file changed, 128 insertions(+), 128 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index 9ae3a6e28a..a465c5a20f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -1,128 +1,128 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.QueuePurgeBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQSessionModel; -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.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; - -public class QueuePurgeHandler implements StateAwareMethodListener -{ - private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); - - public static QueuePurgeHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - - public QueuePurgeHandler() - { - this(true); - } - - public QueuePurgeHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - } - - public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException - { - AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); - VirtualHost virtualHost = protocolConnection.getVirtualHost(); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - - AMQChannel channel = protocolConnection.getChannel(channelId); - - - AMQQueue queue; - if(body.getQueue() == null) - { - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - - //get the default queue on the channel: - queue = channel.getDefaultQueue(); - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); - } - } - } - else - { - queue = queueRegistry.getQueue(body.getQueue()); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); - } - } - else - { - AMQSessionModel session = queue.getExclusiveOwningSession(); - - //Perform ACLs - if (!virtualHost.getAccessManager().authorisePurge(protocolConnection, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection)) - { - throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue is exclusive, but not created on this Connection."); - } - - long purged = queue.clearQueue(); - - - if(!body.getNowait()) - { - - MethodRegistry methodRegistry = protocolConnection.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); - protocolConnection.writeFrame(responseBody.generateFrame(channelId)); - - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.QueuePurgeBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; +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.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.AMQChannel; + +public class QueuePurgeHandler implements StateAwareMethodListener +{ + private static final QueuePurgeHandler _instance = new QueuePurgeHandler(); + + public static QueuePurgeHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + + public QueuePurgeHandler() + { + this(true); + } + + public QueuePurgeHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + } + + public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException + { + AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); + VirtualHost virtualHost = protocolConnection.getVirtualHost(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + AMQChannel channel = protocolConnection.getChannel(channelId); + + + AMQQueue queue; + if(body.getQueue() == null) + { + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified."); + } + } + } + else + { + queue = queueRegistry.getQueue(body.getQueue()); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist."); + } + } + else + { + AMQSessionModel session = queue.getExclusiveOwningSession(); + + //Perform ACLs + if (!virtualHost.getAccessManager().authorisePurge(protocolConnection, queue)) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + } + else if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection)) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue is exclusive, but not created on this Connection."); + } + + long purged = queue.clearQueue(); + + + if(!body.getNowait()) + { + + MethodRegistry methodRegistry = protocolConnection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + protocolConnection.writeFrame(responseBody.generateFrame(channelId)); + + } + } + } +} -- cgit v1.2.1 From e69d31247a70a1ed05b9474be31ce7be765185db Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:01:24 +0000 Subject: QPID-2581: Update configuration manager to allow multiple plugins to handle the same configuration Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949779 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ConfigurationManager.java | 36 ++++----- .../qpid/server/configuration/QueueConfig.java | 4 +- .../server/configuration/QueueConfiguration.java | 2 - .../configuration/SecurityConfiguration.java | 41 ---------- .../server/configuration/ServerConfiguration.java | 70 +++++++++-------- .../configuration/VirtualHostConfiguration.java | 24 ++---- .../configuration/plugins/ConfigurationPlugin.java | 88 +++++++++++++--------- .../plugins/ConfigurationPluginFactory.java | 13 ++-- .../qpid/server/connection/ConnectionRegistry.java | 14 ++-- .../qpid/server/registry/ApplicationRegistry.java | 34 ++++----- .../qpid/server/registry/BrokerConfigAdapter.java | 4 +- .../ConfigurationFileApplicationRegistry.java | 6 +- .../qpid/server/registry/IApplicationRegistry.java | 10 +-- .../server/virtualhost/ManagedVirtualHost.java | 3 +- .../qpid/server/virtualhost/VirtualHost.java | 4 +- .../VirtualHostConfigRecoveryHandler.java | 36 +++++---- .../qpid/server/virtualhost/VirtualHostImpl.java | 29 +++++-- .../plugins/VirtualHostHouseKeepingPlugin.java | 14 +++- .../virtualhost/plugins/VirtualHostPlugin.java | 43 +++++++++++ .../plugins/VirtualHostPluginFactory.java | 3 +- 20 files changed, 257 insertions(+), 221 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java index 9529d1097d..2c492ff6b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationManager.java @@ -20,40 +20,34 @@ */ package org.apache.qpid.server.configuration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.registry.ApplicationRegistry; -import java.util.Map; - public class ConfigurationManager { - Logger _logger = Logger.getLogger(ConfigurationManager.class); - - public ConfigurationPlugin getConfigurationPlugin(String configurationElement, Configuration configuration) throws ConfigurationException + public List getConfigurationPlugins(String configurationElement, Configuration configuration) throws ConfigurationException { - Map configPlugins = - ApplicationRegistry.getInstance().getPluginManager().getConfigurationPlugins(); + List plugins = new ArrayList(); + Map, ConfigurationPluginFactory> factories = + ApplicationRegistry.getInstance().getPluginManager().getConfigurationPlugins(); - ConfigurationPluginFactory factory = configPlugins.get(configurationElement); - - if (_logger.isInfoEnabled()) + for (Entry, ConfigurationPluginFactory> entry : factories.entrySet()) { - _logger.info("Got Factory:" + factory + ": for :" + configurationElement); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Loaded Plugins:"); - for (String key : configPlugins.keySet()) + if (entry.getKey().contains(configurationElement)) { - _logger.debug(key + ":" + configPlugins.get(key)); + ConfigurationPluginFactory factory = entry.getValue(); + plugins.add(factory.newInstance(configurationElement, configuration)); } } - - return factory != null ? factory.newInstance(configurationElement, configuration) : null; + + return plugins; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java index 4c9ec6619e..be34c8d63d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.configuration; import java.util.Map; +import org.apache.qpid.AMQException; + public interface QueueConfig extends ConfiguredObject { @@ -80,5 +82,5 @@ public interface QueueConfig extends ConfiguredObject + * To perform this {@link #initialise()} must be called. + *

      * This has been made a two step process to allow the Plugin Manager and * Configuration Manager to be initialised in the Application Registry. - * + *

      * If using this ServerConfiguration via an ApplicationRegistry there is no - * need to explictly call configure() as this is done via the AR.initialise() + * need to explictly call {@link #initialise()} as this is done via the + * {@link ApplicationRegistry#initialise()} method. * * @param configurationURL * @throws org.apache.commons.configuration.ConfigurationException @@ -149,15 +151,16 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa * * Mainly used during testing and in locations where configuration is not * desired but the interface requires configuration. - * - * If the given configuration has VirtualHost configuration then configure() - * must be called to perform the required setup. - * + *

      + * If the given configuration has VirtualHost configuration then + * {@link #initialise()} must be called to perform the required setup. + *

      * This has been made a two step process to allow the Plugin Manager and * Configuration Manager to be initialised in the Application Registry. - * + *

      * If using this ServerConfiguration via an ApplicationRegistry there is no - * need to explictly call configure() as this is done via the AR.initialise() + * need to explictly call {@link #initialise()} as this is done via the + * {@link ApplicationRegistry#initialise()} method. * * @param conf */ @@ -173,17 +176,17 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa * This has been separated from the constructor to allow the PluginManager * time to be created and provide plugins to the ConfigurationManager for * processing here. - * - * Called by ApplicationRegistry.initialise(); - * + *

      + * Called by {@link ApplicationRegistry#initialise()}. + *

      * NOTE: A DEFAULT ApplicationRegistry must exist when using this method * or a new ApplicationRegistry will be created. * * @throws ConfigurationException */ - public void configure() throws ConfigurationException - { - + public void initialise() throws ConfigurationException + { + setConfiguration("", _configuration); setupVirtualHosts(_configuration); } @@ -380,6 +383,11 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return conf; } + public String getConfigurationURL() + { + return _configFile == null ? "" : _configFile.getAbsolutePath(); + } + public void handle(Signal arg0) { try @@ -388,7 +396,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } catch (ConfigurationException e) { - _log.error("Could not reload configuration file security sections", e); + _logger.error("Could not reload configuration file security sections", e); } } @@ -397,9 +405,9 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa if (_configFile != null) { Configuration newConfig = parseConfig(_configFile); - setConfiguration("", newConfig); - + ApplicationRegistry.getInstance().getSecurityManager().configureHostPlugins(this); + // Reload virtualhosts from correct location Configuration newVhosts; if (_vhostsFile == null) @@ -412,15 +420,16 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); - for (String hostname : _virtualHosts.keySet()) + for (String hostName : _virtualHosts.keySet()) { - VirtualHost vhost = vhostRegistry.getVirtualHost(hostname); - SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newVhosts.subset("virtualhost."+hostname+".security")); - vhost.getAccessManager().configureGlobalPlugins(getSecurityConfiguration()); - vhost.getAccessManager().configureHostPlugins(hostSecurityConfig); + VirtualHost vhost = vhostRegistry.getVirtualHost(hostName); + Configuration vhostConfig = newVhosts.subset("virtualhost." + hostName); + vhost.getConfiguration().setConfiguration("virtualhosts.virtualhost", vhostConfig); // XXX + vhost.getSecurityManager().configureGlobalPlugins(this); + vhost.getSecurityManager().configureHostPlugins(vhost.getConfiguration()); } - _log.warn(SECURITY_CONFIG_RELOADED); + _logger.warn(SECURITY_CONFIG_RELOADED); } } @@ -556,11 +565,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return getStringValue("management.ssl.keyStorePassword"); } - public SecurityConfiguration getSecurityConfiguration() - { - return new SecurityConfiguration(_configuration.subset("security")); - } - public boolean getQueueAutoRegister() { return getBooleanValue("queue.auto_register", true); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 00b109f33b..2be3311403 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -20,20 +20,18 @@ */ package org.apache.qpid.server.configuration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.HashSet; public class VirtualHostConfiguration extends ConfigurationPlugin { @@ -55,7 +53,7 @@ public class VirtualHostConfiguration extends ConfigurationPlugin */ public void setConfiguration(Configuration config) throws ConfigurationException { - super.setConfiguration("virtualhosts.virtualhost",config); + setConfiguration("virtualhosts.virtualhost", config); Iterator i = getListValue("queues.queue.name").iterator(); @@ -97,11 +95,6 @@ public class VirtualHostConfiguration extends ConfigurationPlugin return getListValue("custom-exchanges.class-name"); } - public SecurityConfiguration getSecurityConfiguration() - { - return new SecurityConfiguration(_configuration.subset("security")); - } - public Configuration getStoreConfiguration() { return _configuration.subset("store"); @@ -201,8 +194,7 @@ public class VirtualHostConfiguration extends ConfigurationPlugin public String[] getElementsProcessed() { - return new String[]{"queues", "exchanges", "custom-exchanges", - "security", "store", "housekeeping"}; + return new String[]{"queues", "exchanges", "custom-exchanges", "store", "housekeeping"}; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index cb21f07eaf..9024c6aec6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -1,5 +1,4 @@ /* - * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -16,18 +15,9 @@ * 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.plugins; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.ConversionException; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.ConfigurationManager; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -37,9 +27,16 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConversionException; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.ConfigurationManager; +import org.apache.qpid.server.registry.ApplicationRegistry; + public abstract class ConfigurationPlugin { - protected Logger _logger = Logger.getLogger(this.getClass()); + protected static final Logger _logger = Logger.getLogger(ConfigurationPlugin.class); private Map, ConfigurationPlugin> _pluginConfiguration = new HashMap, ConfigurationPlugin>(); @@ -48,17 +45,24 @@ public abstract class ConfigurationPlugin /** * The Elements that this Plugin can process. - * i.e. + * * For a Queues plugin that would be a list containing: - * queue - the queue entries - * the alerting values for defaults - * exchange - the default exchange - * durable - set the default durablity - * etc - * - * @return + *

        + *
      • queue - the queue entries + *
      • the alerting values for defaults + *
      • exchange - the default exchange + *
      • durable - set the default durablity + *
      */ abstract public String[] getElementsProcessed(); + + /** + * Performs configuration validation. + */ + public void validateConfiguration() throws ConfigurationException + { + // Override in sub-classes + } public Configuration getConfig() { @@ -76,7 +80,6 @@ public abstract class ConfigurationPlugin * @param path * @param configuration the configuration for this plugin. */ - public void setConfiguration(String path, Configuration configuration) throws ConfigurationException { _configuration = configuration; @@ -97,7 +100,7 @@ public abstract class ConfigurationPlugin element = key.substring(0, elementNameIndex).trim(); } - //Trim any element properties + // Trim any element properties elementNameIndex = element.indexOf("["); if (elementNameIndex > 0) { @@ -138,29 +141,46 @@ public abstract class ConfigurationPlugin } // Process the elements in the configuration - for (String element : elements.toArray(new String[elements.size()])) + for (String element : elements) { ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); - - String configurationElement = path + "." + element; - ConfigurationPlugin elementHandler = configurationManager. - getConfigurationPlugin(configurationElement, - configuration.subset(element)); - - if (elementHandler == null) + Configuration handled = element.length() == 0 ? configuration : configuration.subset(element); + + String configurationElement = element; + if (path.length() > 0) { - _logger.warn("Unused configuration element: '" + configurationElement + "'"); + configurationElement = path + "." + configurationElement; } - else + + List handlers = configurationManager.getConfigurationPlugins(configurationElement, handled); + for (ConfigurationPlugin plugin : handlers) { - _pluginConfiguration.put(elementHandler.getClass(), elementHandler); + _pluginConfiguration.put(plugin.getClass(), plugin); } } validateConfiguration(); } - - abstract public void validateConfiguration() throws ConfigurationException; + + /** + * Helper method to print out list of keys in a {@link Configuration}. + */ + public static final void showKeys(Configuration config) + { + if (config.isEmpty()) + { + _logger.info("Configuration is empty"); + } + else + { + Iterator keys = config.getKeys(); + while (keys.hasNext()) + { + String key = (String) keys.next(); + _logger.info("Configuration key: " + key); + } + } + } protected boolean hasConfiguration() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java index 1e928a1728..02560b296e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPluginFactory.java @@ -20,22 +20,19 @@ */ package org.apache.qpid.server.configuration.plugins; +import java.util.List; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; public interface ConfigurationPluginFactory { - /** * The Parent paths of the configuration that this plugin supports. - * i.e. - * For Queue Elements the parent path is - * virtualhosts.virtualhost - * @return + * + * For example, {@code queue} elements have a parent path of {@code virtualhosts.virtualhost}. */ - abstract public String[] getParentPaths(); - + public List getParentPaths(); public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException; - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java index 69bdf94621..bac751e0c8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -20,15 +20,15 @@ */ package org.apache.qpid.server.connection; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + import org.apache.log4j.Logger; -import org.apache.qpid.common.Closeable; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.Closeable; import org.apache.qpid.protocol.AMQConstant; - -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.List; +import org.apache.qpid.server.protocol.AMQProtocolSession; public class ConnectionRegistry implements IConnectionRegistry, Closeable { @@ -38,7 +38,7 @@ public class ConnectionRegistry implements IConnectionRegistry, Closeable public void initialise() { - + // None required } public void expireClosedChannels() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index d339304ab6..4cb3d9e209 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,6 +20,11 @@ */ package org.apache.qpid.server.registry; +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -42,7 +47,7 @@ import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; @@ -52,11 +57,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - /** * An abstract application registry that provides access to configuration information and handles the * construction and caching of configurable objects. @@ -69,8 +69,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private static Map _instanceMap = new HashMap(); - private final Map, Object> _configuredObjects = new HashMap, Object>(); - protected final ServerConfiguration _configuration; public static final int DEFAULT_INSTANCE = 1; @@ -85,7 +83,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected VirtualHostRegistry _virtualHostRegistry; - protected ACLManager _accessManager; + protected SecurityManager _securityManager; protected PrincipalDatabaseManager _databaseManager; @@ -123,8 +121,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry initialise(instance, DEFAULT_INSTANCE); } + @SuppressWarnings("finally") public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception { + _logger.error("initialise(IApplicationRegistry instance, int instanceID)"); if (instance != null) { _logger.info("Initialising Application Registry(" + instance + "):" + instanceID); @@ -134,7 +134,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry store.setRoot(new SystemConfigImpl(store)); instance.setConfigStore(store); - BrokerConfig broker = new BrokerConfigAdapter(instance, instanceID); + BrokerConfig broker = new BrokerConfigAdapter(instance); SystemConfig system = (SystemConfig) store.getRoot(); system.addBroker(broker); @@ -142,6 +142,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { + _logger.error("instance.initialise(instanceID)"); instance.initialise(instanceID); } catch (Exception e) @@ -248,13 +249,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry throw new ConfigurationException(e); } - _configuration.configure(); + _configuration.initialise(); } public void initialise(int instanceID) throws Exception { - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, - new Log4jMessageLogger()); + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); _registryName = String.valueOf(instanceID); // Set the Actor for current log messages @@ -270,7 +270,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _virtualHostRegistry = new VirtualHostRegistry(this); - _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); + _securityManager = new SecurityManager(_configuration, _pluginManager); createDatabaseManager(_configuration); @@ -282,7 +282,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry initialiseVirtualHosts(); - // Startup complete pop the current actor + // Startup complete, so pop the current actor CurrentActor.remove(); } @@ -433,9 +433,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _virtualHostRegistry; } - public ACLManager getAccessManager() throws ConfigurationException + public SecurityManager getSecurityManager() { - return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); + return _securityManager; } public ManagedObjectRegistry getManagedObjectRegistry() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java index c8f5181416..4a4253153c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java @@ -32,7 +32,6 @@ import java.util.concurrent.ConcurrentHashMap; public class BrokerConfigAdapter implements BrokerConfig { private final IApplicationRegistry _instance; - private final int _instanceId; private SystemConfig _system; private final Map _vhosts = new ConcurrentHashMap(); @@ -40,10 +39,9 @@ public class BrokerConfigAdapter implements BrokerConfig private UUID _id; private String _federationTag; - public BrokerConfigAdapter(final IApplicationRegistry instance, final int instanceID) + public BrokerConfigAdapter(final IApplicationRegistry instance) { _instance = instance; - _instanceId = instanceID; _id = instance.getConfigStore().createId(); _federationTag = UUID.randomUUID().toString(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index ae18cc0edb..b1172a880e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -20,8 +20,9 @@ */ package org.apache.qpid.server.registry; -import org.apache.commons.configuration.ConfigurationException; +import java.io.File; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.AMQException; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.logging.actors.BrokerActor; @@ -29,8 +30,6 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import java.io.File; - public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException @@ -38,7 +37,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry super(new ServerConfiguration(configurationURL)); } - @Override public void close() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 62dddeda92..228c3b9112 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -20,7 +20,8 @@ */ package org.apache.qpid.server.registry; -import org.apache.commons.configuration.ConfigurationException; +import java.net.InetSocketAddress; +import java.util.UUID; import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.BrokerConfig; @@ -31,16 +32,13 @@ import org.apache.qpid.server.configuration.ConfigurationManager; import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import java.net.InetSocketAddress; -import java.util.UUID; - public interface IApplicationRegistry { /** @@ -71,7 +69,7 @@ public interface IApplicationRegistry VirtualHostRegistry getVirtualHostRegistry(); - ACLManager getAccessManager() throws ConfigurationException; + SecurityManager getSecurityManager(); PluginManager getPluginManager(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java index 2f0c56cc86..767474d5ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java @@ -25,8 +25,7 @@ import java.io.IOException; import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute; /** - * The management interface exposed to allow management of an Exchange. - * @version 0.1 + * The management interface exposed to allow management of a virtualHost */ public interface ManagedVirtualHost { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 9e1c07863c..4ed0507228 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -32,8 +32,8 @@ import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TransactionLog; import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.binding.BindingFactory; @@ -65,7 +65,7 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo AuthenticationManager getAuthenticationManager(); - ACLManager getAccessManager(); + SecurityManager getSecurityManager(); void close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index ca999ceb0b..675a6f6a91 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -94,21 +94,29 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa public void queue(String queueName, String owner, boolean exclusive, FieldTable arguments) { - AMQShortString queueNameShortString = new AMQShortString(queueName); - - AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); - - if (q == null) + try { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, exclusive, - _virtualHost, arguments); - _virtualHost.getQueueRegistry().registerQueue(q); + AMQShortString queueNameShortString = new AMQShortString(queueName); + + AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + if (q == null) + { + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + arguments); + _virtualHost.getQueueRegistry().registerQueue(q); + } + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true)); + + //Record that we have a queue for recovery + _queueRecoveries.put(queueName, 0); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); } - - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true)); - - //Record that we have a queue for recovery - _queueRecoveries.put(queueName, 0); } public ExchangeRecoveryHandler completeQueueRecovery() @@ -131,9 +139,9 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa } catch (AMQException e) { + // TODO throw new RuntimeException(e); } - } public BindingRecoveryHandler completeExchangeRecovery() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 2542e1e94d..44d178602f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -159,7 +159,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost } /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * Virtual host JMX MBean class. + * + * This has some of the methods implemented from management intrerface for exchanges. Any * implementaion of an Exchange MBean should extend this class. */ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost @@ -183,10 +185,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost { return VirtualHostImpl.this; } - - } // End of MBean class - - + } public VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig) throws Exception { @@ -340,9 +339,25 @@ public class VirtualHostImpl implements Accessable, VirtualHost { try { - VirtualHostHouseKeepingPlugin plugin = - plugins.get(pluginName).newInstance(this); + VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); + + TimeUnit units = TimeUnit.MILLISECONDS; + if (plugin.getTimeUnit() != null) + { + try + { + units = TimeUnit.valueOf(plugin.getTimeUnit()); + } + catch (IllegalArgumentException iae) + { + _logger.warn("Plugin:" + pluginName + + " provided an illegal TimeUnit value:" + + plugin.getTimeUnit()); + // Warn and use default of millseconds + // Should not occur in a well behaved plugin + } + } _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, plugin.getDelay(), plugin.getTimeUnit()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java index d2fd4daaa5..d119190842 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java @@ -20,16 +20,27 @@ */ package org.apache.qpid.server.virtualhost.plugins; +import org.apache.log4j.Logger; import org.apache.qpid.server.virtualhost.HouseKeepingTask; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.concurrent.TimeUnit; -public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask +public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask implements VirtualHostPlugin { + protected final Logger _logger = Logger.getLogger(getClass()); + + protected VirtualHost _virtualhost; + public VirtualHostHouseKeepingPlugin(VirtualHost vhost) { super(vhost); + setVirtualHost(vhost); + } + + public void setVirtualHost(VirtualHost vhost) + { + _virtualhost = vhost; } /** @@ -47,5 +58,4 @@ public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask * @see java.util.concurrent.TimeUnit for valid value. */ public abstract TimeUnit getTimeUnit(); - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java new file mode 100644 index 0000000000..59ab7ec673 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins; + +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public interface VirtualHostPlugin extends Runnable, Plugin +{ + public void setVirtualHost(VirtualHost vhost); + + /** + * Long value representing the delay between repeats + * + * @return + */ + public long getDelay(); + + /** + * Option to specify what the delay value represents + * @see java.util.concurrent.TimeUnit for valid value. + * @return + */ + public String getTimeUnit(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java index c8bea18444..5335925fb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java @@ -20,9 +20,10 @@ */ package org.apache.qpid.server.virtualhost.plugins; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.virtualhost.VirtualHost; public interface VirtualHostPluginFactory { - public VirtualHostHouseKeepingPlugin newInstance(VirtualHost vhost); + public VirtualHostHouseKeepingPlugin newInstance(VirtualHost vhost) throws ConfigurationException; } -- cgit v1.2.1 From 4dabf1ddc0e19a3c914f17b1f366417f205a6054 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:01:48 +0000 Subject: QPID-2585: Upgrade Felix to 2.0.5 Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949780 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/plugins/Activator.java | 12 +- .../org/apache/qpid/server/plugins/Plugin.java | 39 +++ .../apache/qpid/server/plugins/PluginFactory.java | 11 +- .../apache/qpid/server/plugins/PluginManager.java | 338 +++++++++++---------- 4 files changed, 240 insertions(+), 160 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java index 583e480970..df72e87fd8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Activator.java @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.qpid.server.plugins; +import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.osgi.framework.BundleActivator; @@ -26,17 +26,21 @@ import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { + private static final Logger _logger = Logger.getLogger(Activator.class); - BundleContext _context = null; + private BundleContext _context = null; public void start(BundleContext ctx) throws Exception { _context = ctx; - ctx.registerService(ServerConfiguration.class.getName(), ApplicationRegistry.getInstance().getConfiguration(), null); + _logger.info("Registering bundle: " + _context.getBundle().getSymbolicName()); + ctx.registerService(ServerConfiguration.class.getName(), ApplicationRegistry.getInstance().getConfiguration(), null); } public void stop(BundleContext ctx) throws Exception - { + { + _logger.info("Stopping bundle: " + _context.getBundle().getSymbolicName()); + _context = null; } public BundleContext getContext() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java new file mode 100644 index 0000000000..252bd711e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.plugins; + +import org.apache.commons.configuration.ConfigurationException; + +public interface Plugin +{ + /** + * The name of this plugin. + */ + String getPluginName(); + + /** + * Is this plugin configured?. + */ + boolean isConfigured(); + + /** + * Configure this plugin + */ + void configure() throws ConfigurationException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java index 58dbe69fa1..bbf3e74a30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginFactory.java @@ -1,5 +1,4 @@ /* - * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -16,11 +15,17 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * */ package org.apache.qpid.server.plugins; -public interface PluginFactory +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; + +public interface PluginFactory

      { + public Class

      getPluginClass(); + public String getPluginName(); + + public P newInstance(ConfigurationPlugin config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index cba8dda425..9d76e98f4d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -16,180 +16,222 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.qpid.server.plugins; +import static org.apache.felix.framework.util.FelixConstants.*; +import static org.apache.felix.main.AutoProcessor.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + import org.apache.commons.configuration.ConfigurationException; import org.apache.felix.framework.Felix; -import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; -import org.apache.felix.main.AutoProcessor; +import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.qpid.server.security.SecurityPluginFactory; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; -import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin; -import org.apache.qpid.server.security.access.plugins.SimpleXML; -import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin; +import org.apache.qpid.server.security.access.plugins.LegacyAccess; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.util.tracker.ServiceTracker; -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** - * @author aidan - * - * Provides access to pluggable elements, such as exchanges + * Provides access to pluggable elements, such as exchanges */ - +@SuppressWarnings("unchecked") public class PluginManager implements Closeable { + private static final Logger _logger = Logger.getLogger(PluginManager.class); + + private static final int FELIX_STOP_TIMEOUT = 30000; + private static final String VERSION = "2.6.0.4"; + + private Felix _felix; + private ServiceTracker _exchangeTracker = null; private ServiceTracker _securityTracker = null; private ServiceTracker _configTracker = null; private ServiceTracker _virtualHostTracker = null; - private Felix _felix; - - Activator _activator; + private Activator _activator; - private Map _securityPlugins; - private static final int FELIX_STOP_TIMEOUT = 30000; + private Map _securityPlugins = new HashMap(); + private Map, ConfigurationPluginFactory> _configPlugins = new IdentityHashMap, ConfigurationPluginFactory>(); - public PluginManager(String plugindir) throws Exception + public PluginManager(String pluginPath, String cachePath) throws Exception { - StringMap configMap = new StringMap(false); - - // Add the bundle provided service interface package and the core OSGi - // packages to be exported from the class path via the system bundle. - configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES, - "org.osgi.framework; version=1.3.0," + - "org.osgi.service.packageadmin; version=1.2.0," + - "org.osgi.service.startlevel; version=1.0.0," + - "org.osgi.service.url; version=1.0.0," + - "org.osgi.util.tracker; version=1.0.0," + - "org.apache.qpid.junit.extensions.util; version=0.7," + - "org.apache.qpid; version=0.7," + - "org.apache.qpid.framing; version=0.7," + - "org.apache.qpid.protocol; version=0.7," + - "org.apache.qpid.server.exchange; version=0.7," + - "org.apache.qpid.server.management; version=0.7," + - "org.apache.qpid.server.protocol; version=0.7," + - "org.apache.qpid.server.virtualhost; version=0.7," + - "org.apache.qpid.server.virtualhost.plugins; version=0.7," + - "org.apache.qpid.server.registry; version=0.7," + - "org.apache.qpid.server.queue; version=0.7," + - "org.apache.qpid.server.binding; version=0.7," + - "org.apache.qpid.server.configuration; version=0.7," + - "org.apache.qpid.server.configuration.plugins; version=0.7," + - "org.apache.qpid.server.configuration.management; version=0.7," + - "org.apache.qpid.server.persistent; version=0.7," + - "org.apache.qpid.server.plugins; version=0.7," + - "org.apache.qpid.server.queue; version=0.7," + - "org.apache.qpid.server.security; version=0.7," + - "org.apache.qpid.framing.AMQShortString; version=0.7," + - "org.apache.qpid.server.queue.AMQQueue; version=0.7," + - "org.apache.qpid.server.security.access; version=0.7," + - "org.apache.commons.configuration; version=0.7," + - "org.apache.log4j; version=1.2.12," + - "javax.management.openmbean; version=1.0.0," + - "javax.management; version=1.0.0," - ); - - if (plugindir == null) + // Store all non-OSGi plugins + // A little gross that we have to add them here, but not all the plugins are OSGIfied + for (SecurityPluginFactory pluginFactory : Arrays.asList( + AllowAll.FACTORY, DenyAll.FACTORY, LegacyAccess.FACTORY)) { - return; + _securityPlugins.put(pluginFactory.getPluginName(), pluginFactory); + } + for (ConfigurationPluginFactory configFactory : Arrays.asList( + AllowAll.AllowAllConfiguration.FACTORY, + DenyAll.DenyAllConfiguration.FACTORY, + LegacyAccess.LegacyAccessConfiguration.FACTORY)) + { + _configPlugins.put(configFactory.getParentPaths(), configFactory); } - // Set the list of bundles to load - File dir = new File(plugindir); - if (!dir.exists()) + // Check the plugin directory path is set and exist + if (pluginPath == null) { return; } + File pluginDir = new File(pluginPath); + if (!pluginDir.exists()) + { + return; + } - StringBuffer pluginJars = new StringBuffer(); + // Setup OSGi configuration propery map + StringMap configMap = new StringMap(false); - if (dir.isDirectory()) + // Add the bundle provided service interface package and the core OSGi + // packages to be exported from the class path via the system bundle. + configMap.put(FRAMEWORK_SYSTEMPACKAGES, + "org.osgi.framework; version=1.3.0," + + "org.osgi.service.packageadmin; version=1.2.0," + + "org.osgi.service.startlevel; version=1.0.0," + + "org.osgi.service.url; version=1.0.0," + + "org.osgi.util.tracker; version=1.0.0," + + "org.apache.qpid.junit.extensions.util; version=0.7," + + "org.apache.qpid; version=0.7," + + "org.apache.qpid.exchange; version=0.7," + + "org.apache.qpid.framing; version=0.7," + + "org.apache.qpid.protocol; version=0.7," + + "org.apache.qpid.server.binding; version=0.7," + + "org.apache.qpid.server.configuration; version=0.7," + + "org.apache.qpid.server.configuration.plugins; version=0.7," + + "org.apache.qpid.server.configuration.management; version=0.7," + + "org.apache.qpid.server.exchange; version=0.7," + + "org.apache.qpid.server.management; version=0.7," + + "org.apache.qpid.server.persistent; version=0.7," + + "org.apache.qpid.server.plugins; version=0.7," + + "org.apache.qpid.server.protocol; version=0.7," + + "org.apache.qpid.server.queue; version=0.7," + + "org.apache.qpid.server.registry; version=0.7," + + "org.apache.qpid.server.security; version=0.7," + + "org.apache.qpid.server.security.access; version=0.7," + + "org.apache.qpid.server.security.access.plugins; version=0.7," + + "org.apache.qpid.server.virtualhost; version=0.7," + + "org.apache.qpid.server.virtualhost.plugins; version=0.7," + + "org.apache.qpid.util; version=0.7," + + "org.apache.commons.configuration; version=1.0.0," + + "org.apache.commons.lang; version=1.0.0," + + "org.apache.commons.lang.builder; version=1.0.0," + + "org.apache.commons.logging; version=1.0.0," + + "org.apache.log4j; version=1.2.12," + + "javax.management.openmbean; version=1.0.0," + + "javax.management; version=1.0.0" + ); + + // No automatic shutdown hook + configMap.put("felix.shutdown.hook", "false"); + + // Add system activator + List activators = new ArrayList(); + _activator = new Activator(); + activators.add(_activator); + configMap.put(SYSTEMBUNDLE_ACTIVATORS_PROP, activators); + + // Get the list of bundles to load + StringBuffer pluginJars = new StringBuffer(); + if (pluginDir.isDirectory()) { - for (File child : dir.listFiles()) + for (String file : pluginDir.list()) { - if (child.getName().endsWith("jar")) + if (file.endsWith(".jar")) { - pluginJars.append(String.format(" file:%s%s%s", plugindir, File.separator, child.getName())); + pluginJars.append(String.format("file:%s%s%s ", pluginPath, File.separator, file)); } } } - if (pluginJars.length() == 0) - { - return; + if (cachePath != null) + { + File cacheDir = new File(cachePath); + if (!cacheDir.exists() && cacheDir.canWrite()) + { + _logger.info("Creating plugin cache directory: " + cachePath); + cacheDir.mkdir(); + } + + // Set plugin cache directory and empty it + _logger.info("Cache bundles in directory " + cachePath); + configMap.put("org.osgi.framework.storage", cachePath); } - -// configMap.put(FelixConstants.AUTO_START_PROP + ".1", pluginJars.toString()); -// configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, plugindir); - - configMap.put(AutoProcessor.AUTO_START_PROP + ".1", pluginJars.toString()); - - configMap.put(FelixConstants.FRAMEWORK_STORAGE, plugindir); - - - List activators = new ArrayList(); - _activator = new Activator(); - activators.add(_activator); - configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activators); - + configMap.put("org.osgi.framework.storage.clean", "onFirstInit"); + + // Set directory with plugins + _logger.info("Auto deploy bundles from directory " + pluginPath); + + // Set list of auto-start plugin JAR files + configMap.put(AUTO_START_PROP + "." + FRAMEWORK_DEFAULT_STARTLEVEL, pluginJars.toString()); + + // FIXME why does this not work? + configMap.put(AUTO_DEPLOY_DIR_PROPERY, pluginPath); + configMap.put(AUTO_DEPLOY_ACTION_PROPERY, AUTO_DEPLOY_START_VALUE); + + // Start plugin manager and trackers _felix = new Felix(configMap); try { - System.out.println("Starting Plugin manager"); - + _logger.info("Starting plugin manager..."); + _felix.init(); + process(configMap, _felix.getBundleContext()); _felix.start(); - - - AutoProcessor.process(configMap, _felix.getBundleContext()); - - System.out.println("Started Plugin manager"); - - _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); - _exchangeTracker.open(); - - _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null); - _securityTracker.open(); - - _configTracker = new ServiceTracker(_activator.getContext(), ConfigurationPluginFactory.class.getName(), null); - _configTracker.open(); - - _virtualHostTracker = new ServiceTracker(_activator.getContext(), VirtualHostPluginFactory.class.getName(), null); - _virtualHostTracker.open(); - + _logger.info("Started plugin manager"); } catch (BundleException e) { - throw new ConfigurationException("Could not start PluginManager:" + e.getMessage(), e); + throw new ConfigurationException("Could not start plugin manager: " + e.getMessage(), e); } + + // TODO save trackers in a map, keyed by class name + + _exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null); + _exchangeTracker.open(); + + _securityTracker = new ServiceTracker(_activator.getContext(), SecurityPluginFactory.class.getName(), null); + _securityTracker.open(); + + _configTracker = new ServiceTracker(_activator.getContext(), ConfigurationPluginFactory.class.getName(), null); + _configTracker.open(); + + _virtualHostTracker = new ServiceTracker(_activator.getContext(), VirtualHostPluginFactory.class.getName(), null); + _virtualHostTracker.open(); + + _logger.info("Opened service trackers"); + + // Load security and configuration plugins from their trackers for access + _configPlugins.putAll(getConfigurationServices()); + _securityPlugins.putAll(getPlugins(SecurityPluginFactory.class)); } - private Map getServices(ServiceTracker tracker) - { + private static Map getServices(ServiceTracker tracker) + { Map services = new HashMap(); - + if ((tracker != null) && (tracker.getServices() != null)) { for (Object service : tracker.getServices()) { - if (service instanceof PluginFactory) + if (service instanceof PluginFactory) { - services.put(((PluginFactory) service).getPluginName(), (T) service); + services.put(((PluginFactory) service).getPluginName(), (T) service); } else { @@ -201,41 +243,25 @@ public class PluginManager implements Closeable return services; } - public Map> getExchanges() - { - return getServices(_exchangeTracker); - } - - public Map getSecurityPlugins() - { - _securityPlugins = getServices(_securityTracker); - // A little gross that we have to add them here, but not all the plugins are OSGIfied - _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY); - _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY); - _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY); - _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY); - _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY); - - return _securityPlugins; - } - - public Map getConfigurationPlugins() - { - Map services = new HashMap(); - - if ((_configTracker != null) && (_configTracker.getServices() != null)) + private Map, ConfigurationPluginFactory> getConfigurationServices() + { + Map, ConfigurationPluginFactory> services = new IdentityHashMap, ConfigurationPluginFactory>(); + + if (_configTracker.getServices() != null) { for (Object service : _configTracker.getServices()) { - for (String parent : ((ConfigurationPluginFactory) service).getParentPaths()) - { - services.put(parent, ((ConfigurationPluginFactory) service)); - } + ConfigurationPluginFactory factory = (ConfigurationPluginFactory) service; + services.put(factory.getParentPaths(), factory); } } return services; + } + public Map> getExchanges() + { + return getServices(_exchangeTracker); } public Map getVirtualHostPlugins() @@ -243,7 +269,7 @@ public class PluginManager implements Closeable return getServices(_virtualHostTracker); } - public

      Map getPlugins(Class

      plugin) + public

      > Map getPlugins(Class

      plugin) { // If plugins are not configured then return an empty set if (_activator == null) @@ -263,6 +289,16 @@ public class PluginManager implements Closeable tracker.close(); } } + + public Map getSecurityPlugins() + { + return _securityPlugins; + } + + public Map, ConfigurationPluginFactory> getConfigurationPlugins() + { + return _configPlugins; + } public void close() { @@ -270,25 +306,23 @@ public class PluginManager implements Closeable { try { + // Close all bundle trackers _exchangeTracker.close(); - _securityTracker.close(); - _configTracker.close(); - _virtualHostTracker.close(); } finally { - System.out.println("Stopping Plugin manager"); - //fixme should be stopAndWait() but hangs VM, need upgrade in felix + _logger.info("Stopping plugin manager"); try { + // FIXME should be stopAndWait() but hangs VM, need upgrade in felix _felix.stop(); } catch (BundleException e) { - //ignore + // Ignore } try @@ -297,12 +331,10 @@ public class PluginManager implements Closeable } catch (InterruptedException e) { - //ignore + // Ignore } - - System.out.println("Stopped Plugin manager"); + _logger.info("Stopped plugin manager"); } } } - } -- cgit v1.2.1 From 1e32d9447036c3b011ae8bb92962ad8e92fce114 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:03:41 +0000 Subject: QPID-2606: Access Control Modifications Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949781 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/qmf/QMFService.java | 9 +- .../apache/qpid/server/AMQBrokerManagerMBean.java | 52 +- .../java/org/apache/qpid/server/AMQChannel.java | 10 +- .../src/main/java/org/apache/qpid/server/Main.java | 19 +- .../apache/qpid/server/binding/BindingFactory.java | 79 +-- .../server/configuration/QueueConfiguration.java | 3 +- .../server/configuration/ServerConfiguration.java | 51 +- .../server/exchange/AbstractExchangeMBean.java | 15 +- .../server/exchange/DefaultExchangeFactory.java | 22 +- .../server/exchange/DefaultExchangeRegistry.java | 17 +- .../org/apache/qpid/server/exchange/Exchange.java | 3 +- .../qpid/server/exchange/ExchangeFactory.java | 2 - .../org/apache/qpid/server/federation/Bridge.java | 18 +- .../server/handler/BasicConsumeMethodHandler.java | 13 +- .../qpid/server/handler/BasicGetMethodHandler.java | 8 +- .../server/handler/BasicPublishMethodHandler.java | 28 +- .../qpid/server/handler/ChannelOpenHandler.java | 19 +- .../handler/ConnectionOpenMethodHandler.java | 24 +- .../handler/ConnectionSecureOkMethodHandler.java | 2 +- .../handler/ConnectionStartOkMethodHandler.java | 7 +- .../server/handler/ExchangeDeclareHandler.java | 20 +- .../qpid/server/handler/ExchangeDeleteHandler.java | 9 - .../qpid/server/handler/QueueBindHandler.java | 10 +- .../qpid/server/handler/QueueDeclareHandler.java | 22 +- .../qpid/server/handler/QueueDeleteHandler.java | 11 +- .../qpid/server/handler/QueuePurgeHandler.java | 7 +- .../qpid/server/handler/QueueUnbindHandler.java | 33 +- .../management/MBeanInvocationHandlerImpl.java | 288 ++++++----- .../qpid/server/protocol/AMQProtocolEngine.java | 70 ++- .../org/apache/qpid/server/queue/AMQQueue.java | 3 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 21 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 11 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 120 ++--- .../qpid/server/registry/ApplicationRegistry.java | 5 +- .../qpid/server/security/AbstractPlugin.java | 69 +++ .../qpid/server/security/AbstractProxyPlugin.java | 139 ++++++ .../org/apache/qpid/server/security/Result.java | 46 ++ .../qpid/server/security/SecurityManager.java | 384 +++++++++++++++ .../qpid/server/security/SecurityPlugin.java | 47 ++ .../server/security/SecurityPluginActivator.java | 54 +++ .../server/security/SecurityPluginFactory.java | 30 ++ .../qpid/server/security/access/ACLManager.java | 323 ------------ .../qpid/server/security/access/ACLPlugin.java | 70 --- .../server/security/access/ACLPluginFactory.java | 33 -- .../qpid/server/security/access/AccessResult.java | 65 --- .../qpid/server/security/access/AccessRights.java | 63 --- .../qpid/server/security/access/Accessable.java | 27 -- .../security/access/AuthorizationManager.java | 27 -- .../server/security/access/ObjectProperties.java | 315 ++++++++++++ .../qpid/server/security/access/ObjectType.java | 90 ++++ .../qpid/server/security/access/Operation.java | 49 ++ .../qpid/server/security/access/Permission.java | 35 +- .../server/security/access/VirtualHostAccess.java | 68 --- .../access/management/AMQUserManagementMBean.java | 538 -------------------- .../security/access/plugins/AbstractACLPlugin.java | 99 ---- .../server/security/access/plugins/AllowAll.java | 68 ++- .../security/access/plugins/BasicACLPlugin.java | 110 ----- .../security/access/plugins/BasicPlugin.java | 51 ++ .../server/security/access/plugins/DenyAll.java | 85 ++-- .../security/access/plugins/LegacyAccess.java | 81 ++++ .../access/plugins/LegacyAccessPlugin.java | 71 --- .../server/security/auth/AuthenticationResult.java | 2 - .../Base64MD5PasswordFilePrincipalDatabase.java | 2 +- .../ConfigurationFilePrincipalDatabaseManager.java | 16 +- .../auth/management/AMQUserManagementMBean.java | 539 +++++++++++++++++++++ .../auth/manager/AuthenticationManager.java | 7 +- .../PrincipalDatabaseAuthenticationManager.java | 2 +- .../auth/rmi/RMIPasswordAuthenticator.java | 2 +- .../apache/qpid/server/state/AMQStateManager.java | 2 + .../subscription/SubscriptionFactoryImpl.java | 18 +- .../server/transport/ServerConnectionDelegate.java | 35 +- .../qpid/server/transport/ServerSession.java | 1 - .../server/transport/ServerSessionDelegate.java | 326 +++++++------ .../VirtualHostConfigRecoveryHandler.java | 2 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 130 ++--- .../virtualhost/plugins/VirtualHostPlugin.java | 4 +- 76 files changed, 2785 insertions(+), 2371 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java create mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 8bb1a6b9fa..7e999a720b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1063,7 +1063,14 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, final Long request) { - _obj.purge(request); + try + { + _obj.purge(request); + } catch (AMQException e) + { + // TODO + throw new RuntimeException(); + } return factory.createResponseCommand(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index b2e43b4f0d..811e45f4ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -1,5 +1,4 @@ /* - * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -16,24 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * */ package org.apache.qpid.server; @@ -189,8 +170,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param type * @param durable * @throws JMException + * @throws MBeanException */ - public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException, MBeanException { CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try @@ -216,7 +198,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex, "Error in creating exchange " + exchangeName); + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error in creating exchange " + exchangeName); } finally { @@ -229,8 +212,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * * @param exchangeName * @throws JMException + * @throws MBeanException */ - public void unregisterExchange(String exchangeName) throws JMException + public void unregisterExchange(String exchangeName) throws JMException, MBeanException { // TODO // Check if the exchange is in use. @@ -244,7 +228,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error in unregistering exchange " + exchangeName); } finally { @@ -260,8 +245,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param durable * @param owner * @throws JMException + * @throws MBeanException */ - public void createNewQueue(String queueName, String owner, boolean durable) throws JMException + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue != null) @@ -278,8 +264,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr ownerShortString = new AMQShortString(owner); } - queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, - getVirtualHost(), null); + queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, getVirtualHost(), null); if (queue.isDurable() && !queue.isAutoDelete()) { _durableConfig.createQueue(queue); @@ -289,8 +274,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); + JMException jme = new JMException(ex.toString()); throw new MBeanException(jme, "Error in creating queue " + queueName); } finally @@ -309,13 +293,14 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * * @param queueName * @throws JMException + * @throws MBeanException */ - public void deleteQueue(String queueName) throws JMException + public void deleteQueue(String queueName) throws JMException, MBeanException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue == null) { - throw new JMException("The Queue " + queueName + " is not a registerd queue."); + throw new JMException("The Queue " + queueName + " is not a registered queue."); } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); @@ -329,8 +314,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); + JMException jme = new JMException(ex.toString()); throw new MBeanException(jme, "Error in deleting queue " + queueName); } finally @@ -339,14 +323,16 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } } + @Override public ManagedObject getParentObject() { return _virtualHostMBean; } // This will have a single instance for a virtual host, so not having the name property in the ObjectName + @Override public ObjectName getObjectName() throws MalformedObjectNameException { return getObjectNameForSingleInstanceMBean(); } -} // End of MBean class +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 7d0163510a..8a0e49f537 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -23,6 +23,7 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -244,9 +245,12 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return _channelId; } - public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException + public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQSecurityException { - + if (!getVirtualHost().getSecurityManager().authorisePublish(info.isImmediate(), info.getRoutingKey().asString(), e.getName())) + { + throw new AMQSecurityException("Permission denied: " + e.getName()); + } _currentMessage = new IncomingMessage(info); _currentMessage.setExchange(e); } @@ -421,7 +425,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { throw new AMQException("Consumer already exists with same tag: " + tag); } - + Subscription subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 90afd2e4ac..d52267ad57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -25,12 +25,12 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.Properties; -import java.util.Set; +import java.util.Arrays; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; -import java.util.Collection; -import java.util.Arrays; +import java.util.Properties; +import java.util.Set; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -42,8 +42,6 @@ import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; -import org.apache.qpid.transport.network.ConnectionBinding; -import org.apache.qpid.transport.*; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -56,21 +54,18 @@ import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; 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.ServerConnection; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.ssl.SSLContextFactory; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.network.mina.MINANetworkDriver; -import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; /** * Main entry point for AMQPD. * */ -@SuppressWarnings({"AccessStaticViaInstance"}) public class Main { private static Logger _logger; @@ -83,7 +78,6 @@ public class Main private static final int IPV4_ADDRESS_LENGTH = 4; private static final char IPV4_LITERAL_SEPARATOR = '.'; - private static final Collection ALL_VERSIONS = Arrays.asList(VERSION.values()); protected static class InitException extends Exception { @@ -123,6 +117,7 @@ public class Main } } + @SuppressWarnings("static-access") protected void setOptions(Options options) { Option help = new Option("h", "help", false, "print this message"); @@ -403,7 +398,7 @@ public class Main NetworkDriver driver = new MINANetworkDriver(); - Set supported = new HashSet(ALL_VERSIONS); + Set supported = EnumSet.allOf(VERSION.class); if(exclude_0_10.contains(port)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index 5423f02107..59626a7b13 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -20,7 +20,12 @@ */ package org.apache.qpid.server.binding; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.configuration.BindingConfig; @@ -35,13 +40,8 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class BindingFactory { - private final VirtualHost _virtualHost; private final DurableConfigurationStore.Source _configSource; private final Exchange _defaultExchange; @@ -51,14 +51,14 @@ public class BindingFactory public BindingFactory(final VirtualHost vhost) { - this(vhost,vhost.getExchangeRegistry().getDefaultExchange()); + this(vhost, vhost.getExchangeRegistry().getDefaultExchange()); } public BindingFactory(final DurableConfigurationStore.Source configSource, final Exchange defaultExchange) { _configSource = configSource; _defaultExchange = defaultExchange; - if(configSource instanceof VirtualHost) + if (configSource instanceof VirtualHost) { _virtualHost = (VirtualHost) configSource; } @@ -83,7 +83,7 @@ public class BindingFactory private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map arguments) { - super(queue.getVirtualHost().getConfigStore().createId(),bindingKey, queue, exchange, arguments); + super(queue.getVirtualHost().getConfigStore().createId(), bindingKey, queue, exchange, arguments); _logSubject = new BindingLogSubject(bindingKey,exchange,queue); } @@ -94,7 +94,7 @@ public class BindingFactory removeBinding(this); } - public void onClose(final Exchange exchange) + public void onClose(final Exchange exchange) throws AMQSecurityException { removeBinding(this); } @@ -138,7 +138,7 @@ public class BindingFactory - public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) + public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException { return makeBinding(bindingKey, queue, exchange, arguments, false, false); } @@ -147,37 +147,43 @@ public class BindingFactory public boolean replaceBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, - final Map arguments) + final Map arguments) throws AMQSecurityException { return makeBinding(bindingKey, queue, exchange, arguments, false, true); } - private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments, boolean restore, boolean force) + private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments, boolean restore, boolean force) throws AMQSecurityException { assert queue != null; - if(bindingKey == null) + if (bindingKey == null) { bindingKey = ""; } - if(exchange == null) + if (exchange == null) { exchange = _defaultExchange; } - if(arguments == null) + if (arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } - + + //Perform ACLs + if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey))) + { + throw new AMQSecurityException("Permission denied: binding " + bindingKey); + } + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); BindingImpl existingMapping = _bindings.putIfAbsent(b,b); - if(existingMapping == null || force) + if (existingMapping == null || force) { - if(existingMapping != null) + if (existingMapping != null) { removeBinding(existingMapping); } - if(b.isDurable() && !restore) + if (b.isDurable() && !restore) { try { @@ -185,7 +191,7 @@ public class BindingFactory } catch (AMQException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); // FIXME } } @@ -201,8 +207,6 @@ public class BindingFactory { return false; } - - } private ConfigStore getConfigStore() @@ -210,43 +214,49 @@ public class BindingFactory return getVirtualHost().getConfigStore(); } - public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map argumentMap) + public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map argumentMap) throws AMQSecurityException { makeBinding(bindingKey,queue,exchange,argumentMap,true, false); } - public void removeBinding(final Binding b) + public void removeBinding(final Binding b) throws AMQSecurityException { removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments()); } - public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) + public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException { assert queue != null; - if(bindingKey == null) + if (bindingKey == null) { bindingKey = ""; } - if(exchange == null) + if (exchange == null) { exchange = _defaultExchange; } - if(arguments == null) + if (arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } + // Check access + if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue)) + { + throw new AMQSecurityException("Permission denied: binding " + bindingKey); + } + BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments)); - if(b != null) + if (b != null) { exchange.removeBinding(b); queue.removeBinding(b); exchange.removeCloseTask(b); queue.removeQueueDeleteTask(b); - if(b.isDurable()) + if (b.isDurable()) { try { @@ -257,12 +267,11 @@ public class BindingFactory } catch (AMQException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); // FIXME } } b.logDestruction(); getConfigStore().removeConfiguredObject(b); - } return b; @@ -281,7 +290,7 @@ public class BindingFactory } if(arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 7fef4558c8..f62022922a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public class QueueConfiguration extends ConfigurationPlugin @@ -109,7 +110,7 @@ public class QueueConfiguration extends ConfigurationPlugin public String getExchange() { - return getStringValue("exchange", null); + return getStringValue("exchange", ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString()); } public List getRoutingKeys() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 9f1a4c52f2..f8fc27e86a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -20,6 +20,15 @@ package org.apache.qpid.server.configuration; +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; + import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -27,26 +36,17 @@ import org.apache.commons.configuration.ConfigurationFactory; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.transport.NetworkDriverConfiguration; import sun.misc.Signal; import sun.misc.SignalHandler; -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; - public class ServerConfiguration extends ConfigurationPlugin implements SignalHandler { protected static final Logger _logger = Logger.getLogger(ServerConfiguration.class); @@ -63,17 +63,22 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public static final int DEFAULT_SSL_PORT = 8672; public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public static final int DEFAULT_JMXPORT = 8999; + + public static final String QPID_HOME = "QPID_HOME"; + public static final String QPID_WORK = "QPID_WORK"; + public static final String LIB_DIR = "lib"; + public static final String PLUGIN_DIR = "plugins"; + public static final String CACHE_DIR = "cache"; private Map _virtualHosts = new HashMap(); private File _configFile; private File _vhostsFile; - private Logger _log = LoggerFactory.getLogger(this.getClass()); + private Logger _log = Logger.getLogger(this.getClass()); private ConfigurationManagementMBean _mbean; - // Map of environment variables to config items private static final Map envVarMap = new HashMap(); @@ -142,6 +147,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } catch (IllegalArgumentException e) { + _logger.error("Signal HUP not supported for OS: " + System.getProperty("os.name")); // We're on something that doesn't handle SIGHUP, how sad, Windows. } } @@ -192,7 +198,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public String[] getElementsProcessed() { - return new String[]{""}; + return new String[] { "" }; } @Override @@ -308,7 +314,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa */ public Locale getLocale() { - String localeString = getStringValue(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant @@ -432,10 +437,15 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa _logger.warn(SECURITY_CONFIG_RELOADED); } } - + public String getQpidWork() { - return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); + return System.getProperty(QPID_WORK, System.getProperty("java.io.tmpdir")); + } + + public String getQpidHome() + { + return System.getProperty(QPID_HOME); } public void setJMXManagementPort(int mport) @@ -467,11 +477,16 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa { return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); } - + public String getPluginDirectory() { return getStringValue("plugin-directory"); } + + public String getCacheDirectory() + { + return getStringValue("cache-directory"); + } public VirtualHostConfiguration getVirtualHostConfig(String name) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index ece8bc90fe..0dca91b7be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.exchange; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; @@ -32,6 +34,7 @@ import org.apache.qpid.management.common.mbeans.ManagedExchange; import org.apache.qpid.framing.AMQShortString; import javax.management.openmbean.*; +import javax.management.MBeanException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.MalformedObjectNameException; @@ -133,7 +136,15 @@ public abstract class AbstractExchangeMBean extends } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + try + { + vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error creating new binding " + binding); + } CurrentActor.remove(); } -} // End of MBean class +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 9be8bddd28..7837a9bc38 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -26,9 +26,12 @@ import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.qmf.ManagementExchange; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -79,27 +82,26 @@ public class DefaultExchangeFactory implements ExchangeFactory public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException { - ExchangeType exchType = _exchangeClassMap.get(new AMQShortString(type)); - if (exchType == null) - { - - throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); - } - Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete); - return e; - + return createExchange(new AMQShortString(exchange), new AMQShortString(type), durable, autoDelete, 0); } public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException { + // Check access + if (!_host.getSecurityManager().authoriseCreateExchange(autoDelete, durable, exchange, null, null, null, type)) + { + String description = "Permission denied: exchange-name '" + exchange.asString() + "'"; + throw new AMQSecurityException(description); + } + ExchangeType exchType = _exchangeClassMap.get(type); if (exchType == null) { - throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); } + Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); return e; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 84444450c9..0e7459498a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,18 +20,18 @@ */ package org.apache.qpid.server.exchange; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.ExchangeInitialiser; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - public class DefaultExchangeRegistry implements ExchangeRegistry { private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); @@ -87,7 +87,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { + // Check access + if (!_host.getSecurityManager().authoriseDelete(_exchangeMap.get(name))) + { + throw new AMQSecurityException(); + } + // TODO: check inUse argument + Exchange e = _exchangeMap.remove(name); _exchangeMapStr.remove(name.toString()); if (e != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 8a31b1bab1..13fe767d3f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -138,6 +139,6 @@ public interface Exchange extends ExchangeReferrer, ExchangeConfig public static interface Task { - public void onClose(Exchange exchange); + public void onClose(Exchange exchange) throws AMQSecurityException; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index aa4cc1ec24..92795487e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -22,8 +22,6 @@ package org.apache.qpid.server.exchange; import java.util.Collection; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.VirtualHostConfiguration; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index ae578eb196..a4974c75ff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -674,13 +674,22 @@ public class Bridge implements BridgeConfig options.put("qpid.trace.exclude", _link.getFederationTag()); options.put("qpid.trace.id",_link.getRemoteFederationTag()); - _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, + try + { + _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, isDurable(), _link.getFederationTag(), false, false, - getVirtualHost(), options); - + getVirtualHost(), + options); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, @@ -695,14 +704,13 @@ public class Bridge implements BridgeConfig try { _queue.registerSubscription(sub, true); + getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.emptyMap()); } catch (AMQException e) { // TODO throw new RuntimeException(e); } - - getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.EMPTY_MAP); } public void close() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 50019090d9..a5999711bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -51,9 +51,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener { + private static final Logger _logger = Logger.getLogger(ChannelOpenHandler.class); + private static ChannelOpenHandler _instance = new ChannelOpenHandler(); public static ChannelOpenHandler getInstance() @@ -54,19 +60,16 @@ public class ChannelOpenHandler implements StateAwareMethodListener { @@ -57,7 +57,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - final AMQQueue queue; final AMQShortString routingKey; @@ -113,14 +112,7 @@ public class QueueBindHandler implements StateAwareMethodListener try { - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseBind(protocolConnection, exch, - queue, routingKey)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && !queue.isDurable()) + if (queue.isExclusive() && !queue.isDurable()) { AMQSessionModel session = queue.getExclusiveOwningSession(); if (session == null || session.getConnectionModel() != protocolConnection) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 4f7d275e71..8939cfa334 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -69,21 +69,9 @@ public class QueueDeclareHandler implements StateAwareMethodListener { @@ -100,12 +99,6 @@ public class QueueUnbindHandler implements StateAwareMethodListener _adminOnlyMethods = new HashSet(); - { - _adminOnlyMethods.add(UserManagement.TYPE); - _adminOnlyMethods.add(LoggingManagement.TYPE); - _adminOnlyMethods.add(ConfigurationManagement.TYPE); - } public static MBeanServerForwarder newProxyInstance() { final InvocationHandler handler = new MBeanInvocationHandlerImpl(); - final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + final Class[] interfaces = new Class[] { MBeanServerForwarder.class }; _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); @@ -87,7 +82,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - final String methodName = method.getName(); + final String methodName = getMethodName(method, args); if (methodName.equals("getMBeanServer")) { @@ -112,145 +107,165 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati AccessControlContext acc = AccessController.getContext(); Subject subject = Subject.getSubject(acc); - // Allow operations performed locally on behalf of the connector server itself - if (subject == null) - { - return method.invoke(_mbs, args); - } - - if (args == null || DELEGATE.equals(args[0])) - { - return method.invoke(_mbs, args); - } - - // Restrict access to "createMBean" and "unregisterMBean" to any user - if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) - { - _logger.debug("User trying to create or unregister an MBean"); - throw new SecurityException("Access denied"); - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - throw new SecurityException("Access denied"); - } - - Principal principal = principals.iterator().next(); - String identity = principal.getName(); - - if (isAdminMethod(args)) + try { - if (isAdmin(identity)) + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(_mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) { return method.invoke(_mbs, args); } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + _logger.debug("User trying to create or unregister an MBean"); + throw new SecurityException("Access denied: " + methodName); + } + + // Allow querying available object names + if (methodName.equals("queryNames")) + { + return method.invoke(_mbs, args); + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied: no principal"); + } + + // Save the principal + Principal principal = principals.iterator().next(); + SecurityManager.setThreadPrincipal(principal); + + // Get the component, type and impact, which may be null + String type = getType(method, args); + String vhost = getVirtualHost(method, args); + int impact = getImpact(method, args); + + // Get the security manager for the virtual host (if set) + SecurityManager security; + if (vhost == null) + { + security = ApplicationRegistry.getInstance().getSecurityManager(); + } else { - throw new SecurityException("Access denied"); + security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager(); } + + if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO) + { + // Check for read-only method invocation permission + if (!security.authoriseMethod(Operation.ACCESS, type, methodName)) + { + throw new SecurityException("Permission denied: Access " + methodName); + } + } + else if (isUpdateMethod(methodName)) + { + // Check for setting properties permission + if (!security.authoriseMethod(Operation.UPDATE, type, methodName)) + { + throw new SecurityException("Permission denied: Update " + methodName); + } + } + else + { + // Check for invoking/executing method action/operation permission + if (!security.authoriseMethod(Operation.EXECUTE, type, methodName)) + { + throw new SecurityException("Permission denied: Execute " + methodName); + } + } + + // Actually invoke the method + return method.invoke(_mbs, args); } - - // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAllowedToModify(identity)) - { - return method.invoke(_mbs, args); - } - - // These users can only call "getAttribute" on the MBeanServerDelegate MBean - // Here we can add other fine grained permissions like specific method for a particular mbean - if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + catch (InvocationTargetException e) { - return method.invoke(_mbs, args); + throw e.getTargetException(); } + } - throw new SecurityException("Access denied"); + private String getType(Method method, Object[] args) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + String type = object.getKeyProperty("type"); + + return type; + } + return null; } - private boolean isAdminMethod(Object[] args) - { + private String getVirtualHost(Method method, Object[] args) + { if (args[0] instanceof ObjectName) { ObjectName object = (ObjectName) args[0]; + String vhost = object.getKeyProperty("VirtualHost"); - return _adminOnlyMethods.contains(object.getKeyProperty("type")); - } - return false; - } - - // Initialises the user roles - public static void setAccessRights(Properties accessRights) - { - _userRoles = accessRights; - } - - private boolean isAdmin(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName))) - { - return true; + return vhost; } - return false; + return null; } - - private boolean isAllowedToModify(String userName) + + private String getMethodName(Method method, Object[] args) { - if (ADMIN.equals(_userRoles.getProperty(userName)) - || READWRITE.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } + String methodName = method.getName(); - private boolean isReadOnlyUser(String userName) - { - if (READONLY.equals(_userRoles.getProperty(userName))) + // if arguments are set, try and work out real method name + if (args != null && args.length >= 1 && args[0] instanceof ObjectName) { - return true; + if (methodName.equals("getAttribute")) + { + methodName = "get" + (String) args[1]; + } + else if (methodName.equals("setAttribute")) + { + methodName = "set" + ((Attribute) args[1]).getName(); + } + else if (methodName.equals("invoke")) + { + methodName = (String) args[1]; + } } - return false; + + return methodName; } - private boolean isReadOnlyMethod(Method method, Object[] args) + private int getImpact(Method method, Object[] args) { - String methodName = method.getName(); - - //handle standard get/set/query and select 'is' methods from MBeanServer - if (methodName.startsWith("query") || methodName.startsWith("get") - ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) - { - return true; - } - else if (methodName.startsWith("set")) - { - return false; - } - //handle invocation of other methods on mbeans - if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) + if ((args[0] instanceof ObjectName) && (method.getName().equals("invoke"))) { - //get invoked method name String mbeanMethod = (args.length > 1) ? (String) args[1] : null; if (mbeanMethod == null) { - return false; + return -1; } - + try { - //check if the given method is tagged with an INFO impact attribute + //Get the impact attribute MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); if (mbeanInfo != null) { MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); for (MBeanOperationInfo opInfo : opInfos) { - if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + if (opInfo.getName().equals(mbeanMethod)) { - return true; + return opInfo.getImpact(); } } } @@ -261,7 +276,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } } - return false; + return -1; + } + + private boolean isAccessMethod(String methodName) + { + //handle standard get/query/is methods from MBeanServer + return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is")); + } + + + private boolean isUpdateMethod(String methodName) + { + //handle standard set methods from MBeanServer + return methodName.startsWith("set"); } public void handleNotification(Notification notification, Object handback) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 4260307d04..25571f1022 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -20,16 +20,52 @@ */ package org.apache.qpid.server.protocol; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + import org.apache.log4j.Logger; import org.apache.mina.transport.vmpipe.VmPipeAddress; - import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodDispatcher; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.Job; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.protocol.AMQConstant; @@ -61,25 +97,6 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; -import javax.management.JMException; -import javax.security.sasl.SaslServer; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig { private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); @@ -117,6 +134,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Object _lastSent; protected volatile boolean _closed; + // maximum number of channels this session should have private long _maxNoOfChannels = 1000; @@ -358,14 +376,12 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void methodFrameReceived(int channelId, AMQMethodBody methodBody) { - final AMQMethodEvent evt = new AMQMethodEvent(channelId, methodBody); try { try { - boolean wasAnyoneInterested = _stateManager.methodReceived(evt); if (!_frameListeners.isEmpty()) @@ -418,10 +434,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _logger.info(e.getMessage() + " whilst processing:" + methodBody); closeConnection(channelId, e, false); } + catch (AMQSecurityException e) + { + AMQConnectionException ce = evt.getMethod().getConnectionException(AMQConstant.ACCESS_REFUSED, e.getMessage()); + _logger.info(e.getMessage() + " whilst processing:" + methodBody); + closeConnection(channelId, ce, false); + } } catch (Exception e) { - for (AMQMethodListener listener : _frameListeners) { listener.error(e); @@ -999,7 +1020,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { if (throwable instanceof AMQProtocolHeaderException) { - writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); _networkDriver.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 366abd3f7c..8b53257e88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQConnectionModel; @@ -194,7 +195,7 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer void deleteMessageFromTop(); - long clearQueue(); + long clearQueue() throws AMQException; /** * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 3340c1e20a..a547205d27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -29,7 +30,6 @@ import org.apache.qpid.server.configuration.QueueConfiguration; import java.util.Map; import java.util.HashMap; - public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); @@ -128,22 +128,20 @@ public class AMQQueueFactory }; - + /** @see #createAMQQueueImpl(String, boolean, String, boolean, boolean, VirtualHost, Map) */ public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - boolean exclusive, - VirtualHost virtualHost, - final FieldTable arguments) + boolean exclusive, + VirtualHost virtualHost, final FieldTable arguments) throws AMQException { return createAMQQueueImpl(name == null ? null : name.toString(), durable, owner == null ? null : owner.toString(), autoDelete, exclusive, - virtualHost, - FieldTable.convertToMap(arguments)); + virtualHost, FieldTable.convertToMap(arguments)); } @@ -152,8 +150,15 @@ public class AMQQueueFactory String owner, boolean autoDelete, boolean exclusive, - VirtualHost virtualHost, Map arguments) + VirtualHost virtualHost, Map arguments) throws AMQSecurityException { + // Access check + if (!virtualHost.getSecurityManager().authoriseCreateQueue(autoDelete, durable, exclusive, null, null, new AMQShortString(queueName), owner)) + { + String description = "Permission denied: queue-name '" + queueName + "'"; + throw new AMQSecurityException(description); + } + int priorities = 1; String conflationKey = null; if(arguments != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index af1f412843..806b7f3744 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -28,6 +28,7 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; @@ -39,6 +40,7 @@ import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.transport.MessageProperties; import javax.management.JMException; +import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.OperationsException; @@ -336,7 +338,14 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public Long clearQueue() throws JMException { - return _queue.clearQueue(); + try + { + return _queue.clearQueue(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error clearing queue " + _queueName); + } } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index afc7fb6480..7e78fd0481 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,11 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; @@ -50,26 +70,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); @@ -386,9 +386,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Manage Subscriptions - public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException + public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) + throws AMQSecurityException, ExistingExclusiveSubscription, ExistingSubscriptionPreventsExclusive { - + // Access control + if (!getVirtualHost().getSecurityManager().authoriseConsume(this)) + { + throw new AMQSecurityException("Permission denied"); + } + + if (hasExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); @@ -403,7 +410,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener else { _exclusiveSubscriber = subscription; - } } @@ -1212,38 +1218,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void purge(final long request) + public void purge(final long request) throws AMQException { - if(request == 0l) - { - clearQueue(); - } - else if(request > 0l) - { - - QueueEntryIterator queueListIterator = _entries.iterator(); - long count = 0; - - ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); - - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.acquire()) - { - dequeueEntry(node, txn); - if(++count == request) - { - break; - } - } - - } - - txn.commit(); - - - } + clear(request); } public long getCreateTime() @@ -1270,9 +1247,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public long clearQueue() - { + public long clearQueue() throws AMQException + { + return clear(0l); + } + private long clear(final long request) throws AMQSecurityException + { + //Perform ACLs + if (!getVirtualHost().getSecurityManager().authorisePurge(this)) + { + throw new AMQSecurityException("Permission denied: queue " + getName()); + } + QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; @@ -1284,7 +1271,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (!node.isDeleted() && node.acquire()) { dequeueEntry(node, txn); - count++; + if(++count == request) + { + break; + } } } @@ -1292,7 +1282,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener txn.commit(); return count; - } private void dequeueEntry(final QueueEntry node) @@ -1329,12 +1318,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.remove(task); } - public int delete() throws AMQException + // TODO list all thrown exceptions + public int delete() throws AMQSecurityException, AMQException { if (!_deleted.getAndSet(true)) { + // Check access + if (!_virtualHost.getSecurityManager().authoriseDelete(this)) + { + throw new AMQSecurityException("Permission denied: " + getName()); + } - for(Binding b : getBindings()) + for (Binding b : getBindings()) { _virtualHost.getBindingFactory().removeBinding(b); } @@ -1606,6 +1601,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void flushSubscription(Subscription sub) throws AMQException { + // Access control + if (!getVirtualHost().getSecurityManager().authoriseConsume(this)) + { + throw new AMQSecurityException("Permission denied: " + getName()); + } flushSubscription(sub, Long.MAX_VALUE); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 4cb3d9e209..9adab58a0c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -124,7 +124,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry @SuppressWarnings("finally") public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception { - _logger.error("initialise(IApplicationRegistry instance, int instanceID)"); if (instance != null) { _logger.info("Initialising Application Registry(" + instance + "):" + instanceID); @@ -142,7 +141,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { - _logger.error("instance.initialise(instanceID)"); instance.initialise(instanceID); } catch (Exception e) @@ -237,12 +235,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void configure() throws ConfigurationException { - _configurationManager = new ConfigurationManager(); try { - _pluginManager = new PluginManager(_configuration.getPluginDirectory()); + _pluginManager = new PluginManager(_configuration.getPluginDirectory(), _configuration.getCacheDirectory()); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java new file mode 100644 index 0000000000..8c9c2050e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -0,0 +1,69 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This is intended as the parent for all simple plugins. + */ +public abstract class AbstractPlugin implements SecurityPlugin +{ + protected final Logger _logger = Logger.getLogger(getClass()); + + public ConfigurationPlugin _config; + + public String getPluginName() + { + return getClass().getSimpleName(); + } + + public Result getDefault() + { + return Result.ABSTAIN; + } + + public abstract Result access(ObjectType object, Object instance); + + public abstract Result authorise(Operation operation, ObjectType object, ObjectProperties properties); + + public boolean isConfigured() + { + if (_config == null) + { + return false; + } + + for (String key : _config.getElementsProcessed()) + { + if (!_config.getConfig().containsKey(key) && _config.getConfig().subset(key).isEmpty()) + { + return false; + } + } + + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java new file mode 100644 index 0000000000..7f3b89b46b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This {@link SecurityPlugin} proxies the authorise calls to a serries of methods, one per {@link Operation}. + * + * Plugins that extend this class should override the relevant authorise method and implement their own + * {@link #setConfiguration(Configuration)} method. + */ +public abstract class AbstractProxyPlugin extends AbstractPlugin +{ + public Result authoriseConsume(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authorisePublish(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseCreate(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseAccess(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseBind(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseUnbind(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseDelete(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authorisePurge(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseExecute(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseUpdate(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result accessBroker(Object instance) + { + return getDefault(); + } + + public Result accessVirtualhost(Object instance) + { + return getDefault(); + } + + @Override + public Result access(ObjectType objectType, Object instance) + { + switch (objectType) + { + case BROKER: + return accessBroker(instance); + case VIRTUALHOST: + return accessVirtualhost(instance); + } + + return getDefault(); + } + + @Override + public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) + { + switch (operation) + { + case CONSUME: + return authoriseConsume(objectType, properties); + case PUBLISH: + return authorisePublish(objectType, properties); + case CREATE: + return authoriseCreate(objectType, properties); + case ACCESS: + return authoriseAccess(objectType, properties); + case BIND: + return authoriseBind(objectType, properties); + case UNBIND: + return authoriseUnbind(objectType, properties); + case DELETE: + return authoriseDelete(objectType, properties); + case PURGE: + return authorisePurge(objectType, properties); + case EXECUTE: + return authoriseExecute(objectType, properties); + case UPDATE: + return authoriseUpdate(objectType, properties); + } + + return getDefault(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java new file mode 100644 index 0000000000..f79721799e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security; + +/** + * The result of a security plugin decision, normally {@link #ALLOWED} or {@link #DENIED}. + */ +public enum Result +{ + /** + * The request is allowed. + */ + ALLOWED, + + /** + * The request is denied. + */ + DENIED, + + /** + * Indicates that a plugin does not handle a particular type of request. + */ + ABSTAIN, + + /** + * A plugin instance cannot make a decision on a request it is able to handle, + * and another instance of the plugin should be checked. + */ + DEFER; +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java new file mode 100755 index 0000000000..035b7fa854 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security; + +import static org.apache.qpid.server.security.access.ObjectType.*; +import static org.apache.qpid.server.security.access.Operation.*; + +import java.security.Principal; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +/** + * The security manager contains references to all loaded {@link SecurityPlugin}s and delegates security decisions to them based + * on virtual host name. The plugins can be external OSGi .jar files that export the required classes or just internal + * objects for simpler plugins. + * + * @see SecurityPlugin + */ +public class SecurityManager +{ + private static final Logger _logger = Logger.getLogger(SecurityManager.class); + + /** Container for the {@link Principal} that is using to this thread. */ + private static final ThreadLocal _principal = new ThreadLocal(); + + private PluginManager _pluginManager; + private Map _pluginFactories = new HashMap(); + private Map _globalPlugins = new HashMap(); + private Map _hostPlugins = new HashMap(); + + public SecurityManager(SecurityManager parent) throws ConfigurationException + { + _pluginManager = parent._pluginManager; + _pluginFactories = parent._pluginFactories; + + // our global plugins are the parent's host plugins + _globalPlugins = parent._hostPlugins; + } + + public SecurityManager(ConfigurationPlugin configuration, PluginManager manager) throws ConfigurationException + { + this(configuration, manager, null); + } + + public SecurityManager(ConfigurationPlugin configuration, PluginManager manager, SecurityPluginFactory plugin) throws ConfigurationException + { + _pluginManager = manager; + if (manager == null) // No plugin manager, no plugins + { + return; + } + + _pluginFactories = _pluginManager.getSecurityPlugins(); + if (plugin != null) + { + _pluginFactories.put(plugin.getPluginName(), plugin); + } + + configureHostPlugins(configuration); + } + + public static Principal getThreadPrincipal() + { + return _principal.get(); + } + + public static void setThreadPrincipal(Principal principal) + { + _principal.set(principal); + } + + public static void setThreadPrincipal(String authId) + { + setThreadPrincipal(new UsernamePrincipal(authId)); + } + + public void configureHostPlugins(ConfigurationPlugin hostConfig) throws ConfigurationException + { + _hostPlugins = configurePlugins(hostConfig); + } + + public void configureGlobalPlugins(ConfigurationPlugin configuration) throws ConfigurationException + { + _globalPlugins = configurePlugins(configuration); + } + + public Map configurePlugins(ConfigurationPlugin hostConfig) throws ConfigurationException + { + Map plugins = new HashMap(); + for (SecurityPluginFactory factory : _pluginFactories.values()) + { + SecurityPlugin plugin = factory.newInstance(hostConfig); + if (plugin.isConfigured()) + { + plugins.put(factory.getPluginName(), plugin); + } + } + return plugins; + } + + public void addHostPlugin(SecurityPlugin plugin) + { + _hostPlugins.put(plugin.getClass().getName(), plugin); + } + + public static Logger getLogger() + { + return _logger; + } + + private abstract class AccessCheck + { + abstract Result allowed(SecurityPlugin plugin); + } + + private boolean checkAllPlugins(AccessCheck checker) + { + HashMap remainingPlugins = new HashMap(_globalPlugins); + + for (Entry hostEntry : _hostPlugins.entrySet()) + { + // Create set of global only plugins + SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey()); + if (globalPlugin != null) + { + remainingPlugins.remove(hostEntry.getKey()); + } + + Result host = checker.allowed(hostEntry.getValue()); + + if (host == Result.DENIED) + { + // Something vetoed the access, we're done + return false; + } + + // host allow overrides global allow, so only check global on abstain or defer + if (host != Result.ALLOWED) + { + if (globalPlugin == null) + { + if (host == Result.DEFER) + { + host = hostEntry.getValue().getDefault(); + } + if (host == Result.DENIED) + { + return false; + } + } + else + { + Result global = checker.allowed(globalPlugin); + if (global == Result.DEFER) + { + global = globalPlugin.getDefault(); + } + if (global == Result.ABSTAIN && host == Result.DEFER) + { + global = hostEntry.getValue().getDefault(); + } + if (global == Result.DENIED) + { + return false; + } + } + } + } + + for (SecurityPlugin plugin : remainingPlugins.values()) + { + Result remaining = checker.allowed(plugin); + if (remaining == Result.DEFER) + { + remaining = plugin.getDefault(); + } + if (remaining == Result.DENIED) + { + return false; + } + } + + // getting here means either allowed or abstained from all plugins + return true; + } + + public boolean authoriseBind(final Exchange exch, final AMQQueue queue, final AMQShortString routingKey) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(BIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey)); + } + }); + } + + // TODO not implemented yet, awaiting consensus + public boolean authoriseObject(final String packageName, final String className) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + ObjectProperties properties = new ObjectProperties(); + properties.put(ObjectProperties.Property.PACKAGE, packageName); + properties.put(ObjectProperties.Property.CLASS, className); + return plugin.authorise(ACCESS, OBJECT, properties); + } + }); + } + + public boolean authoriseMethod(final Operation operation, final String componentName, final String methodName) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + ObjectProperties properties = new ObjectProperties(); + properties.setName(methodName); + if (componentName != null) + { + // Only set the property if there is a component name + properties.put(ObjectProperties.Property.COMPONENT, componentName); + } + return plugin.authorise(operation, METHOD, properties); + } + }); + } + + // TODO not implemented yet, awaiting consensus + public boolean accessBroker(final AMQProtocolSession session) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.access(BROKER, session); + } + }); + } + + public boolean accessVirtualhost(final String vhostname, final String remoteAddress) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.access(VIRTUALHOST, remoteAddress); + } + }); + } + + public boolean authoriseConsume(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseConsume(final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(exclusive, noAck, noLocal, nowait, queue)); + } + }); + } + + public boolean authoriseCreateExchange(final Boolean autoDelete, final Boolean durable, final AMQShortString exchangeName, + final Boolean internal, final Boolean nowait, final Boolean passive, final AMQShortString exchangeType) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CREATE, EXCHANGE, new ObjectProperties(autoDelete, durable, exchangeName, + internal, nowait, passive, exchangeType)); + } + }); + } + + public boolean authoriseCreateQueue(final Boolean autoDelete, final Boolean durable, final Boolean exclusive, + final Boolean nowait, final Boolean passive, final AMQShortString queueName, final String owner) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CREATE, QUEUE, new ObjectProperties(autoDelete, durable, exclusive, nowait, passive, queueName, owner)); + } + }); + } + + public boolean authoriseDelete(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(DELETE, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseDelete(final Exchange exchange) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(DELETE, EXCHANGE, new ObjectProperties(exchange.getName())); + } + }); + } + + public boolean authorisePublish(final boolean immediate, final String routingKey, final String exchangeName) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(PUBLISH, EXCHANGE, new ObjectProperties(exchangeName, routingKey, immediate)); + } + }); + } + + public boolean authorisePurge(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(PURGE, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseUnbind(final Exchange exch, final AMQShortString routingKey, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(UNBIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey)); + } + }); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java new file mode 100644 index 0000000000..c3c06bf206 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security; + +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * The two methods, {@link #access(ObjectType, Object)} and {@link #authorise(Operation, ObjectType, ObjectProperties)}, + * return the {@link Result} of the security decision, which may be to {@link Result#ABSTAIN} if no decision is made + * by this plugin. + */ +public interface SecurityPlugin extends Plugin +{ + /** + * Default result for {@link #access(ObjectType, Object)} or {@link #authorise(Operation, ObjectType, ObjectProperties)}. + */ + Result getDefault(); + + /** + * Authorise access granted to an object instance. + */ + Result access(ObjectType objectType, Object instance); + + /** + * Authorise an operation on an object defined by a set of properties. + */ + Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java new file mode 100644 index 0000000000..789bdd0073 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java @@ -0,0 +1,54 @@ +package org.apache.qpid.server.security; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * An OSGi {@link BundleActivator} that loads a {@link SecurityPluginFactory}. + */ +public abstract class SecurityPluginActivator implements BundleActivator +{ + private static final Logger _logger = Logger.getLogger(SecurityPluginActivator.class); + + private SecurityPluginFactory _factory; + private ConfigurationPluginFactory _config; + private BundleContext _ctx; + private String _bundleName; + + /** Implement this to return the factory this plugin activates. */ + public abstract SecurityPluginFactory getFactory(); + + /** Implement this to return the factory this plugin activates. */ + public abstract ConfigurationPluginFactory getConfigurationFactory(); + + /** + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext ctx) throws Exception + { + _ctx = ctx; + _factory = getFactory(); + _config = getConfigurationFactory(); + _bundleName = ctx.getBundle().getSymbolicName(); + + // register the service + _logger.info("Registering security plugin: " + _bundleName); + _ctx.registerService(SecurityPluginFactory.class.getName(), _factory, null); + _ctx.registerService(ConfigurationPluginFactory.class.getName(), _config, null); + } + + /** + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception + { + _logger.info("Stopping security plugin: " + _bundleName); + + // null object references + _factory = null; + _config = null; + _ctx = null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java new file mode 100644 index 0000000000..fe81cba282 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import org.apache.qpid.server.plugins.PluginFactory; + +/** + * The factory that generates instances of security plugins. Usually implemented as a static member class in the plugin itself. + */ +public interface SecurityPluginFactory extends PluginFactory +{ +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java deleted file mode 100644 index 7d6ae285c5..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.SecurityConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class ACLManager -{ - private static final Logger _logger = Logger.getLogger(ACLManager.class); - private PluginManager _pluginManager; - private Map _allSecurityPlugins = new HashMap(); - private Map _globalPlugins = new HashMap(); - private Map _hostPlugins = new HashMap(); - - public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException - { - this(configuration, manager, null); - } - - public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException - { - _pluginManager = manager; - - if (manager == null) // No plugin manager, no plugins - { - return; - } - - _allSecurityPlugins = _pluginManager.getSecurityPlugins(); - if (securityPlugin != null) - { - _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); - } - - configureGlobalPlugins(configuration); - } - - public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - _hostPlugins = configurePlugins(hostConfig); - } - - public void configureGlobalPlugins(SecurityConfiguration configuration) throws ConfigurationException - { - _globalPlugins = configurePlugins(configuration); - } - - public Map configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - Configuration securityConfig = hostConfig.getConfiguration(); - Map plugins = new HashMap(); - Iterator keys = securityConfig.getKeys(); - Collection handledTags = new HashSet(); - while (keys.hasNext()) - { - // Splitting the string is necessary here because of the way that getKeys() returns only - // bottom level children - String tag = ((String) keys.next()).split("\\.", 2)[0]; - if (!handledTags.contains(tag)) - { - for (ACLPluginFactory plugin : _allSecurityPlugins.values()) - { - if (plugin.supportsTag(tag)) - { - _logger.info("Plugin handling security section "+tag+" is "+plugin); - handledTags.add(tag); - plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); - } - } - } - if (!handledTags.contains(tag)) - { - _logger.warn("No plugin handled security section "+tag); - } - } - return plugins; - } - - public static Logger getLogger() - { - return _logger; - } - - private abstract class AccessCheck - { - abstract AuthzResult allowed(ACLPlugin plugin); - } - - private boolean checkAllPlugins(AccessCheck checker) - { - AuthzResult result = AuthzResult.ABSTAIN; - HashMap remainingPlugins = new HashMap(); - remainingPlugins.putAll(_globalPlugins); - for (Entry plugin : _hostPlugins.entrySet()) - { - result = checker.allowed(plugin.getValue()); - if (result == AuthzResult.DENIED) - { - // Something vetoed the access, we're done - return false; - } - else if (result == AuthzResult.ALLOWED) - { - // Remove plugin from global check list since - // host allow overrides global allow - remainingPlugins.remove(plugin.getKey()); - } - } - - for (ACLPlugin plugin : remainingPlugins.values()) - { - result = checker.allowed(plugin); - if (result == AuthzResult.DENIED) - { - return false; - } - } - return true; - } - - public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue, - final AMQShortString routingKey) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseBind(session, exch, queue, routingKey); - } - - }); - } - - public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConnect(session, virtualHost); - } - - }); - } - - public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, noAck, queue); - } - - }); - } - - public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck, - final boolean noLocal, final boolean nowait, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue); - } - - }); - } - - public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete, - final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, - final boolean passive, final AMQShortString exchangeType) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait, - passive, exchangeType); - } - - }); - } - - public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete, - final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, - final AMQShortString queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue); - } - - }); - } - - public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, queue); - } - - }); - } - - public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, exchange); - } - - }); - } - - public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory, - final AMQShortString routingKey, final Exchange e) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePublish(session, immediate, mandatory, routingKey, e); - } - - }); - } - - public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePurge(session, queue); - } - - }); - } - - public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch, - final AMQShortString routingKey, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseUnbind(session, exch, routingKey, queue); - } - - }); - } - - public void addHostPlugin(ACLPlugin aclPlugin) - { - _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java deleted file mode 100644 index cf8a3fede9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.PrincipalHolder; - -public interface ACLPlugin -{ - public enum AuthzResult - { - ALLOWED, - DENIED, - ABSTAIN - } - - void setConfiguration(Configuration config) throws ConfigurationException; - - // These return true if the plugin thinks the action should be allowed, and false if not. - - AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey); - - AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - - AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue); - - AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost); - - AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue); - - AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue); - - AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue); - - AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange); - - AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e); - - AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue); - - AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue); - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java deleted file mode 100644 index 256f093477..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -public interface ACLPluginFactory -{ - - public boolean supportsTag(String name); - - public ACLPlugin newInstance(Configuration config) throws ConfigurationException; - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java deleted file mode 100644 index d722da4ae0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessResult -{ - public enum AccessStatus - { - GRANTED, REFUSED - } - - private String _authorizer; - private AccessStatus _status; - - public AccessResult(ACLPlugin authorizer, AccessStatus status) - { - _status = status; - _authorizer = authorizer.getClass().getSimpleName(); - } - - public void setAuthorizer(ACLPlugin authorizer) - { - _authorizer += authorizer.getClass().getSimpleName(); - } - - public String getAuthorizer() - { - return _authorizer; - } - - public void setStatus(AccessStatus status) - { - _status = status; - } - - public AccessStatus getStatus() - { - return _status; - } - - public void addAuthorizer(ACLPlugin accessManager) - { - _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer; - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java deleted file mode 100644 index 1b79a5a0e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class AccessRights -{ - public enum Rights - { - ANY, - READ, - WRITE, - READWRITE - } - - Rights _right; - - public AccessRights(Rights right) - { - _right = right; - } - - public boolean allows(Rights rights) - { - switch (_right) - { - case ANY: - return (rights.equals(Rights.WRITE) - || rights.equals(Rights.READ) - || rights.equals(Rights.READWRITE) - || rights.equals(Rights.ANY)); - case READ: - return rights.equals(Rights.READ) || rights.equals(Rights.ANY); - case WRITE: - return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); - case READWRITE: - return true; - } - return false; - } - - public Rights getRights() - { - return _right; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java deleted file mode 100644 index f51cf24caa..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public interface Accessable -{ - void setAccessableName(String name); - String getAccessableName(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java deleted file mode 100644 index 895ed52222..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.apache.qpid.server.security.access; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -public class AuthorizationManager -{ - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java new file mode 100644 index 0000000000..af47ed6bf9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java @@ -0,0 +1,315 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * An set of properties for an access control v2 rule {@link ObjectType}. + * + * The {@link #matches(ObjectProperties)} method is intended to be used when determining precedence of rules, and + * {@link #equals(Object)} and {@link #hashCode()} are intended for use in maps. This is due to the wildcard matching + * described above. + */ +public class ObjectProperties extends HashMap +{ + /** serialVersionUID */ + private static final long serialVersionUID = -1356019341374170495L; + + public static final String STAR= "*"; + + public static final ObjectProperties EMPTY = new ObjectProperties(); + + public enum Property + { + ROUTING_KEY, + NAME, + QUEUE_NAME, + OWNER, + TYPE, + ALTERNATE, + IMMEDIATE, + INTERNAL, + NO_WAIT, + NO_LOCAL, + NO_ACK, + PASSIVE, + DURABLE, + EXCLUSIVE, + TEMPORARY, + AUTO_DELETE, + COMPONENT, + PACKAGE, + CLASS; + + public static Property parse(String text) + { + for (Property property : values()) + { + if (property.getName().equalsIgnoreCase(text)) + { + return property; + } + } + throw new IllegalArgumentException("Not a valid property: " + text); + } + + public String getName() + { + return StringUtils.remove(name(), '_').toLowerCase(); + } + + public static List getPropertyNames() + { + List properties = new ArrayList(); + for (Property property : values()) + { + properties.add(property.getName()); + } + return properties; + } + } + + public static List getAllPropertyNames() + { + List properties = new ArrayList(); + for (Property property : Property.values()) + { + properties.add(StringUtils.remove(property.name(), '_').toLowerCase()); + } + return properties; + } + + public ObjectProperties() + { + super(); + } + + public ObjectProperties(ObjectProperties copy) + { + super(); + + putAll(copy); + } + + public ObjectProperties(String name) + { + super(); + + setName(name); + } + + + public ObjectProperties(AMQShortString name) + { + super(); + + setName(name); + } + + public ObjectProperties(AMQQueue queue) + { + super(); + + setName(queue.getName()); + + put(Property.AUTO_DELETE, queue.isAutoDelete()); + put(Property.TEMPORARY, queue.isAutoDelete()); + put(Property.DURABLE, queue.isDurable()); + put(Property.EXCLUSIVE, queue.isExclusive()); + if (queue.getAlternateExchange() != null) + { + put(Property.ALTERNATE, queue.getAlternateExchange().getName()); + } + if (queue.getOwner() != null) + { + put(Property.OWNER, queue.getOwner()); + } + else if (queue.getPrincipalHolder() != null) + { + put(Property.OWNER, queue.getPrincipalHolder().getPrincipal().getName()); + } + } + + public ObjectProperties(Exchange exch, AMQQueue queue, AMQShortString routingKey) + { + this(queue); + + setName(exch.getName()); + + put(Property.QUEUE_NAME, queue.getName()); + put(Property.ROUTING_KEY, routingKey); + } + + public ObjectProperties(Exchange exch, AMQShortString routingKey) + { + this(exch.getName(), routingKey.asString()); + } + + public ObjectProperties(String exchangeName, String routingKey, Boolean immediate) + { + this(exchangeName, routingKey); + + put(Property.IMMEDIATE, immediate); + } + + public ObjectProperties(String exchangeName, String routingKey) + { + super(); + + setName(exchangeName); + + put(Property.ROUTING_KEY, routingKey); + } + + public ObjectProperties(Boolean autoDelete, Boolean durable, AMQShortString exchangeName, + Boolean internal, Boolean nowait, Boolean passive, AMQShortString exchangeType) + { + super(); + + setName(exchangeName); + + put(Property.AUTO_DELETE, autoDelete); + put(Property.TEMPORARY, autoDelete); + put(Property.DURABLE, durable); + put(Property.INTERNAL, internal); + put(Property.NO_WAIT, nowait); + put(Property.PASSIVE, passive); + put(Property.TYPE, exchangeType); + } + + public ObjectProperties(Boolean autoDelete, Boolean durable, Boolean exclusive, Boolean nowait, Boolean passive, + AMQShortString queueName, String owner) + { + super(); + + setName(queueName); + + put(Property.AUTO_DELETE, autoDelete); + put(Property.TEMPORARY, autoDelete); + put(Property.DURABLE, durable); + put(Property.EXCLUSIVE, exclusive); + put(Property.NO_WAIT, nowait); + put(Property.PASSIVE, passive); + put(Property.OWNER, owner); + } + + public ObjectProperties(Boolean exclusive, Boolean noAck, Boolean noLocal, Boolean nowait, AMQQueue queue) + { + this(queue); + + put(Property.NO_LOCAL, noLocal); + put(Property.NO_ACK, noAck); + put(Property.EXCLUSIVE, exclusive); + put(Property.NO_WAIT, nowait); + } + + public List getPropertyNames() + { + List properties = new ArrayList(); + for (Property property : keySet()) + { + properties.add(property.getName()); + } + return properties; + } + + public Boolean isSet(Property key) + { + return containsKey(key) && Boolean.valueOf(get(key)); + } + + public String getName() + { + return get(Property.NAME); + } + + public void setName(String name) + { + put(Property.NAME, name); + } + + public void setName(AMQShortString name) + { + put(Property.NAME, name); + } + + public String put(Property key, AMQShortString value) + { + return put(key, value == null ? "" : value.asString()); + } + + @Override + public String put(Property key, String value) + { + return super.put(key, value == null ? "" : value.trim()); + } + + public void put(Property key, Boolean value) + { + if (value != null) + { + super.put(key, Boolean.toString(value)); + } + } + + public boolean matches(ObjectProperties properties) + { + if (properties.keySet().isEmpty()) + { + return true; + } + + if (!keySet().containsAll(properties.keySet())) + { + return false; + } + + for (Property key : properties.keySet()) + { + String ruleValue = properties.get(key); + String thisValue = get(key); + + if (!valueMatches(thisValue, ruleValue)) + { + return false; + } + } + + return true; + } + + private boolean valueMatches(String thisValue, String ruleValue) + { + return (StringUtils.isEmpty(ruleValue) + || StringUtils.equals(thisValue, ruleValue)) + || ruleValue.equals(STAR) + || (ruleValue.endsWith(STAR) + && thisValue != null + && thisValue.length() > ruleValue.length() + && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2))); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java new file mode 100644 index 0000000000..66ef388976 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access; + +import static org.apache.qpid.server.security.access.Operation.*; + +import java.util.EnumSet; +import java.util.Set; + +/** + * An enumeration of all possible object types that can form part of an access control v2 rule. + * + * Each object type is valid only for a certain set of {@link Operation}s, which are passed as a list to + * the constructor, and can be checked using the {@link #isAllowed(Operation)} method. + */ +public enum ObjectType +{ + ALL(Operation.ALL), + VIRTUALHOST(ACCESS), + QUEUE(CREATE, DELETE, PURGE, CONSUME), + TOPIC(CREATE, DELETE, PURGE, CONSUME), + EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH), + BROKER(ACCESS), + LINK, // Not allowed in the Java broker + ROUTE, // Not allowed in the Java broker + METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE), + OBJECT(ACCESS); + + private EnumSet _actions; + + private ObjectType() + { + _actions = EnumSet.noneOf(Operation.class); + } + + private ObjectType(Operation operation) + { + if (operation == Operation.ALL) + { + _actions = EnumSet.allOf(Operation.class); + } + else + { + _actions = EnumSet.of(operation); + } + } + + private ObjectType(Operation first, Operation...rest) + { + _actions = EnumSet.of(first, rest); + } + + public Set getActions() + { + return _actions; + } + + public boolean isAllowed(Operation operation) + { + return _actions.contains(operation); + } + + public static ObjectType parse(String text) + { + for (ObjectType object : values()) + { + if (object.name().equalsIgnoreCase(text)) + { + return object; + } + } + throw new IllegalArgumentException("Not a valid object type: " + text); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java new file mode 100644 index 0000000000..7077257d01 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access; + +/** + * An enumeration of all possible actions that can form part of an access control v2 rule. + */ +public enum Operation +{ + ALL, + CONSUME, + PUBLISH, + CREATE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE, + UPDATE, + EXECUTE; + + public static Operation parse(String text) + { + for (Operation operation : values()) + { + if (operation.name().equalsIgnoreCase(text)) + { + return operation; + } + } + throw new IllegalArgumentException("Not a valid operation: " + text); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java index b65b0cdc6c..49b3a331f9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java @@ -20,19 +20,28 @@ */ package org.apache.qpid.server.security.access; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; +import org.apache.commons.lang.StringUtils; +/** + * An enumeration of all possible permissions that can be applied to an access control v2 rule. + */ public enum Permission { - CONSUME, - PUBLISH, - CREATEQUEUE, - CREATEEXCHANGE, - ACCESS, - BIND, - UNBIND, - DELETE, - PURGE -} + ALLOW, + ALLOW_LOG, + DENY, + DENY_LOG; + + public static Permission parse(String text) + { + + for (Permission permission : values()) + { + if (permission.name().equalsIgnoreCase(StringUtils.replaceChars(text, '-', '_'))) + { + return permission; + } + } + throw new IllegalArgumentException("Not a valid permission: " + text); + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java deleted file mode 100644 index 13151a66b8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access; - -public class VirtualHostAccess -{ - private String _vhost; - private AccessRights _rights; - - public VirtualHostAccess(String vhostaccess) - { - //format () - int hostend = vhostaccess.indexOf('('); - - if (hostend == -1) - { - throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); - } - - _vhost = vhostaccess.substring(0, hostend); - - String rights = vhostaccess.substring(hostend); - - if (rights.indexOf('r') != -1) - { - if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.READWRITE); - } - else - { - _rights = new AccessRights(AccessRights.Rights.READ); - } - } - else if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.WRITE); - } - } - - public AccessRights getAccessRights() - { - return _rights; - } - - public String getVirtualHost() - { - return _vhost; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java deleted file mode 100644 index 5a2965cb32..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.management; - -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.util.FileUtils; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; - -import javax.management.JMException; -import javax.management.remote.JMXPrincipal; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.auth.Subject; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.FileOutputStream; -import java.util.Properties; -import java.util.List; -import java.util.Enumeration; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.AccessControlContext; -import java.security.AccessController; - -/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ -@MBeanDescription("User Management Interface") -public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement -{ - - private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); - - private PrincipalDatabase _principalDatabase; - private Properties _accessRights; - private File _accessFile; - - private ReentrantLock _accessRightsUpdate = new ReentrantLock(); - - // Setup for the TabularType - static TabularType _userlistDataType; // Datatype for representing User Lists - static CompositeType _userDataType; // Composite type for representing User - - static - { - OpenType[] userItemTypes = new OpenType[4]; // User item types. - userItemTypes[0] = SimpleType.STRING; // For Username - userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read - userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write - userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin - - try - { - _userDataType = - new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, userItemTypes); - - _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX); - } - catch (OpenDataException e) - { - _logger.error("Tabular data setup for viewing users incorrect."); - _userlistDataType = null; - } - } - - - public AMQUserManagementMBean() throws JMException - { - super(UserManagement.class, UserManagement.TYPE); - } - - public String getObjectInstanceName() - { - return UserManagement.TYPE; - } - - public boolean setPassword(String username, String password) - { - return setPassword(username, password.toCharArray()); - } - - public boolean setPassword(String username, char[] password) - { - try - { - //delegate password changes to the Principal Database - return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to set password of non-existant user'" + username + "'"); - return false; - } - } - - public boolean setRights(String username, boolean read, boolean write, boolean admin) - { - - Object oldRights = null; - if ((oldRights =_accessRights.get(username)) == null) - { - // If the user doesn't exist in the access rights file check that they at least have an account. - if (_principalDatabase.getUser(username) == null) - { - return false; - } - } - - try - { - _accessRightsUpdate.lock(); - - // Update the access rights - if (admin) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); - } - else - { - if (read | write) - { - if (read) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); - } - if (write) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); - } - } - else - { - _accessRights.remove(username); - } - } - - //save the rights file - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - - //the rights file was not successfully saved, restore user rights to previous value - _logger.warn("Reverting attempted rights update for user'" + username + "'"); - if (oldRights != null) - { - _accessRights.put(username, oldRights); - } - else - { - _accessRights.remove(username); - } - - return false; - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - - return true; - } - - public boolean createUser(String username, String password, boolean read, boolean write, boolean admin) - { - return createUser(username, password.toCharArray(), read, write, admin); - } - - public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) - { - if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) - { - if (!setRights(username, read, write, admin)) - { - //unable to set rights for user, remove account - try - { - _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); - } - catch (AccountNotFoundException e) - { - //ignore - } - return false; - } - else - { - return true; - } - } - - return false; - } - - public boolean deleteUser(String username) - { - try - { - if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) - { - try - { - _accessRightsUpdate.lock(); - - _accessRights.remove(username); - - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - return false; - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - } - catch (AccountNotFoundException e) - { - _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); - return false; - } - - return true; - } - - public boolean reloadData() - { - try - { - loadAccessFile(); - _principalDatabase.reload(); - } - catch (ConfigurationException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - catch (IOException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - // Reload successful - return true; - } - - - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") - public TabularData viewUsers() - { - // Table of users - // Username(string), Access rights Read,Write,Admin(bool,bool,bool) - - if (_userlistDataType == null) - { - _logger.warn("TabluarData not setup correctly"); - return null; - } - - List users = _principalDatabase.getUsers(); - - TabularDataSupport userList = new TabularDataSupport(_userlistDataType); - - try - { - // Create the tabular list of message header contents - for (Principal user : users) - { - // Create header attributes list - - String rights = (String) _accessRights.get(user.getName()); - - Boolean read = false; - Boolean write = false; - Boolean admin = false; - - if (rights != null) - { - read = rights.equals(MBeanInvocationHandlerImpl.READONLY) - || rights.equals(MBeanInvocationHandlerImpl.READWRITE); - write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); - admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); - } - - Object[] itemData = {user.getName(), read, write, admin}; - CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES, itemData); - userList.put(messageData); - } - } - catch (OpenDataException e) - { - _logger.warn("Unable to create user list due to :" + e); - return null; - } - - return userList; - } - - /*** Broker Methods **/ - - /** - * setPrincipalDatabase - * - * @param database set The Database to use for user lookup - */ - public void setPrincipalDatabase(PrincipalDatabase database) - { - _principalDatabase = database; - } - - /** - * setAccessFile - * - * @param accessFile the file to use for updating. - * - * @throws java.io.IOException If the file cannot be accessed - * @throws org.apache.commons.configuration.ConfigurationException - * if checks on the file fail. - */ - public void setAccessFile(String accessFile) throws IOException, ConfigurationException - { - if (accessFile != null) - { - _accessFile = new File(accessFile); - if (!_accessFile.exists()) - { - throw new ConfigurationException("'" + _accessFile + "' does not exist"); - } - - if (!_accessFile.canRead()) - { - throw new ConfigurationException("Cannot read '" + _accessFile + "'."); - } - - if (!_accessFile.canWrite()) - { - _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); - } - - loadAccessFile(); - } - else - { - _logger.warn("Access rights file specified is null. Access rights not changed."); - } - } - - private void loadAccessFile() throws IOException, ConfigurationException - { - if(_accessFile == null) - { - _logger.error("No jmx access rights file has been specified."); - return; - } - - if(_accessFile.exists()) - { - try - { - _accessRightsUpdate.lock(); - - Properties accessRights = new Properties(); - accessRights.load(new FileInputStream(_accessFile)); - checkAccessRights(accessRights); - setAccessRights(accessRights); - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - } - else - { - _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); - } - } - - private void checkAccessRights(Properties accessRights) - { - Enumeration values = accessRights.propertyNames(); - - while (values.hasMoreElements()) - { - String user = (String) values.nextElement(); - - if (_principalDatabase.getUser(user) == null) - { - _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); - } - } - } - - private void saveAccessFile() throws IOException - { - try - { - _accessRightsUpdate.lock(); - - // Create temporary file - Random r = new Random(); - File tmp; - do - { - tmp = new File(_accessFile.getPath() + r.nextInt() + ".tmp"); - } - while(tmp.exists()); - - tmp.deleteOnExit(); - - FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); - output.close(); - - // Swap temp file to main rights file. - File old = new File(_accessFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - - if(!_accessFile.renameTo(old)) - { - //unable to rename the existing file to the backup name - _logger.error("Could not backup the existing management rights file"); - throw new IOException("Could not backup the existing management rights file"); - } - - if(!tmp.renameTo(_accessFile)) - { - //failed to rename the new file to the required filename - - if(!old.renameTo(_accessFile)) - { - //unable to return the backup to required filename - _logger.error("Could not rename the new management rights file into place, and unable to restore original file"); - throw new IOException("Could not rename the new management rights file into place, and unable to restore original file"); - } - - _logger.error("Could not rename the new management rights file into place"); - throw new IOException("Could not rename the new management rights file into place"); - } - } - finally - { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } - } - - } - - private String getCurrentJMXUser() - { - AccessControlContext acc = AccessController.getContext(); - - Subject subject = Subject.getSubject(acc); - if (subject == null) - { - return "Unknown user, authentication Subject was null"; - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - return "Unknown user principals were null"; - } - - Principal principal = principals.iterator().next(); - return principal.getName(); - } - - /** - * user=read user=write user=readwrite user=admin - * - * @param accessRights The properties list of access rights to process - */ - private void setAccessRights(Properties accessRights) - { - _logger.debug("Setting Access Rights:" + accessRights); - _accessRights = accessRights; - MBeanInvocationHandlerImpl.setAccessRights(_accessRights); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java deleted file mode 100644 index f99f3a60f7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.PrincipalHolder; - -/** - * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. - */ -public abstract class AbstractACLPlugin implements ACLPlugin -{ - - private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; - - public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, - AMQShortString routingKey) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) - { - // TODO Auto-generated method stub - return null; - } - - public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, - boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, - AMQQueue queue) - { - return DEFAULT_ANSWER; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 4af178574b..82963bbadc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -15,40 +15,72 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * */ package org.apache.qpid.server.security.access.plugins; +import java.util.Arrays; +import java.util.List; + import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPluginFactory; -public class AllowAll extends BasicACLPlugin +/** Always allow. */ +public class AllowAll extends BasicPlugin { + public static class AllowAllConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public List getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new AllowAllConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "allow-all" }; + } + } + + public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() { - public boolean supportsTag(String name) + public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - return false; + AllowAll plugin = new AllowAll(config); + plugin.configure(); + return plugin; } - public ACLPlugin newInstance(Configuration config) + public String getPluginName() { - return new AllowAll(); + return AllowAll.class.getName(); } - }; - public String getPluginName() - { - return this.getClass().getSimpleName(); + public Class getPluginClass() + { + return AllowAll.class; + } + }; + + @Override + public Result getDefault() + { + return Result.ALLOWED; } - @Override - protected AuthzResult getResult() + public AllowAll(ConfigurationPlugin config) { - // Always allow - return AuthzResult.ALLOWED; + _config = config.getConfiguration(AllowAllConfiguration.class); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java deleted file mode 100644 index d0df354d78..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public abstract class BasicACLPlugin implements ACLPlugin -{ - - // Returns true or false if the plugin should authorise or deny the request - protected abstract AuthzResult getResult(); - - public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, - AMQQueue queue, AMQShortString routingKey) - { - return getResult(); - } - - public AuthzResult authoriseConnect(PrincipalHolder session, - VirtualHost virtualHost) - { - return getResult(); - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, - AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseConsume(PrincipalHolder session, - boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, - AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseCreateExchange(PrincipalHolder session, - boolean autoDelete, boolean durable, AMQShortString exchangeName, - boolean internal, boolean nowait, boolean passive, - AMQShortString exchangeType) - { - return getResult(); - } - - public AuthzResult authoriseCreateQueue(PrincipalHolder session, - boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue) - { - return getResult(); - } - - public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) - { - return getResult(); - } - - public AuthzResult authorisePublish(PrincipalHolder session, - boolean immediate, boolean mandatory, AMQShortString routingKey, - Exchange e) - { - return getResult(); - } - - public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, - AMQShortString routingKey, AMQQueue queue) - { - return getResult(); - } - - public void setConfiguration(Configuration config) - { - // no-op - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java new file mode 100644 index 0000000000..5fc1ef7795 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.security.AbstractPlugin; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPlugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This {@link SecurityPlugin} simply abstains from all authorisation requests and ignores configuration. + */ +public class BasicPlugin extends AbstractPlugin +{ + public Result access(ObjectType objectType, Object instance) + { + return getDefault(); + } + + public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) + { + return getDefault(); + } + + @Override + public void configure() throws ConfigurationException + { + // Not used + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 77d3c4bcdf..24af215a0c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -15,61 +15,72 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * */ package org.apache.qpid.server.security.access.plugins; +import java.util.Arrays; +import java.util.List; + import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Permission; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPluginFactory; -public class DenyAll extends BasicACLPlugin +/** Always Deny. */ +public class DenyAll extends BasicPlugin { - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) + public static class DenyAllConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() { - return false; - } + public List getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } - public ACLPlugin newInstance(Configuration config) + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new DenyAllConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() { - return new DenyAll(); + return new String[] { "deny-all" }; } - }; + } - public AccessResult authorise(AMQProtocolSession session, - Permission permission, AMQMethodBody body, Object... parameters) - throws AMQConnectionException + public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() { + public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException + { + DenyAll plugin = new DenyAll(config); + plugin.configure(); + return plugin; + } - if (ACLManager.getLogger().isInfoEnabled()) + public String getPluginName() { - ACLManager.getLogger().info( - "Denying user:" + session.getPrincipal()); + return DenyAll.class.getName(); } - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, - "DenyAll Plugin"); - } - public String getPluginName() - { - return getClass().getSimpleName(); + public Class getPluginClass() + { + return DenyAll.class; + } + }; + + @Override + public Result getDefault() + { + return Result.DENIED; } - @Override - protected AuthzResult getResult() + public DenyAll(ConfigurationPlugin config) throws ConfigurationException { - // Always deny - return AuthzResult.DENIED; + _config = config.getConfiguration(DenyAllConfiguration.class); } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java new file mode 100644 index 0000000000..2c0994b52a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.plugins; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.SecurityPluginFactory; + +/** Always Abstain. */ +public class LegacyAccess extends BasicPlugin +{ + public static class LegacyAccessConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public List getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } + + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new LegacyAccessConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "principal-databases", "access", "msg-auth", "false", "jmx" }; + } + } + + public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() + { + public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException + { + LegacyAccess plugin = new LegacyAccess(config); + plugin.configure(); + return plugin; + } + + public String getPluginName() + { + return LegacyAccess.class.getName(); + } + + public Class getPluginClass() + { + return LegacyAccess.class; + } + }; + + public LegacyAccess(ConfigurationPlugin config) throws ConfigurationException + { + _config = config.getConfiguration(LegacyAccessConfiguration.class); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java deleted file mode 100644 index fc1bc048d4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.access.plugins; - -import java.util.Collection; -import java.util.HashSet; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -/** - * - * Used to suppress warnings in legacy config files that have things in which aren't handled by a plugin directly. - * - */ -public class LegacyAccessPlugin extends BasicACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - private Collection maskedTags = new HashSet(); - { - maskedTags.add("principal-databases"); - maskedTags.add("access"); - maskedTags.add("msg-auth"); - maskedTags.add("false"); - maskedTags.add("jmx"); - } - - public boolean supportsTag(String name) - { - return maskedTags .contains(name); - } - - public ACLPlugin newInstance(Configuration config) - { - return new LegacyAccessPlugin(); - } - }; - - public String getPluginName() - { - return getClass().getSimpleName(); - } - - @Override - protected AuthzResult getResult() - { - // Always abstain - return AuthzResult.ABSTAIN; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java index 3f846b9dd0..62967ef7eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.security.auth; -import javax.security.sasl.SaslException; - public class AuthenticationResult { public enum AuthenticationStatus diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 889ce815f4..6ca9c8e762 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -21,7 +21,7 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 2619a69cfd..5cebb7d2d8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -38,7 +38,7 @@ import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; import org.apache.qpid.AMQException; import javax.management.JMException; @@ -51,7 +51,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception { - _logger.info("Initialising PrincipleDatabase authentication manager"); + _logger.info("Initialising PrincipalDatabase authentication manager"); _databases = initialisePrincipalDatabases(_configuration); } @@ -171,16 +171,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); List principalDBs = config.getManagementPrincipalDBs(); - - if (principalDBs.size() == 0) + if (principalDBs.isEmpty()) { throw new ConfigurationException("No principal-database specified for jmx security"); } String databaseName = principalDBs.get(0); - PrincipalDatabase database = getDatabases().get(databaseName); - if (database == null) { throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); @@ -189,14 +186,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab _mbean.setPrincipalDatabase(database); List jmxaccesslist = config.getManagementAccessList(); - - if (jmxaccesslist.size() == 0) + if (jmxaccesslist.isEmpty()) { throw new ConfigurationException("No access control files specified for jmx security"); } String jmxaccesssFile = null; - + try { jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); @@ -205,7 +201,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); } - + try { _mbean.setAccessFile(jmxaccesssFile); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java new file mode 100644 index 0000000000..153b8c25db --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -0,0 +1,539 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.management; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Principal; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; +import javax.security.auth.login.AccountNotFoundException; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ +@MBeanDescription("User Management Interface") +public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement +{ + private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + + private PrincipalDatabase _principalDatabase; + private Properties _accessRights; + private File _accessFile; + + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); + + // Setup for the TabularType + static TabularType _userlistDataType; // Datatype for representing User Lists + static CompositeType _userDataType; // Composite type for representing User + + static + { + OpenType[] userItemTypes = new OpenType[4]; // User item types. + userItemTypes[0] = SimpleType.STRING; // For Username + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + + try + { + _userDataType = + new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, userItemTypes); + + _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing users incorrect."); + _userlistDataType = null; + } + } + + + public AMQUserManagementMBean() throws JMException + { + super(UserManagement.class, UserManagement.TYPE); + } + + public String getObjectInstanceName() + { + return UserManagement.TYPE; + } + + public boolean setPassword(String username, String password) + { + return setPassword(username, password.toCharArray()); + } + + public boolean setPassword(String username, char[] password) + { + try + { + //delegate password changes to the Principal Database + return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + return false; + } + } + + public boolean setRights(String username, boolean read, boolean write, boolean admin) + { + + Object oldRights = null; + if ((oldRights =_accessRights.get(username)) == null) + { + // If the user doesn't exist in the access rights file check that they at least have an account. + if (_principalDatabase.getUser(username) == null) + { + return false; + } + } + + try + { + _accessRightsUpdate.lock(); + + // Update the access rights + if (admin) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); + } + else + { + if (read | write) + { + if (read) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); + } + if (write) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); + } + } + else + { + _accessRights.remove(username); + } + } + + //save the rights file + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); + + //the rights file was not successfully saved, restore user rights to previous value + _logger.warn("Reverting attempted rights update for user'" + username + "'"); + if (oldRights != null) + { + _accessRights.put(username, oldRights); + } + else + { + _accessRights.remove(username); + } + + return false; + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + return true; + } + + public boolean createUser(String username, String password, boolean read, boolean write, boolean admin) + { + return createUser(username, password.toCharArray(), read, write, admin); + } + + public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) + { + if (!setRights(username, read, write, admin)) + { + //unable to set rights for user, remove account + try + { + _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); + } + catch (AccountNotFoundException e) + { + //ignore + } + return false; + } + else + { + return true; + } + } + + return false; + } + + public boolean deleteUser(String username) + { + try + { + if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) + { + try + { + _accessRightsUpdate.lock(); + + _accessRights.remove(username); + + try + { + saveAccessFile(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); + return false; + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + return false; + } + + return true; + } + + public boolean reloadData() + { + try + { + loadAccessFile(); + _principalDatabase.reload(); + } + catch (ConfigurationException e) + { + _logger.warn("Reload failed due to:" + e); + return false; + } + catch (IOException e) + { + _logger.warn("Reload failed due to:" + e); + return false; + } + // Reload successful + return true; + } + + + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + public TabularData viewUsers() + { + // Table of users + // Username(string), Access rights Read,Write,Admin(bool,bool,bool) + + if (_userlistDataType == null) + { + _logger.warn("TabluarData not setup correctly"); + return null; + } + + List users = _principalDatabase.getUsers(); + + TabularDataSupport userList = new TabularDataSupport(_userlistDataType); + + try + { + // Create the tabular list of message header contents + for (Principal user : users) + { + // Create header attributes list + + String rights = (String) _accessRights.get(user.getName()); + + Boolean read = false; + Boolean write = false; + Boolean admin = false; + + if (rights != null) + { + read = rights.equals(MBeanInvocationHandlerImpl.READONLY) + || rights.equals(MBeanInvocationHandlerImpl.READWRITE); + write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); + admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); + } + + Object[] itemData = {user.getName(), read, write, admin}; + CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES, itemData); + userList.put(messageData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create user list due to :" + e); + return null; + } + + return userList; + } + + /*** Broker Methods **/ + + /** + * setPrincipalDatabase + * + * @param database set The Database to use for user lookup + */ + public void setPrincipalDatabase(PrincipalDatabase database) + { + _principalDatabase = database; + } + + /** + * setAccessFile + * + * @param accessFile the file to use for updating. + * + * @throws java.io.IOException If the file cannot be accessed + * @throws org.apache.commons.configuration.ConfigurationException + * if checks on the file fail. + */ + public void setAccessFile(String accessFile) throws IOException, ConfigurationException + { + if (accessFile != null) + { + _accessFile = new File(accessFile); + if (!_accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFile + "' does not exist"); + } + + if (!_accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFile + "'."); + } + + if (!_accessFile.canWrite()) + { + _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); + } + + loadAccessFile(); + } + else + { + _logger.warn("Access rights file specified is null. Access rights not changed."); + } + } + + private void loadAccessFile() throws IOException, ConfigurationException + { + if(_accessFile == null) + { + _logger.error("No jmx access rights file has been specified."); + return; + } + + if(_accessFile.exists()) + { + try + { + _accessRightsUpdate.lock(); + + Properties accessRights = new Properties(); + accessRights.load(new FileInputStream(_accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + else + { + _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); + } + } + + private void checkAccessRights(Properties accessRights) + { + Enumeration values = accessRights.propertyNames(); + + while (values.hasMoreElements()) + { + String user = (String) values.nextElement(); + + if (_principalDatabase.getUser(user) == null) + { + _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); + } + } + } + + private void saveAccessFile() throws IOException + { + try + { + _accessRightsUpdate.lock(); + + // Create temporary file + Random r = new Random(); + File tmp; + do + { + tmp = new File(_accessFile.getPath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + + tmp.deleteOnExit(); + + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); + output.close(); + + // Swap temp file to main rights file. + File old = new File(_accessFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + if(!_accessFile.renameTo(old)) + { + //unable to rename the existing file to the backup name + _logger.error("Could not backup the existing management rights file"); + throw new IOException("Could not backup the existing management rights file"); + } + + if(!tmp.renameTo(_accessFile)) + { + //failed to rename the new file to the required filename + + if(!old.renameTo(_accessFile)) + { + //unable to return the backup to required filename + _logger.error("Could not rename the new management rights file into place, and unable to restore original file"); + throw new IOException("Could not rename the new management rights file into place, and unable to restore original file"); + } + + _logger.error("Could not rename the new management rights file into place"); + throw new IOException("Could not rename the new management rights file into place"); + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + } + + private String getCurrentJMXUser() + { + AccessControlContext acc = AccessController.getContext(); + + Subject subject = Subject.getSubject(acc); + if (subject == null) + { + return "Unknown user, authentication Subject was null"; + } + + // Retrieve JMXPrincipal from Subject + Set principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + return "Unknown user principals were null"; + } + + Principal principal = principals.iterator().next(); + return principal.getName(); + } + + /** + * user=read user=write user=readwrite user=admin + * + * @param accessRights The properties list of access rights to process + */ + private void setAccessRights(Properties accessRights) + { + _logger.debug("Setting Access Rights:" + accessRights); + _accessRights = accessRights; + + // TODO check where this is used + // MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index d34d0c4d27..bc771162fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.manager; -import org.apache.qpid.common.Closeable; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.AuthenticationResult; - import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import org.apache.qpid.common.Closeable; +import org.apache.qpid.server.security.auth.AuthenticationResult; + public interface AuthenticationManager extends Closeable { String getMechanisms(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 98c060599a..2a967f02af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -64,7 +64,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception { _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") - + " PrincipleDatabase authentication manager."); + + " PrincipalDatabase authentication manager."); // Fixme This should be done per Vhost but allowing global hack isn't right but ... // required as authentication is done before Vhost selection diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java index 77040e896c..0cbbccb3b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -99,7 +99,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator } catch (AccountNotFoundException e) { - throw new SecurityException(INVALID_CREDENTIALS); + throw new SecurityException(INVALID_CREDENTIALS); // XXX } if (authenticated) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 6850724b10..6cc5e7b019 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -62,6 +62,7 @@ import org.apache.qpid.server.handler.TxCommitHandler; import org.apache.qpid.server.handler.TxRollbackHandler; import org.apache.qpid.server.handler.TxSelectHandler; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; /** @@ -258,6 +259,7 @@ public class AMQStateManager implements AMQMethodListener public AMQProtocolSession getProtocolSession() { + SecurityManager.setThreadPrincipal(_protocolSession.getPrincipal()); return _protocolSession; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java index 5badbad642..1bba2529c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java @@ -20,25 +20,17 @@ */ package org.apache.qpid.server.subscription; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactory; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; public class SubscriptionFactoryImpl implements SubscriptionFactory { - - /* private SubscriptionFactoryImpl() - { - - }*/ - public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal, FlowCreditManager creditManager) throws AMQException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index a56951cf5c..38040ecfce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.transport; import org.apache.qpid.transport.*; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -29,16 +30,13 @@ import javax.security.sasl.SaslServer; import javax.security.sasl.SaslException; import java.util.*; - public class ServerConnectionDelegate extends ServerDelegate { - private String _localFQDN; private final IApplicationRegistry _appRegistry; - public ServerConnectionDelegate(IApplicationRegistry appRegistry, - String localFQDN) + public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN) { this(new HashMap(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); } @@ -50,6 +48,7 @@ public class ServerConnectionDelegate extends ServerDelegate String localFQDN) { super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales); + _appRegistry = appRegistry; _localFQDN = localFQDN; } @@ -65,9 +64,9 @@ public class ServerConnectionDelegate extends ServerDelegate return list; } - @Override public ServerSession getSession(Connection conn, SessionAttach atc) + @Override + public ServerSession getSession(Connection conn, SessionAttach atc) { - SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry); ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0); @@ -75,9 +74,6 @@ public class ServerConnectionDelegate extends ServerDelegate return ssn; } - - - @Override protected SaslServer createSaslServer(String mechanism) throws SaslException { @@ -85,11 +81,10 @@ public class ServerConnectionDelegate extends ServerDelegate } - @Override public void connectionOpen(Connection conn, ConnectionOpen open) { ServerConnection sconn = (ServerConnection) conn; - + VirtualHost vhost; String vhostName; if(open.hasVirtualHost()) @@ -102,19 +97,27 @@ public class ServerConnectionDelegate extends ServerDelegate } vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName); + SecurityManager.setThreadPrincipal(conn.getAuthorizationID()); + if(vhost != null) { sconn.setVirtualHost(vhost); - sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); - - sconn.setState(Connection.State.OPEN); + if (!vhost.getSecurityManager().accessVirtualhost(vhostName, sconn.getConfig().getAddress())) + { + sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, "Permission denied '"+vhostName+"'")); + sconn.setState(Connection.State.CLOSING); + } + else + { + sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); + sconn.setState(Connection.State.OPEN); + } } else { - sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '" + vhostName + "'")); + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'")); sconn.setState(Connection.State.CLOSING); } - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 8a16867ad8..bc7ba085fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -157,7 +157,6 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo catch (AMQException e) { // TODO - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. throw new RuntimeException(e); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 541810d2fe..73ec7f1231 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -20,31 +20,78 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.transport.*; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.*; -import org.apache.qpid.server.queue.QueueRegistry; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeInUseException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.HeadersExchange; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.BaseQueue; -import org.apache.qpid.server.message.MessageTransferMessage; -import org.apache.qpid.server.message.MessageMetaData_0_10; -import org.apache.qpid.server.subscription.Subscription_0_10; -import org.apache.qpid.server.flow.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.store.DurableConfigurationStore; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.framing.*; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.nio.ByteBuffer; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Acquired; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.ExchangeBind; +import org.apache.qpid.transport.ExchangeBound; +import org.apache.qpid.transport.ExchangeBoundResult; +import org.apache.qpid.transport.ExchangeDeclare; +import org.apache.qpid.transport.ExchangeDelete; +import org.apache.qpid.transport.ExchangeQuery; +import org.apache.qpid.transport.ExchangeQueryResult; +import org.apache.qpid.transport.ExchangeUnbind; +import org.apache.qpid.transport.ExecutionErrorCode; +import org.apache.qpid.transport.ExecutionException; +import org.apache.qpid.transport.MessageAccept; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquire; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCancel; +import org.apache.qpid.transport.MessageFlow; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageFlush; +import org.apache.qpid.transport.MessageReject; +import org.apache.qpid.transport.MessageRejectCode; +import org.apache.qpid.transport.MessageRelease; +import org.apache.qpid.transport.MessageResume; +import org.apache.qpid.transport.MessageSetFlowMode; +import org.apache.qpid.transport.MessageStop; +import org.apache.qpid.transport.MessageSubscribe; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.QueueDeclare; +import org.apache.qpid.transport.QueueDelete; +import org.apache.qpid.transport.QueuePurge; +import org.apache.qpid.transport.QueueQuery; +import org.apache.qpid.transport.QueueQueryResult; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import org.apache.qpid.transport.TxCommit; +import org.apache.qpid.transport.TxRollback; +import org.apache.qpid.transport.TxSelect; public class ServerSessionDelegate extends SessionDelegate { @@ -58,6 +105,8 @@ public class ServerSessionDelegate extends SessionDelegate @Override public void command(Session session, Method method) { + SecurityManager.setThreadPrincipal(session.getConnection().getAuthorizationID()); + super.command(session, method); if (method.isSync()) { @@ -317,7 +366,6 @@ public class ServerSessionDelegate extends SessionDelegate catch (AMQException e) { //TODO - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. throw new RuntimeException(e); } } @@ -371,19 +419,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(), - method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(), - new AMQShortString(method.getType()))) - { - - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - String description = "permission denied: exchange-name '" + exchangeName + "'"; - - exception(session, method, errorCode, description); - - - } - else if(exchange == null) + if (exchange == null) { ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); @@ -417,12 +453,18 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType()); } + catch (AMQSecurityException e) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "Permission denied: exchange-name '" + exchangeName + "'"; + + exception(session, method, errorCode, description); + } catch (AMQException e) { //TODO throw new RuntimeException(e); } - } else { @@ -478,47 +520,38 @@ public class ServerSessionDelegate extends SessionDelegate VirtualHost virtualHost = getVirtualHost(session); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session, - exchangeRegistry.getExchange(method.getExchange()))) - { - exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); - - } - else + try { + Exchange exchange = getExchange(session, method.getExchange()); - try + if(exchange != null && exchange.hasReferrers()) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); + } + else { - Exchange exchange = getExchange(session, method.getExchange()); + exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); - if(exchange != null && exchange.hasReferrers()) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); - } - else + if (exchange.isDurable() && !exchange.isAutoDelete()) { - exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); - - if (exchange.isDurable() && !exchange.isAutoDelete()) - { - DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); - store.removeExchange(exchange); - } - + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeExchange(exchange); } } - catch (ExchangeInUseException e) - { - exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); - } - catch (AMQException e) - { - // TODO - throw new RuntimeException(e); - } } - + catch (ExchangeInUseException e) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); + } + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + method.getExchange()); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } @Override @@ -582,13 +615,6 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); } - else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange, - queue, new AMQShortString(method.getBindingKey()))) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() - + "' to Queue: '" + method.getQueue() - + "' not allowed"); - } else if(exchange.getTypeShortString().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) { exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); @@ -600,8 +626,15 @@ public class ServerSessionDelegate extends SessionDelegate if (!exchange.isBound(routingKey, fieldTable, queue)) { - virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); - + try + { + virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); + } + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() + + "' to Queue: '" + method.getQueue() + "' not allowed"); + } } else { @@ -649,7 +682,14 @@ public class ServerSessionDelegate extends SessionDelegate } else { - virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); + try + { + virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); + } + catch (AMQSecurityException e) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); + } } } @@ -768,25 +808,6 @@ public class ServerSessionDelegate extends SessionDelegate DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); String queueName = method.getQueue(); - - if (!method.getPassive()) - { - // Perform ACL if request is not passive - - if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(), - method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName))) - { - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - String description = "permission denied: queue-name '" + queueName + "'"; - - exception(session, method, errorCode, description); - - // TODO control flow - return; - } - } - - AMQQueue queue; QueueRegistry queueRegistry = getQueueRegistry(session); //TODO: do we need to check that the queue already exists with exactly the same "configuration"? @@ -879,34 +900,32 @@ public class ServerSessionDelegate extends SessionDelegate { final AMQQueue q = queue; final ServerSession.Task deleteQueueTask = new ServerSession.Task() - { - - public void doTask(ServerSession session) { - try + public void doTask(ServerSession session) { - q.delete(); + try + { + q.delete(); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } - catch (AMQException e) - { - throw new RuntimeException(e); - } - } - }; + }; final ServerSession s = (ServerSession) session; s.addSessionCloseTask(deleteQueueTask); queue.addQueueDeleteTask(new AMQQueue.Task() - { - - public void doTask(AMQQueue queue) throws AMQException { - s.removeSessionCloseTask(deleteQueueTask); - } - }); + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(deleteQueueTask); + } + }); } else if(method.getExclusive()) { - { final AMQQueue q = queue; final ServerSession.Task removeExclusive = new ServerSession.Task() { @@ -928,31 +947,34 @@ public class ServerSessionDelegate extends SessionDelegate } }); } - } + } + catch (AMQSecurityException e) + { + String description = "Cannot declare queue('" + queueName + "'), permission denied"; + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + exception(session, method, errorCode, description); } catch (AMQException e) { + // TODO throw new RuntimeException(e); } } } else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session))) { - String description = "Cannot declare queue('" + queueName + "')," + " as exclusive queue with same name " + "declared on another session"; ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED; - + exception(session, method, errorCode, description); - + return; } - } } - protected AMQQueue createQueue(final String queueName, QueueDeclare body, VirtualHost virtualHost, @@ -963,15 +985,14 @@ public class ServerSessionDelegate extends SessionDelegate String owner = body.getExclusive() ? session.getClientID() : null; - final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), body.getExclusive(), virtualHost, body.getArguments()); - if (body.getExclusive() && !body.getDurable()) { final ServerSession.Task deleteQueueTask = new ServerSession.Task() - { + { public void doTask(ServerSession session) { if (registry.getQueue(queueName) == queue) @@ -1006,7 +1027,6 @@ public class ServerSessionDelegate extends SessionDelegate @Override public void queueDelete(Session session, QueueDelete method) { - String queueName = method.getQueue(); if(queueName == null || queueName.length()==0) { @@ -1041,36 +1061,28 @@ public class ServerSessionDelegate extends SessionDelegate else { VirtualHost virtualHost = getVirtualHost(session); - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue)) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName); - } - else + + try { - try - { - int purged = queue.delete(); - if (queue.isDurable() && !queue.isAutoDelete()) - { - DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); - store.removeQueue(queue); - } - - } - catch (AMQException e) + queue.delete(); + if (queue.isDurable() && !queue.isAutoDelete()) { - //TODO - throw new RuntimeException(e); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeQueue(queue); } - } - + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } } } - } @Override @@ -1080,24 +1092,32 @@ public class ServerSessionDelegate extends SessionDelegate if(queueName == null || queueName.length()==0) { exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied"); - } else { AMQQueue queue = getQueue(session, queueName); - if (queue == null) { exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); } else { - //TODO - queue.clearQueue(); + try + { + queue.clearQueue(); + } + catch (AMQSecurityException e) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } } - } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 675a6f6a91..98d231a7ea 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -102,7 +102,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (q == null) { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, false, _virtualHost, arguments); _virtualHost.getQueueRegistry().registerQueue(q); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 44d178602f..d104209e98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -20,16 +20,25 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.management.NotCompliantMBeanException; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; @@ -58,29 +67,17 @@ 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.registry.IApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import javax.management.NotCompliantMBeanException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.TimerTask; -import java.util.UUID; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.FutureTask; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class VirtualHostImpl implements Accessable, VirtualHost +public class VirtualHostImpl implements VirtualHost { private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class); @@ -102,7 +99,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost private AuthenticationManager _authenticationManager; - private ACLManager _accessManager; + private SecurityManager _securityManager; private final ScheduledThreadPoolExecutor _houseKeepingTasks; private final IApplicationRegistry _appRegistry; @@ -117,17 +114,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost private final ConcurrentHashMap _links = new ConcurrentHashMap(); private static final int HOUSEKEEPING_SHUTDOWN_TIMEOUT = 5; - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - public IConnectionRegistry getConnectionRegistry() { return _connectionRegistry; @@ -140,7 +126,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost public UUID getId() { - return _id; //To change body of implemented methods use File | Settings | File Templates. + return _id; } public VirtualHostConfigType getConfigType() @@ -200,12 +186,17 @@ public class VirtualHostImpl implements Accessable, VirtualHost private VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig, MessageStore store) throws Exception { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + _appRegistry = appRegistry; - _broker = appRegistry.getBroker(); + _broker = _appRegistry.getBroker(); _configuration = hostConfig; - _name = hostConfig.getName(); + _name = _configuration.getName(); - _id = appRegistry.getConfigStore().createId(); + _id = _appRegistry.getConfigStore().createId(); CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); @@ -214,6 +205,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); } + _securityManager = new SecurityManager(_appRegistry.getSecurityManager()); + _securityManager.configureHostPlugins(_configuration); + _virtualHostMBean = new VirtualHostMBean(); _connectionRegistry = new ConnectionRegistry(); @@ -223,15 +217,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); + _exchangeFactory.initialise(_configuration); _exchangeRegistry = new DefaultExchangeRegistry(this); - - //Create a temporary RT to store the durable entries from the config file - // so we can replay them in to the real _RT after it has been loaded. - /// This should be removed after the _RT has been fully split from the the TL - StartupRoutingTable configFileRT = new StartupRoutingTable(); _durableConfigurationStore = configFileRT; @@ -241,7 +230,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _bindingFactory = new BindingFactory(this); - initialiseModel(hostConfig); + initialiseModel(_configuration); if (store != null) { @@ -250,36 +239,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost } else { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - - - //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config - // file and write them in to the new routing Table. -/* for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) - { - getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); + initialiseMessageStore(hostConfig); } - - for (Exchange exchange : configFileRT.exchange) - { - getDurableConfigurationStore().createExchange(exchange); - } - - for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) - { - getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - }*/ - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); - - _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, _configuration); _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); @@ -330,8 +293,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost } Map plugins = - ApplicationRegistry.getInstance(). - getPluginManager().getVirtualHostPlugins(); + ApplicationRegistry.getInstance().getPluginManager().getVirtualHostPlugins(); if (plugins != null) { @@ -340,24 +302,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost try { VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); - - TimeUnit units = TimeUnit.MILLISECONDS; - - if (plugin.getTimeUnit() != null) - { - try - { - units = TimeUnit.valueOf(plugin.getTimeUnit()); - } - catch (IllegalArgumentException iae) - { - _logger.warn("Plugin:" + pluginName + - " provided an illegal TimeUnit value:" - + plugin.getTimeUnit()); - // Warn and use default of millseconds - // Should not occur in a well behaved plugin - } - } _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, plugin.getDelay(), plugin.getTimeUnit()); @@ -600,9 +544,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _authenticationManager; } - public ACLManager getAccessManager() + public SecurityManager getSecurityManager() { - return _accessManager; + return _securityManager; } public void close() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java index 59ab7ec673..26eb5bbd7f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.virtualhost.plugins; +import java.util.concurrent.TimeUnit; + import org.apache.qpid.server.plugins.Plugin; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -39,5 +41,5 @@ public interface VirtualHostPlugin extends Runnable, Plugin * @see java.util.concurrent.TimeUnit for valid value. * @return */ - public String getTimeUnit(); + public TimeUnit getTimeUnit(); } -- cgit v1.2.1 From 4733fe031d102470c81a36a99781a177cba30b68 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:05:55 +0000 Subject: QPID-2569: Implement the SimpleXML as an OSGi plugin Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949784 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissions.java | 673 --------------------- .../server/security/access/plugins/SimpleXML.java | 483 --------------- 2 files changed, 1156 deletions(-) delete mode 100755 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java deleted file mode 100755 index e7fc8effaf..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ /dev/null @@ -1,673 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; - -public class PrincipalPermissions -{ - - private static final Object CONSUME_QUEUES_KEY = new Object(); - private static final Object CONSUME_TEMPORARY_KEY = new Object(); - private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object(); - - private static final Object CREATE_QUEUES_KEY = new Object(); - private static final Object CREATE_EXCHANGES_KEY = new Object(); - - - private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); - private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); - private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); - - private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); - - private static final int PUBLISH_EXCHANGES_KEY = 0; - - private Map _permissions; - private boolean _fullVHostAccess = false; - - private String _user; - - - public PrincipalPermissions(String user) - { - _user = user; - _permissions = new ConcurrentHashMap(); - } - - /** - * - * @param permission the type of permission to check - * - * @param parameters vararg depending on what permission was passed in - * ACCESS: none - * BIND: none - * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly - * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey - * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class - * DELETE: none - * PUBLISH: Exchange exchange, AMQShortString routingKey - * PURGE: none - * UNBIND: none - */ - public void grant(Permission permission, Object... parameters) - { - switch (permission) - { - case ACCESS:// Parameters : None - grantAccess(permission); - break; - case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly - grantConsume(permission, parameters); - break; - case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName - // , AMQShortString exchangeName , AMQShortString routingKey - grantCreateQueue(permission, parameters); - break; - case CREATEEXCHANGE: - // Parameters AMQShortString exchangeName , AMQShortString Class - grantCreateExchange(permission, parameters); - break; - case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - grantPublish(permission, parameters); - break; - /* The other cases just fall through to no-op */ - case DELETE: - case BIND: // All the details are currently included in the create setup. - case PURGE: - case UNBIND: - break; - } - - } - - private void grantAccess(Permission permission) - { - _fullVHostAccess = true; - } - - private void grantPublish(Permission permission, Object... parameters) { - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - publishRights = new ConcurrentHashMap(); - _permissions.put(permission, publishRights); - } - - if (parameters == null || parameters.length == 0) - { - //If we have no parameters then allow publish to all destinations - // this is signified by having a null value for publish_exchanges - } - else - { - Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - if (publish_exchanges == null) - { - publish_exchanges = new ConcurrentHashMap(); - publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); - } - - - HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); - - // Check to see if we have a routing key - if (parameters.length == 2) - { - if (routingKeys == null) - { - routingKeys = new HashSet(); - } - //Add routing key to permitted publish destinations - routingKeys.add(parameters[1]); - } - - // Add the updated routingkey list or null if all values allowed - publish_exchanges.put(parameters[0], routingKeys); - } - } - - private void grantCreateExchange(Permission permission, Object... parameters) { - Map rights = (Map) _permissions.get(permission); - if (rights == null) - { - rights = new ConcurrentHashMap(); - _permissions.put(permission, rights); - } - - Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); - if (create_exchanges == null) - { - create_exchanges = new ConcurrentHashMap(); - rights.put(CREATE_EXCHANGES_KEY, create_exchanges); - } - - //Should perhaps error if parameters[0] is null; - AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; - AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); - - //Store the exchangeName / class mapping if the mapping is null - rights.put(name, className); - } - - private void grantCreateQueue(Permission permission, Object... parameters) - { - Map createRights = (Map) _permissions.get(permission); - - if (createRights == null) - { - createRights = new ConcurrentHashMap(); - _permissions.put(permission, createRights); - } - - //The existence of the empty map mean permission to all. - if (parameters.length == 0) - { - return; - } - - // Get the queues map - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - //Initialiase the queue permissions if not already done - if (create_queues == null) - { - create_queues = new ConcurrentHashMap(); - //initialise temp queue permission to false and overwrite below if true - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, false); - createRights.put(CREATE_QUEUES_KEY, create_queues); - } - - //Create empty list of queues - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - if (create_queues_queues == null) - { - create_queues_queues = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); - } - - // If we are initialising and granting CREATE rights to all temporary queues, then that's all we do - Boolean temporary = false; - if (parameters.length == 1) - { - temporary = (Boolean) parameters[0]; - create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); - return; - } - - //From here we can be permissioning a variety of things, with varying parameters - AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; - AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; - //Set the routingkey to the specified value or the queueName if present - AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; - // if we have a queueName then we need to store any associated exchange / rk bindings - if (queueName != null) - { - Map queue = (Map) create_queues_queues.get(queueName); - if (queue == null) - { - queue = new ConcurrentHashMap(); - create_queues_queues.put(queueName, queue); - } - - if (exchangeName != null) - { - queue.put(exchangeName, routingKey); - } - - //If no exchange is specified then the presence of the queueName in the map says any exchange is ok - } - - // Store the exchange that we are being granted rights to. This will be used as part of binding - - //Lookup the list of exchanges - Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); - - if (create_queues_exchanges == null) - { - create_queues_exchanges = new ConcurrentHashMap(); - create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); - } - - //if we have an exchange - if (exchangeName != null) - { - //Retrieve the list of permitted exchanges. - Map exchanges = (Map) create_queues_exchanges.get(exchangeName); - - if (exchanges == null) - { - exchanges = new ConcurrentHashMap(); - create_queues_exchanges.put(exchangeName, exchanges); - } - - //Store the binding details of queue/rk for this exchange. - if (queueName != null) - { - //Retrieve the list of permitted routingKeys. - Map rKeys = (Map) exchanges.get(exchangeName); - - if (rKeys == null) - { - rKeys = new ConcurrentHashMap(); - exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); - } - - rKeys.put(queueName, routingKey); - } - } - } - - /** - * Grant consume permissions - */ - private void grantConsume(Permission permission, Object... parameters) - { - Map consumeRights = (Map) _permissions.get(permission); - - if (consumeRights == null) - { - consumeRights = new ConcurrentHashMap(); - _permissions.put(permission, consumeRights); - - //initialise own and temporary rights to false to be overwritten below if set - consumeRights.put(CONSUME_TEMPORARY_KEY, false); - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); - } - - - //if we only have one param then we're permissioning temporary queues and topics - if (parameters.length == 1) - { - Boolean temporary = (Boolean) parameters[0]; - - if (temporary) - { - consumeRights.put(CONSUME_TEMPORARY_KEY, true); - } - } - - //if we have 2 parameters - should be a contract for this, but for now we'll handle it as is - if (parameters.length == 2) - { - AMQShortString queueName = (AMQShortString) parameters[0]; - Boolean ownQueueOnly = (Boolean) parameters[1]; - - if (ownQueueOnly) - { - consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); - } - - LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); - if (queues == null) - { - queues = new LinkedList(); - consumeRights.put(CONSUME_QUEUES_KEY, queues); - } - - if (queueName != null) - { - queues.add(queueName); - } - } - } - - /** - * - * @param permission the type of permission to check - * - * @param parameters vararg depending on what permission was passed in - * ACCESS: none - * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey - * CONSUME: AMQQueue queue - * CREATEQUEUE: Boolean autodelete, AMQShortString name - * CREATEEXCHANGE: AMQShortString exchangeName - * DELETE: none - * PUBLISH: Exchange exchange, AMQShortString routingKey - * PURGE: none - * UNBIND: none - */ - public AuthzResult authorise(Permission permission, Object... parameters) - { - - switch (permission) - { - case ACCESS://No Parameters - return AuthzResult.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised - case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey - return authoriseBind(parameters); - case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name - return authoriseCreateQueue(permission, parameters); - case CREATEEXCHANGE: - return authoriseCreateExchange(permission, parameters); - case CONSUME: // Parameters : AMQQueue - return authoriseConsume(permission, parameters); - case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey - return authorisePublish(permission, parameters); - /* Fall through */ - case DELETE: - case PURGE: - case UNBIND: - default: - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - else - { - //SimpleXML ACL does not implement these permissions and should abstain - return AuthzResult.ABSTAIN; - } - } - - } - - private AuthzResult authoriseConsume(Permission permission, Object... parameters) - { - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - - if (parameters.length == 1 && parameters[0] instanceof AMQQueue) - { - AMQQueue queue = ((AMQQueue) parameters[0]); - Map queuePermissions = (Map) _permissions.get(permission); - - if (queuePermissions == null) - { - //we have a problem - we've never granted this type of permission ..... - return AuthzResult.DENIED; - } - - List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); - - Boolean temporaryQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); - Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); - - - // If user is allowed to consume from temporary queues and this is a temp queue then allow it. - if (temporaryQueues && queue.isAutoDelete()) - { - // This will allow consumption from any temporary queue including ones not owned by this user. - // Of course the exclusivity will not be broken. - { - - // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - //if this is a temporary queue and the user does not have permissions for temporary queues then deny - else if (!temporaryQueues && queue.isAutoDelete()) - { - return AuthzResult.DENIED; - } - - // if queues are white listed then ensure it is ok - if (queues != null) - { - // if no queues are listed then ALL are ok othereise it must be specified. - if (ownQueuesOnly) - { - if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) - { - return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - return AuthzResult.DENIED; - } - } - - // If we are - return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - - // Can't authenticate without the right parameters - return AuthzResult.DENIED; - } - - private AuthzResult authorisePublish(Permission permission, Object... parameters) - { - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - - Map publishRights = (Map) _permissions.get(permission); - - if (publishRights == null) - { - return AuthzResult.DENIED; - } - - Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); - - // Having no exchanges listed gives full publish rights to all exchanges - if (exchanges == null) - { - return AuthzResult.ALLOWED; - } - // Otherwise exchange must be listed in the white list - - // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(((Exchange) parameters[0]).getNameShortString())) - { - return AuthzResult.DENIED; - } - else - { - - // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getNameShortString()); - - // Having no routingKeys in the map then all are allowed. - if (routingKeys == null) - { - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = routingKeys.iterator(); - - - AMQShortString publishRKey = (AMQShortString)parameters[1]; - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - - if (rkey.endsWith("*")) - { - matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); - } - else - { - matched = publishRKey.equals(rkey); - } - } - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - } - } - - private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters) - { - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - - Map rights = (Map) _permissions.get(permission); - - AMQShortString exchangeName = (AMQShortString) parameters[0]; - - // If the exchange list is doesn't exist then all is allowed else - // check the valid exchanges - if (rights == null || rights.containsKey(exchangeName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } - } - - private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters) - { - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - - Map createRights = (Map) _permissions.get(permission); - - // If there are no create rights then deny request - if (createRights == null) - { - return AuthzResult.DENIED; - } - - //Look up the Queue Creation Rights - Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues allowed to be created - Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); - - - AMQShortString queueName = (AMQShortString) parameters[1]; - Boolean autoDelete = (Boolean) parameters[0]; - - if (autoDelete)// we have a temporary queue - { - return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - else - { - // If there is a white list then check - if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) - { - return AuthzResult.ALLOWED; - } - else - { - return AuthzResult.DENIED; - } - - } - } - - private AuthzResult authoriseBind(Object... parameters) - { - if(_fullVHostAccess) - { - //user has been granted full access to the vhost - return AuthzResult.ALLOWED; - } - - Exchange exchange = (Exchange) parameters[1]; - - AMQQueue bind_queueName = (AMQQueue) parameters[2]; - AMQShortString routingKey = (AMQShortString) parameters[3]; - - //Get all Create Rights for this user - Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); - - //Look up the Queue Creation Rights - Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY); - - //Lookup the list of queues - Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); - - // Check and see if we have a queue white list to check - if (bind_create_queues_queues != null) - { - //There a white list for queues - Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); - - if (exchangeDetails == null) //Then all queue can be bound to all exchanges. - { - return AuthzResult.ALLOWED; - } - - // Check to see if we have a white list of routingkeys to check - Map rkeys = (Map) exchangeDetails.get(exchange.getNameShortString()); - - // if keys is null then any rkey is allowed on this exchange - if (rkeys == null) - { - // There is no routingkey white list - return AuthzResult.ALLOWED; - } - else - { - // We have routingKeys so a match must be found to allowed binding - Iterator keys = rkeys.keySet().iterator(); - - boolean matched = false; - while (keys.hasNext() && !matched) - { - AMQShortString rkey = (AMQShortString) keys.next(); - if (rkey.endsWith("*")) - { - matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); - } - else - { - matched = routingKey.equals(rkey); - } - } - - - return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - } - - - } - else - { - //no white list so all allowed. - return AuthzResult.ALLOWED; - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java deleted file mode 100644 index a5bdf662af..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.framing.AMQShortString; - -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.security.access.PrincipalPermissions; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * This uses the default - */ -public class SimpleXML implements ACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return name.startsWith("access_control_list"); - } - - public ACLPlugin newInstance(Configuration config) - { - SimpleXML plugin = new SimpleXML(); - plugin.setConfiguration(config); - return plugin; - } - }; - - private Map _users; - private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); - - public SimpleXML() - { - _users = new ConcurrentHashMap(); - } - - public void setConfiguration(Configuration config) - { - processConfig(config); - } - - private void processConfig(Configuration config) - { - processPublish(config); - - processConsume(config); - - processCreate(config); - - processAccess(config); - } - - private void processAccess(Configuration config) - { - Configuration accessConfig = config.subset("access_control_list.access"); - - if(accessConfig.isEmpty()) - { - //there is no access configuration to process - return; - } - - // Process users that have full access permission - String[] users = accessConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.ACCESS, user); - } - } - - /** - * Publish format takes Exchange + Routing Key Pairs - * - * @param config - * XML Configuration - */ - private void processPublish(Configuration config) - { - Configuration publishConfig = config.subset("access_control_list.publish"); - - // Process users that have full publish permission - String[] users = publishConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.PUBLISH, user); - } - - // Process exchange limited users - int exchangeCount = 0; - Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - // Get Exchange Name - AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); - - // Get Routing Keys - int keyCount = 0; - Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); - - while (!routingkeyConfig.isEmpty()) - { - // Get RoutingKey Value - AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); - - // Apply Exchange + RoutingKey permissions to Users - users = routingkeyConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); - } - - // Apply permissions to Groups - - // Check for more configs - keyCount++; - routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); - } - - // Apply Exchange wide permissions to Users - users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); - - for (String user : users) - { - grant(Permission.PUBLISH, user, exchangeName); - } - - // Apply permissions to Groups - exchangeCount++; - exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - } - - private void grant(Permission permission, String user, Object... parameters) - { - PrincipalPermissions permissions = _users.get(user); - - if (permissions == null) - { - permissions = new PrincipalPermissions(user); - } - - _users.put(user, permissions); - permissions.grant(permission, parameters); - } - - private void processConsume(Configuration config) - { - boolean temporary = false; - Configuration tempConfig = null; - Configuration consumeConfig = config.subset("access_control_list.consume"); - - tempConfig = consumeConfig.subset("queues.temporary(0)"); - if (tempConfig != null) - { - temporary = true; - } - - //Permission all users who have rights to temp queues and topics - if (tempConfig != null && !tempConfig.isEmpty()) - { - String[] tempUsers = tempConfig.getStringArray("users.user"); - for (String user : tempUsers) - { - grant(Permission.CONSUME, user, temporary); - } - } - - // Process queue limited users - int queueCount = 0; - Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); - - while (!queueConfig.isEmpty()) - { - // Get queue Name - AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); - // if there is no name then there may be a temporary element - - boolean ownQueues = queueConfig.containsKey("own_queues"); - - // Process permissions for this queue - String[] users = queueConfig.getStringArray("users.user"); - for (String user : users) - { - grant(Permission.CONSUME, user, queueName, ownQueues); - } - - // See if we have another config - queueCount++; - queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); - } - - // Process users that have full consume permission - String[] users = consumeConfig.getStringArray("users.user"); - - for (String user : users) - { - //NOTE: this call does not appear to do anything inside the grant section for consume - grant(Permission.CONSUME, user); - } - } - - private void processCreate(Configuration config) - { - boolean temporary = false; - Configuration tempConfig = null; - - Configuration createConfig = config.subset("access_control_list.create"); - - tempConfig = createConfig.subset("queues.temporary(0)"); - if (tempConfig != null) - { - temporary = true; - } - - //Permission all users who have rights to temp queues and topics - if (tempConfig != null && !tempConfig.isEmpty()) - { - String[] tempUsers = tempConfig.getStringArray("users.user"); - for (String user : tempUsers) - { - grant(Permission.CREATEQUEUE, user, temporary); - } - } - // Process create permissions for queue creation - int queueCount = 0; - Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); - - while (!queueConfig.isEmpty()) - { - // Get queue Name - AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); - - int exchangeCount = 0; - Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - - AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); - AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); - - // Process permissions for this queue - String[] users = exchangeConfig.getStringArray("users.user"); - for (String user : users) - { - //This is broken as the user name is not stored - grant(Permission.CREATEEXCHANGE, user, exchange); - - //This call could be cleaned up as temporary is now being set earlier (above) - grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange - .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); - } - - // See if we have another config - exchangeCount++; - exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - - // Process users that are not bound to an exchange - String[] users = queueConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.CREATEQUEUE, user, temporary, queueName); - } - - // See if we have another config - queueCount++; - queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); - } - - // Process create permissions for exchange creation - int exchangeCount = 0; - Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - - while (!exchangeConfig.isEmpty()) - { - AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); - AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); - - // Process permissions for this queue - String[] users = exchangeConfig.getStringArray("users.user"); - for (String user : users) - { - //And this is broken too - grant(Permission.CREATEEXCHANGE, user, exchange, clazz); - } - - // See if we have another config - exchangeCount++; - exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); - } - - // Process users that have full create permission - String[] users = createConfig.getStringArray("users.user"); - - for (String user : users) - { - grant(Permission.CREATEEXCHANGE, user); - grant(Permission.CREATEQUEUE, user); - } - - } - - public String getPluginName() - { - return "Simple"; - } - - public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.BIND, null, exch, queue, routingKey); - } - } - - public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.ACCESS); - } - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CONSUME, queue); - } - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue) - { - return authoriseConsume(session, noAck, queue); - } - - public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CREATEEXCHANGE, exchangeName); - } - } - - public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.CREATEQUEUE, autoDelete, queue); - } - } - - public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.DELETE); - } - } - - public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.DELETE); - } - } - - public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.PUBLISH, e, routingKey); - } - } - - public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.PURGE); - } - } - - public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) - { - PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); - if (principalPermissions == null) - { - return AuthzResult.DENIED; - } - else - { - return principalPermissions.authorise(Permission.UNBIND); - } - } - -} -- cgit v1.2.1 From 3ac84aee977316f3cd0d9328d0a3a19654bc1181 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:07:01 +0000 Subject: QPID-2573: Implement the Firewall functionality as an OSGi plugin Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949785 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/plugins/network/FirewallPlugin.java | 256 --------------------- 1 file changed, 256 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java deleted file mode 100644 index 17d80c63fa..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins.network; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Pattern; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.util.NetMatcher; - -public class FirewallPlugin extends AbstractACLPlugin -{ - - public class FirewallPluginException extends Exception {} - - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) - { - return name.startsWith("firewall"); - } - - public ACLPlugin newInstance(Configuration config) throws ConfigurationException - { - FirewallPlugin plugin = new FirewallPlugin(); - plugin.setConfiguration(config.subset("firewall")); - return plugin; - } - }; - - public class FirewallRule - { - - private static final long DNS_TIMEOUT = 30000; - private AuthzResult _access; - private NetMatcher _network; - private Pattern[] _hostnamePatterns; - - public FirewallRule(String access, List networks, List hostnames) - { - _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - - if (networks != null && networks.size() > 0) - { - String[] networkStrings = objListToStringArray(networks); - _network = new NetMatcher(networkStrings); - } - - if (hostnames != null && hostnames.size() > 0) - { - int i = 0; - _hostnamePatterns = new Pattern[hostnames.size()]; - for (String hostname : objListToStringArray(hostnames)) - { - _hostnamePatterns[i++] = Pattern.compile(hostname); - } - } - - } - - private String[] objListToStringArray(List objList) - { - String[] networkStrings = new String[objList.size()]; - int i = 0; - for (Object network : objList) - { - networkStrings[i++] = (String) network; - } - return networkStrings; - } - - public boolean match(InetAddress remote) throws FirewallPluginException - { - if (_hostnamePatterns != null) - { - String hostname = getHostname(remote); - if (hostname == null) - { - throw new FirewallPluginException(); - } - for (Pattern pattern : _hostnamePatterns) - { - if (pattern.matcher(hostname).matches()) - { - return true; - } - } - return false; - } - else - { - return _network.matchInetNetwork(remote); - } - } - - /** - * @param remote the InetAddress to look up - * @return the hostname, null if not found or takes longer than 30s to find - */ - private String getHostname(final InetAddress remote) - { - final String[] hostname = new String[]{null}; - final AtomicBoolean done = new AtomicBoolean(false); - // Spawn thread - Thread thread = new Thread(new Runnable() - { - public void run() - { - hostname[0] = remote.getCanonicalHostName(); - done.getAndSet(true); - synchronized (done) - { - done.notifyAll(); - } - } - }); - - thread.run(); - long endTime = System.currentTimeMillis() + DNS_TIMEOUT; - - while (System.currentTimeMillis() < endTime && !done.get()) - { - try - { - synchronized (done) - { - done.wait(endTime - System.currentTimeMillis()); - } - } - catch (InterruptedException e) - { - // Check the time and if necessary sleep for a bit longer - } - } - return hostname[0]; - } - - public AuthzResult getAccess() - { - return _access; - } - - } - - private AuthzResult _default = AuthzResult.ABSTAIN; - private FirewallRule[] _rules; - - @Override - public AuthzResult authoriseConnect(PrincipalHolder principalHolder, VirtualHost virtualHost) - { - if(!(principalHolder instanceof ProtocolEngine)) - { - return AuthzResult.ABSTAIN; // We only deal with tcp sessions - } - - ProtocolEngine session = (ProtocolEngine) principalHolder; - - SocketAddress sockAddr = session.getRemoteAddress(); - if (!(sockAddr instanceof InetSocketAddress)) - { - return AuthzResult.ABSTAIN; // We only deal with tcp sessions - } - - InetAddress addr = ((InetSocketAddress) sockAddr).getAddress(); - - if (addr == null) - { - return AuthzResult.ABSTAIN; // Not an Inet socket on the other end - } - - boolean match = false; - for (FirewallRule rule : _rules) - { - try - { - match = rule.match(addr); - } - catch (FirewallPluginException e) - { - return AuthzResult.DENIED; - } - if (match) - { - return rule.getAccess(); - } - } - return _default; - - } - - public void setConfiguration(Configuration config) throws ConfigurationException - { - // Get default action - String defaultAction = config.getString("[@default-action]"); - if (defaultAction == null) - { - _default = AuthzResult.ABSTAIN; - } - else if (defaultAction.toLowerCase().equals("allow")) - { - _default = AuthzResult.ALLOWED; - } - else - { - _default = AuthzResult.DENIED; - } - CompositeConfiguration finalConfig = new CompositeConfiguration(config); - - List subFiles = config.getList("xml[@fileName]"); - for (Object subFile : subFiles) - { - finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); - } - - // all rules must have an access attribute - int numRules = finalConfig.getList("rule[@access]").size(); - _rules = new FirewallRule[numRules]; - for (int i = 0; i < numRules; i++) - { - FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), finalConfig.getList("rule(" - + i + ")[@network]"), finalConfig.getList("rule(" + i + ")[@hostname]")); - _rules[i] = rule; - } - } -} -- cgit v1.2.1 From 1b94fd6a6dec4ace311c09ee8a8ea37cd57b93ce Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:08:02 +0000 Subject: QPID-2624: Check whether virtualhosts configuration file exists Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949788 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index f8fc27e86a..7681354f19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -244,6 +244,10 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa { // Open the vhosts XML file and copy values from it to our config _vhostsFile = new File(fileName); + if (!_vhostsFile.exists()) + { + throw new ConfigurationException("Virtualhosts file does not exist"); + } vhostConfiguration = parseConfig(new File(fileName)); // save the default virtualhost name -- cgit v1.2.1 From d09eb6a2f2de9d1b53909671532f2553bb98f33d Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:17:11 +0000 Subject: QPID-2422: fix passing of the queue exclusivity argument during recovery as it was broken by previous commits git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949791 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 98d231a7ea..d6f9146742 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -102,7 +102,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (q == null) { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, false, _virtualHost, + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, exclusive, _virtualHost, arguments); _virtualHost.getQueueRegistry().registerQueue(q); } -- cgit v1.2.1 From 5f076b6c88020ad8f248ae292aa6283d1d40f7cf Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 2 Jun 2010 16:40:57 +0000 Subject: QPID-2625 : Update GenerateLogMessages to probe the property file for 3-Digit LoggingClasses and use that as the basis for generation. Expose LogSubjects from Queue and Session. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950635 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 5 +++ .../server/logging/messages/LogMessages.properties | 48 +++++++++++----------- .../qpid/server/protocol/AMQSessionModel.java | 4 ++ .../org/apache/qpid/server/queue/AMQQueue.java | 3 ++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 5 +++ .../qpid/server/transport/ServerSession.java | 7 ++++ 6 files changed, 49 insertions(+), 23 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 8a0e49f537..9d90694f55 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -1079,6 +1079,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return String.valueOf(_session.getContextKey()); } + public LogSubject getLogSubject() + { + return _logSubject; + } + private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index 7159c6b02c..9e19b44430 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -207,7 +207,7 @@ # # # Default File used for all non-defined locales. -#Broker +BRK=Broker # 0 - Version # 1 = Build BRK_STARTUP = BRK-1001 : Startup : Version: {0} Build: {1} @@ -224,7 +224,8 @@ BRK_CONFIG = BRK-1006 : Using configuration : {0} # 0 - path BRK_LOG_CONFIG = BRK-1007 : Using logging configuration : {0} -#ManagementConsole + +MNG=ManagementConsole MNG_STARTUP = MNG-1001 : Startup # 0 - Service # 1 - Port @@ -240,12 +241,13 @@ MNG_OPEN = MNG-1007 : Open : User {0} MNG_CLOSE = MNG-1008 : Close -#VirtualHost +VHT=VirtualHost + # 0 - name VHT_CREATED = VHT-1001 : Created : {0} VHT_CLOSED = VHT-1002 : Closed -#MessageStore +MST=MessageStore # 0 - name MST_CREATED = MST-1001 : Created : {0} # 0 - path @@ -255,36 +257,36 @@ MST_RECOVERY_START = MST-1004 : Recovery Start MST_RECOVERED = MST-1005 : Recovered {0,number} messages MST_RECOVERY_COMPLETE = MST-1006 : Recovery Complete -#ConfigStore +CFG=ConfigStore # 0 - name -CFG-1001 = CFG-1001 : Created : {0} +CFG_1001 = CFG-1001 : Created : {0} # 0 - path -CFG-1002 = CFG-1002 : Store location : {0} -CFG-1003 = CFG-1003 : Closed -CFG-1004 = CFG-1004 : Recovery Start -CFG-1005 = CFG-1005 : Recovery Complete +CFG_1002 = CFG-1002 : Store location : {0} +CFG_1003 = CFG-1003 : Closed +CFG_1004 = CFG-1004 : Recovery Start +CFG_1005 = CFG-1005 : Recovery Complete -#TransactionLog +TXN=TransactionLog # 0 - name -TXN-1001 = TXN-1001 : Created : {0} +TXN_1001 = TXN-1001 : Created : {0} # 0 - path -TXN-1002 = TXN-1002 : Store location : {0} -TXN-1003 = TXN-1003 : Closed +TXN_1002 = TXN-1002 : Store location : {0} +TXN_1003 = TXN-1003 : Closed # 0 - queue name -TXN-1004 = TXN-1004 : Recovery Start[ : {0}] +TXN_1004 = TXN-1004 : Recovery Start[ : {0}] # 0 - count # 1 - queue count -TXN-1005 = TXN-1005 : Recovered {0,number} messages for queue {1} +TXN_1005 = TXN-1005 : Recovered {0,number} messages for queue {1} # 0 - queue name -TXN-1006 = TXN-1006 : Recovery Complete[ : {0}] +TXN_1006 = TXN-1006 : Recovery Complete[ : {0}] -#Connection +CON=Connection # 0 - Client id # 1 - Protocol Version CON_OPEN = CON-1001 : Open[ : Client ID : {0}][ : Protocol Version : {1}] CON_CLOSE = CON-1002 : Close -#Channel +CHN=Channel CHN_CREATE = CHN-1001 : Create # 0 - flow CHN_FLOW = CHN-1002 : Flow {0} @@ -296,7 +298,7 @@ CHN_PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,numbe CHN_FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0}) CHN_FLOW_REMOVED = CHN-1006 : Flow Control Removed -#Queue +QUE=Queue # 0 - owner # 1 - priority QUE_CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] @@ -305,17 +307,17 @@ QUE_OVERFULL = QUE-1003 : Overfull : Size : {0,number} bytes, Capacity : {1,numb QUE_UNDERFULL = QUE-1004 : Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} -#Exchange +EXH=Exchange # 0 - type # 1 - name EXH_CREATED = EXH-1001 : Create :[ Durable] Type: {0} Name: {1} EXH_DELETED = EXH-1002 : Deleted -#Binding +BND=Binding BND_CREATED = BND-1001 : Create[ : Arguments : {0}] BND_DELETED = BND-1002 : Deleted -#Subscription +SUB=Subscription SUB_CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}] SUB_CLOSE = SUB-1002 : Close # 0 - The current subscription state diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java index 31784fd034..a9b2354d75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.protocol; +import org.apache.qpid.server.logging.LogSubject; + public interface AMQSessionModel { Object getID(); @@ -27,4 +29,6 @@ public interface AMQSessionModel AMQConnectionModel getConnectionModel(); String getClientID(); + + LogSubject getLogSubject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 8b53257e88..3b60734a2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -24,6 +24,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; @@ -58,6 +59,8 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer int getBindingCount(); + LogSubject getLogSubject(); + public interface Context { QueueEntry getLastSeenEntry(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 7e78fd0481..b3e0b4fba9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -526,6 +526,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return getBindings().size(); } + public LogSubject getLogSubject() + { + return _logSubject; + } + // ------ Enqueue / Dequeue public void enqueue(ServerMessage message) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index bc7ba085fc..f79a43f330 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -28,6 +28,8 @@ import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.ConnectionConfig; import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.configuration.SessionConfigType; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; @@ -571,4 +573,9 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo return getPrincipal().getName(); } + public LogSubject getLogSubject() + { + return null; + } + } -- cgit v1.2.1 From adb75b9462b1e494fc074405a3d89fdaf39a1bb6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 2 Jun 2010 16:41:22 +0000 Subject: QPID-1447 : Add Logging to SCD. Update PluginManager to expose the logging packages via OSGi. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950636 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 9d76e98f4d..bbbe586ed3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -117,6 +117,8 @@ public class PluginManager implements Closeable "org.apache.qpid.server.configuration.plugins; version=0.7," + "org.apache.qpid.server.configuration.management; version=0.7," + "org.apache.qpid.server.exchange; version=0.7," + + "org.apache.qpid.server.logging; version=0.7," + + "org.apache.qpid.server.logging.actors; version=0.7," + "org.apache.qpid.server.management; version=0.7," + "org.apache.qpid.server.persistent; version=0.7," + "org.apache.qpid.server.plugins; version=0.7," + -- cgit v1.2.1 From 6488b54f89899b6b2c5be32f48acb745f78421f2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 2 Jun 2010 16:43:12 +0000 Subject: QPID-2632 : Remove NullApplicationRegistry git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950642 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/registry/ApplicationRegistry.java | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 9adab58a0c..2164ef1b30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -72,8 +72,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected final ServerConfiguration _configuration; public static final int DEFAULT_INSTANCE = 1; - public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; - public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; protected final Map _acceptors = new HashMap(); @@ -315,20 +313,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry 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", e); - } + throw new IllegalStateException("Application Registry (" + instanceID + ") not created"); } else { @@ -420,11 +405,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } - public static void setDefaultApplicationRegistry(String clazz) - { - _APPLICATION_REGISTRY = clazz; - } - public VirtualHostRegistry getVirtualHostRegistry() { return _virtualHostRegistry; -- cgit v1.2.1 From 45256699f28ea572791cb0b3062dba6c5dedbf39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 2 Jun 2010 16:47:34 +0000 Subject: QPID-2581 : Update Plugins to have a consistent configure(ConfigurationPlugin config) method. Further work is required to ensure that all ConfigurationPlugins perform config validation rather than leaving that to the plugin. The plugin should just use the config. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950656 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/Plugin.java | 9 +++------ .../java/org/apache/qpid/server/security/AbstractPlugin.java | 5 ----- .../org/apache/qpid/server/security/access/plugins/AllowAll.java | 8 ++++---- .../apache/qpid/server/security/access/plugins/BasicPlugin.java | 8 +------- .../org/apache/qpid/server/security/access/plugins/DenyAll.java | 7 ++++--- .../apache/qpid/server/security/access/plugins/LegacyAccess.java | 6 +++--- 6 files changed, 15 insertions(+), 28 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java index 252bd711e8..27bb050db4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java @@ -19,14 +19,11 @@ package org.apache.qpid.server.plugins; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public interface Plugin { - /** - * The name of this plugin. - */ - String getPluginName(); - + /** * Is this plugin configured?. */ @@ -35,5 +32,5 @@ public interface Plugin /** * Configure this plugin */ - void configure() throws ConfigurationException; + public void configure(ConfigurationPlugin config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java index 8c9c2050e8..e0813b1fa7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -35,11 +35,6 @@ public abstract class AbstractPlugin implements SecurityPlugin public ConfigurationPlugin _config; - public String getPluginName() - { - return getClass().getSimpleName(); - } - public Result getDefault() { return Result.ABSTAIN; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 82963bbadc..7525362bfc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -57,8 +57,8 @@ public class AllowAll extends BasicPlugin { public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - AllowAll plugin = new AllowAll(config); - plugin.configure(); + AllowAll plugin = new AllowAll(); + plugin.configure(config); return plugin; } @@ -79,8 +79,8 @@ public class AllowAll extends BasicPlugin return Result.ALLOWED; } - public AllowAll(ConfigurationPlugin config) + public void configure(ConfigurationPlugin config) throws ConfigurationException { _config = config.getConfiguration(AllowAllConfiguration.class); - } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java index 5fc1ef7795..f3161551dc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java @@ -31,7 +31,7 @@ import org.apache.qpid.server.security.access.Operation; /** * This {@link SecurityPlugin} simply abstains from all authorisation requests and ignores configuration. */ -public class BasicPlugin extends AbstractPlugin +public abstract class BasicPlugin extends AbstractPlugin { public Result access(ObjectType objectType, Object instance) { @@ -42,10 +42,4 @@ public class BasicPlugin extends AbstractPlugin { return getDefault(); } - - @Override - public void configure() throws ConfigurationException - { - // Not used - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 24af215a0c..7647072abc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -57,8 +57,8 @@ public class DenyAll extends BasicPlugin { public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - DenyAll plugin = new DenyAll(config); - plugin.configure(); + DenyAll plugin = new DenyAll(); + plugin.configure(config); return plugin; } @@ -79,8 +79,9 @@ public class DenyAll extends BasicPlugin return Result.DENIED; } - public DenyAll(ConfigurationPlugin config) throws ConfigurationException + public void configure(ConfigurationPlugin config) throws ConfigurationException { _config = config.getConfiguration(DenyAllConfiguration.class); } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java index 2c0994b52a..d2b72503a4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -58,8 +58,8 @@ public class LegacyAccess extends BasicPlugin { public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException { - LegacyAccess plugin = new LegacyAccess(config); - plugin.configure(); + LegacyAccess plugin = new LegacyAccess(); + plugin.configure(config); return plugin; } @@ -74,7 +74,7 @@ public class LegacyAccess extends BasicPlugin } }; - public LegacyAccess(ConfigurationPlugin config) throws ConfigurationException + public void configure(ConfigurationPlugin config) throws ConfigurationException { _config = config.getConfiguration(LegacyAccessConfiguration.class); } -- cgit v1.2.1 From c1d1a1d8336beb13838c35f37d1e7e7c12ca93cc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 2 Jun 2010 19:58:39 +0000 Subject: Add the ASF License to various classes currently missing it git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950740 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/SecurityPluginActivator.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java index 789bdd0073..5ee7833c4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ package org.apache.qpid.server.security; import org.apache.log4j.Logger; -- cgit v1.2.1 From 378a7020fdb911c2009fa5846f554cd8dbf14b39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:26:59 +0000 Subject: Remove Plugin.isConfigured Only configured plugins should be created git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951158 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/plugins/Plugin.java | 10 ++++------ .../qpid/server/security/AbstractPlugin.java | 23 ++++++---------------- 2 files changed, 10 insertions(+), 23 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java index 27bb050db4..e094422a1e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java @@ -25,12 +25,10 @@ public interface Plugin { /** - * Is this plugin configured?. - */ - boolean isConfigured(); - - /** - * Configure this plugin + * Provide Configuration to this plugin + * + * FIXME Should not throw ConfigurationException, + * Only ConfigurationPlugin should throw ConfigurationException */ public void configure(ConfigurationPlugin config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java index e0813b1fa7..87cc6e89aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.security; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.security.access.ObjectProperties; @@ -33,7 +34,7 @@ public abstract class AbstractPlugin implements SecurityPlugin { protected final Logger _logger = Logger.getLogger(getClass()); - public ConfigurationPlugin _config; + protected ConfigurationPlugin _config; public Result getDefault() { @@ -43,22 +44,10 @@ public abstract class AbstractPlugin implements SecurityPlugin public abstract Result access(ObjectType object, Object instance); public abstract Result authorise(Operation operation, ObjectType object, ObjectProperties properties); - - public boolean isConfigured() - { - if (_config == null) - { - return false; - } - - for (String key : _config.getElementsProcessed()) - { - if (!_config.getConfig().containsKey(key) && _config.getConfig().subset(key).isEmpty()) - { - return false; - } - } - return true; + public void configure(ConfigurationPlugin config) throws ConfigurationException + { + _config = config; } + } -- cgit v1.2.1 From 1fcfcde8c0ecb27ccd8387857006646bebd44d39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:27:48 +0000 Subject: QPID-2581 : Update Plugins that use configuration to only throw ConfigurationExceptions during the configuration phase of loading configuration. Creating a plugin and providing it with configuration should not throw a configuration exception. Added configuration validation to newer plugins SimpleXML still needs validation. todo Docuement Configuration mechanism. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951159 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/plugins/Plugin.java | 5 +-- .../apache/qpid/server/plugins/PluginManager.java | 2 + .../qpid/server/security/AbstractPlugin.java | 2 +- .../qpid/server/security/SecurityManager.java | 51 ++++++++++++++++++++-- .../server/security/access/plugins/AllowAll.java | 29 ++++++++---- .../server/security/access/plugins/DenyAll.java | 28 ++++++++---- .../security/access/plugins/LegacyAccess.java | 22 +++++++--- .../qpid/server/virtualhost/VirtualHostImpl.java | 6 +-- .../plugins/VirtualHostPluginFactory.java | 3 +- 9 files changed, 109 insertions(+), 39 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java index e094422a1e..e7f9983fff 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/Plugin.java @@ -26,9 +26,6 @@ public interface Plugin /** * Provide Configuration to this plugin - * - * FIXME Should not throw ConfigurationException, - * Only ConfigurationPlugin should throw ConfigurationException */ - public void configure(ConfigurationPlugin config) throws ConfigurationException; + public void configure(ConfigurationPlugin config); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index bbbe586ed3..466bc9e228 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -36,6 +36,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.SecurityPluginFactory; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; @@ -78,6 +79,7 @@ public class PluginManager implements Closeable _securityPlugins.put(pluginFactory.getPluginName(), pluginFactory); } for (ConfigurationPluginFactory configFactory : Arrays.asList( + SecurityManager.SecurityConfiguration.FACTORY, AllowAll.AllowAllConfiguration.FACTORY, DenyAll.DenyAllConfiguration.FACTORY, LegacyAccess.LegacyAccessConfiguration.FACTORY)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java index 87cc6e89aa..ff80499bc2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -45,7 +45,7 @@ public abstract class AbstractPlugin implements SecurityPlugin public abstract Result authorise(Operation operation, ObjectType object, ObjectProperties properties); - public void configure(ConfigurationPlugin config) throws ConfigurationException + public void configure(ConfigurationPlugin config) { _config = config; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java index 035b7fa854..362d919a5e 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -22,14 +22,18 @@ import static org.apache.qpid.server.security.access.ObjectType.*; import static org.apache.qpid.server.security.access.Operation.*; import java.security.Principal; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -57,6 +61,39 @@ public class SecurityManager private Map _globalPlugins = new HashMap(); private Map _hostPlugins = new HashMap(); + public static class SecurityConfiguration extends ConfigurationPlugin + { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new SecurityConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + + public List getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } + }; + + @Override + public String[] getElementsProcessed() + { + return new String[]{"security"}; + } + + public void validateConfiguration() throws ConfigurationException + { + if (_configuration.isEmpty()) + { + throw new ConfigurationException("security section is incomplete, no elements found."); + } + } + } + + public SecurityManager(SecurityManager parent) throws ConfigurationException { _pluginManager = parent._pluginManager; @@ -116,12 +153,18 @@ public class SecurityManager public Map configurePlugins(ConfigurationPlugin hostConfig) throws ConfigurationException { Map plugins = new HashMap(); - for (SecurityPluginFactory factory : _pluginFactories.values()) + SecurityConfiguration securityConfig = hostConfig.getConfiguration(SecurityConfiguration.class); + + // If we have no security Configuration then there is nothing to configure. + if (securityConfig != null) { - SecurityPlugin plugin = factory.newInstance(hostConfig); - if (plugin.isConfigured()) + for (SecurityPluginFactory factory : _pluginFactories.values()) { - plugins.put(factory.getPluginName(), plugin); + SecurityPlugin plugin = factory.newInstance(securityConfig); + if (plugin != null) + { + plugins.put(factory.getPluginName(), plugin); + } } } return plugins; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 7525362bfc..24ff44b1ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -36,7 +36,7 @@ public class AllowAll extends BasicPlugin { public List getParentPaths() { - return Arrays.asList("security", "virtualhosts.virtualhost.security"); + return Arrays.asList("security.allow-all", "virtualhosts.virtualhost.security.allow-all"); } public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException @@ -49,16 +49,33 @@ public class AllowAll extends BasicPlugin public String[] getElementsProcessed() { - return new String[] { "allow-all" }; + return new String[] { "" }; } + + public void validateConfiguration() throws ConfigurationException + { + if (!_configuration.isEmpty()) + { + throw new ConfigurationException("allow-all section takes no elements."); + } + } + } public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() { - public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException + public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException { + AllowAllConfiguration configuration = config.getConfiguration(AllowAllConfiguration.class); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + return null; + } + AllowAll plugin = new AllowAll(); - plugin.configure(config); + plugin.configure(configuration); return plugin; } @@ -79,8 +96,4 @@ public class AllowAll extends BasicPlugin return Result.ALLOWED; } - public void configure(ConfigurationPlugin config) throws ConfigurationException - { - _config = config.getConfiguration(AllowAllConfiguration.class); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 7647072abc..cd68511730 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -36,7 +36,7 @@ public class DenyAll extends BasicPlugin { public List getParentPaths() { - return Arrays.asList("security", "virtualhosts.virtualhost.security"); + return Arrays.asList("security.deny-all", "virtualhosts.virtualhost.security.deny-all"); } public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException @@ -49,16 +49,33 @@ public class DenyAll extends BasicPlugin public String[] getElementsProcessed() { - return new String[] { "deny-all" }; + return new String[] { "" }; } + + public void validateConfiguration() throws ConfigurationException + { + if (!_configuration.isEmpty()) + { + throw new ConfigurationException("deny-all section takes no elements."); + } + } + } public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() { public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException { + DenyAllConfiguration configuration = config.getConfiguration(DenyAllConfiguration.class); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + return null; + } + DenyAll plugin = new DenyAll(); - plugin.configure(config); + plugin.configure(configuration); return plugin; } @@ -79,9 +96,4 @@ public class DenyAll extends BasicPlugin return Result.DENIED; } - public void configure(ConfigurationPlugin config) throws ConfigurationException - { - _config = config.getConfiguration(DenyAllConfiguration.class); - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java index d2b72503a4..8cebedbc26 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -37,7 +37,11 @@ public class LegacyAccess extends BasicPlugin { public List getParentPaths() { - return Arrays.asList("security", "virtualhosts.virtualhost.security"); + return Arrays.asList("security.jmx", "virtualhosts.virtualhost.security.jmx", + "security.false", "virtualhosts.virtualhost.security.false", + "security.msg-auth", "virtualhosts.virtualhost.security.msg-auth", + "security.access", "virtualhosts.virtualhost.security.access", + "security.principal-databases", "virtualhosts.virtualhost.security.principal-databases"); } public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException @@ -50,7 +54,7 @@ public class LegacyAccess extends BasicPlugin public String[] getElementsProcessed() { - return new String[] { "principal-databases", "access", "msg-auth", "false", "jmx" }; + return new String[] { "" }; } } @@ -58,8 +62,16 @@ public class LegacyAccess extends BasicPlugin { public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException { + LegacyAccessConfiguration configuration = config.getConfiguration(LegacyAccessConfiguration.class); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + return null; + } + LegacyAccess plugin = new LegacyAccess(); - plugin.configure(config); + plugin.configure(configuration); return plugin; } @@ -74,8 +86,4 @@ public class LegacyAccess extends BasicPlugin } }; - public void configure(ConfigurationPlugin config) throws ConfigurationException - { - _config = config.getConfiguration(LegacyAccessConfiguration.class); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index d104209e98..f7ad934a57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -308,11 +308,7 @@ public class VirtualHostImpl implements VirtualHost _logger.info("Loaded VirtualHostPlugin:" + plugin); } - catch (IllegalArgumentException iae) - { - _logger.warn("VirtualHostPlugin:" + pluginName + " has not been configured for this virtualhost(" + getName() + ")"); - } - catch (Exception e) + catch (RuntimeException e) { _logger.error("Unable to load VirtualHostPlugin:" + pluginName + " due to:" + e.getMessage(), e); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java index 5335925fb0..c8bea18444 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPluginFactory.java @@ -20,10 +20,9 @@ */ package org.apache.qpid.server.virtualhost.plugins; -import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.virtualhost.VirtualHost; public interface VirtualHostPluginFactory { - public VirtualHostHouseKeepingPlugin newInstance(VirtualHost vhost) throws ConfigurationException; + public VirtualHostHouseKeepingPlugin newInstance(VirtualHost vhost); } -- cgit v1.2.1 From ee4a5e6b660562bd1f83d85d0b9ecefc88d434c5 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:29:34 +0000 Subject: Cleanup code. Configuration security.access is not used anymore git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951167 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/security/access/plugins/AllowAll.java | 8 ++++---- .../apache/qpid/server/security/access/plugins/LegacyAccess.java | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 24ff44b1ae..d4777b8cb3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -54,10 +54,10 @@ public class AllowAll extends BasicPlugin public void validateConfiguration() throws ConfigurationException { - if (!_configuration.isEmpty()) - { - throw new ConfigurationException("allow-all section takes no elements."); - } +// if (!_configuration.isEmpty()) +// { +// throw new ConfigurationException("allow-all section takes no elements."); +// } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java index 8cebedbc26..1250cdcb1b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -38,9 +38,7 @@ public class LegacyAccess extends BasicPlugin public List getParentPaths() { return Arrays.asList("security.jmx", "virtualhosts.virtualhost.security.jmx", - "security.false", "virtualhosts.virtualhost.security.false", "security.msg-auth", "virtualhosts.virtualhost.security.msg-auth", - "security.access", "virtualhosts.virtualhost.security.access", "security.principal-databases", "virtualhosts.virtualhost.security.principal-databases"); } -- cgit v1.2.1 From 88782570f5e820c449dd3c5c47cc417f0751226d Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:29:48 +0000 Subject: QPID-1447 : Ensure we only attempt to load plugins that are configured and so will be created. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951168 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/virtualhost/VirtualHostImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index f7ad934a57..5ea4ade559 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -303,10 +303,14 @@ public class VirtualHostImpl implements VirtualHost { VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); - _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, - plugin.getDelay(), plugin.getTimeUnit()); + // If we had configuration for the plugin the schedule it. + if (plugin != null) + { + _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, + plugin.getDelay(), plugin.getTimeUnit()); - _logger.info("Loaded VirtualHostPlugin:" + plugin); + _logger.info("Loaded VirtualHostPlugin:" + plugin); + } } catch (RuntimeException e) { -- cgit v1.2.1 From ece27b59fa3b1d328091c6e0c3fafad72a6d8fa0 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 9 Jun 2010 09:46:11 +0000 Subject: QPID-2650: Make use of connections with auto-commit transactions disabled for metadata, content, and queue entries. Additionally, make remaining uses of auto-commit enabled connections more visible and remove the erroneous explicit commits on these. Close completed Statements after use. Add/correct various related debug log statements. Stop adding vhost name to all environment paths, now just the default value. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@952930 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/store/DerbyMessageStore.java | 212 ++++++++++----------- .../VirtualHostConfigRecoveryHandler.java | 8 +- 2 files changed, 104 insertions(+), 116 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index a87cd32e37..aeec8798d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -218,9 +218,8 @@ public class DerbyMessageStore implements MessageStore { initialiseDriver(); - //Update to pick up QPID_WORK and use that as the default location not just derbyDB - - final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); + final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, + System.getProperty("QPID_WORK")+"/derbyDB/" + name); File environmentPath = new File(databasePath); if (!environmentPath.exists()) @@ -234,7 +233,7 @@ public class DerbyMessageStore implements MessageStore CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_STORE_LOCATION(environmentPath.getAbsolutePath())); - createOrOpenDatabase(name, databasePath); + createOrOpenDatabase(databasePath); } private static synchronized void initialiseDriver() throws ClassNotFoundException @@ -245,12 +244,11 @@ public class DerbyMessageStore implements MessageStore } } - private void createOrOpenDatabase(String name, final String environmentPath) throws SQLException + private void createOrOpenDatabase(final String environmentPath) throws SQLException { - //fixme this the _vhost name should not be added here. - _connectionURL = "jdbc:derby:" + environmentPath + "/" + name + ";create=true"; + _connectionURL = "jdbc:derby:" + environmentPath + ";create=true"; - Connection conn = newConnection(); + Connection conn = newAutoCommitConnection(); createVersionTable(conn); createExchangeTable(conn); @@ -394,8 +392,7 @@ public class DerbyMessageStore implements MessageStore private List loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException, AMQException { - Connection conn = newConnection(); - + Connection conn = newAutoCommitConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); @@ -425,6 +422,9 @@ public class DerbyMessageStore implements MessageStore queues.add(queueName); } + + conn.close(); + return queues; } @@ -436,8 +436,7 @@ public class DerbyMessageStore implements MessageStore Connection conn = null; try { - conn = newConnection(); - + conn = newAutoCommitConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); @@ -468,16 +467,12 @@ public class DerbyMessageStore implements MessageStore private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List exchanges) throws AMQException, SQLException { - - _logger.info("Recovering bindings..."); - - Connection conn = null; try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); @@ -504,6 +499,8 @@ public class DerbyMessageStore implements MessageStore brh.binding(exchangeName, queueName, bindingKey, buf); } + + stmt.close(); } finally { @@ -544,20 +541,16 @@ public class DerbyMessageStore implements MessageStore Connection conn = null; try { - - conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA); stmt.setLong(1,messageId); int results = stmt.executeUpdate(); - + stmt.close(); + if (results == 0) { - - throw new RuntimeException("Message metadata not found for message id " + messageId); } - stmt.close(); if (_logger.isDebugEnabled()) { @@ -567,8 +560,7 @@ public class DerbyMessageStore implements MessageStore stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); stmt.setLong(1,messageId); results = stmt.executeUpdate(); - - + stmt.close(); conn.commit(); conn.close(); @@ -588,7 +580,7 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error removing Message with id " + messageId + " to database: " + e, e); + throw new RuntimeException("Error removing message with id " + messageId + " from database: " + e, e); } } @@ -603,13 +595,12 @@ public class DerbyMessageStore implements MessageStore try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); stmt.setString(1, exchange.getNameShortString().toString()); stmt.execute(); stmt.close(); - conn.commit(); ResultSet rs = stmt.executeQuery(); @@ -622,7 +613,6 @@ public class DerbyMessageStore implements MessageStore stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); stmt.execute(); stmt.close(); - conn.commit(); } } @@ -636,7 +626,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing Exchange with name " + exchange.getNameShortString() + " to database: " + e, e); + throw new AMQException("Error adding Exchange with name " + exchange.getNameShortString() + " to database: " + e, e); } } @@ -648,23 +638,19 @@ public class DerbyMessageStore implements MessageStore try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); stmt.setString(1, exchange.getNameShortString().toString()); int results = stmt.executeUpdate(); + stmt.close(); if(results == 0) { throw new AMQException("Exchange " + exchange.getNameShortString() + " not found"); } - else - { - conn.commit(); - stmt.close(); - } } catch (SQLException e) { - throw new AMQException("Error writing deleting with name " + exchange.getNameShortString() + " from database: " + e, e); + throw new AMQException("Error deleting exchange with name " + exchange.getNameShortString() + " from database: " + e, e); } finally { @@ -690,10 +676,9 @@ public class DerbyMessageStore implements MessageStore { Connection conn = null; - try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); stmt.setString(1, exchange.getNameShortString().toString() ); @@ -726,7 +711,6 @@ public class DerbyMessageStore implements MessageStore } stmt.executeUpdate(); - conn.commit(); stmt.close(); } } @@ -761,24 +745,23 @@ public class DerbyMessageStore implements MessageStore { Connection conn = null; - try { - conn = newConnection(); + conn = newAutoCommitConnection(); // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); stmt.setString(1, exchange.getNameShortString().toString() ); stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); - - - if(stmt.executeUpdate() != 1) + + int result = stmt.executeUpdate(); + stmt.close(); + + if(result != 1) { throw new AMQException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange " + exchange.getNameShortString() + " not found"); } - conn.commit(); - stmt.close(); } catch (SQLException e) { @@ -817,7 +800,7 @@ public class DerbyMessageStore implements MessageStore { try { - Connection conn = newConnection(); + Connection conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); stmt.setString(1, queue.getNameShortString().toString()); @@ -849,11 +832,8 @@ public class DerbyMessageStore implements MessageStore stmt.setBinaryStream(4,bis,underlying.length); stmt.execute(); - stmt.close(); - conn.commit(); - conn.close(); } } @@ -864,9 +844,27 @@ public class DerbyMessageStore implements MessageStore } } + /** + * Convenience method to create a new Connection configured for TRANSACTION_READ_COMMITED + * isolation and with auto-commit transactions enabled. + */ + private Connection newAutoCommitConnection() throws SQLException + { + final Connection connection = newConnection(); + connection.setAutoCommit(true); + + return connection; + } + + /** + * Convenience method to create a new Connection configured for TRANSACTION_READ_COMMITED + * isolation and with auto-commit transactions disabled. + */ private Connection newConnection() throws SQLException { final Connection connection = DriverManager.getConnection(_connectionURL); + connection.setAutoCommit(false); + connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); return connection; } @@ -876,22 +874,18 @@ public class DerbyMessageStore implements MessageStore _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); Connection conn = null; - try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE); stmt.setString(1, name.toString()); int results = stmt.executeUpdate(); - - + stmt.close(); + if (results == 0) { throw new AMQException("Queue " + name + " not found"); } - - conn.commit(); - stmt.close(); } catch (SQLException e) { @@ -930,16 +924,16 @@ public class DerbyMessageStore implements MessageStore try { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); - stmt.setString(1,name); - stmt.setLong(2,messageId); - stmt.executeUpdate(); - connWrapper.requiresCommit(); - if (_logger.isDebugEnabled()) { _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); } + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); + stmt.setString(1,name); + stmt.setLong(2,messageId); + stmt.executeUpdate(); + stmt.close(); } catch (SQLException e) { @@ -964,8 +958,7 @@ public class DerbyMessageStore implements MessageStore stmt.setString(1,name); stmt.setLong(2,messageId); int results = stmt.executeUpdate(); - - connWrapper.requiresCommit(); + stmt.close(); if(results != 1) { @@ -989,23 +982,12 @@ public class DerbyMessageStore implements MessageStore private static final class ConnectionWrapper { private final Connection _connection; - private boolean _requiresCommit; public ConnectionWrapper(Connection conn) { _connection = conn; } - public void setRequiresCommit() - { - _requiresCommit = true; - } - - public boolean requiresCommit() - { - return _requiresCommit; - } - public Connection getConnection() { return _connection; @@ -1071,11 +1053,7 @@ public class DerbyMessageStore implements MessageStore try { Connection conn = connWrapper.getConnection(); - if(connWrapper.requiresCommit()) - { - conn.rollback(); - } - + conn.rollback(); conn.close(); } catch (SQLException e) @@ -1094,6 +1072,11 @@ public class DerbyMessageStore implements MessageStore private void storeMetaData(Connection conn, long messageId, StorableMessageMetaData metaData) throws SQLException { + if(_logger.isDebugEnabled()) + { + _logger.debug("Adding metadata for message " +messageId); + } + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_META_DATA); stmt.setLong(1,messageId); @@ -1107,8 +1090,13 @@ public class DerbyMessageStore implements MessageStore metaData.writeToBuffer(0, buf); ByteArrayInputStream bis = new ByteArrayInputStream(underlying); stmt.setBinaryStream(2,bis,underlying.length); - stmt.executeUpdate(); - + int result = stmt.executeUpdate(); + stmt.close(); + + if(result == 0) + { + throw new RuntimeException("Unable to add meta data for message " +messageId); + } } @@ -1116,7 +1104,7 @@ public class DerbyMessageStore implements MessageStore private void recoverMessages(MessageStoreRecoveryHandler recoveryHandler) throws SQLException { - Connection conn = newConnection(); + Connection conn = newAutoCommitConnection(); MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin(); @@ -1144,8 +1132,6 @@ public class DerbyMessageStore implements MessageStore StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false); messageHandler.message(message); - - } _messageId.set(maxId); @@ -1157,14 +1143,13 @@ public class DerbyMessageStore implements MessageStore private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws SQLException { - Connection conn = newConnection(); + Connection conn = newAutoCommitConnection(); TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); - while(rs.next()) { @@ -1172,17 +1157,16 @@ public class DerbyMessageStore implements MessageStore long messageId = rs.getLong(2); queueEntryHandler.queueEntry(queueName,messageId); } - - + + stmt.close(); queueEntryHandler.completeQueueEntryRecovery(); - } StorableMessageMetaData getMetaData(long messageId) throws SQLException { - Connection conn = newConnection(); + Connection conn = newAutoCommitConnection(); try { PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_META_DATA); @@ -1191,7 +1175,8 @@ public class DerbyMessageStore implements MessageStore if(rs.next()) { - + stmt.close(); + Blob dataAsBlob = rs.getBlob(1); byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); @@ -1205,6 +1190,8 @@ public class DerbyMessageStore implements MessageStore } else { + stmt.close(); + throw new RuntimeException("Meta data not found for message with id " + messageId); } @@ -1218,18 +1205,13 @@ public class DerbyMessageStore implements MessageStore private void addContent(Connection conn, long messageId, int offset, ByteBuffer src) { - - + if(_logger.isDebugEnabled()) + { + _logger.debug("Adding content chunk offset " + offset + " for message " +messageId); + } try { - final boolean newConnection = conn == null; - - if(newConnection) - { - conn = newConnection(); - } - src = src.slice(); byte[] chunkData = new byte[src.limit()]; @@ -1249,12 +1231,7 @@ public class DerbyMessageStore implements MessageStore ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); stmt.setBinaryStream(4, bis, chunkData.length); stmt.executeUpdate(); - - if(newConnection) - { - conn.commit(); - conn.close(); - } + stmt.close(); } catch (SQLException e) { @@ -1270,10 +1247,9 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + throw new RuntimeException("Error adding content chunk offset " + offset + " for message " + messageId + ": " + e, e); } - } @@ -1284,7 +1260,7 @@ public class DerbyMessageStore implements MessageStore try { - conn = newConnection(); + conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); stmt.setLong(1,messageId); @@ -1317,6 +1293,7 @@ public class DerbyMessageStore implements MessageStore } } + stmt.close(); conn.close(); return written; @@ -1335,7 +1312,7 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + throw new RuntimeException("Error retrieving content from offset " + offset + " for message " + messageId + ": " + e, e); } @@ -1478,12 +1455,21 @@ public class DerbyMessageStore implements MessageStore { if(_conn != null) { + if(_logger.isDebugEnabled()) + { + _logger.debug("Flushing message " + _messageId + " to store"); + } + _conn.commit(); _conn.close(); } } catch (SQLException e) { + if(_logger.isDebugEnabled()) + { + _logger.debug("Error when trying to flush message " + _messageId + " to store: " + e); + } throw new RuntimeException(e); } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index d6f9146742..a1d0f62348 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -167,9 +167,11 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa serverMessage = new MessageTransferMessage(message, null); break; default: - throw new RuntimeException("Unknown message type retreived from store " + message.getMetaData().getClass()); + throw new RuntimeException("Unknown message type retrieved from store " + message.getMetaData().getClass()); } + //_logger.debug("Recovered message with id " + serverMessage); + _recoveredMessages.put(message.getMessageNumber(), serverMessage); _unusedMessages.put(message.getMessageNumber(), message); @@ -222,7 +224,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); if (queue == null) { - _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " + _logger.error("Unknown queue: " + queueName + " cannot be bound to exchange: " + exchange.getNameShortString()); } else @@ -302,7 +304,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa } else { - _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getNameShortString() + " is unknwon, entry will be discarded"); + _logger.warn("Message id " + messageId + " referenced in log as enqueued in queue " + queue.getNameShortString() + " is unknown, entry will be discarded"); TransactionLog.Transaction txn = _transactionLog.newTransaction(); txn.dequeueMessage(queue, messageId); txn.commitTranAsync(); -- cgit v1.2.1 From 0e0c82bec1cb5a99e29040f5339b1ccd729204dc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 10 Jun 2010 09:05:03 +0000 Subject: QPID-2650: revert change in r952930 which removed the extraneous vhost subdir. A slightly larger change is required as it turns out derby wont use a provided empty directory git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@953254 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/store/DerbyMessageStore.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index aeec8798d5..bea4648b30 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -218,8 +218,9 @@ public class DerbyMessageStore implements MessageStore { initialiseDriver(); - final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, - System.getProperty("QPID_WORK")+"/derbyDB/" + name); + //Update to pick up QPID_WORK and use that as the default location not just derbyDB + + final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) @@ -233,7 +234,7 @@ public class DerbyMessageStore implements MessageStore CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_STORE_LOCATION(environmentPath.getAbsolutePath())); - createOrOpenDatabase(databasePath); + createOrOpenDatabase(name, databasePath); } private static synchronized void initialiseDriver() throws ClassNotFoundException @@ -244,9 +245,10 @@ public class DerbyMessageStore implements MessageStore } } - private void createOrOpenDatabase(final String environmentPath) throws SQLException + private void createOrOpenDatabase(String name, final String environmentPath) throws SQLException { - _connectionURL = "jdbc:derby:" + environmentPath + ";create=true"; + //FIXME this the _vhost name should not be added here, but derby wont use an empty directory as was possibly just created. + _connectionURL = "jdbc:derby:" + environmentPath + "/" + name + ";create=true"; Connection conn = newAutoCommitConnection(); -- cgit v1.2.1 From 16a79007527c096c7da40aa8cd0645279765227a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 14 Jun 2010 12:35:51 +0000 Subject: QPID-2625 : Moved Logging generation to moudule.xml to allow plugins to utilise the same functionality. To enable generation for your plugin just add : to your build.xml Logging is now defined in a X_logmessage.properties file. Where X is used to make the XMessages.java class. Also updated all existing usages to remove the 3 digit prefix that wasn't adding any info. Updated ConfigStore and Transaction Log to use named properties rather than numeric values. If we are going to continue with <3 alpha>-<4 numeric> ids for messages then we'll need to have some registry to prevent clases. Perhaps it is simpler to relax this and require a plugin creator to provide a unique identifier for their messages. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@954432 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 14 +- .../src/main/java/org/apache/qpid/server/Main.java | 11 +- .../apache/qpid/server/binding/BindingFactory.java | 4 +- .../qpid/server/exchange/AbstractExchange.java | 4 +- .../server/logging/actors/SubscriptionActor.java | 5 +- .../messages/Binding_logmessages.properties | 213 ++++++++++++++ .../logging/messages/Broker_logmessages.properties | 226 ++++++++++++++ .../messages/Channel_logmessages.properties | 221 ++++++++++++++ .../messages/ConfigStore_logmessages.properties | 218 ++++++++++++++ .../messages/Connection_logmessages.properties | 215 ++++++++++++++ .../messages/Exchange_logmessages.properties | 215 ++++++++++++++ .../server/logging/messages/LogMessages.properties | 325 --------------------- .../ManagementConsole_logmessages.properties | 224 ++++++++++++++ .../messages/MessageStore_logmessages.properties | 219 ++++++++++++++ .../logging/messages/Queue_logmessages.properties | 217 ++++++++++++++ .../messages/Subscription_logmessages.properties | 215 ++++++++++++++ .../messages/TransactionLog_logmessages.properties | 223 ++++++++++++++ .../messages/VirtualHost_logmessages.properties | 214 ++++++++++++++ .../management/JMXManagedObjectRegistry.java | 20 +- .../management/MBeanInvocationHandlerImpl.java | 4 +- .../qpid/server/protocol/AMQProtocolEngine.java | 8 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 12 +- .../qpid/server/registry/ApplicationRegistry.java | 6 +- .../qpid/server/store/AbstractMessageStore.java | 5 +- .../qpid/server/store/DerbyMessageStore.java | 12 +- .../qpid/server/store/MemoryMessageStore.java | 14 +- .../qpid/server/subscription/SubscriptionImpl.java | 6 +- .../VirtualHostConfigRecoveryHandler.java | 10 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 4 +- 29 files changed, 2682 insertions(+), 402 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 9d90694f55..3e31115dcb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -170,7 +170,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); _id = getConfigStore().createId(); - _actor.message(ChannelMessages.CHN_CREATE()); + _actor.message(ChannelMessages.CREATE()); getConfigStore().addConfiguredObject(this); @@ -492,7 +492,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return; } - CurrentActor.get().message(_logSubject, ChannelMessages.CHN_CLOSE()); + CurrentActor.get().message(_logSubject, ChannelMessages.CLOSE()); unsubscribeAllConsumers(); _transaction.rollback(); @@ -827,7 +827,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel // Log Flow Started before we start the subscriptions if (!suspended) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Started")); + _actor.message(_logSubject, ChannelMessages.FLOW("Started")); } @@ -878,7 +878,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel // stopped. if (suspended) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Stopped")); + _actor.message(_logSubject, ChannelMessages.FLOW("Stopped")); } } @@ -1001,7 +1001,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel public void setCredit(final long prefetchSize, final int prefetchCount) { - _actor.message(ChannelMessages.CHN_PREFETCH_SIZE(prefetchSize, prefetchCount)); + _actor.message(ChannelMessages.PREFETCH_SIZE(prefetchSize, prefetchCount)); _creditManager.setCreditLimits(prefetchSize, prefetchCount); } @@ -1306,7 +1306,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel if(_blocking.compareAndSet(false,true)) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getNameShortString().toString())); + _actor.message(_logSubject, ChannelMessages.FLOW_ENFORCED(queue.getNameShortString().toString())); flow(false); } } @@ -1318,7 +1318,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { if(_blocking.compareAndSet(true,false)) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW_REMOVED()); + _actor.message(_logSubject, ChannelMessages.FLOW_REMOVED()); flow(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index d52267ad57..4bca4e5161 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -25,7 +25,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.Arrays; import java.util.EnumSet; import java.util.HashSet; import java.util.List; @@ -268,7 +267,7 @@ public class Main } else { - CurrentActor.get().message(BrokerMessages.BRK_CONFIG(configFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.CONFIG(configFile.getAbsolutePath())); } String logConfig = commandLine.getOptionValue("l"); @@ -427,7 +426,7 @@ public class Main serverConfig.getNetworkConfiguration(), null); ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP", port)); + CurrentActor.get().message(BrokerMessages.LISTENING("TCP", port)); } @@ -441,14 +440,14 @@ public class Main new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory); ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, serverConfig.getSSLPort()), new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP/SSL", serverConfig.getSSLPort())); + CurrentActor.get().message(BrokerMessages.LISTENING("TCP/SSL", serverConfig.getSSLPort())); } //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - CurrentActor.get().message(BrokerMessages.BRK_READY()); + CurrentActor.get().message(BrokerMessages.READY()); } finally @@ -568,7 +567,7 @@ public class Main { if (logConfigFile.exists() && logConfigFile.canRead()) { - CurrentActor.get().message(BrokerMessages.BRK_LOG_CONFIG(logConfigFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.LOG_CONFIG(logConfigFile.getAbsolutePath())); System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index 59626a7b13..50377eaf52 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -101,12 +101,12 @@ public class BindingFactory void logCreation() { - CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(getArguments()), getArguments() != null && !getArguments().isEmpty())); + CurrentActor.get().message(_logSubject, BindingMessages.CREATED(String.valueOf(getArguments()), getArguments() != null && !getArguments().isEmpty())); } void logDestruction() { - CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); + CurrentActor.get().message(_logSubject, BindingMessages.DELETED()); } public String getOrigin() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 7f6eccdc64..3aa9178d5d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -150,7 +150,7 @@ public abstract class AbstractExchange implements Exchange, Managable _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation - CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getTypeShortString()), String.valueOf(name), durable)); + CurrentActor.get().message(ExchangeMessages.CREATED(String.valueOf(getTypeShortString()), String.valueOf(name), durable)); } public ConfigStore getConfigStore() @@ -190,7 +190,7 @@ public abstract class AbstractExchange implements Exchange, Managable _alternateExchange.removeReference(this); } - CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); + CurrentActor.get().message(_logSubject, ExchangeMessages.DELETED()); for(Task task : _closeTaskList) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java index 542984e76c..612074fbe9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java @@ -21,15 +21,12 @@ package org.apache.qpid.server.logging.actors; import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; import org.apache.qpid.server.subscription.Subscription; -import java.text.MessageFormat; - /** * The subscription actor provides formatted logging for actions that are - * performed by the subsciption. Such as SUB_STATE changes. + * performed by the subsciption. Such as STATE changes. */ public class SubscriptionActor extends AbstractActor { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties new file mode 100644 index 0000000000..6956a396b0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties @@ -0,0 +1,213 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +CREATED = BND-1001 : Create[ : Arguments : {0}] +DELETED = BND-1002 : Deleted diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties new file mode 100644 index 0000000000..9a0bdec929 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties @@ -0,0 +1,226 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - Version +# 1 = Build +STARTUP = BRK-1001 : Startup : Version: {0} Build: {1} +# 0 - Transport +# 1 - Port +LISTENING = BRK-1002 : Starting : Listening on {0} port {1,number,#} +# 0 - Transport +# 1 - Port +SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +READY = BRK-1004 : Ready +STOPPED = BRK-1005 : Stopped +# 0 - path +CONFIG = BRK-1006 : Using configuration : {0} +# 0 - path +LOG_CONFIG = BRK-1007 : Using logging configuration : {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties new file mode 100644 index 0000000000..53b8e995f4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties @@ -0,0 +1,221 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +CREATE = CHN-1001 : Create +# 0 - flow +FLOW = CHN-1002 : Flow {0} +CLOSE = CHN-1003 : Close +# 0 - bytes allowed in prefetch +# 1 - number of messagse. +PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} +# 0 - queue causing flow control +FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0}) +FLOW_REMOVED = CHN-1006 : Flow Control Removed diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties new file mode 100644 index 0000000000..a6a36b15fe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties @@ -0,0 +1,218 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - name +CREATED = CFG-1001 : Created : {0} +# 0 - path +STORE_LOCATION = CFG-1002 : Store location : {0} +CLOSE = CFG-1003 : Closed +RECOVERY_START = CFG-1004 : Recovery Start +RECOVERY_COMPLETE = CFG-1005 : Recovery Complete diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties new file mode 100644 index 0000000000..08393f5e00 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties @@ -0,0 +1,215 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - Client id +# 1 - Protocol Version +OPEN = CON-1001 : Open[ : Client ID : {0}][ : Protocol Version : {1}] +CLOSE = CON-1002 : Close \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties new file mode 100644 index 0000000000..6df7c5862c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties @@ -0,0 +1,215 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - type +# 1 - name +CREATED = EXH-1001 : Create :[ Durable] Type: {0} Name: {1} +DELETED = EXH-1002 : Deleted \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties deleted file mode 100644 index 9e19b44430..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ /dev/null @@ -1,325 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# Default File used for all non-defined locales. -# -# LogMessages used within the Java Broker as originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded through a ResourceBundle named LogMessages. the en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is requried then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat peforms its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addtion of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexepcted. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formating. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the first and final stage of processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# paramters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important is it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java -# Currently the following classes are created and are populated with the -# messages that bear their 3-digit type identifier: -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage BRK_SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain paramters -# however nesting of options is not permitted. Identification is performed on -# first matchings so give the message: -# Msg = Log Message [option1] [option2] -# Two options will be identifed and enabled to select text 'option1 and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# The final processing that is done in the generation is the conversion of the -# property name. As a '-' is an illegal character in the method name it is -# converted to '_' This processing gives the final method signature as follows: -# Message._(,) -# -# -# Default File used for all non-defined locales. -BRK=Broker -# 0 - Version -# 1 = Build -BRK_STARTUP = BRK-1001 : Startup : Version: {0} Build: {1} -# 0 - Transport -# 1 - Port -BRK_LISTENING = BRK-1002 : Starting : Listening on {0} port {1,number,#} -# 0 - Transport -# 1 - Port -BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -BRK_READY = BRK-1004 : Ready -BRK_STOPPED = BRK-1005 : Stopped -# 0 - path -BRK_CONFIG = BRK-1006 : Using configuration : {0} -# 0 - path -BRK_LOG_CONFIG = BRK-1007 : Using logging configuration : {0} - - -MNG=ManagementConsole -MNG_STARTUP = MNG-1001 : Startup -# 0 - Service -# 1 - Port -MNG_LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} -# 0 - Service -# 1 - Port -MNG_SHUTTING_DOWN = MNG-1003 : Shuting down : {0} : port {1,number,#} -MNG_READY = MNG-1004 : Ready -MNG_STOPPED = MNG-1005 : Stopped -# 0 - Path -MNG_SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0} -MNG_OPEN = MNG-1007 : Open : User {0} -MNG_CLOSE = MNG-1008 : Close - - -VHT=VirtualHost - -# 0 - name -VHT_CREATED = VHT-1001 : Created : {0} -VHT_CLOSED = VHT-1002 : Closed - -MST=MessageStore -# 0 - name -MST_CREATED = MST-1001 : Created : {0} -# 0 - path -MST_STORE_LOCATION = MST-1002 : Store location : {0} -MST_CLOSED = MST-1003 : Closed -MST_RECOVERY_START = MST-1004 : Recovery Start -MST_RECOVERED = MST-1005 : Recovered {0,number} messages -MST_RECOVERY_COMPLETE = MST-1006 : Recovery Complete - -CFG=ConfigStore -# 0 - name -CFG_1001 = CFG-1001 : Created : {0} -# 0 - path -CFG_1002 = CFG-1002 : Store location : {0} -CFG_1003 = CFG-1003 : Closed -CFG_1004 = CFG-1004 : Recovery Start -CFG_1005 = CFG-1005 : Recovery Complete - -TXN=TransactionLog -# 0 - name -TXN_1001 = TXN-1001 : Created : {0} -# 0 - path -TXN_1002 = TXN-1002 : Store location : {0} -TXN_1003 = TXN-1003 : Closed -# 0 - queue name -TXN_1004 = TXN-1004 : Recovery Start[ : {0}] -# 0 - count -# 1 - queue count -TXN_1005 = TXN-1005 : Recovered {0,number} messages for queue {1} -# 0 - queue name -TXN_1006 = TXN-1006 : Recovery Complete[ : {0}] - -CON=Connection -# 0 - Client id -# 1 - Protocol Version -CON_OPEN = CON-1001 : Open[ : Client ID : {0}][ : Protocol Version : {1}] -CON_CLOSE = CON-1002 : Close - -CHN=Channel -CHN_CREATE = CHN-1001 : Create -# 0 - flow -CHN_FLOW = CHN-1002 : Flow {0} -CHN_CLOSE = CHN-1003 : Close -# 0 - bytes allowed in prefetch -# 1 - number of messagse. -CHN_PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} -# 0 - queue causing flow control -CHN_FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0}) -CHN_FLOW_REMOVED = CHN-1006 : Flow Control Removed - -QUE=Queue -# 0 - owner -# 1 - priority -QUE_CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -QUE_DELETED = QUE-1002 : Deleted -QUE_OVERFULL = QUE-1003 : Overfull : Size : {0,number} bytes, Capacity : {1,number} -QUE_UNDERFULL = QUE-1004 : Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} - - -EXH=Exchange -# 0 - type -# 1 - name -EXH_CREATED = EXH-1001 : Create :[ Durable] Type: {0} Name: {1} -EXH_DELETED = EXH-1002 : Deleted - -BND=Binding -BND_CREATED = BND-1001 : Create[ : Arguments : {0}] -BND_DELETED = BND-1002 : Deleted - -SUB=Subscription -SUB_CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}] -SUB_CLOSE = SUB-1002 : Close -# 0 - The current subscription state -SUB_STATE = SUB-1003 : State : {0} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties new file mode 100644 index 0000000000..910706a250 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties @@ -0,0 +1,224 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +STARTUP = MNG-1001 : Startup +# 0 - Service +# 1 - Port +LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} +# 0 - Service +# 1 - Port +SHUTTING_DOWN = MNG-1003 : Shuting down : {0} : port {1,number,#} +READY = MNG-1004 : Ready +STOPPED = MNG-1005 : Stopped +# 0 - Path +SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0} +OPEN = MNG-1007 : Open : User {0} +CLOSE = MNG-1008 : Close \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties new file mode 100644 index 0000000000..d60fafd196 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties @@ -0,0 +1,219 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - name +CREATED = MST-1001 : Created : {0} +# 0 - path +STORE_LOCATION = MST-1002 : Store location : {0} +CLOSED = MST-1003 : Closed +RECOVERY_START = MST-1004 : Recovery Start +RECOVERED = MST-1005 : Recovered {0,number} messages +RECOVERY_COMPLETE = MST-1006 : Recovery Complete \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties new file mode 100644 index 0000000000..59a8c87f76 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties @@ -0,0 +1,217 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - owner +# 1 - priority +CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +DELETED = QUE-1002 : Deleted +OVERFULL = QUE-1003 : Overfull : Size : {0,number} bytes, Capacity : {1,number} +UNDERFULL = QUE-1004 : Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties new file mode 100644 index 0000000000..7ad62d2049 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties @@ -0,0 +1,215 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}] +CLOSE = SUB-1002 : Close +# 0 - The current subscription state +STATE = SUB-1003 : State : {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties new file mode 100644 index 0000000000..fe50134cdd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties @@ -0,0 +1,223 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - name +CREATED = TXN-1001 : Created : {0} +# 0 - path +STORE_LOCATION = TXN-1002 : Store location : {0} +CLOSED = TXN-1003 : Closed +# 0 - queue name +RECOVERY_START = TXN-1004 : Recovery Start[ : {0}] +# 0 - count +# 1 - queue count +RECOVERED = TXN-1005 : Recovered {0,number} messages for queue {1} +# 0 - queue name +RECOVERY_COMPLETE = TXN-1006 : Recovery Complete[ : {0}] diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties new file mode 100644 index 0000000000..3129844495 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties @@ -0,0 +1,214 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. +# +# This file was derivied from LogMessages used within the Java Broker and +# originally defined on the wiki: +# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages +# +# Technical Notes: +# This is a standard Java Properties file so white space is respected at the +# end of the lines. This file is processed in a number of ways. +# 1) ResourceBundle +# This file is loaded as a ResourceBundle. The en_US +# addition to the file is the localisation. Additional localisations can be +# provided and will automatically be selected based on the value in +# the config.xml. The default is en_US. +# +# 2) MessasgeFormat +# Each entry is prepared with the Java Core MessageFormat methods. Therefore +# most functionality you can do via MessageFormat can be done here: +# +# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html +# +# The cavet here is that only default String and number FormatTypes can be used. +# This is due to the processing described in 3 below. If support for date, time +# or choice is required then the GenerateLogMessages class should be updated to +# provide support. +# +# Format Note: +# As mentioned earlier white space in this file is very important. One thing +# in particular to note is the way MessageFormat performs its replacements. +# The replacement text will totally replace the {xxx} section so there will be +# no addition of white space or removal e.g. +# MSG = Text----{0}---- +# When given parameter 'Hello' result in text: +# Text----Hello---- +# +# For simple arguments this is expected however when using Style formats then +# it can be a little unexpected. In particular a common pattern is used for +# number replacements : {0,number,#}. This is used in the Broker to display an +# Integer simply as the Integer with no formatting. e.g new Integer(1234567) +# becomes the String "1234567" which is can be contrasted with the pattern +# without a style format field : {0,number} which becomes string "1,234,567". +# +# What you may not expect is that {0,number, #} would produce the String " 1234567" +# note the space after the ',' here /\ has resulted in a space /\ in +# the output. +# +# More details on the SubformatPattern can be found on the API link above. +# +# 3) GenerateLogMessage/Velocity Macro +# This is the only processing that this file goes through. +# 1) Class Generation: +# The GenerateLogMessage processes this file and uses the velocity Macro +# to create classes with static methods to perform the logging and give us +# compile time validation. +# +# 2) Property Processing: +# During the class generation the message properties ({x}) are identified +# and used to create the method signature. +# +# 3) Option Processing: +# The Classes perform final formatting of the messages at runtime based on +# optional parameters that are defined within the message. Optional +# parameters are enclosed in square brackets e.g. [optional]. +# +# To provide fixed log messages as required by the Technical Specification: +# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages +# +# This file is processed by Velocity to create a number of classes that contain +# static methods that provide LogMessages in the code to provide compile time +# validation. +# +# For details of what processing is done see GenerateLogMessages. +# +# What a localiser or developer need know is the following: +# +# The Property structure is important as it defines how the class and methods +# will be built. +# +# Class Generation: +# ================= +# +# Each class of messages will be split in to their own Messages.java. +# Each logmessage file contains only one class of messages the name +# is derived from the name of the logmessages file e.g. _logmessages.properties. +# +# Property Format +# =============== +# The property format MUST adhere to the follow format to make it easier to +# use the logging API as a developer but also so that operations staff can +# easily locate log messages in the output. +# +# The property file should contain entries in the following format +# +# = : +# +# eg: +# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} +# +# Note: the developer focused identifier will become a method name so only a +# valid method name should be used. Currently only '-' are converted to '_'. +# +# That said properties generate the logging code at build time so any error +# can be easily identified. +# +# The three character identifier show above in BRK-1003 should ideally be unique. +# This is the only requirement, limiting to 3 characters is not required. +# That said the current broker contains the following mappings. +# +# Class | Type +# ---------------------|-------- +# Broker | BKR +# ManagementConsole | MNG +# VirtualHost | VHT +# MessageStore | MST +# ConfigStore | CFG +# TransactionLog | TXN +# Connection | CON +# Channel | CHN +# Queue | QUE +# Exchange | EXH +# Binding | BND +# Subscription | SUB +# +# +# Property Processing: +# ==================== +# +# Each property is then processed by the GenerateLogMessages class to identify +# The number and type of parameters, {x} entries. Parameters are defaulted to +# String types but the use of FormatType number (e.g.{0,number}) will result +# in a Number type being used. These parameters are then used to build the +# method parameter list. e.g: +# Property: +# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} +# becomes Method: +# public static LogMessage SHUTTING_DOWN(String param1, Number param2) +# +# This improves our compile time validation of log message content and +# ensures that change in the message format does not accidentally cause +# erroneous messages. +# +# Option Processing: +# ==================== +# +# Options are identified in the log message as being surrounded by square +# brackets ([ ]). These optional values can themselves contain parameters +# however nesting of options is not permitted. Identification is performed on +# first matching so given the message: +# Msg = Log Message [option1] [option2] +# Two options will be identified and enabled to select text 'option1' and +# 'option2'. +# +# The nesting of a options is not supported and will provide +# unexpected results. e.g. Using Message: +# Msg = Log Message [option1 [sub-option2]] +# +# The options will be 'option1 [sub-option2' and 'sub-option2'. The first +# option includes the second option as the nesting is not detected. +# +# The detected options are presented in the method signature as boolean options +# numerically identified by their position in the message. e.g. +# Property: +# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] +# becomes Method: +# public static LogMessage CON_1001(String param1, String param2, boolean opt1) +# +# The value of 'opt1' will show/hide the option in the message. Note that +# 'param2' is still required however a null value can be used if the optional +# section is not desired. +# +# Again here the importance of white space needs to be highlighted. +# Looking at the QUE-1001 message as an example. The first thought on how this +# would look would be as follows: +# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] +# Each option is correctly defined so the text that is defined will appear when +# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is +# the white space. Using the above definition of QUE-1001 if we were to print +# the message with only the Priority option displayed it would appear as this: +# "Create : Owner: guest Priority: 1" +# Note the spaces here /\ This is because only the text between the brackets +# has been removed. +# +# Each option needs to include white space to correctly format the message. So +# the correct definition of QUE-1001 is as follows: +# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] +# Note that white space is included with each option and there is no extra +# white space between the options. As a result the output with just Priority +# enabled is as follows: +# "Create : Owner: guest Priority: 1" +# +# +# Default File used for all non-defined locales. + +# 0 - name +CREATED = VHT-1001 : Created : {0} +CLOSED = VHT-1002 : Closed \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 7ce0f6022b..90e0bba6f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -102,7 +102,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry public void start() throws IOException, ConfigurationException { - CurrentActor.get().message(ManagementConsoleMessages.MNG_STARTUP()); + CurrentActor.get().message(ManagementConsoleMessages.STARTUP()); //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) @@ -173,7 +173,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - CurrentActor.get().message(ManagementConsoleMessages.MNG_SSL_KEYSTORE(ksf.getAbsolutePath())); + CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(ksf.getAbsolutePath())); } //check the key store password is set @@ -201,8 +201,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + (port +PORT_EXPORT_OFFSET) + ") with SSL"); - CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); } else @@ -213,8 +213,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server @@ -329,7 +329,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _cs.start(); - CurrentActor.get().message(ManagementConsoleMessages.MNG_READY()); + CurrentActor.get().message(ManagementConsoleMessages.READY()); } /* @@ -410,7 +410,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry // Stopping the JMX ConnectorServer try { - CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort())); + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort())); _cs.stop(); } catch (IOException e) @@ -422,7 +422,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry if (_rmiRegistry != null) { // Stopping the RMI registry - CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET)); try { UnicastRemoteObject.unexportObject(_rmiRegistry, false); @@ -456,7 +456,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } } - CurrentActor.get().message(ManagementConsoleMessages.MNG_STOPPED()); + CurrentActor.get().message(ManagementConsoleMessages.STOPPED()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 7e7ac94d06..e0a7c9c756 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -301,12 +301,12 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati if (notification.getType().equals(JMXConnectionNotification.OPENED)) { - _logActor.message(ManagementConsoleMessages.MNG_OPEN(user)); + _logActor.message(ManagementConsoleMessages.OPEN(user)); } else if (notification.getType().equals(JMXConnectionNotification.CLOSED) || notification.getType().equals(JMXConnectionNotification.FAILED)) { - _logActor.message(ManagementConsoleMessages.MNG_CLOSE()); + _logActor.message(ManagementConsoleMessages.CLOSE()); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 25571f1022..5d1346ffd8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -196,7 +196,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _id = _configStore.createId(); - _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false)); + _actor.message(ConnectionMessages.OPEN(null, null, false, false)); } @@ -347,7 +347,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol try { // Log incomming protocol negotiation request - _actor.message(ConnectionMessages.CON_OPEN(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); + _actor.message(ConnectionMessages.OPEN(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true)); ProtocolVersion pv = pi.checkVersion(); // Fails if not correct @@ -746,7 +746,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol notifyAll(); } _poolReference.releaseExecutorService(); - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_CLOSE()); + CurrentActor.get().message(_logSubject, ConnectionMessages.CLOSE()); } } else @@ -866,7 +866,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol setContextKey(new AMQShortString(clientID)); // Log the Opening of the connection for this client - _actor.message(ConnectionMessages.CON_OPEN(clientID, _protocolVersion.toString(), true, true)); + _actor.message(ConnectionMessages.OPEN(clientID, _protocolVersion.toString(), true, true)); } if (_clientProperties.getString(ClientProperties.version.toString()) != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b3e0b4fba9..f81a4a6911 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -25,9 +25,7 @@ import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.ConfigStore; @@ -256,7 +254,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Log the creation of this Queue. // The priorities display is toggled on if we set priorities > 0 CurrentActor.get().message(_logSubject, - QueueMessages.QUE_CREATED(String.valueOf(_owner), + QueueMessages.CREATED(String.valueOf(_owner), priorities, _owner != null, autoDelete, @@ -1467,7 +1465,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener stop(); //Log Queue Deletion - CurrentActor.get().message(_logSubject, QueueMessages.QUE_DELETED()); + CurrentActor.get().message(_logSubject, QueueMessages.DELETED()); } return getMessageCount(); @@ -1490,7 +1488,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { _overfull.set(true); //Overfull log message - _logActor.message(_logSubject, QueueMessages.QUE_OVERFULL(_atomicQueueSize.get(), _capacity)); + _logActor.message(_logSubject, QueueMessages.OVERFULL(_atomicQueueSize.get(), _capacity)); if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null) { @@ -1501,7 +1499,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { //Underfull log message - _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); + _logActor.message(_logSubject, QueueMessages.UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); channel.unblock(this); _blockedChannels.remove(channel); @@ -1523,7 +1521,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if(_overfull.compareAndSet(true,false)) {//Underfull log message - _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); + _logActor.message(_logSubject, QueueMessages.UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 2164ef1b30..bc68fa0c79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -259,7 +259,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _qmfService = new QMFService(getConfigStore(), this); - CurrentActor.get().message(BrokerMessages.BRK_STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); + CurrentActor.get().message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); initialiseManagedObjectRegistry(); @@ -367,7 +367,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry close(_pluginManager); - CurrentActor.get().message(BrokerMessages.BRK_STOPPED()); + CurrentActor.get().message(BrokerMessages.STOPPED()); } private void unbind() @@ -387,7 +387,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.error("Unable to close network driver due to:" + e.getMessage()); } - CurrentActor.get().message(BrokerMessages.BRK_SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); + CurrentActor.get().message(BrokerMessages.SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java index ef8f1ab70e..b9adaeacdf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.store; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; @@ -34,11 +33,11 @@ public abstract class AbstractMessageStore implements MessageStore public void configure(VirtualHost virtualHost) throws Exception { _logSubject = new MessageStoreLogSubject(virtualHost, this); - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); } public void close() throws Exception { - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index bea4648b30..40f265e00f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -152,7 +152,7 @@ public class DerbyMessageStore implements MessageStore { stateTransition(State.INITIAL, State.CONFIGURING); _logSubject = logSubject; - CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CREATED(this.getClass().getName())); if(!_configured) { @@ -174,7 +174,7 @@ public class DerbyMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); if(!_configured) { @@ -196,7 +196,7 @@ public class DerbyMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, TransactionLogMessages.CREATED(this.getClass().getName())); if(!_configured) { @@ -232,7 +232,7 @@ public class DerbyMessageStore implements MessageStore } } - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_STORE_LOCATION(environmentPath.getAbsolutePath())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.STORE_LOCATION(environmentPath.getAbsolutePath())); createOrOpenDatabase(name, databasePath); } @@ -370,7 +370,7 @@ public class DerbyMessageStore implements MessageStore { stateTransition(State.CONFIGURING, State.RECOVERING); - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_RECOVERY_START()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.RECOVERY_START()); try { @@ -517,7 +517,7 @@ public class DerbyMessageStore implements MessageStore public void close() throws Exception { - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED()); _closed.getAndSet(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index e3e9432e6b..565afd2539 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -24,25 +24,17 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.message.ServerMessage; import org.apache.commons.configuration.Configuration; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import java.nio.ByteBuffer; /** A simple message store that stores the messages in a threadsafe structure in memory. */ public class MemoryMessageStore implements MessageStore @@ -86,7 +78,7 @@ public class MemoryMessageStore implements MessageStore public void configureConfigStore(String name, ConfigurationRecoveryHandler handler, Configuration configuration, LogSubject logSubject) throws Exception { _logSubject = logSubject; - CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CREATED(this.getClass().getName())); } @@ -102,13 +94,13 @@ public class MemoryMessageStore implements MessageStore } int hashtableCapacity = config.getInt(name + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); _log.info("Using capacity " + hashtableCapacity + " for hash tables"); - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName())); + CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); } public void close() throws Exception { _closed.getAndSet(true); - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED()); + CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index eed57fbf39..1740e3db1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -392,7 +392,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage CurrentActor.get(). message(_logSubject, - SubscriptionMessages.SUB_CREATE(filterLogString, + SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive, filterLogString != null)); } @@ -535,7 +535,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage getConfigStore().removeConfiguredObject(this); //Log Subscription closed - CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_CLOSE()); + CurrentActor.get().message(_logSubject, SubscriptionMessages.CLOSE()); } public boolean isClosed() @@ -623,7 +623,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); } } - CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_STATE(_state.get().toString())); + CurrentActor.get().message(_logSubject,SubscriptionMessages.STATE(_state.get().toString())); } public State getState() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index a1d0f62348..635155d1b0 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -87,7 +87,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa { _logSubject = new MessageStoreLogSubject(_virtualHost,store); _store = store; - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(null, false)); + CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_START(null, false)); return this; } @@ -107,7 +107,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa _virtualHost.getQueueRegistry().registerQueue(q); } - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true)); + CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_START(queueName, true)); //Record that we have a queue for recovery _queueRecoveries.put(queueName, 0); @@ -348,12 +348,12 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa for(Map.Entry entry : _queueRecoveries.entrySet()) { - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey())); + CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERED(entry.getValue(), entry.getKey())); - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true)); + CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_COMPLETE(entry.getKey(), true)); } - CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false)); + CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_COMPLETE(null, false)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 5ea4ade559..fcb06f56bf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -198,7 +198,7 @@ public class VirtualHostImpl implements VirtualHost _id = _appRegistry.getConfigStore().createId(); - CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); + CurrentActor.get().message(VirtualHostMessages.CREATED(_name)); if (_name == null || _name.length() == 0) { @@ -596,7 +596,7 @@ public class VirtualHostImpl implements VirtualHost } } - CurrentActor.get().message(VirtualHostMessages.VHT_CLOSED()); + CurrentActor.get().message(VirtualHostMessages.CLOSED()); } public ManagedObject getBrokerMBean() -- cgit v1.2.1 From ed9058f6a2584b9e4aa29caed99410ce71dbe814 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 14 Jun 2010 12:36:56 +0000 Subject: QPID-2638 : Add initial support for Topics section in configuration file. Added getQueueConfiguration(AMQQueue) which will return a new configuration for the given queue reflecting its binding status. This will allow the queue to be reconfigured during the binding process. Full Docs on this approach to appear on wiki. AMQQueue.configure and getConfiguration() have been updated to use ConfigurationPlugin rather than QueueConfiguration, The queue may be configured by a TopicConfiguration now. Update SlowConsumerTest to be GlobalQueuesTest and add a GlobalTopicsTest to match, where the config is added to the queues or topics section respectively git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@954433 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/binding/BindingFactory.java | 11 ++ .../server/configuration/TopicConfiguration.java | 120 +++++++++++++++++++++ .../configuration/VirtualHostConfiguration.java | 76 +++++++++++++ .../configuration/plugins/ConfigurationPlugin.java | 8 +- .../apache/qpid/server/plugins/PluginManager.java | 3 + .../org/apache/qpid/server/queue/AMQQueue.java | 5 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 26 +++-- .../qpid/server/security/SecurityManager.java | 2 +- .../server/security/access/plugins/AllowAll.java | 2 +- .../server/security/access/plugins/DenyAll.java | 2 +- .../security/access/plugins/LegacyAccess.java | 2 +- 11 files changed, 237 insertions(+), 20 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index 50377eaf52..b24a326ed3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -32,6 +32,8 @@ import org.apache.qpid.server.configuration.BindingConfig; import org.apache.qpid.server.configuration.BindingConfigType; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BindingMessages; @@ -201,6 +203,15 @@ public class BindingFactory exchange.addBinding(b); getConfigStore().addConfiguredObject(b); b.logCreation(); + + //Reconfigure the queue for to reflect this new binding. + ConfigurationPlugin config = queue.getVirtualHost().getConfiguration().getQueueConfiguration(queue); + + if (config != null) + { + // Reconfigure with new config. + queue.configure(config); + } return true; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java new file mode 100644 index 0000000000..0218bf7273 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java @@ -0,0 +1,120 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class TopicConfiguration extends ConfigurationPlugin +{ + public static final ConfigurationPluginFactory FACTORY = new TopicConfigurationFactory(); + + private static final String VIRTUALHOSTS_VIRTUALHOST_TOPICS = "virtualhosts.virtualhost.topics"; + + public static class TopicConfigurationFactory implements ConfigurationPluginFactory + { + + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + TopicConfiguration topicsConfig = new TopicConfiguration(); + topicsConfig.setConfiguration(path, config); + return topicsConfig; + } + + public List getParentPaths() + { + return Arrays.asList(VIRTUALHOSTS_VIRTUALHOST_TOPICS); + } + } + + Map _topics = new HashMap(); + + public String[] getElementsProcessed() + { + return new String[]{"topic"}; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + if (_configuration.isEmpty()) + { + throw new ConfigurationException("Topics section cannot be empty."); + } + + int topics = _configuration.getList("topic.name").size(); + + for(int index=0; index bindings = new ArrayList(queue.getBindings()); + + List exchangeClasses = new ArrayList(bindings.size()); + + //Remove default exchange + for (int index = 0; index < bindings.size(); index++) + { + // Ignore the DEFAULT Exchange binding + if (bindings.get(index).getExchange().getNameShortString().equals(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)) + { + bindings.remove(index); + } + else + { + exchangeClasses.add(bindings.get(index).getExchange().getType().getName()); + + if (exchangeClasses.size() > 1) + { + // If we have more than 1 class of exchange then we can only use the global queue configuration. + // and this will be returned from the default getQueueConfiguration + return null; + } + } + } + + // If we are just bound the the default exchange then use the default. + if (bindings.isEmpty()) + { + return null; + } + + // If we are bound to only one type of exchange then we are going + // to have to resolve the configuration for that exchange. + + String exchangeName = bindings.get(0).getExchange().getType().getName().toString(); + + // Lookup a Configuration handler for this Exchange. + + // Build the expected class name. sConfiguration + // i.e. TopicConfiguration or HeadersConfiguration + String exchangeClass = "org.apache.qpid.server.configuration." + + exchangeName.substring(0, 1).toUpperCase() + + exchangeName.substring(1) + "Configuration"; + + ConfigurationPlugin configPlugin + = queue.getVirtualHost().getConfiguration().getConfiguration(exchangeClass); + + + // now need to perform the queue-topic-topics-queue magic. + + System.err.println("*********** Reconfiguring queue with config:"+configPlugin); + + return configPlugin; + } + public long getMemoryUsageMaximum() { return getLongValue("queues.maximumMemoryUsage"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index 9024c6aec6..1da1459f70 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -38,8 +38,8 @@ public abstract class ConfigurationPlugin { protected static final Logger _logger = Logger.getLogger(ConfigurationPlugin.class); - private Map, ConfigurationPlugin> - _pluginConfiguration = new HashMap, ConfigurationPlugin>(); + private Map + _pluginConfiguration = new HashMap(); protected Configuration _configuration; @@ -69,7 +69,7 @@ public abstract class ConfigurationPlugin return _configuration; } - public C getConfiguration(Class plugin) + public C getConfiguration(String plugin) { return (C) _pluginConfiguration.get(plugin); } @@ -155,7 +155,7 @@ public abstract class ConfigurationPlugin List handlers = configurationManager.getConfigurationPlugins(configurationElement, handled); for (ConfigurationPlugin plugin : handlers) { - _pluginConfiguration.put(plugin.getClass(), plugin); + _pluginConfiguration.put(plugin.getClass().getName(), plugin); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 466bc9e228..8364635632 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -34,6 +34,8 @@ import org.apache.felix.framework.Felix; import org.apache.felix.framework.util.StringMap; import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; +import org.apache.qpid.server.configuration.TopicConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.SecurityManager; @@ -79,6 +81,7 @@ public class PluginManager implements Closeable _securityPlugins.put(pluginFactory.getPluginName(), pluginFactory); } for (ConfigurationPluginFactory configFactory : Arrays.asList( + TopicConfiguration.FACTORY, SecurityManager.SecurityConfiguration.FACTORY, AllowAll.AllowAllConfiguration.FACTORY, DenyAll.DenyAllConfiguration.FACTORY, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 3b60734a2e..225fbec930 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -24,6 +24,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; @@ -274,9 +275,9 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer public void doTask(AMQQueue queue) throws AMQException; } - void configure(QueueConfiguration config); + void configure(ConfigurationPlugin config); - QueueConfiguration getConfiguration(); + ConfigurationPlugin getConfiguration(); ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index f81a4a6911..451d59b2e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -26,6 +26,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.ConfigStore; @@ -185,7 +186,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener //TODO : persist creation time private long _createTime = System.currentTimeMillis(); - private QueueConfiguration _queueConfiguration; + private ConfigurationPlugin _queueConfiguration; @@ -2065,24 +2066,29 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void configure(QueueConfiguration config) + public void configure(ConfigurationPlugin config) { if (config != null) { - setMaximumMessageAge(config.getMaximumMessageAge()); - setMaximumQueueDepth(config.getMaximumQueueDepth()); - setMaximumMessageSize(config.getMaximumMessageSize()); - setMaximumMessageCount(config.getMaximumMessageCount()); - setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap()); - _capacity = config.getCapacity(); - _flowResumeCapacity = config.getFlowResumeCapacity(); + if (config instanceof QueueConfiguration) + { + + setMaximumMessageAge(((QueueConfiguration)config).getMaximumMessageAge()); + setMaximumQueueDepth(((QueueConfiguration)config).getMaximumQueueDepth()); + setMaximumMessageSize(((QueueConfiguration)config).getMaximumMessageSize()); + setMaximumMessageCount(((QueueConfiguration)config).getMaximumMessageCount()); + setMinimumAlertRepeatGap(((QueueConfiguration)config).getMinimumAlertRepeatGap()); + _capacity = ((QueueConfiguration)config).getCapacity(); + _flowResumeCapacity = ((QueueConfiguration)config).getFlowResumeCapacity(); + } _queueConfiguration = config; + } } - public QueueConfiguration getConfiguration() + public ConfigurationPlugin getConfiguration() { return _queueConfiguration; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java index 362d919a5e..ff28d76053 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -153,7 +153,7 @@ public class SecurityManager public Map configurePlugins(ConfigurationPlugin hostConfig) throws ConfigurationException { Map plugins = new HashMap(); - SecurityConfiguration securityConfig = hostConfig.getConfiguration(SecurityConfiguration.class); + SecurityConfiguration securityConfig = hostConfig.getConfiguration(SecurityConfiguration.class.getName()); // If we have no security Configuration then there is nothing to configure. if (securityConfig != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index d4777b8cb3..db18a89231 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -66,7 +66,7 @@ public class AllowAll extends BasicPlugin { public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - AllowAllConfiguration configuration = config.getConfiguration(AllowAllConfiguration.class); + AllowAllConfiguration configuration = config.getConfiguration(AllowAllConfiguration.class.getName()); // If there is no configuration for this plugin then don't load it. if (configuration == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index cd68511730..6c0fb1eaa4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -66,7 +66,7 @@ public class DenyAll extends BasicPlugin { public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - DenyAllConfiguration configuration = config.getConfiguration(DenyAllConfiguration.class); + DenyAllConfiguration configuration = config.getConfiguration(DenyAllConfiguration.class.getName()); // If there is no configuration for this plugin then don't load it. if (configuration == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java index 1250cdcb1b..bd99cdd1fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -60,7 +60,7 @@ public class LegacyAccess extends BasicPlugin { public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException { - LegacyAccessConfiguration configuration = config.getConfiguration(LegacyAccessConfiguration.class); + LegacyAccessConfiguration configuration = config.getConfiguration(LegacyAccessConfiguration.class.getName()); // If there is no configuration for this plugin then don't load it. if (configuration == null) -- cgit v1.2.1 From 62984a521bd9dc1be5c7117480b761a6f8d93622 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 17 Jun 2010 11:31:41 +0000 Subject: QPID-2673: dont hold a disposition change listener for messages when accept-mode=NONE and acquire-mode=PRE_ACQUIRED (ie NO_ACK mode) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@955557 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/subscription/Subscription_0_10.java | 11 +++++++++-- .../java/org/apache/qpid/server/transport/ServerSession.java | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 5b3f5250c5..a800ea3328 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -296,7 +296,10 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr public void run() { - _session.onMessageDispositionChange(_xfr, _action); + if(_action != null) + { + _session.onMessageDispositionChange(_xfr, _action); + } } } @@ -558,10 +561,14 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); } - else + else if(_acquireMode != MessageAcquireMode.PRE_ACQUIRED) { _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); } + else + { + _postIdSettingAction._action = null; + } _session.sendMessage(xfr, _postIdSettingAction); _deliveredCount.incrementAndGet(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index f79a43f330..17a8ce8a43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -256,7 +256,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo if(range != null && range.includes(next)) { MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.get(next); - if(changeListener.acquire()) + if(changeListener != null && changeListener.acquire()) { acquired.add(next); } -- cgit v1.2.1 From 3a720a9bb841f97f3684543827e79ba1a79c9b58 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 17 Jun 2010 14:37:59 +0000 Subject: QPID-2662: Use actual SocketAddress instead of the String representation Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@955617 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java | 2 +- .../src/main/java/org/apache/qpid/server/security/SecurityManager.java | 3 ++- .../org/apache/qpid/server/transport/ServerConnectionDelegate.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 76d1e5378f..4f3f95bd6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -77,7 +77,7 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener Date: Thu, 17 Jun 2010 15:32:12 +0000 Subject: QPID-2654: Add Actor logging to the ACL plugin Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@955642 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 1 + .../java/org/apache/qpid/server/security/access/ObjectType.java | 6 ++++++ .../main/java/org/apache/qpid/server/security/access/Operation.java | 6 ++++++ 3 files changed, 13 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 8364635632..62d8f87641 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -124,6 +124,7 @@ public class PluginManager implements Closeable "org.apache.qpid.server.exchange; version=0.7," + "org.apache.qpid.server.logging; version=0.7," + "org.apache.qpid.server.logging.actors; version=0.7," + + "org.apache.qpid.server.logging.subjects; version=0.7," + "org.apache.qpid.server.management; version=0.7," + "org.apache.qpid.server.persistent; version=0.7," + "org.apache.qpid.server.plugins; version=0.7," + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java index 66ef388976..1fedc8134a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java @@ -87,4 +87,10 @@ public enum ObjectType } throw new IllegalArgumentException("Not a valid object type: " + text); } + + public String toString() + { + String name = name(); + return name.charAt(0) + name.substring(1).toLowerCase(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java index 7077257d01..06d7f8fd0c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java @@ -46,4 +46,10 @@ public enum Operation } throw new IllegalArgumentException("Not a valid operation: " + text); } + + public String toString() + { + String name = name(); + return name.charAt(0) + name.substring(1).toLowerCase(); + } } \ No newline at end of file -- cgit v1.2.1 From 8c90c1b263f429d49069cdf96e61dc25c1d80c5a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 17 Jun 2010 16:04:11 +0000 Subject: QPID-2665: Remove BROKER from object types for plugins Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@955654 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/security/AbstractProxyPlugin.java | 2 -- .../org/apache/qpid/server/security/SecurityManager.java | 12 ------------ .../org/apache/qpid/server/security/access/ObjectType.java | 1 - 3 files changed, 15 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java index 7f3b89b46b..7d0fcfb6cb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java @@ -98,8 +98,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin { switch (objectType) { - case BROKER: - return accessBroker(instance); case VIRTUALHOST: return accessVirtualhost(instance); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java index 240be9efe7..f18c327692 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -300,18 +300,6 @@ public class SecurityManager } }); } - - // TODO not implemented yet, awaiting consensus - public boolean accessBroker(final AMQProtocolSession session) - { - return checkAllPlugins(new AccessCheck() - { - Result allowed(SecurityPlugin plugin) - { - return plugin.access(BROKER, session); - } - }); - } public boolean accessVirtualhost(final String vhostname, final SocketAddress remoteAddress) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java index 1fedc8134a..7103b30283 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java @@ -36,7 +36,6 @@ public enum ObjectType QUEUE(CREATE, DELETE, PURGE, CONSUME), TOPIC(CREATE, DELETE, PURGE, CONSUME), EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH), - BROKER(ACCESS), LINK, // Not allowed in the Java broker ROUTE, // Not allowed in the Java broker METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE), -- cgit v1.2.1 From c5ae512cc708fa67404075e4dfe01b12b748b695 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 22 Jun 2010 13:41:24 +0000 Subject: QPID-2555 : Modified the MANIFEST to include org.apache.qpid.common and org.apache.qpid.server.registry Patch provided by Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@956888 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 62d8f87641..93f0a6bc37 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -114,6 +114,7 @@ public class PluginManager implements Closeable "org.osgi.util.tracker; version=1.0.0," + "org.apache.qpid.junit.extensions.util; version=0.7," + "org.apache.qpid; version=0.7," + + "org.apache.qpid.common; version=0.7," + "org.apache.qpid.exchange; version=0.7," + "org.apache.qpid.framing; version=0.7," + "org.apache.qpid.protocol; version=0.7," + -- cgit v1.2.1 From 799400f28d495ea7184f53dc650e383a6981a029 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 23 Jun 2010 14:40:08 +0000 Subject: QPID-2687: Make PluginManager auto-deploy bundles properly Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@957223 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 32 +++++----------------- 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 93f0a6bc37..717f0d1bee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -35,7 +35,6 @@ import org.apache.felix.framework.util.StringMap; import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.TopicConfiguration; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.SecurityManager; @@ -46,6 +45,7 @@ import org.apache.qpid.server.security.access.plugins.LegacyAccess; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; +import org.osgi.framework.launch.Framework; import org.osgi.util.tracker.ServiceTracker; /** @@ -59,7 +59,7 @@ public class PluginManager implements Closeable private static final int FELIX_STOP_TIMEOUT = 30000; private static final String VERSION = "2.6.0.4"; - private Felix _felix; + private Framework _felix; private ServiceTracker _exchangeTracker = null; private ServiceTracker _securityTracker = null; @@ -155,19 +155,6 @@ public class PluginManager implements Closeable _activator = new Activator(); activators.add(_activator); configMap.put(SYSTEMBUNDLE_ACTIVATORS_PROP, activators); - - // Get the list of bundles to load - StringBuffer pluginJars = new StringBuffer(); - if (pluginDir.isDirectory()) - { - for (String file : pluginDir.list()) - { - if (file.endsWith(".jar")) - { - pluginJars.append(String.format("file:%s%s%s ", pluginPath, File.separator, file)); - } - } - } if (cachePath != null) { @@ -180,19 +167,14 @@ public class PluginManager implements Closeable // Set plugin cache directory and empty it _logger.info("Cache bundles in directory " + cachePath); - configMap.put("org.osgi.framework.storage", cachePath); + configMap.put(FRAMEWORK_STORAGE, cachePath); } - configMap.put("org.osgi.framework.storage.clean", "onFirstInit"); - - // Set directory with plugins - _logger.info("Auto deploy bundles from directory " + pluginPath); - - // Set list of auto-start plugin JAR files - configMap.put(AUTO_START_PROP + "." + FRAMEWORK_DEFAULT_STARTLEVEL, pluginJars.toString()); + configMap.put(FRAMEWORK_STORAGE_CLEAN, FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT); - // FIXME why does this not work? + // Set directory with plugins to auto-deploy + _logger.info("Auto deploying bundles from directory " + pluginPath); configMap.put(AUTO_DEPLOY_DIR_PROPERY, pluginPath); - configMap.put(AUTO_DEPLOY_ACTION_PROPERY, AUTO_DEPLOY_START_VALUE); + configMap.put(AUTO_DEPLOY_ACTION_PROPERY, AUTO_DEPLOY_INSTALL_VALUE + "," + AUTO_DEPLOY_START_VALUE); // Start plugin manager and trackers _felix = new Felix(configMap); -- cgit v1.2.1 From e06552778b981fad355d3eb5b03df84de65380e6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:14:10 +0000 Subject: QPID-1447 : Move Queue Reconfiguration to the Queue rather than the Binding Factory git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960541 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/binding/BindingFactory.java | 8 -------- .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index b24a326ed3..7393f27ab4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -204,14 +204,6 @@ public class BindingFactory getConfigStore().addConfiguredObject(b); b.logCreation(); - //Reconfigure the queue for to reflect this new binding. - ConfigurationPlugin config = queue.getVirtualHost().getConfiguration().getQueueConfiguration(queue); - - if (config != null) - { - // Reconfigure with new config. - queue.configure(config); - } return true; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 451d59b2e9..c4567b2e8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -503,6 +503,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener break; } } + + //Reconfigure the queue for to reflect this new binding. + ConfigurationPlugin config = getVirtualHost().getConfiguration().getQueueConfiguration(this); + + if (config != null) + { + // Reconfigure with new config. + configure(config); + } } public int getBindingCountHigh() -- cgit v1.2.1 From 985afcea2d2dc14ad67863e6ac4413e9633bd2b2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:15:02 +0000 Subject: QPID-2581 : Process new topic configuration git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960544 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/TopicConfig.java | 72 +++++++++ .../server/configuration/TopicConfiguration.java | 179 ++++++++++++++++++--- 2 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java new file mode 100644 index 0000000000..b4ccc75f10 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java @@ -0,0 +1,72 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; + +public class TopicConfig extends ConfigurationPlugin +{ + @Override + public String[] getElementsProcessed() + { + return new String[]{"name", "subscriptionName"}; + } + + public String getName() + { + // If we don't have a specific topic then this config is for all topics. + return getStringValue("name", "#"); + } + + public String getSubscriptionName() + { + return getStringValue("subscriptionName"); + } + + public void validateConfiguration() throws ConfigurationException + { + if (_configuration.isEmpty()) + { + throw new ConfigurationException("Topic section cannot be empty."); + } + + if (getStringValue("name") == null && getSubscriptionName() == null) + { + throw new ConfigurationException("Topic section must have a 'name' or 'subscriptionName' element."); + } + + System.err.println("********* Created TC:"+this); + } + + + @Override + public String formatToString() + { + String response = "Topic:"+getName(); + if (getSubscriptionName() != null) + { + response += ", SubscriptionName:"+getSubscriptionName(); + } + + return response; + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java index 0218bf7273..a16198788f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java @@ -22,8 +22,11 @@ package org.apache.qpid.server.configuration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.exchange.TopicExchange; +import org.apache.qpid.server.queue.AMQQueue; import java.util.Arrays; import java.util.HashMap; @@ -31,7 +34,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -public class TopicConfiguration extends ConfigurationPlugin +public class TopicConfiguration extends ConfigurationPlugin implements ExchangeConfigurationPlugin { public static final ConfigurationPluginFactory FACTORY = new TopicConfigurationFactory(); @@ -54,6 +57,7 @@ public class TopicConfiguration extends ConfigurationPlugin } Map _topics = new HashMap(); + Map> _subscriptions = new HashMap>(); public String[] getElementsProcessed() { @@ -68,53 +72,186 @@ public class TopicConfiguration extends ConfigurationPlugin throw new ConfigurationException("Topics section cannot be empty."); } - int topics = _configuration.getList("topic.name").size(); + int topics = _configuration.getList("topic.name").size() + + _configuration.getList("topic.subscriptionName").size(); - for(int index=0; index topics; + if (_subscriptions.containsKey(name)) + { + topics = _subscriptions.get(name); + + if (topics.containsKey(topic.getName())) + { + throw new ConfigurationException("Subcription cannot contain two entries for the same topic."); + } + } + else { - return new String[]{"name"}; + topics = new HashMap(); } - public String getName() + topics.put(topic.getName(),topic); + _subscriptions.put(name, topics); + + } + + @Override + public String formatToString() + { + return "Topics:" + _topics + ", Subscriptions:" + _subscriptions; + } + + /** + * This processes the given queue and apply configuration in the following + * order: + * + * Global Topic Values -> Topic Values -> Subscription Values + * + * @param queue + * + * @return + */ + public ConfigurationPlugin getConfiguration(AMQQueue queue) + { + TopicConfig config = new TopicConfig(); + + // Add global topic configuration + config.addConfiguration(this); + + // Process Topic Bindings as these are more generic than subscriptions + List boundToTopics = new LinkedList(); + + //Merge the configuration in the order that they are bound + for (Binding binding : queue.getBindings()) { - // If we don't specify a topic name then match all topics - String configName = getStringValue("name"); - return configName == null ? "#" : configName; + if (binding.getExchange().getType().equals(TopicExchange.TYPE)) + { + // Identify topic for the binding key + TopicConfig topicConfig = getTopicConfigForRoutingKey(binding.getBindingKey()); + if (topicConfig != null) + { + boundToTopics.add(topicConfig); + } + } } + // If the Queue is bound to a number of topics then only use the global + // topic configuration. + // todo - What does it mean in terms of configuration to be bound to a + // number of topics? Do we try and merge? + // YES - right thing to do would be to merge from generic to specific. + // Means we need to be able to get an ordered list of topics for this + // binding. + if (boundToTopics.size() == 1) + { + config.addConfiguration(boundToTopics.get(0)); + } - public void validateConfiguration() throws ConfigurationException + // Apply subscription configurations + if (_subscriptions.containsKey(queue.getName())) { - if(_configuration.isEmpty()) + Map topics = _subscriptions.get(queue.getName()); + + TopicConfig subscriptionSpecificConfig = null; + + // See if we have a TopicConfig in topics for a topic we are bound to. + for (Binding binding : queue.getBindings()) + { + if (binding.getExchange().getType().equals(TopicExchange.TYPE)) + { + //todo - What does it mean to have multiple matches? + // Take the first match we get + if (subscriptionSpecificConfig == null) + { + // lookup the binding to see if we have a match in the subscription configs + subscriptionSpecificConfig = topics.get(binding.getBindingKey()); + } + } + } + + // Apply subscription specfic config. + if (subscriptionSpecificConfig != null) { - throw new ConfigurationException("Topic section cannot be empty."); + config.addConfiguration(subscriptionSpecificConfig); } } + + return config; + } + + /** + * This method should perform the same heuristics as the TopicExchange + * to attempt to identify a piece of configuration for the give routingKey. + * + * i.e. If we have 'stocks.*' defined in the config + * and we bind 'stocks.appl' then we should return the 'stocks.*' + * configuration. + * + * @param routingkey the key to lookup + * + * @return the TopicConfig if found. + */ + private TopicConfig getTopicConfigForRoutingKey(String routingkey) + { + //todo actually perform TopicExchange style lookup not just straight + // lookup as we are just now. + return _topics.get(routingkey); } } -- cgit v1.2.1 From ca2413955f751c1201f1be2f2e1c7c21e75b047e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:15:25 +0000 Subject: QPID-2681 : Provide ability to merge configurations. This does simple merging of sub configuration elements. Currently the last value to be merged is taken as is. No explicit merging is performed. Merging is performed in the order Queues->(Exchange)->Queue, Where a configured Exchange Configuration component can decide how to perform its merge. TopicConfiguration performs the order Topics->Topic->Subscriptions, this allows Global Topic configuration to be overwritten by a specific topic version. Currently the Topic is only identified by a straight string wild card matching has not yet been implemented. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960546 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/ExchangeConfigurationPlugin.java | 29 +++++ .../server/configuration/QueueConfiguration.java | 40 +++++- .../configuration/VirtualHostConfiguration.java | 47 +++++-- .../configuration/plugins/ConfigurationPlugin.java | 142 +++++++++++++++++---- 4 files changed, 224 insertions(+), 34 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigurationPlugin.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigurationPlugin.java new file mode 100644 index 0000000000..bfb2de4235 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigurationPlugin.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.queue.AMQQueue; + +public interface ExchangeConfigurationPlugin +{ + ConfigurationPlugin getConfiguration(AMQQueue queue); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index f62022922a..4512de6fb4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -23,7 +23,6 @@ package org.apache.qpid.server.configuration; import java.util.List; import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; @@ -167,4 +166,43 @@ public class QueueConfiguration extends ConfigurationPlugin { return getStringValue("lvqKey", null); } + + + public static class QueueConfig extends ConfigurationPlugin + { + @Override + public String[] getElementsProcessed() + { + return new String[]{"name"}; + } + + public String getName() + { + return getStringValue("name"); + } + + + public void validateConfiguration() throws ConfigurationException + { + if (_configuration.isEmpty()) + { + throw new ConfigurationException("Queue section cannot be empty."); + } + + if (getName() == null) + { + throw new ConfigurationException("Queue section must have a 'name' element."); + } + + } + + + @Override + public String formatToString() + { + return "Name:"+getName(); + } + + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 7dab02aee7..967e8a03f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -34,11 +34,7 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.binding.Binding; -import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; @@ -212,15 +208,48 @@ public class VirtualHostConfiguration extends ConfigurationPlugin + exchangeName.substring(0, 1).toUpperCase() + exchangeName.substring(1) + "Configuration"; - ConfigurationPlugin configPlugin - = queue.getVirtualHost().getConfiguration().getConfiguration(exchangeClass); - + ExchangeConfigurationPlugin exchangeConfiguration + = (ExchangeConfigurationPlugin) queue.getVirtualHost().getConfiguration().getConfiguration(exchangeClass); // now need to perform the queue-topic-topics-queue magic. + // So make a new ConfigurationObject that will hold all the configuration for this queue. + ConfigurationPlugin queueConfig = new QueueConfiguration.QueueConfig(); + + // Initialise the queue with any Global values we may have + QueueConfiguration config = getConfiguration(QueueConfiguration.class.getName()); + if (config == null) + { + PropertiesConfiguration newQueueConfig = new PropertiesConfiguration(); + newQueueConfig.setProperty("name", queue.getName()); - System.err.println("*********** Reconfiguring queue with config:"+configPlugin); + try + { + queueConfig.setConfiguration("", newQueueConfig); + } + catch (ConfigurationException e) + { + // This will not occur as queues only require a name. + _logger.error("QueueConfiguration requirements have changed."); + } + } + else + { + queueConfig.addConfiguration(config); + } + + // Merge any configuration the Exchange wishes to apply + if (exchangeConfiguration != null) + { + queueConfig.addConfiguration(exchangeConfiguration.getConfiguration(queue)); + } + + //Finally merge in any specific queue configuration we have. + if (_queues.containsKey(queue.getName())) + { + queueConfig.addConfiguration(_queues.get(queue.getName())); + } - return configPlugin; + return queueConfig; } public long getMemoryUsageMaximum() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java index 1da1459f70..82b576ea51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/ConfigurationPlugin.java @@ -18,6 +18,13 @@ */ package org.apache.qpid.server.configuration.plugins; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConversionException; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.ConfigurationManager; +import org.apache.qpid.server.registry.ApplicationRegistry; + import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -27,13 +34,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.ConversionException; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.ConfigurationManager; -import org.apache.qpid.server.registry.ApplicationRegistry; - public abstract class ConfigurationPlugin { protected static final Logger _logger = Logger.getLogger(ConfigurationPlugin.class); @@ -45,20 +45,18 @@ public abstract class ConfigurationPlugin /** * The Elements that this Plugin can process. - * + * * For a Queues plugin that would be a list containing: *

        *
      • queue - the queue entries *
      • the alerting values for defaults *
      • exchange - the default exchange *
      • durable - set the default durablity - *
      + * */ abstract public String[] getElementsProcessed(); - - /** - * Performs configuration validation. - */ + + /** Performs configuration validation. */ public void validateConfiguration() throws ConfigurationException { // Override in sub-classes @@ -145,14 +143,20 @@ public abstract class ConfigurationPlugin { ConfigurationManager configurationManager = ApplicationRegistry.getInstance().getConfigurationManager(); Configuration handled = element.length() == 0 ? configuration : configuration.subset(element); - + String configurationElement = element; if (path.length() > 0) { - configurationElement = path + "." + configurationElement; + configurationElement = path + "." + configurationElement; } List handlers = configurationManager.getConfigurationPlugins(configurationElement, handled); + + if(_logger.isDebugEnabled()) + { + _logger.debug("For '" + element + "' found handlers (" + handlers.size() + "):" + handlers); + } + for (ConfigurationPlugin plugin : handlers) { _pluginConfiguration.put(plugin.getClass().getName(), plugin); @@ -161,10 +165,8 @@ public abstract class ConfigurationPlugin validateConfiguration(); } - - /** - * Helper method to print out list of keys in a {@link Configuration}. - */ + + /** Helper method to print out list of keys in a {@link Configuration}. */ public static final void showKeys(Configuration config) { if (config.isEmpty()) @@ -186,7 +188,7 @@ public abstract class ConfigurationPlugin { return _configuration != null; } - + /// Getters protected double getDoubleValue(String property) @@ -199,7 +201,6 @@ public abstract class ConfigurationPlugin return _configuration.getDouble(property, defaultValue); } - protected long getLongValue(String property) { return getLongValue(property, 0); @@ -250,8 +251,6 @@ public abstract class ConfigurationPlugin return _configuration.getList(property, defaultValue); } - - /// Validation Helpers protected boolean contains(String property) @@ -259,7 +258,6 @@ public abstract class ConfigurationPlugin return _configuration.getProperty(property) != null; } - /** * Provide mechanism to validate Configuration contains a Postiive Long Value * @@ -354,6 +352,102 @@ public abstract class ConfigurationPlugin } } + /** + * Given another configuration merge the configuration into our own config + * + * The new values being merged in will take precedence over existing values. + * + * In the simplistic case this means something like: + * + * So if we have configuration set + * name = 'fooo' + * + * And the new configuration contains a name then that will be reset. + * name = 'new' + * + * However this plugin will simply contain other plugins so the merge will + * be called until we end up at a base plugin that understand how to merge + * items. i.e Alerting values. Where the provided configuration will take + * precedence. + * + * @param configuration the config to merge in to our own. + */ + public void addConfiguration(ConfigurationPlugin configuration) + { + // If given configuration is null then there is nothing to process. + if (configuration == null) + { + return; + } + + // Merge all the sub configuration items + for (Map.Entry newPlugins : configuration._pluginConfiguration.entrySet()) + { + String key = newPlugins.getKey(); + ConfigurationPlugin config = newPlugins.getValue(); + + if (_pluginConfiguration.containsKey(key)) + { + //Merge the configuration if we already have this type of config + _pluginConfiguration.get(key).mergeConfiguration(config); + } + else + { + //otherwise just add it to our config. + _pluginConfiguration.put(key, config); + } + } + + //Merge the configuration itself + String key = configuration.getClass().getName(); + if (_pluginConfiguration.containsKey(key)) + { + //Merge the configuration if we already have this type of config + _pluginConfiguration.get(key).mergeConfiguration(configuration); + } + else + { + //If we are adding a configuration of our own type then merge + if (configuration.getClass() == this.getClass()) + { + mergeConfiguration(configuration); + } + else + { + // just store this in case someone else needs it. + _pluginConfiguration.put(key, configuration); + } + + } + + } + + protected void mergeConfiguration(ConfigurationPlugin configuration) + { + _configuration = configuration.getConfig(); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("\n").append(getClass().getSimpleName()); + sb.append("=[ (").append(formatToString()).append(")"); + + for(Map.Entry item : _pluginConfiguration.entrySet()) + { + sb.append("\n").append(item.getValue()); + } + + sb.append("]\n"); + + return sb.toString(); + } + + public String formatToString() + { + return super.toString(); + } } -- cgit v1.2.1 From 89a83eed58fcbbf07e5f85c3dee15e70a734131a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:16:17 +0000 Subject: QPID-2681 : Correcly process global configuration, added test to cover git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960549 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/TopicConfiguration.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java index a16198788f..c7a195f9e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java @@ -77,8 +77,6 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC for (int index = 0; index < topics; index++) { - TopicConfig topic = new TopicConfig(); - Configuration topicSubset = _configuration.subset("topic(" + index + ")"); // This will occur when we have a subscriptionName that is bound to a @@ -88,6 +86,8 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC break; } + TopicConfig topic = new TopicConfig(); + topic.setConfiguration(VIRTUALHOSTS_VIRTUALHOST_TOPICS + ".topic", topicSubset ); String name = _configuration.getString("topic(" + index + ").name"); @@ -169,6 +169,7 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC */ public ConfigurationPlugin getConfiguration(AMQQueue queue) { + //Create config with global topic configuration TopicConfig config = new TopicConfig(); // Add global topic configuration @@ -225,7 +226,15 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC } } - // Apply subscription specfic config. + //todo we don't account for wild cards here. only explict matching and all subscriptions + if (subscriptionSpecificConfig == null) + { + // lookup the binding to see if we have a match in the subscription configs + subscriptionSpecificConfig = topics.get("#"); + } + + + // Apply subscription specific config. if (subscriptionSpecificConfig != null) { config.addConfiguration(subscriptionSpecificConfig); -- cgit v1.2.1 From d79b57a2d19bde77e16c508c375c992d44bc8cba Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:15:47 +0000 Subject: QPID-2681 : Update VHC to correctly merge queues-(exchange)-queue git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960550 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 967e8a03f2..d9d7083543 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -211,30 +211,30 @@ public class VirtualHostConfiguration extends ConfigurationPlugin ExchangeConfigurationPlugin exchangeConfiguration = (ExchangeConfigurationPlugin) queue.getVirtualHost().getConfiguration().getConfiguration(exchangeClass); - // now need to perform the queue-topic-topics-queue magic. + // now need to perform the queue-topic-topics-queues magic. // So make a new ConfigurationObject that will hold all the configuration for this queue. ConfigurationPlugin queueConfig = new QueueConfiguration.QueueConfig(); // Initialise the queue with any Global values we may have - QueueConfiguration config = getConfiguration(QueueConfiguration.class.getName()); - if (config == null) + PropertiesConfiguration newQueueConfig = new PropertiesConfiguration(); + newQueueConfig.setProperty("name", queue.getName()); + + try { - PropertiesConfiguration newQueueConfig = new PropertiesConfiguration(); - newQueueConfig.setProperty("name", queue.getName()); + //Set the queue name + CompositeConfiguration mungedConf = new CompositeConfiguration(); + //Set the queue name + mungedConf.addConfiguration(newQueueConfig); + //Set the global queue configuration + mungedConf.addConfiguration(getConfig().subset("queues")); - try - { - queueConfig.setConfiguration("", newQueueConfig); - } - catch (ConfigurationException e) - { - // This will not occur as queues only require a name. - _logger.error("QueueConfiguration requirements have changed."); - } + // Set configuration + queueConfig.setConfiguration("virtualhosts.virtualhost.queues", mungedConf); } - else + catch (ConfigurationException e) { - queueConfig.addConfiguration(config); + // This will not occur as queues only require a name. + _logger.error("QueueConfiguration requirements have changed."); } // Merge any configuration the Exchange wishes to apply -- cgit v1.2.1 From e7699d4097e1d0d2b8753fe4e17547a5821abf5a Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:16:47 +0000 Subject: QPID-1447 : Added some addition debug log to queue to aid understanding when queues are reconfigured git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960551 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index c4567b2e8b..d47d229658 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -507,6 +507,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener //Reconfigure the queue for to reflect this new binding. ConfigurationPlugin config = getVirtualHost().getConfiguration().getQueueConfiguration(this); + if (_logger.isDebugEnabled()) + { + _logger.debug("Reconfiguring queue(" + this + ") with config:" + config + " was "+ _queueConfiguration); + } + if (config != null) { // Reconfigure with new config. -- cgit v1.2.1 From 86cb7e98fcd5ebdb0f0e10e9a4efdeaf87799719 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:16:16 +0000 Subject: QPID-2681 : Provide default empty configuration for TopicConfig git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960552 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/configuration/TopicConfig.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java index b4ccc75f10..d5420d9718 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfig.java @@ -21,10 +21,16 @@ package org.apache.qpid.server.configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public class TopicConfig extends ConfigurationPlugin { + public TopicConfig() + { + _configuration = new PropertiesConfiguration(); + } + @Override public String[] getElementsProcessed() { -- cgit v1.2.1 From 039b5385d0ebd8a8571fa2443c8a8fd73f788bb2 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Jul 2010 11:17:23 +0000 Subject: QPID-2681 : Add final SCD testing for Topic and Subscriptions git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960553 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/configuration/TopicConfiguration.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java index c7a195f9e4..8716fed8c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/TopicConfiguration.java @@ -204,14 +204,19 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC config.addConfiguration(boundToTopics.get(0)); } + // If we have a subscription then attempt to look it up. + String subscriptionName = queue.getName(); + // Apply subscription configurations - if (_subscriptions.containsKey(queue.getName())) + if (_subscriptions.containsKey(subscriptionName)) { - Map topics = _subscriptions.get(queue.getName()); + + //Get all the Configuration that this subscription is bound to. + Map topics = _subscriptions.get(subscriptionName); TopicConfig subscriptionSpecificConfig = null; - // See if we have a TopicConfig in topics for a topic we are bound to. + // See if we have a TopicConfig in topics for a topic we are bound to. for (Binding binding : queue.getBindings()) { if (binding.getExchange().getType().equals(TopicExchange.TYPE)) @@ -226,21 +231,19 @@ public class TopicConfiguration extends ConfigurationPlugin implements ExchangeC } } - //todo we don't account for wild cards here. only explict matching and all subscriptions + //todo we don't account for wild cards here. only explicit matching and all subscriptions if (subscriptionSpecificConfig == null) { // lookup the binding to see if we have a match in the subscription configs subscriptionSpecificConfig = topics.get("#"); } - // Apply subscription specific config. if (subscriptionSpecificConfig != null) { config.addConfiguration(subscriptionSpecificConfig); } } - return config; } -- cgit v1.2.1 From 8db7ae7ca30bdf2f71598d5a52b5711705a1a011 Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Mon, 5 Jul 2010 20:00:54 +0000 Subject: QPID-2700 Patch for ability to remove bindings from exchanges and additional tests for direct and topic exchange add/remove logic from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@960678 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/exchange/AbstractExchangeMBean.java | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index 0dca91b7be..c69d499674 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -20,6 +20,9 @@ */ package org.apache.qpid.server.exchange; +import java.util.Collections; +import java.util.Map; + import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.server.management.AMQManagedObject; @@ -28,6 +31,7 @@ import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; import org.apache.qpid.management.common.mbeans.ManagedExchange; @@ -147,4 +151,31 @@ public abstract class AbstractExchangeMBean extends } CurrentActor.remove(); } + + /** + * Removes a queue binding from the exchange. + * + * @see BindingFactory#removeBinding(String, AMQQueue, Exchange, Map) + */ + public void removeBinding(String queueName, String binding) throws JMException + { + VirtualHost vhost = getExchange().getVirtualHost(); + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); + try + { + vhost.getBindingFactory().removeBinding(binding, queue, _exchange, Collections.emptyMap()); + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error removing binding " + binding); + } + CurrentActor.remove(); + } } -- cgit v1.2.1 From 0f8291961d43b664116b4cc1fe99d19fe92d8007 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 8 Jul 2010 20:35:36 +0000 Subject: QPID-2726: move the password verification process to an easily overridable protected method git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@961923 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/auth/sasl/plain/PlainSaslServer.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java index 731ac70c0e..1187aac303 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -79,8 +79,7 @@ public class PlainSaslServer implements SaslServer AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; _cbh.handle(callbacks); - String storedPwd = new String(passwordCb.getPassword()); - if (storedPwd.equals(pwd)) + if (validatePassword(pwd, passwordCb)) { _complete = true; } @@ -104,6 +103,20 @@ public class PlainSaslServer implements SaslServer } } + /** + * Compares the incoming plain text password with that contained in the given PasswordCallback + * + * @param incomingPwd The incoming plain text password + * @param storedPwdCb PasswordCallback containing the stored password + * @return Whether the incoming password authenticates against the stored password + */ + protected boolean validatePassword(String incomingPwd, PasswordCallback storedPwdCb) + { + String storedPwd = new String(storedPwdCb.getPassword()); + + return incomingPwd.equals(storedPwd); + } + private int findNullPosition(byte[] response, int startPosition) { int position = startPosition; -- cgit v1.2.1 From 2062588ec0f4cae8fe45bf4e37a8b871211560b5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 10 Jul 2010 16:14:25 +0000 Subject: QPID-2726: add custom PlainPasswordCallback to enable PLAIN auth against custom PrincipalDatabase's which cant actually return password data, and revert r961923 changes. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@962870 13f79535-47bb-0310-9956-ffa450edef68 --- .../auth/sasl/plain/PlainPasswordCallback.java | 81 ++++++++++++++++++++++ .../security/auth/sasl/plain/PlainSaslServer.java | 23 ++---- 2 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java new file mode 100644 index 0000000000..7230e8ee53 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java @@ -0,0 +1,81 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl.plain; + +import java.util.Arrays; + +import javax.security.auth.callback.PasswordCallback; + +/** + * Custom PasswordCallback for use during the PLAIN authentication process. + * + * To be used in combination with PrincipalDatabase implementations that + * can either set a plain text value in the parent callback, or use the + * setAuthenticated(bool) method after observing the incoming plain text. + * + * isAuthenticated() should then be used to determine the final result. + * + */ +public class PlainPasswordCallback extends PasswordCallback +{ + private char[] _plainPassword; + private boolean _authenticated = false; + + /** + * Constructs a new PlainPasswordCallback with the incoming plain text password. + * + * @throws NullPointerException if the incoming plain text is null + */ + public PlainPasswordCallback(String prompt, boolean echoOn, String plainPassword) + { + super(prompt, echoOn); + + if(plainPassword == null) + { + throw new NullPointerException("Incoming plain text cannot be null"); + } + + _plainPassword = plainPassword.toCharArray(); + } + + public String getPlainPassword() + { + return new String(_plainPassword); + } + + public void setAuthenticated(boolean authenticated) + { + _authenticated = authenticated; + } + + /** + * Method to determine if the incoming plain password is authenticated + * + * @return true if the stored password matches the incoming text, or setAuthenticated(true) has been called + */ + public boolean isAuthenticated() + { + char[] storedPassword = getPassword(); + + return Arrays.equals(_plainPassword, storedPassword) || _authenticated; + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java index 1187aac303..847a3a34ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -70,16 +70,19 @@ public class PlainSaslServer implements SaslServer // String authcid = new String(response, 0, authzidNullPosition, "utf8"); String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - authzidNullPosition - 1, "utf8"); - // we do not care about the prompt but it throws if null - NameCallback nameCb = new NameCallback("prompt", authzid); - 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"); + + // we do not care about the prompt but it throws if null + NameCallback nameCb = new NameCallback("prompt", authzid); + PlainPasswordCallback passwordCb = new PlainPasswordCallback("prompt", false, pwd); AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); + Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; _cbh.handle(callbacks); - if (validatePassword(pwd, passwordCb)) + + if (passwordCb.isAuthenticated()) { _complete = true; } @@ -103,19 +106,7 @@ public class PlainSaslServer implements SaslServer } } - /** - * Compares the incoming plain text password with that contained in the given PasswordCallback - * - * @param incomingPwd The incoming plain text password - * @param storedPwdCb PasswordCallback containing the stored password - * @return Whether the incoming password authenticates against the stored password - */ - protected boolean validatePassword(String incomingPwd, PasswordCallback storedPwdCb) - { - String storedPwd = new String(storedPwdCb.getPassword()); - return incomingPwd.equals(storedPwd); - } private int findNullPosition(byte[] response, int startPosition) { -- cgit v1.2.1 From 2c591c4241da3bfba6dfa03e65b2fb81e17f4250 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 16 Jul 2010 15:19:46 +0000 Subject: QPID-2731: enable getting/setting queue exclusivity via JMX git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@964825 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueue.java | 2 + .../apache/qpid/server/queue/AMQQueueMBean.java | 17 ++++++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 12 ++++++ .../qpid/server/store/DerbyMessageStore.java | 45 ++++++++++++++++++++++ .../server/store/DurableConfigurationStore.java | 9 +++++ .../qpid/server/store/MemoryMessageStore.java | 5 +++ .../qpid/server/virtualhost/VirtualHostImpl.java | 4 ++ 7 files changed, 94 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 225fbec930..de9dc42de8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -280,4 +280,6 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer ConfigurationPlugin getConfiguration(); ManagedObject getManagedObject(); + + void setExclusive(boolean exclusive) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 806b7f3744..32b71a554b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -274,6 +274,23 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que return _queue.isOverfull(); } + public boolean isExclusive() + { + return _queue.isExclusive(); + } + + public void setExclusive(boolean exclusive) throws JMException + { + try + { + _queue.setExclusive(exclusive); + } + catch (AMQException e) + { + throw new JMException(e.toString()); + } + } + /** * Checks if there is any notification to be send to the listeners */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d47d229658..489a724254 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -53,6 +53,8 @@ import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; + +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -328,6 +330,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { return _exclusive; } + + public void setExclusive(boolean exclusive) throws AMQException + { + _exclusive = exclusive; + + if(isDurable()) + { + getVirtualHost().getDurableConfigurationStore().updateQueue(this); + } + } public Exchange getAlternateExchange() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 40f265e00f..627f059c53 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -94,6 +94,7 @@ public class DerbyMessageStore implements MessageStore private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; private static final String SELECT_FROM_QUEUE = "SELECT name, owner, exclusive, arguments FROM " + QUEUE_TABLE_NAME; private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + private static final String UPDATE_QUEUE_EXCLUSIVITY = "UPDATE " + QUEUE_TABLE_NAME + " SET exclusive = ? WHERE name = ?"; private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; private static final String SELECT_FROM_BINDINGS = "SELECT exchange_name, queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " ORDER BY exchange_name"; @@ -845,6 +846,50 @@ public class DerbyMessageStore implements MessageStore } } } + + /** + * Updates the specified queue in the persistent store, IF it is already present. If the queue + * is not present in the store, it will not be added. + * + * NOTE: Currently only updates the exclusivity. + * + * @param queue The queue to update the entry for. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + public void updateQueue(final AMQQueue queue) throws AMQException + { + if (_state != State.RECOVERING) + { + try + { + Connection conn = newAutoCommitConnection(); + + PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); + stmt.setString(1, queue.getNameShortString().toString()); + + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) + { + PreparedStatement stmt2 = conn.prepareStatement(UPDATE_QUEUE_EXCLUSIVITY); + + stmt2.setBoolean(1,queue.isExclusive()); + stmt2.setString(2, queue.getNameShortString().toString()); + + stmt2.execute(); + stmt2.close(); + } + + stmt.close(); + conn.close(); + } + catch (SQLException e) + { + throw new AMQException("Error updating AMQQueue with name " + queue.getNameShortString() + " to database: " + e, e); + } + } + + } /** * Convenience method to create a new Connection configured for TRANSACTION_READ_COMMITED diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java index a50e8e99b4..c169e3bcff 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -118,4 +118,13 @@ public interface DurableConfigurationStore * @throws org.apache.qpid.AMQException If the operation fails for any reason. */ void removeQueue(AMQQueue queue) throws AMQException; + + /** + * Updates the specified queue in the persistent store, IF it is already present. If the queue + * is not present in the store, it will not be added. + * + * @param queue The queue to update the entry for. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void updateQueue(AMQQueue queue) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 565afd2539..9d9312cd26 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -148,6 +148,11 @@ public class MemoryMessageStore implements MessageStore { // Not required to do anything } + + public void updateQueue(final AMQQueue queue) throws AMQException + { + // Not required to do anything + } public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index fcb06f56bf..c6055f35f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -765,6 +765,10 @@ public class VirtualHostImpl implements VirtualHost arguments = args; } } + + public void updateQueue(AMQQueue queue) throws AMQException + { + } } @Override -- cgit v1.2.1 From 4832a5c954f5e99f938ce9531e7d2feb8f012acd Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 16 Jul 2010 15:20:01 +0000 Subject: QPID-2741: issue the shutdown command to Derby during close() git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@964827 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/store/DerbyMessageStore.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 627f059c53..ae4f6f3796 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -520,6 +520,22 @@ public class DerbyMessageStore implements MessageStore { CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED()); _closed.getAndSet(true); + + try + { + DriverManager.getConnection(_connectionURL + ";shutdown=true"); + } + catch (SQLException e) + { + if (e.getSQLState().equalsIgnoreCase("XJ015")) + { + //XJ015 is expected and represents a clean shutdown, do nothing. + } + else + { + _logger.error("Exception whilst shutting down the store: " + e); + } + } } public StoredMessage addMessage(StorableMessageMetaData metaData) -- cgit v1.2.1 From 9306ead5ad10a70b475d8777caf8c8c2bce63668 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 16 Jul 2010 15:20:16 +0000 Subject: QPID-2742: Gather exchange type name properly, and remove the extraneous statement execution and move its closure after use use the output ResultSet. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@964829 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index ae4f6f3796..62f2d14e09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -618,17 +618,17 @@ public class DerbyMessageStore implements MessageStore PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); stmt.setString(1, exchange.getNameShortString().toString()); - stmt.execute(); - stmt.close(); ResultSet rs = stmt.executeQuery(); // If we don't have any data in the result set then we can add this exchange if (!rs.next()) { + stmt.close(); + stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); stmt.setString(1, exchange.getName().toString()); - stmt.setString(2, exchange.getType().toString()); + stmt.setString(2, exchange.getTypeShortString().asString()); stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); stmt.execute(); stmt.close(); -- cgit v1.2.1 From d7be043edcd9ffdac74471089aa493a4a87aa37e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 16 Jul 2010 15:20:05 +0000 Subject: QPID-2731, QPID-2741, QPID-2742: Enable the MessageStoreTest to run for the DerbyMessageStore. Test update of queue exclusivity. Apply various fixes to allowtest to pass (correct exchange count checks, flush messages to the store, delete store directory properly, check for the proper value for selector argument, add ability to unregister virtualhosts from the registry) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@964830 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 4b140f1ca7..32d0c4c4d1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -51,6 +51,11 @@ public class VirtualHostRegistry implements Closeable } _registry.put(host.getName(),host); } + + public synchronized void unregisterVirtualHost(VirtualHost host) + { + _registry.remove(host.getName()); + } public VirtualHost getVirtualHost(String name) { -- cgit v1.2.1 From 0046e917a447e051ee5b8aaf509985e465981502 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Thu, 22 Jul 2010 13:02:49 +0000 Subject: QPID-2679: cache queues that are configured on a per-virtualhost basis git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@966634 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 489a724254..484dd5971d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -515,7 +515,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener break; } } - + + reconfigure(); + } + + private void reconfigure() + { //Reconfigure the queue for to reflect this new binding. ConfigurationPlugin config = getVirtualHost().getConfiguration().getQueueConfiguration(this); @@ -539,6 +544,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void removeBinding(final Binding binding) { _bindings.remove(binding); + + reconfigure(); } public List getBindings() -- cgit v1.2.1 From 28094213ff2f572d21b272853fd9063903564a7a Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Thu, 22 Jul 2010 13:09:56 +0000 Subject: QPID-2682: Move slow consumer disconnection mechanism to the broker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@966637 13f79535-47bb-0310-9956-ffa450edef68 --- .../plugin/SlowConsumerDetectionConfiguration.java | 92 ++++++++++++ .../SlowConsumerDetectionPolicyConfiguration.java | 76 ++++++++++ .../SlowConsumerDetectionQueueConfiguration.java | 153 ++++++++++++++++++++ .../apache/qpid/server/plugins/PluginManager.java | 90 +++++++----- .../plugin/ConfiguredQueueBindingListener.java | 86 +++++++++++ .../virtualhost/plugin/SlowConsumerDetection.java | 161 +++++++++++++++++++++ .../SlowConsumerDetection_logmessages.properties | 4 + .../TopicDeletePolicy_logmessages.properties | 3 + .../plugin/policies/TopicDeletePolicy.java | 141 ++++++++++++++++++ .../policies/TopicDeletePolicyConfiguration.java | 81 +++++++++++ .../policies/SlowConsumerPolicyPlugin.java | 29 ++++ .../policies/SlowConsumerPolicyPluginFactory.java | 27 ++++ 12 files changed, 903 insertions(+), 40 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPlugin.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPluginFactory.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java new file mode 100644 index 0000000000..dd63c9b698 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugin; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConversionException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SlowConsumerDetectionConfiguration extends ConfigurationPlugin +{ + public static class SlowConsumerDetectionConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionConfiguration slowConsumerConfig = new SlowConsumerDetectionConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList("virtualhosts.virtualhost.slow-consumer-detection"); + } + } + + //Set Default time unit to seconds + TimeUnit _timeUnit = TimeUnit.SECONDS; + + public String[] getElementsProcessed() + { + return new String[]{"delay", + "timeunit"}; + } + + public long getDelay() + { + return getLongValue("delay", 10); + } + + public TimeUnit getTimeUnit() + { + return _timeUnit; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + validatePositiveLong("delay"); + + String timeUnit = getStringValue("timeunit"); + + if (timeUnit != null) + { + try + { + _timeUnit = TimeUnit.valueOf(timeUnit.toUpperCase()); + } + catch (IllegalArgumentException iae) + { + throw new ConfigurationException("Unable to configure Slow Consumer Detection invalid TimeUnit:" + timeUnit); + } + } + + System.out.println("Configured SCDC"); + System.out.println("Delay:" + getDelay()); + System.out.println("TimeUnit:" + getTimeUnit()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java new file mode 100644 index 0000000000..8e2ecff6fb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugin; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; + +public class SlowConsumerDetectionPolicyConfiguration extends ConfigurationPlugin +{ + public static class SlowConsumerDetectionPolicyConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionPolicyConfiguration slowConsumerConfig = new SlowConsumerDetectionPolicyConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection.policy", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy", + "virtualhosts.virtualhost.topics.slow-consumer-detection.policy", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"name"}; + } + + public String getPolicyName() + { + return getStringValue("name"); + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + if (getPolicyName() == null) + { + throw new ConfigurationException("No Slow consumer policy defined."); + } + } + + @Override + public String formatToString() + { + return "Policy:"+getPolicyName(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java new file mode 100644 index 0000000000..58131760da --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java @@ -0,0 +1,153 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugin; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin +{ + private SlowConsumerPolicyPlugin _policyPlugin; + + public static class SlowConsumerDetectionQueueConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionQueueConfiguration slowConsumerConfig = new SlowConsumerDetectionQueueConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection", + "virtualhosts.virtualhost.topics.slow-consumer-detection", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"messageAge", + "depth", + "messageCount"}; + } + + public long getMessageAge() + { + return getLongValue("messageAge"); + } + + public long getDepth() + { + return getLongValue("depth"); + } + + public long getMessageCount() + { + return getLongValue("messageCount"); + } + + public SlowConsumerPolicyPlugin getPolicy() + { + return _policyPlugin; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + if (!containsPositiveLong("messageAge") && + !containsPositiveLong("depth") && + !containsPositiveLong("messageCount")) + { + throw new ConfigurationException("At least one configuration property" + + "('messageAge','depth' or 'messageCount') must be specified."); + } + + SlowConsumerDetectionPolicyConfiguration policyConfig = getConfiguration(SlowConsumerDetectionPolicyConfiguration.class.getName()); + + PluginManager pluginManager = ApplicationRegistry.getInstance().getPluginManager(); + Map factories = pluginManager.getSlowConsumerPlugins(); + + if (policyConfig == null) + { + throw new ConfigurationException("No Slow Consumer Policy specified. Known Policies:" + factories.keySet()); + } + + if (_logger.isDebugEnabled()) + { + Iterator keys = policyConfig.getConfig().getKeys(); + + while (keys.hasNext()) + { + String key = (String) keys.next(); + + _logger.debug("Policy Keys:" + key); + } + + } + + SlowConsumerPolicyPluginFactory pluginFactory = factories.get(policyConfig.getPolicyName().toLowerCase()); + + if (pluginFactory == null) + { + throw new ConfigurationException("Unknown Slow Consumer Policy specified:" + policyConfig.getPolicyName() + " Known Policies:" + factories.keySet()); + } + + _policyPlugin = pluginFactory.newInstance(policyConfig); + + // Debug the creation of this Config + _logger.debug(this); + } + + public String formatToString() + { + StringBuilder sb = new StringBuilder(); + if (getMessageAge() > 0) + { + sb.append("Age:").append(getMessageAge()).append(":"); + } + if (getDepth() > 0) + { + sb.append("Depth:").append(getDepth()).append(":"); + } + if (getMessageCount() > 0) + { + sb.append("Count:").append(getMessageCount()).append(":"); + } + + sb.append("Policy[").append(getPolicy()).append("]"); + return sb.toString(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 717f0d1bee..97c43b940b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -35,6 +35,9 @@ import org.apache.felix.framework.util.StringMap; import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.TopicConfiguration; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionConfiguration.SlowConsumerDetectionConfigurationFactory; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionPolicyConfiguration.SlowConsumerDetectionPolicyConfigurationFactory; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration.SlowConsumerDetectionQueueConfigurationFactory; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.SecurityManager; @@ -43,6 +46,9 @@ import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; import org.apache.qpid.server.security.access.plugins.LegacyAccess; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; +import org.apache.qpid.server.virtualhost.plugin.SlowConsumerDetection; +import org.apache.qpid.server.virtualhost.plugin.policies.TopicDeletePolicy; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; import org.osgi.framework.launch.Framework; @@ -57,7 +63,6 @@ public class PluginManager implements Closeable private static final Logger _logger = Logger.getLogger(PluginManager.class); private static final int FELIX_STOP_TIMEOUT = 30000; - private static final String VERSION = "2.6.0.4"; private Framework _felix; @@ -65,11 +70,14 @@ public class PluginManager implements Closeable private ServiceTracker _securityTracker = null; private ServiceTracker _configTracker = null; private ServiceTracker _virtualHostTracker = null; + private ServiceTracker _policyTracker = null; private Activator _activator; private Map _securityPlugins = new HashMap(); private Map, ConfigurationPluginFactory> _configPlugins = new IdentityHashMap, ConfigurationPluginFactory>(); + private Map _vhostPlugins = new HashMap(); + private Map _policyPlugins = new HashMap(); public PluginManager(String pluginPath, String cachePath) throws Exception { @@ -85,10 +93,23 @@ public class PluginManager implements Closeable SecurityManager.SecurityConfiguration.FACTORY, AllowAll.AllowAllConfiguration.FACTORY, DenyAll.DenyAllConfiguration.FACTORY, - LegacyAccess.LegacyAccessConfiguration.FACTORY)) + LegacyAccess.LegacyAccessConfiguration.FACTORY, + new SlowConsumerDetectionConfigurationFactory(), + new SlowConsumerDetectionPolicyConfigurationFactory(), + new SlowConsumerDetectionQueueConfigurationFactory())) { _configPlugins.put(configFactory.getParentPaths(), configFactory); } + for (SlowConsumerPolicyPluginFactory pluginFactory : Arrays.asList( + new TopicDeletePolicy.TopicDeletePolicyFactory())) + { + _policyPlugins.put(pluginFactory.getPluginName(), pluginFactory); + } + for (VirtualHostPluginFactory pluginFactory : Arrays.asList( + new SlowConsumerDetection.SlowConsumerFactory())) + { + _vhostPlugins.put(pluginFactory.getClass().getName(), pluginFactory); + } // Check the plugin directory path is set and exist if (pluginPath == null) @@ -117,6 +138,7 @@ public class PluginManager implements Closeable "org.apache.qpid.common; version=0.7," + "org.apache.qpid.exchange; version=0.7," + "org.apache.qpid.framing; version=0.7," + + "org.apache.qpid.management.common.mbeans.annotations; version=0.7," + "org.apache.qpid.protocol; version=0.7," + "org.apache.qpid.server.binding; version=0.7," + "org.apache.qpid.server.configuration; version=0.7," + @@ -157,7 +179,7 @@ public class PluginManager implements Closeable configMap.put(SYSTEMBUNDLE_ACTIVATORS_PROP, activators); if (cachePath != null) - { + { File cacheDir = new File(cachePath); if (!cacheDir.exists() && cacheDir.canWrite()) { @@ -204,12 +226,11 @@ public class PluginManager implements Closeable _virtualHostTracker = new ServiceTracker(_activator.getContext(), VirtualHostPluginFactory.class.getName(), null); _virtualHostTracker.open(); - - _logger.info("Opened service trackers"); + + _policyTracker = new ServiceTracker(_activator.getContext(), SlowConsumerPolicyPluginFactory.class.getName(), null); + _policyTracker.open(); - // Load security and configuration plugins from their trackers for access - _configPlugins.putAll(getConfigurationServices()); - _securityPlugins.putAll(getPlugins(SecurityPluginFactory.class)); + _logger.info("Opened service trackers"); } private static Map getServices(ServiceTracker tracker) @@ -234,11 +255,18 @@ public class PluginManager implements Closeable return services; } - private Map, ConfigurationPluginFactory> getConfigurationServices() + public static Map getServices(ServiceTracker tracker, Map plugins) + { + Map services = getServices(tracker); + services.putAll(plugins); + return services; + } + + public Map, ConfigurationPluginFactory> getConfigurationPlugins() { Map, ConfigurationPluginFactory> services = new IdentityHashMap, ConfigurationPluginFactory>(); - if (_configTracker.getServices() != null) + if (_configTracker != null && _configTracker.getServices() != null) { for (Object service : _configTracker.getServices()) { @@ -246,49 +274,30 @@ public class PluginManager implements Closeable services.put(factory.getParentPaths(), factory); } } + + services.putAll(_configPlugins); return services; } - public Map> getExchanges() - { - return getServices(_exchangeTracker); + public Map getVirtualHostPlugins() + { + return getServices(_virtualHostTracker, _vhostPlugins); } - public Map getVirtualHostPlugins() - { - return getServices(_virtualHostTracker); + public Map getSlowConsumerPlugins() + { + return getServices(_policyTracker, _policyPlugins); } - public

      > Map getPlugins(Class

      plugin) + public Map> getExchanges() { - // If plugins are not configured then return an empty set - if (_activator == null) - { - return new HashMap(); - } - - ServiceTracker tracker = new ServiceTracker(_activator.getContext(), plugin.getName(), null); - tracker.open(); - - try - { - return getServices(tracker); - } - finally - { - tracker.close(); - } + return getServices(_exchangeTracker); } public Map getSecurityPlugins() { - return _securityPlugins; - } - - public Map, ConfigurationPluginFactory> getConfigurationPlugins() - { - return _configPlugins; + return getServices(_securityTracker, _securityPlugins); } public void close() @@ -302,6 +311,7 @@ public class PluginManager implements Closeable _securityTracker.close(); _configTracker.close(); _virtualHostTracker.close(); + _policyTracker.close(); } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java new file mode 100644 index 0000000000..d947e9a367 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java @@ -0,0 +1,86 @@ +package org.apache.qpid.server.virtualhost.plugin; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration; +import org.apache.qpid.server.exchange.AbstractExchange; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.Exchange.BindingListener; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * This is a listener that caches queues that are configured for slow consumer disconnection. + * + * There should be one listener per virtual host, which can be added to all exchanges on + * that host. + * + * TODO In future, it will be possible to configure the policy at runtime, so only the queue + * itself is cached, and the configuration looked up by the housekeeping thread. This means + * that there may be occasions where the copy of the cache contents retrieved by the thread + * does not contain queues that are configured, or that configured queues are not present. + * + * @see BindingListener + */ +public class ConfiguredQueueBindingListener implements BindingListener +{ + private static final Logger _log = Logger.getLogger(ConfiguredQueueBindingListener.class); + + private String _vhostName; + private Set _cache = Collections.synchronizedSet(new HashSet()); + + public ConfiguredQueueBindingListener(String vhostName) + { + _vhostName = vhostName; + } + + /** + * @see BindingListener#bindingAdded(Exchange, Binding) + */ + public void bindingAdded(Exchange exchange, Binding binding) + { + processBinding(binding); + } + + /** + * @see BindingListener#bindingRemoved(Exchange, Binding) + */ + public void bindingRemoved(Exchange exchange, Binding binding) + { + processBinding(binding); + } + + private void processBinding(Binding binding) + { + AMQQueue queue = binding.getQueue(); + + SlowConsumerDetectionQueueConfiguration config = + queue.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); + if (config != null) + { + _cache.add(queue); + } + else + { + _cache.remove(queue); + } + } + + /** + * Lookup and return the cache of configured {@link AMQQueue}s. + * + * Note that when accessing the cached queues, the {@link Iterator} is not thread safe + * (see the {@link Collections#synchronizedSet(Set)} documentation) so a copy of the + * cache is returned. + * + * @return a copy of the cached {@link java.util.Set} of queues + */ + public Set getQueueCache() + { + return new HashSet(_cache); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java new file mode 100644 index 0000000000..6acb0bc11e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java @@ -0,0 +1,161 @@ +/* + * + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugin; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionConfiguration; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.plugin.logging.SlowConsumerDetectionMessages; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; + +public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin +{ + private SlowConsumerDetectionConfiguration _config; + private ConfiguredQueueBindingListener _listener; + + public static class SlowConsumerFactory implements VirtualHostPluginFactory + { + public SlowConsumerDetection newInstance(VirtualHost vhost) + { + SlowConsumerDetectionConfiguration config = vhost.getConfiguration().getConfiguration(SlowConsumerDetectionConfiguration.class.getName()); + + if (config == null) + { + return null; + } + + SlowConsumerDetection plugin = new SlowConsumerDetection(vhost); + plugin.configure(config); + return plugin; + } + } + + /** + * Configures the slow consumer disconnect plugin by adding a listener to each exchange on this + * cirtual host to record all the configured queues in a cache for processing by the housekeeping + * thread. + * + * @see Plugin#configure(ConfigurationPlugin) + */ + public void configure(ConfigurationPlugin config) + { + _config = (SlowConsumerDetectionConfiguration) config; + _listener = new ConfiguredQueueBindingListener(_virtualhost.getName()); + for (AMQShortString exchangeName : _virtualhost.getExchangeRegistry().getExchangeNames()) + { + _virtualhost.getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener); + } + } + + public SlowConsumerDetection(VirtualHost vhost) + { + super(vhost); + } + + public void execute() + { + CurrentActor.get().message(SlowConsumerDetectionMessages.RUNNING()); + + Set cache = _listener.getQueueCache(); + for (AMQQueue q : cache) + { + CurrentActor.get().message(SlowConsumerDetectionMessages.CHECKING_QUEUE(q.getName())); + + try + { + SlowConsumerDetectionQueueConfiguration config = + q.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); + if (checkQueueStatus(q, config)) + { + config.getPolicy().performPolicy(q); + } + } + catch (Exception e) + { + // Don't throw exceptions as this will stop the house keeping task from running. + _logger.error("Exception in SlowConsumersDetection for queue: " + q.getName(), e); + } + } + + CurrentActor.get().message(SlowConsumerDetectionMessages.COMPLETE()); + } + + public long getDelay() + { + return _config.getDelay(); + } + + public TimeUnit getTimeUnit() + { + return _config.getTimeUnit(); + } + + /** + * Check the depth,messageSize,messageAge,messageCount values for this q + * + * @param q the queue to check + * @param config the queue configuration to compare against the queue state + * + * @return true if the queue has reached a threshold. + */ + private boolean checkQueueStatus(AMQQueue q, SlowConsumerDetectionQueueConfiguration config) + { + if (config != null) + { + _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config); + + int count = q.getMessageCount(); + + // First Check message counts + if ((config.getMessageCount() != 0 && count >= config.getMessageCount()) || + // The check queue depth + (config.getDepth() != 0 && q.getQueueDepth() >= config.getDepth()) || + // finally if we have messages on the queue check Arrival time. + // We must check count as OldestArrival time is Long.MAX_LONG when + // there are no messages. + (config.getMessageAge() != 0 && + ((count > 0) && q.getOldestMessageArrivalTime() >= config.getMessageAge()))) + { + + if (_logger.isDebugEnabled()) + { + _logger.debug("Detected Slow Consumer on Queue(" + q.getName() + ")"); + _logger.debug("Queue Count:" + q.getMessageCount() + ":" + config.getMessageCount()); + _logger.debug("Queue Depth:" + q.getQueueDepth() + ":" + config.getDepth()); + _logger.debug("Queue Arrival:" + q.getOldestMessageArrivalTime() + ":" + config.getMessageAge()); + } + + return true; + } + } + return false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties new file mode 100644 index 0000000000..2714935a71 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties @@ -0,0 +1,4 @@ +#SlowConsumerDetection.logMessages +RUNNING = SCD-1001 : Running +COMPLETE = SCD-1002 : Complete +CHECKING_QUEUE = SCD-1003 : Checking Status of Queue {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties new file mode 100644 index 0000000000..d0f5965c39 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties @@ -0,0 +1,3 @@ +#TopicDeletePolicy.logMessages +DELETING_QUEUE = TDP-1001 : Deleting Queue +DISCONNECTING = TDP-1002 : Disconnecting Session \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java new file mode 100644 index 0000000000..3bd4ae8d4e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java @@ -0,0 +1,141 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugin.policies; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionPolicyConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.exchange.TopicExchange; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.plugin.logging.TopicDeletePolicyMessages; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; + +public class TopicDeletePolicy implements SlowConsumerPolicyPlugin +{ + Logger _logger = Logger.getLogger(TopicDeletePolicy.class); + private TopicDeletePolicyConfiguration _configuration; + + public static class TopicDeletePolicyFactory implements SlowConsumerPolicyPluginFactory + { + public TopicDeletePolicy newInstance(ConfigurationPlugin configuration) throws ConfigurationException + { + TopicDeletePolicyConfiguration config = + configuration.getConfiguration(TopicDeletePolicyConfiguration.class.getName()); + + TopicDeletePolicy policy = new TopicDeletePolicy(); + policy.configure(config); + return policy; + } + + public String getPluginName() + { + return "topicdelete"; + } + + public Class getPluginClass() + { + return TopicDeletePolicy.class; + } + } + + public void performPolicy(AMQQueue q) + { + if (q == null) + { + return; + } + + AMQSessionModel owner = q.getExclusiveOwningSession(); + + // Only process exclusive queues + if (owner == null) + { + return; + } + + //Only process Topics + if (!validateQueueIsATopic(q)) + { + return; + } + + try + { + CurrentActor.get().message(owner.getLogSubject(),TopicDeletePolicyMessages.DISCONNECTING()); + // Close the consumer . this will cause autoDelete Queues to be purged + owner.getConnectionModel(). + closeSession(owner, AMQConstant.RESOURCE_ERROR, + "Consuming to slow."); + + // Actively delete non autoDelete queues if deletePersistent is set + if (!q.isAutoDelete() && (_configuration != null && _configuration.deletePersistent())) + { + CurrentActor.get().message(q.getLogSubject(), TopicDeletePolicyMessages.DELETING_QUEUE()); + q.delete(); + } + + } + catch (AMQException e) + { + _logger.warn("Unable to close consumer:" + owner + ", on queue:" + q.getName()); + } + + } + + /** + * Check the queue bindings to validate the queue is bound to the + * topic exchange. + * + * @param q the Queue + * + * @return true iff Q is bound to a TopicExchange + */ + private boolean validateQueueIsATopic(AMQQueue q) + { + for (Binding binding : q.getBindings()) + { + if (binding.getExchange() instanceof TopicExchange) + { + return true; + } + } + + return false; + } + + public void configure(ConfigurationPlugin config) + { + _configuration = (TopicDeletePolicyConfiguration) config; + } + + @Override + public String toString() + { + return "TopicDelete" + (_configuration == null ? "" : "[" + _configuration + "]"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java new file mode 100644 index 0000000000..e6ad1cbcc3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java @@ -0,0 +1,81 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugin.policies; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +public class TopicDeletePolicyConfiguration extends ConfigurationPlugin +{ + + public static class TopicDeletePolicyConfigurationFactory + implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, + Configuration config) + throws ConfigurationException + { + TopicDeletePolicyConfiguration slowConsumerConfig = + new TopicDeletePolicyConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.topics.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy.topicDelete"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"delete-persistent"}; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + // No validation required. + } + + public boolean deletePersistent() + { + // If we don't have configuration then we don't deletePersistent Queues + return (hasConfiguration() && contains("delete-persistent")); + } + + @Override + public String formatToString() + { + return (deletePersistent()?"delete-durable":""); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPlugin.java new file mode 100644 index 0000000000..7f600abdc9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPlugin.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.slowconsumerdetection.policies; + +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.queue.AMQQueue; + +public interface SlowConsumerPolicyPlugin extends Plugin +{ + public void performPolicy(AMQQueue Queue); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPluginFactory.java new file mode 100644 index 0000000000..b2fe6766a6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/slowconsumerdetection/policies/SlowConsumerPolicyPluginFactory.java @@ -0,0 +1,27 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.slowconsumerdetection.policies; + +import org.apache.qpid.server.plugins.PluginFactory; + +public interface SlowConsumerPolicyPluginFactory

      extends PluginFactory

      +{ +} -- cgit v1.2.1 From a5ef4c47edad45cf1e83cfc6d68afae6f78adf35 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 22 Jul 2010 14:21:05 +0000 Subject: QPID-2739 : Updated deleteFile to add the backupFilesToPath for delete requests if it is set. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@966677 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 39 ++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index be52b82789..1ad04af274 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -674,10 +674,43 @@ public class QpidCompositeRollingAppender extends FileAppender } } - /** Delete's the specified file if it exists */ - protected void deleteFile(String fileName) + /** + * Delete the given file that is prepended with the relative path to the log + * directory. + * + * Compress is enabled check for file with COMPRESS_EXTENSION(.gz) + * + * if backupFilesToPath is set then check in this directory not the + * main log directory. + */ + protected void deleteFile(String relativeFileName) { - File file = compress ? new File(fileName + COMPRESS_EXTENSION) : new File(fileName); + String fileName=""; + // If we have configured a backup location then we should look in there + // for the file we are trying to delete + if (backupFilesToPath != null) + { + int index = relativeFileName.lastIndexOf(File.separator); + if (index != -1) + { + fileName = backupFilesToPath + File.separator + + relativeFileName.substring(index); + } + else + { + fileName = relativeFileName; + } + } + + // If we are compressing the at the extension + if (compress) + { + fileName += COMPRESS_EXTENSION; + } + + + File file = new File(fileName); + if (file.exists()) { file.delete(); -- cgit v1.2.1 From 21844710b4e6726220e0d9150551566dd7fa13b6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 22 Jul 2010 14:21:18 +0000 Subject: QPID-2740 : Update to use backupFilesToPath for non-compressed files. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@966678 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 28 ++++++++-------------- 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 1ad04af274..83a6ff705d 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -629,6 +629,11 @@ public class QpidCompositeRollingAppender extends FileAppender return; } + if (backupFilesToPath != null) + { + to = backupFilesToPath + System.getProperty("file.separator") + new File(to).getName(); + } + File target = new File(to); File file = new File(from); @@ -690,16 +695,9 @@ public class QpidCompositeRollingAppender extends FileAppender // for the file we are trying to delete if (backupFilesToPath != null) { - int index = relativeFileName.lastIndexOf(File.separator); - if (index != -1) - { - fileName = backupFilesToPath + File.separator - + relativeFileName.substring(index); - } - else - { - fileName = relativeFileName; - } + File file = new File(relativeFileName); + + fileName = backupFilesToPath + System.getProperty("file.separator") + file.getName(); } // If we are compressing the at the extension @@ -1025,14 +1023,8 @@ public class QpidCompositeRollingAppender extends FileAppender protected synchronized void doCompress(File from, File to) { String toFile; - if (backupFilesToPath == null) - { - toFile = to.getPath() + COMPRESS_EXTENSION; - } - else - { - toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + COMPRESS_EXTENSION; - } + + toFile = to.getPath() + COMPRESS_EXTENSION; File target = new File(toFile); if (target.exists()) -- cgit v1.2.1 From 4d02e072b47235cfb56635412aea6a4ed30e6869 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Thu, 22 Jul 2010 16:09:40 +0000 Subject: QPID-2657: Make Exceptions propagate to client for 0-10 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@966722 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/subscription/Subscription_0_10.java | 2 +- .../qpid/server/transport/ServerConnection.java | 2 +- .../server/transport/ServerSessionDelegate.java | 146 +++++++++++++-------- 3 files changed, 96 insertions(+), 54 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index a800ea3328..8b5064e19d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -79,7 +79,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr public void stateChange(Subscription sub, State oldState, State newState) { - + // TODO something ? log a message here ? } }; private AMQQueue _queue; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 58dbc95224..e71782b116 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -105,7 +105,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException { ExecutionException ex = new ExecutionException(); - ex.setErrorCode(ExecutionErrorCode.RESOURCE_LIMIT_EXCEEDED); + ex.setErrorCode(ExecutionErrorCode.get(cause.getCode())); ex.setDescription(message); ((ServerSession)session).invoke(ex); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 73ec7f1231..95ac75bc34 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -26,7 +26,6 @@ import java.util.Collection; import java.util.Map; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQSecurityException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -233,8 +232,13 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot subscribe to '" + destination + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } @@ -259,7 +263,7 @@ public class ServerSessionDelegate extends SessionDelegate { exchange = exchangeRegistry.getDefaultExchange(); } - + DeliveryProperties delvProps = null; if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) @@ -268,6 +272,17 @@ public class ServerSessionDelegate extends SessionDelegate } MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); + + if (!getVirtualHost(ssn).getSecurityManager().authorisePublish(messageMetaData.isImmediate(), messageMetaData.getRoutingKey(), exchange.getName())) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.UNAUTHORIZED_ACCESS; + String description = "Permission denied: exchange-name '" + exchange.getName() + "'"; + exception(ssn, xfr, errorCode, description); + + ssn.processed(xfr); + return; + } + final MessageStore store = getVirtualHost(ssn).getMessageStore(); StoredMessage storeMessage = store.addMessage(messageMetaData); ByteBuffer body = xfr.getBody(); @@ -365,8 +380,13 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - //TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot flush subscription '" + destination + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } @@ -453,17 +473,15 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType()); } - catch (AMQSecurityException e) - { - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - String description = "Permission denied: exchange-name '" + exchangeName + "'"; - - exception(session, method, errorCode, description); - } catch (AMQException e) { - //TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot declare exchange '" + exchangeName + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } else @@ -486,6 +504,7 @@ public class ServerSessionDelegate extends SessionDelegate session.invoke(ex); + session.close(); } private Exchange getExchange(Session session, String exchangeName) @@ -543,14 +562,15 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); } - catch (AMQSecurityException e) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + method.getExchange()); - } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot delete exchange '" + method.getExchange() + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } @@ -630,10 +650,15 @@ public class ServerSessionDelegate extends SessionDelegate { virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); } - catch (AMQSecurityException e) + catch (AMQException e) { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() - + "' to Queue: '" + method.getQueue() + "' not allowed"); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot add binding '" + method.getBindingKey() + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } else @@ -686,9 +711,15 @@ public class ServerSessionDelegate extends SessionDelegate { virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); } - catch (AMQSecurityException e) + catch (AMQException e) { - exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot remove binding '" + method.getBindingKey() + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } @@ -801,7 +832,7 @@ public class ServerSessionDelegate extends SessionDelegate } @Override - public void queueDeclare(Session session, QueueDeclare method) + public void queueDeclare(Session session, final QueueDeclare method) { VirtualHost virtualHost = getVirtualHost(session); @@ -909,8 +940,13 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot delete '" + method.getQueue() + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } }; @@ -948,16 +984,15 @@ public class ServerSessionDelegate extends SessionDelegate }); } } - catch (AMQSecurityException e) - { - String description = "Cannot declare queue('" + queueName + "'), permission denied"; - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - exception(session, method, errorCode, description); - } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot declare queue '" + queueName + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } @@ -976,7 +1011,7 @@ public class ServerSessionDelegate extends SessionDelegate } protected AMQQueue createQueue(final String queueName, - QueueDeclare body, + final QueueDeclare body, VirtualHost virtualHost, final ServerSession session) throws AMQException @@ -1003,8 +1038,13 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - //TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot delete queue '" + body.getQueue() + "': " + e.getMessage(); + exception(session, body, errorCode, description); } } } @@ -1071,14 +1111,15 @@ public class ServerSessionDelegate extends SessionDelegate store.removeQueue(queue); } } - catch (AMQSecurityException e) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); - } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot delete queue '" + queueName + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } @@ -1107,14 +1148,15 @@ public class ServerSessionDelegate extends SessionDelegate { queue.clearQueue(); } - catch (AMQSecurityException e) - { - exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); - } catch (AMQException e) { - // TODO - throw new RuntimeException(e); + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (e.getErrorCode() != null) + { + errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); + } + String description = "Cannot purge queue '" + queueName + "': " + e.getMessage(); + exception(session, method, errorCode, description); } } } -- cgit v1.2.1 From b786059d21d5378b9f6eea1dc4158f3f4edf2db6 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 26 Jul 2010 09:12:26 +0000 Subject: QPID-2757: Remove double checked locking git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@979208 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ThreadPoolFilter.java | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java index bdd27f2d1c..db02a7bf76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -280,30 +280,23 @@ public class ThreadPoolFilter extends IoFilterAdapter private SessionBuffer getSessionBuffer(IoSession session) { - final Map buffers = this.buffers; - SessionBuffer buf = (SessionBuffer) buffers.get(session); - if (buf == null) + synchronized (buffers) { - synchronized (buffers) + SessionBuffer buf = (SessionBuffer) buffers.get(session); + if (buf == null) { - buf = (SessionBuffer) buffers.get(session); - if (buf == null) - { - buf = new SessionBuffer(session); - buffers.put(session, buf); - } + buf = new SessionBuffer(session); + buffers.put(session, buf); } + return buf; } - return buf; } private void removeSessionBuffer(SessionBuffer buf) { - final Map buffers = this.buffers; - final IoSession session = buf.session; synchronized (buffers) { - buffers.remove(session); + buffers.remove(buf.session); } } -- cgit v1.2.1 From c7119d95ee6650053350c15af138ca8d60f3c33c Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 26 Jul 2010 14:08:24 +0000 Subject: QPID-2657: Remove unnecessary ssn.processed() call git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@979289 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/transport/ServerSessionDelegate.java | 1 - 1 file changed, 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 95ac75bc34..47ce0b9336 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -279,7 +279,6 @@ public class ServerSessionDelegate extends SessionDelegate String description = "Permission denied: exchange-name '" + exchange.getName() + "'"; exception(ssn, xfr, errorCode, description); - ssn.processed(xfr); return; } -- cgit v1.2.1 From b66126435b32a4a8f1b8c2034f68c379acbcd561 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 26 Jul 2010 14:09:18 +0000 Subject: QPID-2661: Throw a NOT_IMPLEMENTED AMQException for 0-10 messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@979293 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 83ca526578..790027f293 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -141,7 +141,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener Date: Mon, 26 Jul 2010 14:37:43 +0000 Subject: QPID-2659: Add AMQStoreException to message stores This is a sub-class of AMQInternalException, which encapsulates error code 541, or INTERNAL_ERROR. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@979315 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/binding/BindingFactory.java | 39 ++---- .../org/apache/qpid/server/exchange/Exchange.java | 3 +- .../qpid/server/store/DerbyMessageStore.java | 134 +++++++++++---------- .../server/store/DurableConfigurationStore.java | 45 +++---- .../qpid/server/store/MemoryMessageStore.java | 43 +++---- .../apache/qpid/server/store/TransactionLog.java | 23 ++-- .../qpid/server/virtualhost/VirtualHostImpl.java | 18 +-- 7 files changed, 151 insertions(+), 154 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index 7393f27ab4..400ce50bc4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInternalException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -96,7 +97,7 @@ public class BindingFactory removeBinding(this); } - public void onClose(final Exchange exchange) throws AMQSecurityException + public void onClose(final Exchange exchange) throws AMQSecurityException, AMQInternalException { removeBinding(this); } @@ -140,7 +141,7 @@ public class BindingFactory - public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException + public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException, AMQInternalException { return makeBinding(bindingKey, queue, exchange, arguments, false, false); } @@ -149,12 +150,12 @@ public class BindingFactory public boolean replaceBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, - final Map arguments) throws AMQSecurityException + final Map arguments) throws AMQSecurityException, AMQInternalException { return makeBinding(bindingKey, queue, exchange, arguments, false, true); } - private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments, boolean restore, boolean force) throws AMQSecurityException + private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments, boolean restore, boolean force) throws AMQSecurityException, AMQInternalException { assert queue != null; if (bindingKey == null) @@ -187,14 +188,7 @@ public class BindingFactory if (b.isDurable() && !restore) { - try - { - _configSource.getDurableConfigurationStore().bindQueue(exchange,new AMQShortString(bindingKey),queue,FieldTable.convertToFieldTable(arguments)); - } - catch (AMQException e) - { - throw new RuntimeException(e); // FIXME - } + _configSource.getDurableConfigurationStore().bindQueue(exchange,new AMQShortString(bindingKey),queue,FieldTable.convertToFieldTable(arguments)); } queue.addQueueDeleteTask(b); @@ -217,18 +211,18 @@ public class BindingFactory return getVirtualHost().getConfigStore(); } - public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map argumentMap) throws AMQSecurityException + public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map argumentMap) throws AMQSecurityException, AMQInternalException { makeBinding(bindingKey,queue,exchange,argumentMap,true, false); } - public void removeBinding(final Binding b) throws AMQSecurityException + public void removeBinding(final Binding b) throws AMQSecurityException, AMQInternalException { removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments()); } - public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException + public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map arguments) throws AMQSecurityException, AMQInternalException { assert queue != null; if (bindingKey == null) @@ -261,17 +255,10 @@ public class BindingFactory if (b.isDurable()) { - try - { - _configSource.getDurableConfigurationStore().unbindQueue(exchange, - new AMQShortString(bindingKey), - queue, - FieldTable.convertToFieldTable(arguments)); - } - catch (AMQException e) - { - throw new RuntimeException(e); // FIXME - } + _configSource.getDurableConfigurationStore().unbindQueue(exchange, + new AMQShortString(bindingKey), + queue, + FieldTable.convertToFieldTable(arguments)); } b.logDestruction(); getConfigStore().removeConfiguredObject(b); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 13fe767d3f..356a7f89b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInternalException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -139,6 +140,6 @@ public interface Exchange extends ExchangeReferrer, ExchangeConfig public static interface Task { - public void onClose(Exchange exchange) throws AMQSecurityException; + public void onClose(Exchange exchange) throws AMQSecurityException, AMQInternalException; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 62f2d14e09..838867f233 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -20,20 +20,6 @@ */ package org.apache.qpid.server.store; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.ConfigStoreMessages; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.messages.TransactionLogMessages; -import org.apache.qpid.server.queue.AMQQueue; - import java.io.ByteArrayInputStream; import java.io.File; import java.lang.ref.SoftReference; @@ -52,7 +38,26 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.queue.AMQQueue; +/** + * An implementation of a {@link MessageStore} that uses Apache Derby as the persistance + * mechanism. + * + * TODO extract the SQL statements into a generic JDBC store + */ public class DerbyMessageStore implements MessageStore { @@ -221,7 +226,8 @@ public class DerbyMessageStore implements MessageStore //Update to pick up QPID_WORK and use that as the default location not just derbyDB - final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); + final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK") + + File.separator + "derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) @@ -387,13 +393,13 @@ public class DerbyMessageStore implements MessageStore catch (SQLException e) { - throw new AMQException("Error recovering persistent state: " + e, e); + throw new AMQStoreException("Error recovering persistent state: " + e.getMessage(), e); } } - private List loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException, AMQException + private List loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException { Connection conn = newAutoCommitConnection(); @@ -432,7 +438,7 @@ public class DerbyMessageStore implements MessageStore } - private List loadExchanges(ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh) throws AMQException, SQLException + private List loadExchanges(ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh) throws SQLException { List exchanges = new ArrayList(); @@ -468,7 +474,7 @@ public class DerbyMessageStore implements MessageStore } - private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List exchanges) throws AMQException, SQLException + private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List exchanges) throws SQLException { _logger.info("Recovering bindings..."); @@ -552,7 +558,7 @@ public class DerbyMessageStore implements MessageStore public StoredMessage getMessage(long messageNumber) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public void removeMessage(long messageId) @@ -599,12 +605,12 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error removing message with id " + messageId + " from database: " + e, e); + throw new RuntimeException("Error removing message with id " + messageId + " from database: " + e.getMessage(), e); } } - public void createExchange(Exchange exchange) throws AMQException + public void createExchange(Exchange exchange) throws AMQStoreException { if (_state != State.RECOVERING) { @@ -645,13 +651,13 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error adding Exchange with name " + exchange.getNameShortString() + " to database: " + e, e); + throw new AMQStoreException("Error writing Exchange with name " + exchange.getNameShortString() + " to database: " + e.getMessage(), e); } } } - public void removeExchange(Exchange exchange) throws AMQException + public void removeExchange(Exchange exchange) throws AMQStoreException { Connection conn = null; @@ -664,12 +670,12 @@ public class DerbyMessageStore implements MessageStore stmt.close(); if(results == 0) { - throw new AMQException("Exchange " + exchange.getNameShortString() + " not found"); + throw new AMQStoreException("Exchange " + exchange.getNameShortString() + " not found"); } } catch (SQLException e) { - throw new AMQException("Error deleting exchange with name " + exchange.getNameShortString() + " from database: " + e, e); + throw new AMQStoreException("Error deleting Exchange with name " + exchange.getNameShortString() + " from database: " + e.getMessage(), e); } finally { @@ -689,7 +695,7 @@ public class DerbyMessageStore implements MessageStore } public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - throws AMQException + throws AMQStoreException { if (_state != State.RECOVERING) { @@ -735,8 +741,8 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " - + exchange.getNameShortString() + " to database: " + e, e); + throw new AMQStoreException("Error writing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " to database: " + e.getMessage(), e); } finally { @@ -760,7 +766,7 @@ public class DerbyMessageStore implements MessageStore } public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - throws AMQException + throws AMQStoreException { Connection conn = null; @@ -778,14 +784,14 @@ public class DerbyMessageStore implements MessageStore if(result != 1) { - throw new AMQException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange " + throw new AMQStoreException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange " + exchange.getNameShortString() + " not found"); } } catch (SQLException e) { - throw new AMQException("Error removing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " - + exchange.getNameShortString() + " in database: " + e, e); + throw new AMQStoreException("Error removing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " in database: " + e.getMessage(), e); } finally { @@ -806,12 +812,12 @@ public class DerbyMessageStore implements MessageStore } - public void createQueue(AMQQueue queue) throws AMQException + public void createQueue(AMQQueue queue) throws AMQStoreException { createQueue(queue, null); } - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException { _logger.debug("public void createQueue(AMQQueue queue = " + queue + "): called"); @@ -858,7 +864,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing AMQQueue with name " + queue.getNameShortString() + " to database: " + e, e); + throw new AMQStoreException("Error writing AMQQueue with name " + queue.getNameShortString() + " to database: " + e.getMessage(), e); } } } @@ -870,9 +876,9 @@ public class DerbyMessageStore implements MessageStore * NOTE: Currently only updates the exclusivity. * * @param queue The queue to update the entry for. - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - public void updateQueue(final AMQQueue queue) throws AMQException + public void updateQueue(final AMQQueue queue) throws AMQStoreException { if (_state != State.RECOVERING) { @@ -901,7 +907,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error updating AMQQueue with name " + queue.getNameShortString() + " to database: " + e, e); + throw new AMQStoreException("Error updating AMQQueue with name " + queue.getNameShortString() + " to database: " + e.getMessage(), e); } } @@ -931,7 +937,7 @@ public class DerbyMessageStore implements MessageStore return connection; } - public void removeQueue(final AMQQueue queue) throws AMQException + public void removeQueue(final AMQQueue queue) throws AMQStoreException { AMQShortString name = queue.getNameShortString(); _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); @@ -947,12 +953,12 @@ public class DerbyMessageStore implements MessageStore if (results == 0) { - throw new AMQException("Queue " + name + " not found"); + throw new AMQStoreException("Queue " + name + " not found"); } } catch (SQLException e) { - throw new AMQException("Error writing deleting with name " + name + " from database: " + e, e); + throw new AMQStoreException("Error deleting AMQQueue with name " + name + " from database: " + e.getMessage(), e); } finally { @@ -978,7 +984,7 @@ public class DerbyMessageStore implements MessageStore return new DerbyTransaction(); } - public void enqueueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException + public void enqueueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQStoreException { String name = queue.getResourceName(); @@ -1000,14 +1006,14 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - _logger.error("Failed to enqueue: " + e, e); - throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name + _logger.error("Failed to enqueue: " + e.getMessage(), e); + throw new AMQStoreException("Error writing enqueued message with id " + messageId + " for queue " + name + " to database", e); } } - public void dequeueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException + public void dequeueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQStoreException { String name = queue.getResourceName(); @@ -1025,7 +1031,7 @@ public class DerbyMessageStore implements MessageStore if(results != 1) { - throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); + throw new AMQStoreException("Unable to find message with id " + messageId + " on queue " + name); } if (_logger.isDebugEnabled()) @@ -1035,8 +1041,8 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - _logger.error("Failed to dequeue: " + e, e); - throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name + _logger.error("Failed to dequeue: " + e.getMessage(), e); + throw new AMQStoreException("Error deleting enqueued message with id " + messageId + " for queue " + name + " from database", e); } @@ -1058,7 +1064,7 @@ public class DerbyMessageStore implements MessageStore } - public void commitTran(ConnectionWrapper connWrapper) throws AMQException + public void commitTran(ConnectionWrapper connWrapper) throws AMQStoreException { try @@ -1075,7 +1081,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error commit tx: " + e, e); + throw new AMQStoreException("Error commit tx: " + e.getMessage(), e); } finally { @@ -1083,7 +1089,7 @@ public class DerbyMessageStore implements MessageStore } } - public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQException + public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQStoreException { commitTran(connWrapper); return new StoreFuture() @@ -1101,11 +1107,11 @@ public class DerbyMessageStore implements MessageStore } - public void abortTran(ConnectionWrapper connWrapper) throws AMQException + public void abortTran(ConnectionWrapper connWrapper) throws AMQStoreException { if (connWrapper == null) { - throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); + throw new AMQStoreException("Fatal internal error: transactional context is empty at abortTran"); } if (_logger.isDebugEnabled()) @@ -1121,7 +1127,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error aborting transaction: " + e, e); + throw new AMQStoreException("Error aborting transaction: " + e.getMessage(), e); } } @@ -1310,7 +1316,7 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error adding content chunk offset " + offset + " for message " + messageId + ": " + e, e); + throw new RuntimeException("Error adding content chunk offset " + offset + " for message " + messageId + ": " + e.getMessage(), e); } } @@ -1375,7 +1381,7 @@ public class DerbyMessageStore implements MessageStore } } - throw new RuntimeException("Error retrieving content from offset " + offset + " for message " + messageId + ": " + e, e); + throw new RuntimeException("Error retrieving content from offset " + offset + " for message " + messageId + ": " + e.getMessage(), e); } @@ -1388,11 +1394,11 @@ public class DerbyMessageStore implements MessageStore } - private synchronized void stateTransition(State requiredState, State newState) throws AMQException + private synchronized void stateTransition(State requiredState, State newState) throws AMQStoreException { if (_state != requiredState) { - throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + throw new AMQStoreException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + "; currently in state: " + _state); } @@ -1417,28 +1423,28 @@ public class DerbyMessageStore implements MessageStore } } - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException { DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId); } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException { DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId); } - public void commitTran() throws AMQException + public void commitTran() throws AMQStoreException { DerbyMessageStore.this.commitTran(_connWrapper); } - public StoreFuture commitTranAsync() throws AMQException + public StoreFuture commitTranAsync() throws AMQStoreException { return DerbyMessageStore.this.commitTranAsync(_connWrapper); } - public void abortTran() throws AMQException + public void abortTran() throws AMQStoreException { DerbyMessageStore.this.abortTran(_connWrapper); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java index c169e3bcff..5fb23653cb 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.server.store; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.AMQException; +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.queue.AMQQueue; public interface DurableConfigurationStore { @@ -55,18 +55,18 @@ public interface DurableConfigurationStore * * @param exchange The exchange to persist. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void createExchange(Exchange exchange) throws AMQException; + void createExchange(Exchange exchange) throws AMQStoreException; /** * Removes the specified persistent exchange. * * @param exchange The exchange to remove. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void removeExchange(Exchange exchange) throws AMQException; + void removeExchange(Exchange exchange) throws AMQStoreException; /** * Binds the specified queue to an exchange with a routing key. @@ -76,9 +76,9 @@ public interface DurableConfigurationStore * @param queue The queue to bind. * @param args Additional parameters. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException if the operation fails for any reason. */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException; /** * Unbinds the specified from an exchange under a particular routing key. @@ -88,43 +88,44 @@ public interface DurableConfigurationStore * @param queue The queue to unbind. * @param args Additonal parameters. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException; /** * Makes the specified queue persistent. * * @param queue The queue to store. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void createQueue(AMQQueue queue) throws AMQException; + void createQueue(AMQQueue queue) throws AMQStoreException; /** * Makes the specified queue persistent. * * @param queue The queue to store. - * * @param arguments The additional arguments to the binding - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * + * @throws AMQStoreException If the operation fails for any reason. */ - void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException; /** * Removes the specified queue from the persistent store. * * @param queue The queue to remove. - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * + * @throws AMQStoreException If the operation fails for any reason. */ - void removeQueue(AMQQueue queue) throws AMQException; + void removeQueue(AMQQueue queue) throws AMQStoreException; /** * Updates the specified queue in the persistent store, IF it is already present. If the queue * is not present in the store, it will not be added. * * @param queue The queue to update the entry for. - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void updateQueue(AMQQueue queue) throws AMQException; + void updateQueue(AMQQueue queue) throws AMQStoreException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 9d9312cd26..d008d42fa0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -20,21 +20,22 @@ */ package org.apache.qpid.server.store; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.commons.configuration.Configuration; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.queue.AMQQueue; /** A simple message store that stores the messages in a threadsafe structure in memory. */ public class MemoryMessageStore implements MessageStore @@ -52,24 +53,24 @@ public class MemoryMessageStore implements MessageStore private static final Transaction IN_MEMORY_TRANSACTION = new Transaction() { - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException { } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException { } - public void commitTran() throws AMQException + public void commitTran() throws AMQStoreException { } - public StoreFuture commitTranAsync() throws AMQException + public StoreFuture commitTranAsync() throws AMQStoreException { return IMMEDIATE_FUTURE; } - public void abortTran() throws AMQException + public void abortTran() throws AMQStoreException { } @@ -113,43 +114,43 @@ public class MemoryMessageStore implements MessageStore } - public void createExchange(Exchange exchange) throws AMQException + public void createExchange(Exchange exchange) throws AMQStoreException { } - public void removeExchange(Exchange exchange) throws AMQException + public void removeExchange(Exchange exchange) throws AMQStoreException { } - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { } - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { } - public void createQueue(AMQQueue queue) throws AMQException + public void createQueue(AMQQueue queue) throws AMQStoreException { // Not requred to do anything } - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException { // Not required to do anything } - public void removeQueue(final AMQQueue queue) throws AMQException + public void removeQueue(final AMQQueue queue) throws AMQStoreException { // Not required to do anything } - public void updateQueue(final AMQQueue queue) throws AMQException + public void updateQueue(final AMQQueue queue) throws AMQStoreException { // Not required to do anything } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java index e6a33e23d6..d196a91930 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java @@ -20,9 +20,8 @@ */ package org.apache.qpid.server.store; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; import org.apache.commons.configuration.Configuration; public interface TransactionLog @@ -35,40 +34,40 @@ public interface TransactionLog * * @param queue The queue to place the message on. * @param messageId The message to enqueue. - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException; /** * Extracts a message from a specified queue, in a given transactional context. * * @param queue The queue to place the message on. * @param messageId The message to dequeue. - * @throws org.apache.qpid.AMQException If the operation fails for any reason, or if the specified message does not exist. + * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException; /** * Commits all operations performed within a given transactional context. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void commitTran() throws AMQException; + void commitTran() throws AMQStoreException; /** * Commits all operations performed within a given transactional context. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - StoreFuture commitTranAsync() throws AMQException; + StoreFuture commitTranAsync() throws AMQStoreException; /** * Abandons all operations performed within a given transactional context. * - * @throws org.apache.qpid.AMQException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - void abortTran() throws AMQException; + void abortTran() throws AMQStoreException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index c6055f35f6..f2444718af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -36,6 +36,8 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInternalException; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; @@ -696,7 +698,7 @@ public class VirtualHostImpl implements VirtualHost //To change body of implemented methods use File | Settings | File Templates. } - public void createExchange(Exchange exchange) throws AMQException + public void createExchange(Exchange exchange) throws AMQStoreException { if (exchange.isDurable()) { @@ -704,11 +706,11 @@ public class VirtualHostImpl implements VirtualHost } } - public void removeExchange(Exchange exchange) throws AMQException + public void removeExchange(Exchange exchange) throws AMQStoreException { } - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { if (exchange.isDurable() && queue.isDurable()) { @@ -716,16 +718,16 @@ public class VirtualHostImpl implements VirtualHost } } - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { } - public void createQueue(AMQQueue queue) throws AMQException + public void createQueue(AMQQueue queue) throws AMQStoreException { createQueue(queue, null); } - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException { if (queue.isDurable()) { @@ -733,7 +735,7 @@ public class VirtualHostImpl implements VirtualHost } } - public void removeQueue(AMQQueue queue) throws AMQException + public void removeQueue(AMQQueue queue) throws AMQStoreException { } @@ -766,7 +768,7 @@ public class VirtualHostImpl implements VirtualHost } } - public void updateQueue(AMQQueue queue) throws AMQException + public void updateQueue(AMQQueue queue) throws AMQStoreException { } } -- cgit v1.2.1 From 3b641bf3bc773c4077c191dc139be84fc6e6fae4 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Wed, 28 Jul 2010 11:09:46 +0000 Subject: QPID-2657: Factor out exception handling Created a proxy method that calls exception() which takes a thrown AMQException and gets the error code if it can be translated and creates the error message description from the exception message. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@980020 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transport/ServerSessionDelegate.java | 108 ++++++--------------- 1 file changed, 31 insertions(+), 77 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 47ce0b9336..44a677a76d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -232,13 +232,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot subscribe to '" + destination + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot subscribe to '" + destination); } } } @@ -379,13 +373,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot flush subscription '" + destination + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot flush subscription '" + destination); } } } @@ -474,13 +462,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot declare exchange '" + exchangeName + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot declare exchange '" + exchangeName); } } else @@ -494,6 +476,26 @@ public class ServerSessionDelegate extends SessionDelegate } } + // TODO decouple AMQException and AMQConstant error codes + private void exception(Session session, Method method, AMQException exception, String message) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; + if (exception.getErrorCode() != null) + { + try + { + errorCode = ExecutionErrorCode.get(exception.getErrorCode().getCode()); + } + catch (IllegalArgumentException iae) + { + // ignore, already set to INTERNAL_ERROR + } + } + String description = message + "': " + exception.getMessage(); + + exception(session, method, errorCode, description); + } + private void exception(Session session, Method method, ExecutionErrorCode errorCode, String description) { ExecutionException ex = new ExecutionException(); @@ -563,13 +565,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot delete exchange '" + method.getExchange() + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot delete exchange '" + method.getExchange() ); } } @@ -651,13 +647,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot add binding '" + method.getBindingKey() + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot add binding '" + method.getBindingKey()); } } else @@ -712,13 +702,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot remove binding '" + method.getBindingKey() + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot remove binding '" + method.getBindingKey()); } } } @@ -939,13 +923,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot delete '" + method.getQueue() + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot delete '" + method.getQueue()); } } }; @@ -985,13 +963,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot declare queue '" + queueName + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot declare queue '" + queueName); } } } @@ -1037,13 +1009,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot delete queue '" + body.getQueue() + "': " + e.getMessage(); - exception(session, body, errorCode, description); + exception(session, body, e, "Cannot delete queue '" + body.getQueue()); } } } @@ -1112,13 +1078,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot delete queue '" + queueName + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot delete queue '" + queueName); } } } @@ -1149,13 +1109,7 @@ public class ServerSessionDelegate extends SessionDelegate } catch (AMQException e) { - ExecutionErrorCode errorCode = ExecutionErrorCode.INTERNAL_ERROR; - if (e.getErrorCode() != null) - { - errorCode = ExecutionErrorCode.get(e.getErrorCode().getCode()); - } - String description = "Cannot purge queue '" + queueName + "': " + e.getMessage(); - exception(session, method, errorCode, description); + exception(session, method, e, "Cannot purge queue '" + queueName); } } } -- cgit v1.2.1 From a814c3a19ab2357bc6ea3a7cae19ec10df3a254e Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sat, 31 Jul 2010 23:46:15 +0000 Subject: QPID-2668: Improve PlainPasswordPrincipalDatabase lock management Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@981103 13f79535-47bb-0310-9956-ffa450edef68 --- .../PlainPasswordFilePrincipalDatabase.java | 41 ++++++++-------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 8665e579ba..cea4e90c31 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -179,39 +179,28 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase throw new AccountNotFoundException(principal.getName()); } + char[] orig = user.getPassword(); + _userUpdate.lock(); try { - try - { - _userUpdate.lock(); - char[] orig = user.getPassword(); - user.setPassword(password); + user.setPassword(password); - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to save password file, password change for user '" + principal + "' discarded"); - //revert the password change - user.setPassword(orig); - return false; - } - return true; - } - finally - { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } - } + savePasswordFile(); + + return true; } - catch (Exception e) + catch (IOException e) { + _logger.error("Unable to save password file due to '"+e.getMessage() + +"', password change for user '" + principal + "' discarded"); + //revert the password change + user.setPassword(orig); return false; } + finally + { + _userUpdate.unlock(); + } } public boolean createPrincipal(Principal principal, char[] password) -- cgit v1.2.1 From 4717efa81dda8d680713ea506bc50971cd6292ca Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sat, 31 Jul 2010 23:51:18 +0000 Subject: QPID-2642: Replace bitwise and with short-circuit and operator Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@981105 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java index 4afc209ba7..6fa412cce6 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -259,7 +259,7 @@ public class QpidLog4JConfigurator //let log4j replace any properties in the string String log4jConfiguredString = domConfig.subst(levelString); - if(log4jConfiguredString.equals("") & ! log4jConfiguredString.equals(levelString)) + if(log4jConfiguredString.equals("") && ! log4jConfiguredString.equals(levelString)) { //log4j has returned an empty string but this isnt what we gave it. //There may have been an undefined property. Unlike an incorrect -- cgit v1.2.1 From 0dc91156f3357619b046a63b7cddd9c0867ce4e3 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 8 Aug 2010 15:55:26 +0000 Subject: QPID-2783: Eliminate the UnknownMessageTypeException from o.a.q.server.protocol package Appled patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@983441 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/protocol/AMQProtocolEngine.java | 2 +- .../protocol/UnknnownMessageTypeException.java | 46 ---------------------- 2 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 5d1346ffd8..5a7c9923f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -280,7 +280,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } else { - throw new UnknnownMessageTypeException(message); + throw new AMQException("Unknown message type: " + message.getClass().getName() + ": " + message); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java deleted file mode 100644 index 6e72aa062f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; - -/** - * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type. - * - *

      - *
      CRC Card
      Responsibilities Collaborations - *
      Represents failure to cast a frame to its expected type. - *
      - * - * @todo Not an AMQP exception as no status code. - * - * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would - * be better just to leave that as a ClassCastException. However, check the framing layer catches this error - * first. - */ -public class UnknnownMessageTypeException extends AMQException -{ - public UnknnownMessageTypeException(AMQDataBlock message) - { - super("Unknown message type: " + message.getClass().getName() + ": " + message); - } -} -- cgit v1.2.1 From 2e305605d6960a88ab9bfa96d742d6a15b3b2353 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 9 Aug 2010 10:05:54 +0000 Subject: QPID-2787: Add test for persistence of Conflation/LastValue queues git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@983571 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/queue/AMQQueueFactory.java | 7 +++---- .../org/apache/qpid/server/queue/ConflationQueue.java | 4 ++++ .../apache/qpid/server/queue/ConflationQueueList.java | 19 +++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index a547205d27..6bfd7470ac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -33,10 +33,9 @@ import java.util.HashMap; public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); - - private static final String QPID_LVQ_KEY = "qpid.LVQ_key"; - private static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; - private static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key"; + public static final String QPID_LVQ_KEY = "qpid.LVQ_key"; + public static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; + public static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key"; private abstract static class QueueProperty { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java index 400d9867ae..b5293f51be 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java @@ -39,5 +39,9 @@ public class ConflationQueue extends SimpleAMQQueue super(name, durable, owner, autoDelete, exclusive, virtualHost, new ConflationQueueList.Factory(conflationKey), args); } + public String getConflationKey() + { + return ((ConflationQueueList) _entries).getConflationKey(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java index 9a6e5c884a..2c1883e763 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java @@ -21,19 +21,13 @@ package org.apache.qpid.server.queue; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.server.txn.AutoCommitTransaction; -import org.apache.qpid.server.message.ServerMessage; - import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; + public class ConflationQueueList extends SimpleQueueEntryList { @@ -47,6 +41,11 @@ public class ConflationQueueList extends SimpleQueueEntryList _conflationKey = conflationKey; } + public String getConflationKey() + { + return _conflationKey; + } + @Override protected ConflationQueueEntry createQueueEntry(ServerMessage message) { -- cgit v1.2.1 From e12ef87757faaee94079b3ce2eec73e33a00857b Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 13 Aug 2010 13:54:18 +0000 Subject: Remove the accessBroker method as it is unused git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@985200 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/security/AbstractProxyPlugin.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java index 7d0fcfb6cb..8b5ff6781d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java @@ -83,11 +83,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin return getDefault(); } - public Result accessBroker(Object instance) - { - return getDefault(); - } - public Result accessVirtualhost(Object instance) { return getDefault(); -- cgit v1.2.1 From e9e542aabce4d9a15e8556a9750df6e86bcecd16 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 13 Aug 2010 16:19:28 +0000 Subject: QPID-2657: Correct handling of sync on 0-10 client session for exceptions AMQSession_0_10 is modified to contain a pair of get/set methods for the current exception, using the set method to post the exception to the listener. The sync method will now throw an exception if one has occurred and all other methods that used to call sync()/getCurrentException() can just call sync(0 and get the expected behaviour. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@985262 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerConnection.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index e71782b116..8c7b374791 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -105,11 +105,19 @@ public class ServerConnection extends Connection implements AMQConnectionModel public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException { ExecutionException ex = new ExecutionException(); - ex.setErrorCode(ExecutionErrorCode.get(cause.getCode())); + ExecutionErrorCode code = ExecutionErrorCode.INTERNAL_ERROR; + try + { + code = ExecutionErrorCode.get(cause.getCode()); + } + catch (IllegalArgumentException iae) + { + // Ignore, already set to INTERNAL_ERROR + } + ex.setErrorCode(code); ex.setDescription(message); ((ServerSession)session).invoke(ex); ((ServerSession)session).close(); } - } -- cgit v1.2.1 From f375ba740f96b77627cb70215617d6ec43f342fa Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 26 Aug 2010 15:03:33 +0000 Subject: QPID-2802: Add support for a status-logging hierarchy, such that the Log4jMessageLogger may use this to allow individual on/off toggling of each status message. Combine the RootLogger and RawLogger interfaces. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@989734 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 4 +- .../server/logging/AbstractRootMessageLogger.java | 59 ++++++++++++++++++++++ .../org/apache/qpid/server/logging/LogMessage.java | 2 +- .../qpid/server/logging/NullRootMessageLogger.java | 31 ++++-------- .../qpid/server/logging/RawMessageLogger.java | 44 ---------------- .../qpid/server/logging/RootMessageLogger.java | 23 ++++++--- .../qpid/server/logging/RootMessageLoggerImpl.java | 57 --------------------- .../server/logging/StartupRootMessageLogger.java | 49 ------------------ .../server/logging/SystemOutMessageLogger.java | 51 +++++++++++++++++++ .../qpid/server/logging/actors/AbstractActor.java | 10 ++-- .../logging/rawloggers/Log4jMessageLogger.java | 53 +++++++++++++------ .../logging/rawloggers/SystemOutMessageLogger.java | 40 --------------- .../qpid/server/registry/ApplicationRegistry.java | 4 +- .../qpid/server/subscription/SubscriptionImpl.java | 2 +- 14 files changed, 185 insertions(+), 244 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/AbstractRootMessageLogger.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/SystemOutMessageLogger.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 4bca4e5161..7d7eefc541 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -46,7 +46,7 @@ import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.information.management.ServerInformationMBean; -import org.apache.qpid.server.logging.StartupRootMessageLogger; +import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; @@ -223,7 +223,7 @@ public class Main { try { - CurrentActor.set(new BrokerActor(new StartupRootMessageLogger())); + CurrentActor.set(new BrokerActor(new SystemOutMessageLogger())); startup(); CurrentActor.remove(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/AbstractRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/AbstractRootMessageLogger.java new file mode 100644 index 0000000000..545f2adea2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/AbstractRootMessageLogger.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.server.configuration.ServerConfiguration; + +public abstract class AbstractRootMessageLogger implements RootMessageLogger +{ + public static final String DEFAULT_LOG_HIERARCHY_PREFIX = "qpid.message."; + + private boolean _enabled = true; + + public AbstractRootMessageLogger() + { + + } + + public AbstractRootMessageLogger(ServerConfiguration config) + { + _enabled = config.getStatusUpdatesEnabled(); + } + + public boolean isEnabled() + { + return _enabled; + } + + public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHierarchy) + { + return _enabled; + } + + public boolean isMessageEnabled(LogActor actor, String logHierarchy) + { + return _enabled; + } + + public abstract void rawMessage(String message, String logHierarchy); + + public abstract void rawMessage(String message, Throwable throwable, String logHierarchy); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java index 5c112ff100..fa18435fab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java @@ -22,5 +22,5 @@ package org.apache.qpid.server.logging; public interface LogMessage { - + String getLogHierarchy(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java index 6cd29b95fb..db8b24e90e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java @@ -20,41 +20,28 @@ */ package org.apache.qpid.server.logging; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.commons.configuration.ConfigurationException; - -public class NullRootMessageLogger extends RootMessageLoggerImpl +public class NullRootMessageLogger extends AbstractRootMessageLogger { - public NullRootMessageLogger() throws ConfigurationException - { - super(new ServerConfiguration(new PropertiesConfiguration()), new NullMessageLogger()); - } - @Override - public boolean isMessageEnabled(LogActor actor, LogSubject subject) + public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHeirarchy) { return false; } @Override - public boolean isMessageEnabled(LogActor actor) + public boolean isMessageEnabled(LogActor actor, String logHierarchy) { return false; } - public static class NullMessageLogger implements RawMessageLogger + public void rawMessage(String message, String logHierarchy) { - public void rawMessage(String message) - { - // drop message - } - - public void rawMessage(String message, Throwable throwable) - { - // drop message - } + // drop message } + public void rawMessage(String message, Throwable throwable, String logHierarchy) + { + // drop message + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java deleted file mode 100644 index 7d515f3263..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging; - -/** - * A RawMessage Logger takes the given String and any Throwable and writes the - * data to its resource. - */ -public interface RawMessageLogger -{ - - /** - * Log the given message. - * - * @param message String to log. - */ - public void rawMessage(String message); - - /** - * Log the message and formatted stack trace for any Throwable. - * - * @param message String to log. - * @param throwable Throwable for which to provide stack trace. - */ - public void rawMessage(String message, Throwable throwable); -} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java index 5ac5eab6c4..1431dd1da9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java @@ -27,31 +27,41 @@ package org.apache.qpid.server.logging; */ public interface RootMessageLogger { + /** + * Determine whether the MessageLogger is enabled + * + * @return boolean true if enabled. + */ + boolean isEnabled(); + /** * Determine if the LogSubject and the LogActor should be * generating log messages. - * - * @param subject The subject of this log request * @param actor The actor requesting the logging + * @param subject The subject of this log request + * @param logHierarchy The log hierarchy for this request + * * @return boolean true if the message should be logged. */ - boolean isMessageEnabled(LogActor actor, LogSubject subject); + boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHierarchy); /** * Determine if the LogActor should be generating log messages. * * @param actor The actor requesting the logging + * @param logHierarchy The log hierarchy for this request * * @return boolean true if the message should be logged. */ - boolean isMessageEnabled(LogActor actor); + boolean isMessageEnabled(LogActor actor, String logHierarchy); /** * Log the raw message to the configured logger. * * @param message The message to log + * @param logHierarchy The log hierarchy for this request */ - public void rawMessage(String message); + public void rawMessage(String message, String logHierarchy); /** * Log the raw message to the configured logger. @@ -59,6 +69,7 @@ public interface RootMessageLogger * * @param message The message to log * @param throwable Optional Throwable that should provide stact trace + * @param logHierarchy The log hierarchy for this request */ - void rawMessage(String message, Throwable throwable); + void rawMessage(String message, Throwable throwable, String logHierarchy); } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java deleted file mode 100644 index a3bf276d1e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.server.configuration.ServerConfiguration; - -public class RootMessageLoggerImpl implements RootMessageLogger -{ - private boolean _enabled; - - RawMessageLogger _rawLogger; - private static final String MESSAGE = "MESSAGE "; - - public RootMessageLoggerImpl(ServerConfiguration configuration, RawMessageLogger rawLogger) - { - _enabled = configuration.getStatusUpdatesEnabled(); - _rawLogger = rawLogger; - } - - public boolean isMessageEnabled(LogActor actor, LogSubject subject) - { - return _enabled; - } - - public boolean isMessageEnabled(LogActor actor) - { - return _enabled; - } - - public void rawMessage(String message) - { - _rawLogger.rawMessage(MESSAGE + message); - } - - public void rawMessage(String message, Throwable throwable) - { - _rawLogger.rawMessage(MESSAGE + message, throwable); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java deleted file mode 100644 index bfb122985b..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.logging.rawloggers.SystemOutMessageLogger; - -public class StartupRootMessageLogger extends RootMessageLoggerImpl -{ - public StartupRootMessageLogger() throws ConfigurationException - { - super(new ServerConfiguration(new PropertiesConfiguration()), - new SystemOutMessageLogger()); - } - - @Override - public boolean isMessageEnabled(LogActor actor, LogSubject subject) - { - return true; - } - - @Override - public boolean isMessageEnabled(LogActor actor) - { - return true; - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/SystemOutMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/SystemOutMessageLogger.java new file mode 100644 index 0000000000..b384b3fde3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/SystemOutMessageLogger.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + + +public class SystemOutMessageLogger extends AbstractRootMessageLogger +{ + @Override + public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHeirarchy) + { + return true; + } + + @Override + public boolean isMessageEnabled(LogActor actor, String logHierarchy) + { + return true; + } + + public void rawMessage(String message, String logHierarchy) + { + rawMessage(message, null, logHierarchy); + } + + public void rawMessage(String message, Throwable throwable, String logHierarchy) + { + System.out.println(message); + if (throwable != null) + { + throwable.printStackTrace(System.out); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 1fa2bd9600..05ac8c4b7e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -27,6 +27,8 @@ import org.apache.qpid.server.logging.RootMessageLogger; public abstract class AbstractActor implements LogActor { + public static final String DEFAULT_MSG_PREFIX = "MESSAGE "; + protected RootMessageLogger _rootLogger; public AbstractActor(RootMessageLogger rootLogger) @@ -40,17 +42,17 @@ public abstract class AbstractActor implements LogActor public void message(LogSubject subject, LogMessage message) { - if (_rootLogger.isMessageEnabled(this, subject)) + if (_rootLogger.isMessageEnabled(this, subject, message.getLogHierarchy())) { - _rootLogger.rawMessage(getLogMessage() + String.valueOf(subject) + message); + _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + String.valueOf(subject) + message, message.getLogHierarchy()); } } public void message(LogMessage message) { - if (_rootLogger.isMessageEnabled(this)) + if (_rootLogger.isMessageEnabled(this, message.getLogHierarchy())) { - _rootLogger.rawMessage(getLogMessage() + message); + _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + message, message.getLogHierarchy()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java index f996576f31..fffd16a812 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java @@ -22,35 +22,56 @@ package org.apache.qpid.server.logging.rawloggers; import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.apache.qpid.server.logging.RawMessageLogger; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.AbstractRootMessageLogger; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; -public class Log4jMessageLogger implements RawMessageLogger +public class Log4jMessageLogger extends AbstractRootMessageLogger { - public static final String DEFAULT_LEVEL = "INFO"; - public static final String DEFAULT_LOGGER = "qpid.message"; - private Level _level; - private Logger _rawMessageLogger; - + public static final Level LEVEL = Level.toLevel("INFO"); + public Log4jMessageLogger() { - this(DEFAULT_LEVEL, DEFAULT_LOGGER); + super(); } - public Log4jMessageLogger(String level, String logger) + public Log4jMessageLogger(ServerConfiguration config) + { + super(config); + } + + @Override + public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHierarchy) { - _level = Level.toLevel(level); + return isMessageEnabled(actor, logHierarchy); + } - _rawMessageLogger = Logger.getLogger(logger); - _rawMessageLogger.setLevel(_level); + @Override + public boolean isMessageEnabled(LogActor actor, String logHierarchy) + { + if(isEnabled()) + { + Logger logger = Logger.getLogger(logHierarchy); + return logger.isEnabledFor(LEVEL); + } + else + { + return false; + } } - public void rawMessage(String message) + @Override + public void rawMessage(String message, String logHierarchy) { - rawMessage(message, null); + rawMessage(message, null, logHierarchy); } - public void rawMessage(String message, Throwable throwable) + @Override + public void rawMessage(String message, Throwable throwable, String logHierarchy) { - _rawMessageLogger.log(_level, message, throwable); + Logger logger = Logger.getLogger(logHierarchy); + + logger.log(LEVEL, message, throwable); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java deleted file mode 100644 index b9f0532d05..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging.rawloggers; - -import org.apache.qpid.server.logging.RawMessageLogger; - -public class SystemOutMessageLogger implements RawMessageLogger -{ - public void rawMessage(String message) - { - rawMessage(message, null); - } - - public void rawMessage(String message, Throwable throwable) - { - System.out.println(message); - if (throwable != null) - { - throwable.printStackTrace(System.out); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index bc68fa0c79..5cddfda059 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -39,7 +39,7 @@ import org.apache.qpid.server.configuration.SystemConfig; import org.apache.qpid.server.configuration.SystemConfigImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.AbstractRootMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; @@ -249,7 +249,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void initialise(int instanceID) throws Exception { - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); + _rootMessageLogger = new Log4jMessageLogger(_configuration); _registryName = String.valueOf(instanceID); // Set the Actor for current log messages diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 1740e3db1a..d8f44c9f7f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -362,7 +362,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); if (CurrentActor.get().getRootMessageLogger(). - isMessageEnabled(CurrentActor.get(), _logSubject)) + isMessageEnabled(CurrentActor.get(), _logSubject, SubscriptionMessages.CREATE_LOG_HIERARCHY)) { // Get the string value of the filters String filterLogString = null; -- cgit v1.2.1 From 94fc428be267d83de3a1210ea04d2830727039d1 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 26 Aug 2010 15:03:56 +0000 Subject: QPID-2802: move Log4jMessageLogger and update its test to account for use of per-message log heirarchies rather than a single default Logger git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@989735 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/Log4jMessageLogger.java | 74 +++++++++++++++++++++ .../logging/rawloggers/Log4jMessageLogger.java | 77 ---------------------- .../qpid/server/registry/ApplicationRegistry.java | 2 +- 3 files changed, 75 insertions(+), 78 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/Log4jMessageLogger.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/Log4jMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/Log4jMessageLogger.java new file mode 100644 index 0000000000..a0285ebfc4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/Log4jMessageLogger.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.logging; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.ServerConfiguration; + +public class Log4jMessageLogger extends AbstractRootMessageLogger +{ + public static final Level LEVEL = Level.toLevel("INFO"); + + public Log4jMessageLogger() + { + super(); + } + + public Log4jMessageLogger(ServerConfiguration config) + { + super(config); + } + + @Override + public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHierarchy) + { + return isMessageEnabled(actor, logHierarchy); + } + + @Override + public boolean isMessageEnabled(LogActor actor, String logHierarchy) + { + if(isEnabled()) + { + Logger logger = Logger.getLogger(logHierarchy); + return logger.isEnabledFor(LEVEL); + } + else + { + return false; + } + } + + @Override + public void rawMessage(String message, String logHierarchy) + { + rawMessage(message, null, logHierarchy); + } + + @Override + public void rawMessage(String message, Throwable throwable, String logHierarchy) + { + Logger logger = Logger.getLogger(logHierarchy); + + logger.log(LEVEL, message, throwable); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java deleted file mode 100644 index fffd16a812..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.logging.rawloggers; - -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.logging.AbstractRootMessageLogger; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.LogSubject; - -public class Log4jMessageLogger extends AbstractRootMessageLogger -{ - public static final Level LEVEL = Level.toLevel("INFO"); - - public Log4jMessageLogger() - { - super(); - } - - public Log4jMessageLogger(ServerConfiguration config) - { - super(config); - } - - @Override - public boolean isMessageEnabled(LogActor actor, LogSubject subject, String logHierarchy) - { - return isMessageEnabled(actor, logHierarchy); - } - - @Override - public boolean isMessageEnabled(LogActor actor, String logHierarchy) - { - if(isEnabled()) - { - Logger logger = Logger.getLogger(logHierarchy); - return logger.isEnabledFor(LEVEL); - } - else - { - return false; - } - } - - @Override - public void rawMessage(String message, String logHierarchy) - { - rawMessage(message, null, logHierarchy); - } - - @Override - public void rawMessage(String message, Throwable throwable, String logHierarchy) - { - Logger logger = Logger.getLogger(logHierarchy); - - logger.log(LEVEL, message, throwable); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 5cddfda059..e9d1ead4f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -38,12 +38,12 @@ import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.SystemConfig; import org.apache.qpid.server.configuration.SystemConfigImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.Log4jMessageLogger; import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.logging.AbstractRootMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -- cgit v1.2.1 From 89e0c5bb4ddf5ae5594aa89161b0bfa1a19c033e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Aug 2010 13:27:02 +0000 Subject: QPID-2822: move documentation of the log message property files from the files themselves to a Docbook format file for inclusion in a future developer docs book Applied patches from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990146 13f79535-47bb-0310-9956-ffa450edef68 --- .../messages/Binding_logmessages.properties | 191 --------------------- .../logging/messages/Broker_logmessages.properties | 191 --------------------- .../messages/Channel_logmessages.properties | 191 --------------------- .../messages/ConfigStore_logmessages.properties | 191 --------------------- .../messages/Connection_logmessages.properties | 191 --------------------- .../messages/Exchange_logmessages.properties | 191 --------------------- .../ManagementConsole_logmessages.properties | 191 --------------------- .../messages/MessageStore_logmessages.properties | 191 --------------------- .../logging/messages/Queue_logmessages.properties | 191 --------------------- .../messages/Subscription_logmessages.properties | 191 --------------------- .../messages/TransactionLog_logmessages.properties | 190 -------------------- .../messages/VirtualHost_logmessages.properties | 191 --------------------- 12 files changed, 2291 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties index 6956a396b0..808ec7918f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Binding_logmessages.properties @@ -18,196 +18,5 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - CREATED = BND-1001 : Create[ : Arguments : {0}] DELETED = BND-1002 : Deleted diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties index 9a0bdec929..3782026bad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties @@ -17,197 +17,6 @@ # under the License. # # Default File used for all non-defined locales. -# -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. # 0 - Version # 1 = Build diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties index 53b8e995f4..53bcd712f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties @@ -17,197 +17,6 @@ # under the License. # # Default File used for all non-defined locales. -# -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. CREATE = CHN-1001 : Create # 0 - flow diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties index a6a36b15fe..3bc5074777 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ConfigStore_logmessages.properties @@ -17,197 +17,6 @@ # under the License. # # Default File used for all non-defined locales. -# -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. # 0 - name CREATED = CFG-1001 : Created : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties index 08393f5e00..81ae6f3bd0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Connection_logmessages.properties @@ -17,197 +17,6 @@ # under the License. # # Default File used for all non-defined locales. -# -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. # 0 - Client id # 1 - Protocol Version diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties index 6df7c5862c..b9890d9f27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Exchange_logmessages.properties @@ -17,197 +17,6 @@ # under the License. # # Default File used for all non-defined locales. -# -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. # 0 - type # 1 - name diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties index 910706a250..bd42425033 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties @@ -18,197 +18,6 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - STARTUP = MNG-1001 : Startup # 0 - Service # 1 - Port diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties index d60fafd196..a2cedeb22a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/MessageStore_logmessages.properties @@ -18,197 +18,6 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - # 0 - name CREATED = MST-1001 : Created : {0} # 0 - path diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties index 59a8c87f76..538bf994ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Queue_logmessages.properties @@ -18,197 +18,6 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - # 0 - owner # 1 - priority CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties index 7ad62d2049..ef5f885b50 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Subscription_logmessages.properties @@ -18,197 +18,6 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}] CLOSE = SUB-1002 : Close # 0 - The current subscription state diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties index fe50134cdd..fadc2e2098 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/TransactionLog_logmessages.properties @@ -18,197 +18,7 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages # -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - # 0 - name CREATED = TXN-1001 : Created : {0} # 0 - path diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties index 3129844495..66bbefacb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties @@ -18,197 +18,6 @@ # # Default File used for all non-defined locales. # -# This file was derivied from LogMessages used within the Java Broker and -# originally defined on the wiki: -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded as a ResourceBundle. The en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is required then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat performs its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addition of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexpected. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formatting. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the only processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# parameters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important as it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own Messages.java. -# Each logmessage file contains only one class of messages the name -# is derived from the name of the logmessages file e.g. _logmessages.properties. -# -# Property Format -# =============== -# The property format MUST adhere to the follow format to make it easier to -# use the logging API as a developer but also so that operations staff can -# easily locate log messages in the output. -# -# The property file should contain entries in the following format -# -# = : -# -# eg: -# SHUTTING_DOWN = BRK-1003 : Shutting down : {0} port {1,number,#} -# -# Note: the developer focused identifier will become a method name so only a -# valid method name should be used. Currently only '-' are converted to '_'. -# -# That said properties generate the logging code at build time so any error -# can be easily identified. -# -# The three character identifier show above in BRK-1003 should ideally be unique. -# This is the only requirement, limiting to 3 characters is not required. -# That said the current broker contains the following mappings. -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# ConfigStore | CFG -# TransactionLog | TXN -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage SHUTTING_DOWN(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain parameters -# however nesting of options is not permitted. Identification is performed on -# first matching so given the message: -# Msg = Log Message [option1] [option2] -# Two options will be identified and enabled to select text 'option1' and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# -# Default File used for all non-defined locales. - # 0 - name CREATED = VHT-1001 : Created : {0} CLOSED = VHT-1002 : Closed \ No newline at end of file -- cgit v1.2.1 From 8c53dcf46d002d28d012cb9bf98eb262aa9ecb0a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Aug 2010 13:27:18 +0000 Subject: QPID-2822: add ASF licence to SCD log message property files git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990147 13f79535-47bb-0310-9956-ffa450edef68 --- .../SlowConsumerDetection_logmessages.properties | 21 ++++++++++++++++++++- .../TopicDeletePolicy_logmessages.properties | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties index 2714935a71..03c56910c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties @@ -1,4 +1,23 @@ -#SlowConsumerDetection.logMessages +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. + RUNNING = SCD-1001 : Running COMPLETE = SCD-1002 : Complete CHECKING_QUEUE = SCD-1003 : Checking Status of Queue {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties index d0f5965c39..ed4fb1d45a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties @@ -1,3 +1,22 @@ -#TopicDeletePolicy.logMessages +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. + DELETING_QUEUE = TDP-1001 : Deleting Queue DISCONNECTING = TDP-1002 : Disconnecting Session \ No newline at end of file -- cgit v1.2.1 From 0164c68decc5e81d9784b9eea096b83e9a610545 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 27 Aug 2010 19:32:37 +0000 Subject: QPID-2771: rename package from plugin to plugins Applied patches from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990236 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ConfiguredObject.java | 2 +- .../plugin/SlowConsumerDetectionConfiguration.java | 92 ------------ .../SlowConsumerDetectionPolicyConfiguration.java | 76 ---------- .../SlowConsumerDetectionQueueConfiguration.java | 153 -------------------- .../SlowConsumerDetectionConfiguration.java | 92 ++++++++++++ .../SlowConsumerDetectionPolicyConfiguration.java | 76 ++++++++++ .../SlowConsumerDetectionQueueConfiguration.java | 153 ++++++++++++++++++++ .../apache/qpid/server/plugins/PluginManager.java | 10 +- .../plugin/ConfiguredQueueBindingListener.java | 86 ----------- .../virtualhost/plugin/SlowConsumerDetection.java | 161 --------------------- .../SlowConsumerDetection_logmessages.properties | 23 --- .../TopicDeletePolicy_logmessages.properties | 22 --- .../plugin/policies/TopicDeletePolicy.java | 141 ------------------ .../policies/TopicDeletePolicyConfiguration.java | 81 ----------- .../plugins/ConfiguredQueueBindingListener.java | 86 +++++++++++ .../virtualhost/plugins/SlowConsumerDetection.java | 161 +++++++++++++++++++++ .../SlowConsumerDetection_logmessages.properties | 23 +++ .../TopicDeletePolicy_logmessages.properties | 22 +++ .../plugins/policies/TopicDeletePolicy.java | 141 ++++++++++++++++++ .../policies/TopicDeletePolicyConfiguration.java | 81 +++++++++++ 20 files changed, 841 insertions(+), 841 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionPolicyConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/SlowConsumerDetection_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/TopicDeletePolicy_logmessages.properties create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicy.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicyConfiguration.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java index 34689abe2f..78666a3f93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java @@ -29,7 +29,7 @@ public interface ConfiguredObject, C extends Con public T getConfigType(); - public ConfiguredObject getParent(); + public ConfiguredObject getParent(); public boolean isDurable(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java deleted file mode 100644 index dd63c9b698..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionConfiguration.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.plugin; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.ConversionException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class SlowConsumerDetectionConfiguration extends ConfigurationPlugin -{ - public static class SlowConsumerDetectionConfigurationFactory implements ConfigurationPluginFactory - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - SlowConsumerDetectionConfiguration slowConsumerConfig = new SlowConsumerDetectionConfiguration(); - slowConsumerConfig.setConfiguration(path, config); - return slowConsumerConfig; - } - - public List getParentPaths() - { - return Arrays.asList("virtualhosts.virtualhost.slow-consumer-detection"); - } - } - - //Set Default time unit to seconds - TimeUnit _timeUnit = TimeUnit.SECONDS; - - public String[] getElementsProcessed() - { - return new String[]{"delay", - "timeunit"}; - } - - public long getDelay() - { - return getLongValue("delay", 10); - } - - public TimeUnit getTimeUnit() - { - return _timeUnit; - } - - @Override - public void validateConfiguration() throws ConfigurationException - { - validatePositiveLong("delay"); - - String timeUnit = getStringValue("timeunit"); - - if (timeUnit != null) - { - try - { - _timeUnit = TimeUnit.valueOf(timeUnit.toUpperCase()); - } - catch (IllegalArgumentException iae) - { - throw new ConfigurationException("Unable to configure Slow Consumer Detection invalid TimeUnit:" + timeUnit); - } - } - - System.out.println("Configured SCDC"); - System.out.println("Delay:" + getDelay()); - System.out.println("TimeUnit:" + getTimeUnit()); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java deleted file mode 100644 index 8e2ecff6fb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionPolicyConfiguration.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.plugin; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; - -import java.util.Arrays; -import java.util.List; - -public class SlowConsumerDetectionPolicyConfiguration extends ConfigurationPlugin -{ - public static class SlowConsumerDetectionPolicyConfigurationFactory implements ConfigurationPluginFactory - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - SlowConsumerDetectionPolicyConfiguration slowConsumerConfig = new SlowConsumerDetectionPolicyConfiguration(); - slowConsumerConfig.setConfiguration(path, config); - return slowConsumerConfig; - } - - public List getParentPaths() - { - return Arrays.asList( - "virtualhosts.virtualhost.queues.slow-consumer-detection.policy", - "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy", - "virtualhosts.virtualhost.topics.slow-consumer-detection.policy", - "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy"); - } - } - - public String[] getElementsProcessed() - { - return new String[]{"name"}; - } - - public String getPolicyName() - { - return getStringValue("name"); - } - - @Override - public void validateConfiguration() throws ConfigurationException - { - if (getPolicyName() == null) - { - throw new ConfigurationException("No Slow consumer policy defined."); - } - } - - @Override - public String formatToString() - { - return "Policy:"+getPolicyName(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java deleted file mode 100644 index 58131760da..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugin/SlowConsumerDetectionQueueConfiguration.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration.plugin; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; -import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin -{ - private SlowConsumerPolicyPlugin _policyPlugin; - - public static class SlowConsumerDetectionQueueConfigurationFactory implements ConfigurationPluginFactory - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - SlowConsumerDetectionQueueConfiguration slowConsumerConfig = new SlowConsumerDetectionQueueConfiguration(); - slowConsumerConfig.setConfiguration(path, config); - return slowConsumerConfig; - } - - public List getParentPaths() - { - return Arrays.asList( - "virtualhosts.virtualhost.queues.slow-consumer-detection", - "virtualhosts.virtualhost.queues.queue.slow-consumer-detection", - "virtualhosts.virtualhost.topics.slow-consumer-detection", - "virtualhosts.virtualhost.topics.topic.slow-consumer-detection"); - } - } - - public String[] getElementsProcessed() - { - return new String[]{"messageAge", - "depth", - "messageCount"}; - } - - public long getMessageAge() - { - return getLongValue("messageAge"); - } - - public long getDepth() - { - return getLongValue("depth"); - } - - public long getMessageCount() - { - return getLongValue("messageCount"); - } - - public SlowConsumerPolicyPlugin getPolicy() - { - return _policyPlugin; - } - - @Override - public void validateConfiguration() throws ConfigurationException - { - if (!containsPositiveLong("messageAge") && - !containsPositiveLong("depth") && - !containsPositiveLong("messageCount")) - { - throw new ConfigurationException("At least one configuration property" + - "('messageAge','depth' or 'messageCount') must be specified."); - } - - SlowConsumerDetectionPolicyConfiguration policyConfig = getConfiguration(SlowConsumerDetectionPolicyConfiguration.class.getName()); - - PluginManager pluginManager = ApplicationRegistry.getInstance().getPluginManager(); - Map factories = pluginManager.getSlowConsumerPlugins(); - - if (policyConfig == null) - { - throw new ConfigurationException("No Slow Consumer Policy specified. Known Policies:" + factories.keySet()); - } - - if (_logger.isDebugEnabled()) - { - Iterator keys = policyConfig.getConfig().getKeys(); - - while (keys.hasNext()) - { - String key = (String) keys.next(); - - _logger.debug("Policy Keys:" + key); - } - - } - - SlowConsumerPolicyPluginFactory pluginFactory = factories.get(policyConfig.getPolicyName().toLowerCase()); - - if (pluginFactory == null) - { - throw new ConfigurationException("Unknown Slow Consumer Policy specified:" + policyConfig.getPolicyName() + " Known Policies:" + factories.keySet()); - } - - _policyPlugin = pluginFactory.newInstance(policyConfig); - - // Debug the creation of this Config - _logger.debug(this); - } - - public String formatToString() - { - StringBuilder sb = new StringBuilder(); - if (getMessageAge() > 0) - { - sb.append("Age:").append(getMessageAge()).append(":"); - } - if (getDepth() > 0) - { - sb.append("Depth:").append(getDepth()).append(":"); - } - if (getMessageCount() > 0) - { - sb.append("Count:").append(getMessageCount()).append(":"); - } - - sb.append("Policy[").append(getPolicy()).append("]"); - return sb.toString(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java new file mode 100644 index 0000000000..c5fbb6efd9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.ConversionException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SlowConsumerDetectionConfiguration extends ConfigurationPlugin +{ + public static class SlowConsumerDetectionConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionConfiguration slowConsumerConfig = new SlowConsumerDetectionConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList("virtualhosts.virtualhost.slow-consumer-detection"); + } + } + + //Set Default time unit to seconds + TimeUnit _timeUnit = TimeUnit.SECONDS; + + public String[] getElementsProcessed() + { + return new String[]{"delay", + "timeunit"}; + } + + public long getDelay() + { + return getLongValue("delay", 10); + } + + public TimeUnit getTimeUnit() + { + return _timeUnit; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + validatePositiveLong("delay"); + + String timeUnit = getStringValue("timeunit"); + + if (timeUnit != null) + { + try + { + _timeUnit = TimeUnit.valueOf(timeUnit.toUpperCase()); + } + catch (IllegalArgumentException iae) + { + throw new ConfigurationException("Unable to configure Slow Consumer Detection invalid TimeUnit:" + timeUnit); + } + } + + System.out.println("Configured SCDC"); + System.out.println("Delay:" + getDelay()); + System.out.println("TimeUnit:" + getTimeUnit()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionPolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionPolicyConfiguration.java new file mode 100644 index 0000000000..ca8dec851a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionPolicyConfiguration.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; + +public class SlowConsumerDetectionPolicyConfiguration extends ConfigurationPlugin +{ + public static class SlowConsumerDetectionPolicyConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionPolicyConfiguration slowConsumerConfig = new SlowConsumerDetectionPolicyConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection.policy", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy", + "virtualhosts.virtualhost.topics.slow-consumer-detection.policy", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"name"}; + } + + public String getPolicyName() + { + return getStringValue("name"); + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + if (getPolicyName() == null) + { + throw new ConfigurationException("No Slow consumer policy defined."); + } + } + + @Override + public String formatToString() + { + return "Policy:"+getPolicyName(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java new file mode 100644 index 0000000000..0638ea362f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java @@ -0,0 +1,153 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration.plugins; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin +{ + private SlowConsumerPolicyPlugin _policyPlugin; + + public static class SlowConsumerDetectionQueueConfigurationFactory implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + SlowConsumerDetectionQueueConfiguration slowConsumerConfig = new SlowConsumerDetectionQueueConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection", + "virtualhosts.virtualhost.topics.slow-consumer-detection", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"messageAge", + "depth", + "messageCount"}; + } + + public long getMessageAge() + { + return getLongValue("messageAge"); + } + + public long getDepth() + { + return getLongValue("depth"); + } + + public long getMessageCount() + { + return getLongValue("messageCount"); + } + + public SlowConsumerPolicyPlugin getPolicy() + { + return _policyPlugin; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + if (!containsPositiveLong("messageAge") && + !containsPositiveLong("depth") && + !containsPositiveLong("messageCount")) + { + throw new ConfigurationException("At least one configuration property" + + "('messageAge','depth' or 'messageCount') must be specified."); + } + + SlowConsumerDetectionPolicyConfiguration policyConfig = getConfiguration(SlowConsumerDetectionPolicyConfiguration.class.getName()); + + PluginManager pluginManager = ApplicationRegistry.getInstance().getPluginManager(); + Map factories = pluginManager.getSlowConsumerPlugins(); + + if (policyConfig == null) + { + throw new ConfigurationException("No Slow Consumer Policy specified. Known Policies:" + factories.keySet()); + } + + if (_logger.isDebugEnabled()) + { + Iterator keys = policyConfig.getConfig().getKeys(); + + while (keys.hasNext()) + { + String key = (String) keys.next(); + + _logger.debug("Policy Keys:" + key); + } + + } + + SlowConsumerPolicyPluginFactory pluginFactory = factories.get(policyConfig.getPolicyName().toLowerCase()); + + if (pluginFactory == null) + { + throw new ConfigurationException("Unknown Slow Consumer Policy specified:" + policyConfig.getPolicyName() + " Known Policies:" + factories.keySet()); + } + + _policyPlugin = pluginFactory.newInstance(policyConfig); + + // Debug the creation of this Config + _logger.debug(this); + } + + public String formatToString() + { + StringBuilder sb = new StringBuilder(); + if (getMessageAge() > 0) + { + sb.append("Age:").append(getMessageAge()).append(":"); + } + if (getDepth() > 0) + { + sb.append("Depth:").append(getDepth()).append(":"); + } + if (getMessageCount() > 0) + { + sb.append("Count:").append(getMessageCount()).append(":"); + } + + sb.append("Policy[").append(getPolicy()).append("]"); + return sb.toString(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 97c43b940b..b61da12b05 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -35,9 +35,9 @@ import org.apache.felix.framework.util.StringMap; import org.apache.log4j.Logger; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.configuration.TopicConfiguration; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionConfiguration.SlowConsumerDetectionConfigurationFactory; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionPolicyConfiguration.SlowConsumerDetectionPolicyConfigurationFactory; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration.SlowConsumerDetectionQueueConfigurationFactory; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionConfiguration.SlowConsumerDetectionConfigurationFactory; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionPolicyConfiguration.SlowConsumerDetectionPolicyConfigurationFactory; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionQueueConfiguration.SlowConsumerDetectionQueueConfigurationFactory; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.security.SecurityManager; @@ -46,8 +46,8 @@ import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.access.plugins.DenyAll; import org.apache.qpid.server.security.access.plugins.LegacyAccess; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import org.apache.qpid.server.virtualhost.plugin.SlowConsumerDetection; -import org.apache.qpid.server.virtualhost.plugin.policies.TopicDeletePolicy; +import org.apache.qpid.server.virtualhost.plugins.SlowConsumerDetection; +import org.apache.qpid.server.virtualhost.plugins.policies.TopicDeletePolicy; import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java deleted file mode 100644 index d947e9a367..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/ConfiguredQueueBindingListener.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.apache.qpid.server.virtualhost.plugin; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.binding.Binding; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration; -import org.apache.qpid.server.exchange.AbstractExchange; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.Exchange.BindingListener; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * This is a listener that caches queues that are configured for slow consumer disconnection. - * - * There should be one listener per virtual host, which can be added to all exchanges on - * that host. - * - * TODO In future, it will be possible to configure the policy at runtime, so only the queue - * itself is cached, and the configuration looked up by the housekeeping thread. This means - * that there may be occasions where the copy of the cache contents retrieved by the thread - * does not contain queues that are configured, or that configured queues are not present. - * - * @see BindingListener - */ -public class ConfiguredQueueBindingListener implements BindingListener -{ - private static final Logger _log = Logger.getLogger(ConfiguredQueueBindingListener.class); - - private String _vhostName; - private Set _cache = Collections.synchronizedSet(new HashSet()); - - public ConfiguredQueueBindingListener(String vhostName) - { - _vhostName = vhostName; - } - - /** - * @see BindingListener#bindingAdded(Exchange, Binding) - */ - public void bindingAdded(Exchange exchange, Binding binding) - { - processBinding(binding); - } - - /** - * @see BindingListener#bindingRemoved(Exchange, Binding) - */ - public void bindingRemoved(Exchange exchange, Binding binding) - { - processBinding(binding); - } - - private void processBinding(Binding binding) - { - AMQQueue queue = binding.getQueue(); - - SlowConsumerDetectionQueueConfiguration config = - queue.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); - if (config != null) - { - _cache.add(queue); - } - else - { - _cache.remove(queue); - } - } - - /** - * Lookup and return the cache of configured {@link AMQQueue}s. - * - * Note that when accessing the cached queues, the {@link Iterator} is not thread safe - * (see the {@link Collections#synchronizedSet(Set)} documentation) so a copy of the - * cache is returned. - * - * @return a copy of the cached {@link java.util.Set} of queues - */ - public Set getQueueCache() - { - return new HashSet(_cache); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java deleted file mode 100644 index 6acb0bc11e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/SlowConsumerDetection.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugin; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionConfiguration; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionQueueConfiguration; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.plugins.Plugin; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.plugin.logging.SlowConsumerDetectionMessages; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; - -public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin -{ - private SlowConsumerDetectionConfiguration _config; - private ConfiguredQueueBindingListener _listener; - - public static class SlowConsumerFactory implements VirtualHostPluginFactory - { - public SlowConsumerDetection newInstance(VirtualHost vhost) - { - SlowConsumerDetectionConfiguration config = vhost.getConfiguration().getConfiguration(SlowConsumerDetectionConfiguration.class.getName()); - - if (config == null) - { - return null; - } - - SlowConsumerDetection plugin = new SlowConsumerDetection(vhost); - plugin.configure(config); - return plugin; - } - } - - /** - * Configures the slow consumer disconnect plugin by adding a listener to each exchange on this - * cirtual host to record all the configured queues in a cache for processing by the housekeeping - * thread. - * - * @see Plugin#configure(ConfigurationPlugin) - */ - public void configure(ConfigurationPlugin config) - { - _config = (SlowConsumerDetectionConfiguration) config; - _listener = new ConfiguredQueueBindingListener(_virtualhost.getName()); - for (AMQShortString exchangeName : _virtualhost.getExchangeRegistry().getExchangeNames()) - { - _virtualhost.getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener); - } - } - - public SlowConsumerDetection(VirtualHost vhost) - { - super(vhost); - } - - public void execute() - { - CurrentActor.get().message(SlowConsumerDetectionMessages.RUNNING()); - - Set cache = _listener.getQueueCache(); - for (AMQQueue q : cache) - { - CurrentActor.get().message(SlowConsumerDetectionMessages.CHECKING_QUEUE(q.getName())); - - try - { - SlowConsumerDetectionQueueConfiguration config = - q.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); - if (checkQueueStatus(q, config)) - { - config.getPolicy().performPolicy(q); - } - } - catch (Exception e) - { - // Don't throw exceptions as this will stop the house keeping task from running. - _logger.error("Exception in SlowConsumersDetection for queue: " + q.getName(), e); - } - } - - CurrentActor.get().message(SlowConsumerDetectionMessages.COMPLETE()); - } - - public long getDelay() - { - return _config.getDelay(); - } - - public TimeUnit getTimeUnit() - { - return _config.getTimeUnit(); - } - - /** - * Check the depth,messageSize,messageAge,messageCount values for this q - * - * @param q the queue to check - * @param config the queue configuration to compare against the queue state - * - * @return true if the queue has reached a threshold. - */ - private boolean checkQueueStatus(AMQQueue q, SlowConsumerDetectionQueueConfiguration config) - { - if (config != null) - { - _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config); - - int count = q.getMessageCount(); - - // First Check message counts - if ((config.getMessageCount() != 0 && count >= config.getMessageCount()) || - // The check queue depth - (config.getDepth() != 0 && q.getQueueDepth() >= config.getDepth()) || - // finally if we have messages on the queue check Arrival time. - // We must check count as OldestArrival time is Long.MAX_LONG when - // there are no messages. - (config.getMessageAge() != 0 && - ((count > 0) && q.getOldestMessageArrivalTime() >= config.getMessageAge()))) - { - - if (_logger.isDebugEnabled()) - { - _logger.debug("Detected Slow Consumer on Queue(" + q.getName() + ")"); - _logger.debug("Queue Count:" + q.getMessageCount() + ":" + config.getMessageCount()); - _logger.debug("Queue Depth:" + q.getQueueDepth() + ":" + config.getDepth()); - _logger.debug("Queue Arrival:" + q.getOldestMessageArrivalTime() + ":" + config.getMessageAge()); - } - - return true; - } - } - return false; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties deleted file mode 100644 index 03c56910c2..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/SlowConsumerDetection_logmessages.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# Default File used for all non-defined locales. - -RUNNING = SCD-1001 : Running -COMPLETE = SCD-1002 : Complete -CHECKING_QUEUE = SCD-1003 : Checking Status of Queue {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties deleted file mode 100644 index ed4fb1d45a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/logging/TopicDeletePolicy_logmessages.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# Default File used for all non-defined locales. - -DELETING_QUEUE = TDP-1001 : Deleting Queue -DISCONNECTING = TDP-1002 : Disconnecting Session \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java deleted file mode 100644 index 3bd4ae8d4e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicy.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugin.policies; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.binding.Binding; -import org.apache.qpid.server.configuration.plugin.SlowConsumerDetectionPolicyConfiguration; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.exchange.TopicExchange; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.plugin.logging.TopicDeletePolicyMessages; -import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; -import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; - -public class TopicDeletePolicy implements SlowConsumerPolicyPlugin -{ - Logger _logger = Logger.getLogger(TopicDeletePolicy.class); - private TopicDeletePolicyConfiguration _configuration; - - public static class TopicDeletePolicyFactory implements SlowConsumerPolicyPluginFactory - { - public TopicDeletePolicy newInstance(ConfigurationPlugin configuration) throws ConfigurationException - { - TopicDeletePolicyConfiguration config = - configuration.getConfiguration(TopicDeletePolicyConfiguration.class.getName()); - - TopicDeletePolicy policy = new TopicDeletePolicy(); - policy.configure(config); - return policy; - } - - public String getPluginName() - { - return "topicdelete"; - } - - public Class getPluginClass() - { - return TopicDeletePolicy.class; - } - } - - public void performPolicy(AMQQueue q) - { - if (q == null) - { - return; - } - - AMQSessionModel owner = q.getExclusiveOwningSession(); - - // Only process exclusive queues - if (owner == null) - { - return; - } - - //Only process Topics - if (!validateQueueIsATopic(q)) - { - return; - } - - try - { - CurrentActor.get().message(owner.getLogSubject(),TopicDeletePolicyMessages.DISCONNECTING()); - // Close the consumer . this will cause autoDelete Queues to be purged - owner.getConnectionModel(). - closeSession(owner, AMQConstant.RESOURCE_ERROR, - "Consuming to slow."); - - // Actively delete non autoDelete queues if deletePersistent is set - if (!q.isAutoDelete() && (_configuration != null && _configuration.deletePersistent())) - { - CurrentActor.get().message(q.getLogSubject(), TopicDeletePolicyMessages.DELETING_QUEUE()); - q.delete(); - } - - } - catch (AMQException e) - { - _logger.warn("Unable to close consumer:" + owner + ", on queue:" + q.getName()); - } - - } - - /** - * Check the queue bindings to validate the queue is bound to the - * topic exchange. - * - * @param q the Queue - * - * @return true iff Q is bound to a TopicExchange - */ - private boolean validateQueueIsATopic(AMQQueue q) - { - for (Binding binding : q.getBindings()) - { - if (binding.getExchange() instanceof TopicExchange) - { - return true; - } - } - - return false; - } - - public void configure(ConfigurationPlugin config) - { - _configuration = (TopicDeletePolicyConfiguration) config; - } - - @Override - public String toString() - { - return "TopicDelete" + (_configuration == null ? "" : "[" + _configuration + "]"); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java deleted file mode 100644 index e6ad1cbcc3..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugin/policies/TopicDeletePolicyConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.virtualhost.plugin.policies; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; - -public class TopicDeletePolicyConfiguration extends ConfigurationPlugin -{ - - public static class TopicDeletePolicyConfigurationFactory - implements ConfigurationPluginFactory - { - public ConfigurationPlugin newInstance(String path, - Configuration config) - throws ConfigurationException - { - TopicDeletePolicyConfiguration slowConsumerConfig = - new TopicDeletePolicyConfiguration(); - slowConsumerConfig.setConfiguration(path, config); - return slowConsumerConfig; - } - - public List getParentPaths() - { - return Arrays.asList( - "virtualhosts.virtualhost.queues.slow-consumer-detection.policy.topicDelete", - "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy.topicDelete", - "virtualhosts.virtualhost.topics.slow-consumer-detection.policy.topicDelete", - "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy.topicDelete"); - } - } - - public String[] getElementsProcessed() - { - return new String[]{"delete-persistent"}; - } - - @Override - public void validateConfiguration() throws ConfigurationException - { - // No validation required. - } - - public boolean deletePersistent() - { - // If we don't have configuration then we don't deletePersistent Queues - return (hasConfiguration() && contains("delete-persistent")); - } - - @Override - public String formatToString() - { - return (deletePersistent()?"delete-durable":""); - } - - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java new file mode 100644 index 0000000000..259f8574e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java @@ -0,0 +1,86 @@ +package org.apache.qpid.server.virtualhost.plugins; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionQueueConfiguration; +import org.apache.qpid.server.exchange.AbstractExchange; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.Exchange.BindingListener; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * This is a listener that caches queues that are configured for slow consumer disconnection. + * + * There should be one listener per virtual host, which can be added to all exchanges on + * that host. + * + * TODO In future, it will be possible to configure the policy at runtime, so only the queue + * itself is cached, and the configuration looked up by the housekeeping thread. This means + * that there may be occasions where the copy of the cache contents retrieved by the thread + * does not contain queues that are configured, or that configured queues are not present. + * + * @see BindingListener + */ +public class ConfiguredQueueBindingListener implements BindingListener +{ + private static final Logger _log = Logger.getLogger(ConfiguredQueueBindingListener.class); + + private String _vhostName; + private Set _cache = Collections.synchronizedSet(new HashSet()); + + public ConfiguredQueueBindingListener(String vhostName) + { + _vhostName = vhostName; + } + + /** + * @see BindingListener#bindingAdded(Exchange, Binding) + */ + public void bindingAdded(Exchange exchange, Binding binding) + { + processBinding(binding); + } + + /** + * @see BindingListener#bindingRemoved(Exchange, Binding) + */ + public void bindingRemoved(Exchange exchange, Binding binding) + { + processBinding(binding); + } + + private void processBinding(Binding binding) + { + AMQQueue queue = binding.getQueue(); + + SlowConsumerDetectionQueueConfiguration config = + queue.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); + if (config != null) + { + _cache.add(queue); + } + else + { + _cache.remove(queue); + } + } + + /** + * Lookup and return the cache of configured {@link AMQQueue}s. + * + * Note that when accessing the cached queues, the {@link Iterator} is not thread safe + * (see the {@link Collections#synchronizedSet(Set)} documentation) so a copy of the + * cache is returned. + * + * @return a copy of the cached {@link java.util.Set} of queues + */ + public Set getQueueCache() + { + return new HashSet(_cache); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java new file mode 100644 index 0000000000..ddc55652a8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java @@ -0,0 +1,161 @@ +/* + * + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionConfiguration; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionQueueConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.plugins.logging.SlowConsumerDetectionMessages; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; + +public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin +{ + private SlowConsumerDetectionConfiguration _config; + private ConfiguredQueueBindingListener _listener; + + public static class SlowConsumerFactory implements VirtualHostPluginFactory + { + public SlowConsumerDetection newInstance(VirtualHost vhost) + { + SlowConsumerDetectionConfiguration config = vhost.getConfiguration().getConfiguration(SlowConsumerDetectionConfiguration.class.getName()); + + if (config == null) + { + return null; + } + + SlowConsumerDetection plugin = new SlowConsumerDetection(vhost); + plugin.configure(config); + return plugin; + } + } + + /** + * Configures the slow consumer disconnect plugin by adding a listener to each exchange on this + * cirtual host to record all the configured queues in a cache for processing by the housekeeping + * thread. + * + * @see Plugin#configure(ConfigurationPlugin) + */ + public void configure(ConfigurationPlugin config) + { + _config = (SlowConsumerDetectionConfiguration) config; + _listener = new ConfiguredQueueBindingListener(_virtualhost.getName()); + for (AMQShortString exchangeName : _virtualhost.getExchangeRegistry().getExchangeNames()) + { + _virtualhost.getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener); + } + } + + public SlowConsumerDetection(VirtualHost vhost) + { + super(vhost); + } + + public void execute() + { + CurrentActor.get().message(SlowConsumerDetectionMessages.RUNNING()); + + Set cache = _listener.getQueueCache(); + for (AMQQueue q : cache) + { + CurrentActor.get().message(SlowConsumerDetectionMessages.CHECKING_QUEUE(q.getName())); + + try + { + SlowConsumerDetectionQueueConfiguration config = + q.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName()); + if (checkQueueStatus(q, config)) + { + config.getPolicy().performPolicy(q); + } + } + catch (Exception e) + { + // Don't throw exceptions as this will stop the house keeping task from running. + _logger.error("Exception in SlowConsumersDetection for queue: " + q.getName(), e); + } + } + + CurrentActor.get().message(SlowConsumerDetectionMessages.COMPLETE()); + } + + public long getDelay() + { + return _config.getDelay(); + } + + public TimeUnit getTimeUnit() + { + return _config.getTimeUnit(); + } + + /** + * Check the depth,messageSize,messageAge,messageCount values for this q + * + * @param q the queue to check + * @param config the queue configuration to compare against the queue state + * + * @return true if the queue has reached a threshold. + */ + private boolean checkQueueStatus(AMQQueue q, SlowConsumerDetectionQueueConfiguration config) + { + if (config != null) + { + _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config); + + int count = q.getMessageCount(); + + // First Check message counts + if ((config.getMessageCount() != 0 && count >= config.getMessageCount()) || + // The check queue depth + (config.getDepth() != 0 && q.getQueueDepth() >= config.getDepth()) || + // finally if we have messages on the queue check Arrival time. + // We must check count as OldestArrival time is Long.MAX_LONG when + // there are no messages. + (config.getMessageAge() != 0 && + ((count > 0) && q.getOldestMessageArrivalTime() >= config.getMessageAge()))) + { + + if (_logger.isDebugEnabled()) + { + _logger.debug("Detected Slow Consumer on Queue(" + q.getName() + ")"); + _logger.debug("Queue Count:" + q.getMessageCount() + ":" + config.getMessageCount()); + _logger.debug("Queue Depth:" + q.getQueueDepth() + ":" + config.getDepth()); + _logger.debug("Queue Arrival:" + q.getOldestMessageArrivalTime() + ":" + config.getMessageAge()); + } + + return true; + } + } + return false; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/SlowConsumerDetection_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/SlowConsumerDetection_logmessages.properties new file mode 100644 index 0000000000..03c56910c2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/SlowConsumerDetection_logmessages.properties @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. + +RUNNING = SCD-1001 : Running +COMPLETE = SCD-1002 : Complete +CHECKING_QUEUE = SCD-1003 : Checking Status of Queue {0} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/TopicDeletePolicy_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/TopicDeletePolicy_logmessages.properties new file mode 100644 index 0000000000..ed4fb1d45a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/logging/TopicDeletePolicy_logmessages.properties @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Default File used for all non-defined locales. + +DELETING_QUEUE = TDP-1001 : Deleting Queue +DISCONNECTING = TDP-1002 : Disconnecting Session \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicy.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicy.java new file mode 100644 index 0000000000..6028f63fdb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicy.java @@ -0,0 +1,141 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins.policies; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionPolicyConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.exchange.TopicExchange; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.plugins.logging.TopicDeletePolicyMessages; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin; +import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPluginFactory; + +public class TopicDeletePolicy implements SlowConsumerPolicyPlugin +{ + Logger _logger = Logger.getLogger(TopicDeletePolicy.class); + private TopicDeletePolicyConfiguration _configuration; + + public static class TopicDeletePolicyFactory implements SlowConsumerPolicyPluginFactory + { + public TopicDeletePolicy newInstance(ConfigurationPlugin configuration) throws ConfigurationException + { + TopicDeletePolicyConfiguration config = + configuration.getConfiguration(TopicDeletePolicyConfiguration.class.getName()); + + TopicDeletePolicy policy = new TopicDeletePolicy(); + policy.configure(config); + return policy; + } + + public String getPluginName() + { + return "topicdelete"; + } + + public Class getPluginClass() + { + return TopicDeletePolicy.class; + } + } + + public void performPolicy(AMQQueue q) + { + if (q == null) + { + return; + } + + AMQSessionModel owner = q.getExclusiveOwningSession(); + + // Only process exclusive queues + if (owner == null) + { + return; + } + + //Only process Topics + if (!validateQueueIsATopic(q)) + { + return; + } + + try + { + CurrentActor.get().message(owner.getLogSubject(),TopicDeletePolicyMessages.DISCONNECTING()); + // Close the consumer . this will cause autoDelete Queues to be purged + owner.getConnectionModel(). + closeSession(owner, AMQConstant.RESOURCE_ERROR, + "Consuming to slow."); + + // Actively delete non autoDelete queues if deletePersistent is set + if (!q.isAutoDelete() && (_configuration != null && _configuration.deletePersistent())) + { + CurrentActor.get().message(q.getLogSubject(), TopicDeletePolicyMessages.DELETING_QUEUE()); + q.delete(); + } + + } + catch (AMQException e) + { + _logger.warn("Unable to close consumer:" + owner + ", on queue:" + q.getName()); + } + + } + + /** + * Check the queue bindings to validate the queue is bound to the + * topic exchange. + * + * @param q the Queue + * + * @return true iff Q is bound to a TopicExchange + */ + private boolean validateQueueIsATopic(AMQQueue q) + { + for (Binding binding : q.getBindings()) + { + if (binding.getExchange() instanceof TopicExchange) + { + return true; + } + } + + return false; + } + + public void configure(ConfigurationPlugin config) + { + _configuration = (TopicDeletePolicyConfiguration) config; + } + + @Override + public String toString() + { + return "TopicDelete" + (_configuration == null ? "" : "[" + _configuration + "]"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicyConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicyConfiguration.java new file mode 100644 index 0000000000..7dfd22c733 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/policies/TopicDeletePolicyConfiguration.java @@ -0,0 +1,81 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost.plugins.policies; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +public class TopicDeletePolicyConfiguration extends ConfigurationPlugin +{ + + public static class TopicDeletePolicyConfigurationFactory + implements ConfigurationPluginFactory + { + public ConfigurationPlugin newInstance(String path, + Configuration config) + throws ConfigurationException + { + TopicDeletePolicyConfiguration slowConsumerConfig = + new TopicDeletePolicyConfiguration(); + slowConsumerConfig.setConfiguration(path, config); + return slowConsumerConfig; + } + + public List getParentPaths() + { + return Arrays.asList( + "virtualhosts.virtualhost.queues.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.queues.queue.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.topics.slow-consumer-detection.policy.topicDelete", + "virtualhosts.virtualhost.topics.topic.slow-consumer-detection.policy.topicDelete"); + } + } + + public String[] getElementsProcessed() + { + return new String[]{"delete-persistent"}; + } + + @Override + public void validateConfiguration() throws ConfigurationException + { + // No validation required. + } + + public boolean deletePersistent() + { + // If we don't have configuration then we don't deletePersistent Queues + return (hasConfiguration() && contains("delete-persistent")); + } + + @Override + public String formatToString() + { + return (deletePersistent()?"delete-durable":""); + } + + +} -- cgit v1.2.1 From 47dff25b6d643d27b41fcd362a414ca69d9f143d Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 28 Aug 2010 22:50:43 +0000 Subject: QPID-2769: add serialVersionUID Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990462 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/handler/UnexpectedMethodException.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java index fb18519fe1..3526fdcae5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java @@ -26,6 +26,9 @@ import org.apache.qpid.AMQException; public class UnexpectedMethodException extends AMQException { + + private static final long serialVersionUID = -255921574946294892L; + public UnexpectedMethodException(AMQMethodBody body) { super("Unexpected method recevied: " + body.getClass().getName()); -- cgit v1.2.1 From 9443fc6166b4a572479bcc633c24f8f46ca0b359 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 28 Aug 2010 22:50:59 +0000 Subject: QPID-2820: remove unused ManagedChannel interface Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990463 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/ManagedChannel.java | 68 ---------------------- 1 file changed, 68 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java deleted file mode 100644 index e76f9c3f6c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server; - -import java.io.IOException; - -import javax.management.JMException; - -/** - * 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; - -} -- cgit v1.2.1 From df4c2e62f52fe49cb7473a8ab3107facffb4cda5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 30 Aug 2010 15:19:34 +0000 Subject: QPID-2824: Use toLogString rather than toString on LogSubject(s) Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@990820 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/logging/LogSubject.java | 5 ++--- .../org/apache/qpid/server/logging/actors/AMQPChannelActor.java | 2 +- .../apache/qpid/server/logging/actors/AMQPConnectionActor.java | 2 +- .../org/apache/qpid/server/logging/actors/AbstractActor.java | 2 +- .../java/org/apache/qpid/server/logging/actors/QueueActor.java | 2 +- .../org/apache/qpid/server/logging/actors/SubscriptionActor.java | 2 +- .../apache/qpid/server/logging/subjects/AbstractLogSubject.java | 7 +++---- .../qpid/server/logging/subjects/ConnectionLogSubject.java | 5 ++--- .../org/apache/qpid/server/logging/subjects/QueueLogSubject.java | 2 +- .../qpid/server/logging/subjects/SubscriptionLogSubject.java | 6 +++--- .../java/org/apache/qpid/server/transport/ServerSession.java | 9 ++++++++- 11 files changed, 24 insertions(+), 20 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java index e53ef364bf..09a277e520 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java @@ -24,14 +24,13 @@ package org.apache.qpid.server.logging; * Each LogSubject that wishes to be logged will implement this to provide their * own display representation. * - * The display representation is retrieved through the toString() method. */ public interface LogSubject { /** - * Logs the message as provided by String.valueOf(message). + * Provides the log message as as String. * * @returns String the display representation of this LogSubject */ - public String toString(); + public String toLogString(); } \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java index d961836acc..9c7ffcc5f8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java @@ -58,7 +58,7 @@ public class AMQPChannelActor extends AbstractActor public String getLogMessage() { - return _logString.toString(); + return _logString.toLogString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java index 4149aed529..1b4bc91bc1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java @@ -48,7 +48,7 @@ public class AMQPConnectionActor extends AbstractActor public String getLogMessage() { - return _logSubject.toString(); + return _logSubject.toLogString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 05ac8c4b7e..a94e4b84e2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -44,7 +44,7 @@ public abstract class AbstractActor implements LogActor { if (_rootLogger.isMessageEnabled(this, subject, message.getLogHierarchy())) { - _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + String.valueOf(subject) + message, message.getLogHierarchy()); + _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + subject.toLogString() + message, message.getLogHierarchy()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java index 7d81b03de4..3364365b61 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java @@ -49,7 +49,7 @@ public class QueueActor extends AbstractActor public String getLogMessage() { - return _logSubject.toString(); + return _logSubject.toLogString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java index 612074fbe9..a2dbf2f6ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java @@ -41,6 +41,6 @@ public class SubscriptionActor extends AbstractActor public String getLogMessage() { - return _logSubject.toString(); + return _logSubject.toLogString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java index d7be9ea4c7..779db01601 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java @@ -34,7 +34,7 @@ import java.text.MessageFormat; public abstract class AbstractLogSubject implements LogSubject { /** - * The logString that will be returned via toString + * The logString that will be returned via toLogString */ protected String _logString; @@ -50,13 +50,12 @@ public abstract class AbstractLogSubject implements LogSubject } /** - * ToString is how the Logging infrastructure will get the text for this + * toLogString is how the Logging infrastructure will get the text for this * LogSubject * * @return String representing this LogSubject */ - @Override - public String toString() + public String toLogString() { return _logString; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index f3df87c432..6c41718177 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -128,10 +128,9 @@ public class ConnectionLogSubject extends AbstractLogSubject } } - @Override - public String toString() + public String toLogString() { updateLogString(); - return super.toString(); + return super.toLogString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java index fd97318e8b..b132d9e93f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -40,6 +40,6 @@ public class QueueLogSubject extends AbstractLogSubject { setLogStringWithFormat(LOG_FORMAT, queue.getVirtualHost().getName(), - queue.getNameShortString()); + queue.getName()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java index 2dde1b6b41..0683c8e361 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -29,8 +29,8 @@ public class SubscriptionLogSubject extends AbstractLogSubject /** * LOG FORMAT for the SubscriptionLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: + * Uses a MessageFormat call to insert the required values according to + * these indices: * * 0 - Subscription ID */ @@ -47,7 +47,7 @@ public class SubscriptionLogSubject extends AbstractLogSubject // log string format is: // [ sub:(vh()/qu()) ] - String queueString = new QueueLogSubject(subscription.getQueue()).toString(); + String queueString = new QueueLogSubject(subscription.getQueue()).toLogString(); _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT, subscription.getSubscriptionID()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 17a8ce8a43..42ccee3b3f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -575,7 +575,14 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public LogSubject getLogSubject() { - return null; + return new LogSubject() + { + public String toLogString() + { + return "[ ]"; + } + + }; } } -- cgit v1.2.1 From 728641d5340b2b5ae34cff3cdf87c5f27ea2aa64 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 2 Sep 2010 16:18:40 +0000 Subject: QPID-2843: Remove old logging and use the operational logging framework to provide startup information, directed to both stdout and the log file. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992003 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 23 ++------- .../logging/CompositeStartupMessageLogger.java | 31 ++++++++++++ .../ManagementConsole_logmessages.properties | 2 +- .../management/JMXManagedObjectRegistry.java | 18 ++----- .../management/MBeanInvocationHandlerImpl.java | 2 +- .../qpid/server/registry/ApplicationRegistry.java | 58 ++++++++++++++++------ 6 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 7d7eefc541..13927f28ab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -68,7 +68,6 @@ import org.apache.qpid.transport.network.mina.MINANetworkDriver; public class Main { private static Logger _logger; - private static Logger _brokerLogger; private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; @@ -230,13 +229,11 @@ public class Main catch (InitException e) { System.out.println("Initialisation Error : " + e.getMessage()); - _brokerLogger.error("Initialisation Error : " + e.getMessage()); shutdown(1); } catch (Throwable e) { System.out.println("Error initialising message broker: " + e); - _brokerLogger.error("Error initialising message broker: " + e); e.printStackTrace(); shutdown(1); } @@ -308,9 +305,9 @@ public class Main // the configuration. BrokerMessages.reload(); - // AR.initialise() sets its own actor so we now need to set the actor - // for the remainder of the startup - CurrentActor.set(new BrokerActor(config.getRootMessageLogger())); + // AR.initialise() sets and removes its own actor so we now need to set the actor + // for the remainder of the startup, and the default actor if the stack is empty + CurrentActor.set(new BrokerActor(config.getCompositeStartupMessageLogger())); CurrentActor.setDefault(new BrokerActor(config.getRootMessageLogger())); try @@ -324,13 +321,6 @@ public class Main new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion()); sysInfoMBean.register(); - //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues - // that are causing the broker build to pick up the wrong properties file and hence say - // Starting Qpid Client - _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - - String[] portStr = commandLine.getOptionValues("p"); @@ -443,10 +433,6 @@ public class Main CurrentActor.get().message(BrokerMessages.LISTENING("TCP/SSL", serverConfig.getSSLPort())); } - //fixme qpid.AMQP should be using qpidproperties to get value - _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() - + " build: " + QpidProperties.getBuildVersion()); - CurrentActor.get().message(BrokerMessages.READY()); } @@ -530,7 +516,6 @@ public class Main //now that the override status is know, we can instantiate the Loggers _logger = Logger.getLogger(Main.class); - _brokerLogger = Logger.getLogger("Qpid.Broker"); new Main(args); } @@ -568,7 +553,7 @@ public class Main if (logConfigFile.exists() && logConfigFile.canRead()) { CurrentActor.get().message(BrokerMessages.LOG_CONFIG(logConfigFile.getAbsolutePath())); - System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); + if (logWatchTime > 0) { System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java new file mode 100644 index 0000000000..d2838f0789 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java @@ -0,0 +1,31 @@ +package org.apache.qpid.server.logging; + +public class CompositeStartupMessageLogger extends AbstractRootMessageLogger +{ + private RootMessageLogger[] _loggers; + + public CompositeStartupMessageLogger(RootMessageLogger[] loggers) + { + super(); + _loggers = loggers; + } + + @Override + public void rawMessage(String message, String logHierarchy) + { + for(RootMessageLogger l : _loggers) + { + l.rawMessage(message, logHierarchy); + } + } + + @Override + public void rawMessage(String message, Throwable throwable, String logHierarchy) + { + for(RootMessageLogger l : _loggers) + { + l.rawMessage(message, throwable, logHierarchy); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties index bd42425033..722b02d935 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties @@ -24,7 +24,7 @@ STARTUP = MNG-1001 : Startup LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} # 0 - Service # 1 - Port -SHUTTING_DOWN = MNG-1003 : Shuting down : {0} : port {1,number,#} +SHUTTING_DOWN = MNG-1003 : Shutting down : {0} : port {1,number,#} READY = MNG-1004 : Ready STOPPED = MNG-1005 : Stopped # 0 - Path diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 90e0bba6f7..fb369b4d5b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -73,7 +73,6 @@ import java.util.Map; public class JMXManagedObjectRegistry implements ManagedObjectRegistry { private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); - private static final Logger _startupLog = Logger.getLogger("Qpid.Broker"); public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport"; public static final int MANAGEMENT_PORT_DEFAULT = 8999; @@ -108,7 +107,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry if (areOutOfTheBoxJMXOptionsSet()) { _log.warn("JMX: Using the out of the box JMX Agent"); - _startupLog.warn("JMX: Using the out of the box JMX Agent"); return; } @@ -170,9 +168,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry + ksf + ". Check permissions."); } - _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath()); - CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(ksf.getAbsolutePath())); } @@ -196,13 +191,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry csf = new SslRMIClientSocketFactory(); ssf = new SslRMIServerSocketFactory(); - _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" + - (port +PORT_EXPORT_OFFSET) + ") with SSL"); - - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL JMX RMIConnectorServer", port + PORT_EXPORT_OFFSET)); } else @@ -211,10 +201,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry csf = null; ssf = null; - _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); - _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")"); CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI ConnectorServer", port + PORT_EXPORT_OFFSET)); + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("JMX RMIConnectorServer", port + PORT_EXPORT_OFFSET)); } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index e0a7c9c756..19b4586017 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -74,7 +74,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati final Class[] interfaces = new Class[] { MBeanServerForwarder.class }; - _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); + _logActor = new ManagementActor(ApplicationRegistry.getInstance().getRootMessageLogger()); Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); return MBeanServerForwarder.class.cast(proxy); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index e9d1ead4f7..78a642f22f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -38,9 +38,11 @@ import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.SystemConfig; import org.apache.qpid.server.configuration.SystemConfigImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.CompositeStartupMessageLogger; import org.apache.qpid.server.logging.Log4jMessageLogger; import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.logging.AbstractRootMessageLogger; +import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; @@ -91,6 +93,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected RootMessageLogger _rootMessageLogger; + protected CompositeStartupMessageLogger _startupMessageLogger; + protected UUID _brokerId = UUID.randomUUID(); protected QMFService _qmfService; @@ -249,36 +253,53 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void initialise(int instanceID) throws Exception { + //Create the RootLogger to be used during broker operation _rootMessageLogger = new Log4jMessageLogger(_configuration); _registryName = String.valueOf(instanceID); - // Set the Actor for current log messages - CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - - configure(); + //Create the composite (log4j+SystemOut MessageLogger to be used during startup + RootMessageLogger[] messageLoggers = {new SystemOutMessageLogger(), _rootMessageLogger}; + _startupMessageLogger = new CompositeStartupMessageLogger(messageLoggers); + + CurrentActor.set(new BrokerActor(_startupMessageLogger)); - _qmfService = new QMFService(getConfigStore(), this); + try + { + configure(); - CurrentActor.get().message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); + _qmfService = new QMFService(getConfigStore(), this); - initialiseManagedObjectRegistry(); + CurrentActor.get().message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); - _virtualHostRegistry = new VirtualHostRegistry(this); + initialiseManagedObjectRegistry(); - _securityManager = new SecurityManager(_configuration, _pluginManager); + _virtualHostRegistry = new VirtualHostRegistry(this); - createDatabaseManager(_configuration); + _securityManager = new SecurityManager(_configuration, _pluginManager); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + createDatabaseManager(_configuration); - _databaseManager.initialiseManagement(_configuration); + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); - _managedObjectRegistry.start(); + _databaseManager.initialiseManagement(_configuration); - initialiseVirtualHosts(); + _managedObjectRegistry.start(); + } + finally + { + CurrentActor.remove(); + } - // Startup complete, so pop the current actor - CurrentActor.remove(); + CurrentActor.set(new BrokerActor(_rootMessageLogger)); + try + { + initialiseVirtualHosts(); + } + finally + { + // Startup complete, so pop the current actor + CurrentActor.remove(); + } } protected void createDatabaseManager(ServerConfiguration configuration) throws Exception @@ -444,6 +465,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { return _rootMessageLogger; } + + public RootMessageLogger getCompositeStartupMessageLogger() + { + return _startupMessageLogger; + } public UUID getBrokerId() { -- cgit v1.2.1 From 0d690bbbd3d3b972fb6bc4187252d461a918aed6 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 3 Sep 2010 10:57:02 +0000 Subject: QPID-2843: move the 2 management port listening messages to after the respective points listening has been initiated git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992264 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/management/JMXManagedObjectRegistry.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index fb369b4d5b..a33f61ce8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -190,19 +190,12 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //create the SSL RMI socket factories csf = new SslRMIClientSocketFactory(); ssf = new SslRMIServerSocketFactory(); - - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("SSL JMX RMIConnectorServer", port + PORT_EXPORT_OFFSET)); - } else { //Do not specify any specific RMI socket factories, resulting in use of the defaults. csf = null; ssf = null; - - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("JMX RMIConnectorServer", port + PORT_EXPORT_OFFSET)); } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server @@ -224,6 +217,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry { _rmiRegistry = LocateRegistry.createRegistry(port, null, null); } + + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", port)); /* * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls @@ -316,6 +311,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _cs.start(); + String connectorServer = (sslEnabled ? "SSL " : "") + "JMX RMIConnectorServer"; + CurrentActor.get().message(ManagementConsoleMessages.LISTENING(connectorServer, port + PORT_EXPORT_OFFSET)); CurrentActor.get().message(ManagementConsoleMessages.READY()); } @@ -398,7 +395,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry // Stopping the JMX ConnectorServer try { - CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort())); + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("JMX RMIConnectorServer", _cs.getAddress().getPort())); _cs.stop(); } catch (IOException e) -- cgit v1.2.1 From e05d000fea861e01d5a98dac417642f47a8ccbc5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 3 Sep 2010 15:35:44 +0000 Subject: QPID-2843: Ensure that a MNG-1004 message is logged when using the platform agent (and indicates use of the platform agent), merge the BRK-1004 message text with the previously used stdout startup log message. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992330 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/logging/messages/Broker_logmessages.properties | 2 +- .../server/logging/messages/ManagementConsole_logmessages.properties | 2 +- .../org/apache/qpid/server/management/JMXManagedObjectRegistry.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties index 3782026bad..6b83a7e7a5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties @@ -27,7 +27,7 @@ LISTENING = BRK-1002 : Starting : Listening on {0} port {1,number,#} # 0 - Transport # 1 - Port SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#} -READY = BRK-1004 : Ready +READY = BRK-1004 : Qpid Broker Ready STOPPED = BRK-1005 : Stopped # 0 - path CONFIG = BRK-1006 : Using configuration : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties index 722b02d935..9bdfe41f0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties @@ -25,7 +25,7 @@ LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} # 0 - Service # 1 - Port SHUTTING_DOWN = MNG-1003 : Shutting down : {0} : port {1,number,#} -READY = MNG-1004 : Ready +READY = MNG-1004 : Ready[ : {0}] STOPPED = MNG-1005 : Stopped # 0 - Path SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index a33f61ce8c..9f09afa1de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -106,7 +106,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) { - _log.warn("JMX: Using the out of the box JMX Agent"); + CurrentActor.get().message(ManagementConsoleMessages.READY("Using the platform JMX Agent", true)); return; } @@ -314,7 +314,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry String connectorServer = (sslEnabled ? "SSL " : "") + "JMX RMIConnectorServer"; CurrentActor.get().message(ManagementConsoleMessages.LISTENING(connectorServer, port + PORT_EXPORT_OFFSET)); - CurrentActor.get().message(ManagementConsoleMessages.READY()); + CurrentActor.get().message(ManagementConsoleMessages.READY("", false)); } /* -- cgit v1.2.1 From 8b2e499dc048359c2bc37d1e9e36b2f8cd3cb3bc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 5 Sep 2010 18:51:15 +0000 Subject: QPID-2418: updates to fix test failures when using the 0-10 client test profiles. Use a transacted session when querying for queue counts following consumption, as the 0-10 client batches auto-acks asynchronously. Always send the selector filter argument even if empty, to allow querying the brokers via 0-10 to detect whether the selector is being added/removed/modified at subscribe time. Enable the Java broker to perform argument matching during the 0-10 isBound check. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992856 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/transport/ServerSessionDelegate.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 44a677a76d..7b51b68e61 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -756,7 +756,9 @@ public class ServerSessionDelegate extends SessionDelegate if(method.hasArguments()) { - // TODO + FieldTable args = FieldTable.convertToFieldTable(method.getArguments()); + + result.setArgsNotMatched(!exchange.isBound(new AMQShortString(method.getBindingKey()), args, queue)); } if(queueMatched) { -- cgit v1.2.1 From 79d23103437e1d06aa7ea45b7951ad21de9fa0d5 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 5 Sep 2010 22:03:40 +0000 Subject: QPID-2837: The o.a.q.server.transport.ThreadPoolFilter class is not used and can be safely removed Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992903 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ThreadPoolFilter.java | 698 --------------------- 1 file changed, 698 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java deleted file mode 100644 index db02a7bf76..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ /dev/null @@ -1,698 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * 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 java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoFilterAdapter; -import org.apache.mina.common.IoHandler; -import org.apache.mina.common.IoSession; -import org.apache.mina.util.BlockingQueue; -import org.apache.mina.util.ByteBufferUtil; -import org.apache.mina.util.IdentityHashSet; -import org.apache.mina.util.Queue; -import org.apache.mina.util.Stack; - -/** - * 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) - { - synchronized (buffers) - { - SessionBuffer buf = (SessionBuffer) buffers.get(session); - if (buf == null) - { - buf = new SessionBuffer(session); - buffers.put(session, buf); - } - return buf; - } - } - - private void removeSessionBuffer(SessionBuffer buf) - { - synchronized (buffers) - { - buffers.remove(buf.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); - } -} -- cgit v1.2.1 From b2e1df541a341418d297cd1f59ef562d859a89cd Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 6 Sep 2010 10:06:06 +0000 Subject: QPID-2843: move the text to the properties file to allow for il8n git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@992988 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/messages/ManagementConsole_logmessages.properties | 2 +- .../org/apache/qpid/server/management/JMXManagedObjectRegistry.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties index 9bdfe41f0f..ab77476da2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/ManagementConsole_logmessages.properties @@ -25,7 +25,7 @@ LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#} # 0 - Service # 1 - Port SHUTTING_DOWN = MNG-1003 : Shutting down : {0} : port {1,number,#} -READY = MNG-1004 : Ready[ : {0}] +READY = MNG-1004 : Ready[ : Using the platform JMX Agent] STOPPED = MNG-1005 : Stopped # 0 - Path SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 9f09afa1de..03e1d1fcaa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -106,7 +106,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) { - CurrentActor.get().message(ManagementConsoleMessages.READY("Using the platform JMX Agent", true)); + CurrentActor.get().message(ManagementConsoleMessages.READY(true)); return; } @@ -314,7 +314,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry String connectorServer = (sslEnabled ? "SSL " : "") + "JMX RMIConnectorServer"; CurrentActor.get().message(ManagementConsoleMessages.LISTENING(connectorServer, port + PORT_EXPORT_OFFSET)); - CurrentActor.get().message(ManagementConsoleMessages.READY("", false)); + CurrentActor.get().message(ManagementConsoleMessages.READY(false)); } /* -- cgit v1.2.1 From 97956f50aefa04dc9a8951e816022b4054ca6296 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 8 Sep 2010 15:40:53 +0000 Subject: QPID-2840: make the status logging message prefix configurable but empty by default Applied patch from Sorin Suciu git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@995102 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/logging/actors/AbstractActor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index a94e4b84e2..638d08738f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -27,7 +27,7 @@ import org.apache.qpid.server.logging.RootMessageLogger; public abstract class AbstractActor implements LogActor { - public static final String DEFAULT_MSG_PREFIX = "MESSAGE "; + public static final String DEFAULT_MSG_PREFIX = System.getProperty("qpid.logging.prefix",""); protected RootMessageLogger _rootLogger; -- cgit v1.2.1 From 4b99962a08f8fd6d67f5360f94fe6b2bc7c102f9 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 9 Sep 2010 08:58:14 +0000 Subject: QPID-2840: update to fix issue with InVM tests passing in isolation but failing as part of the suite git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@995352 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/logging/actors/AbstractActor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java index 638d08738f..e0bf180cc4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java @@ -27,7 +27,7 @@ import org.apache.qpid.server.logging.RootMessageLogger; public abstract class AbstractActor implements LogActor { - public static final String DEFAULT_MSG_PREFIX = System.getProperty("qpid.logging.prefix",""); + public final String _msgPrefix = System.getProperty("qpid.logging.prefix",""); protected RootMessageLogger _rootLogger; @@ -44,7 +44,7 @@ public abstract class AbstractActor implements LogActor { if (_rootLogger.isMessageEnabled(this, subject, message.getLogHierarchy())) { - _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + subject.toLogString() + message, message.getLogHierarchy()); + _rootLogger.rawMessage(_msgPrefix + getLogMessage() + subject.toLogString() + message, message.getLogHierarchy()); } } @@ -52,7 +52,7 @@ public abstract class AbstractActor implements LogActor { if (_rootLogger.isMessageEnabled(this, message.getLogHierarchy())) { - _rootLogger.rawMessage(DEFAULT_MSG_PREFIX + getLogMessage() + message, message.getLogHierarchy()); + _rootLogger.rawMessage(_msgPrefix + getLogMessage() + message, message.getLogHierarchy()); } } -- cgit v1.2.1 From 052c26efb0c66241984d8a5c3dd912938a12d012 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 9 Sep 2010 14:01:21 +0000 Subject: QPID-2606: remove erroneous logging, missed when applying the half megabyte patch :) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@995430 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java | 1 - 1 file changed, 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 4f3f95bd6c..9a79467526 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -83,7 +83,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener Date: Sun, 12 Sep 2010 12:29:59 +0000 Subject: QPID-2854 : Correct implemention of 0-10 Queue Exclusivity in the Java Broker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@996300 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transport/ServerSessionDelegate.java | 73 +++++++++------------- 1 file changed, 30 insertions(+), 43 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 7b51b68e61..73eebec7bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -29,11 +29,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeInUseException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.HeadersExchange; +import org.apache.qpid.server.exchange.*; import org.apache.qpid.server.flow.FlowCreditManager_0_10; import org.apache.qpid.server.flow.WindowCreditManager; import org.apache.qpid.server.message.MessageMetaData_0_10; @@ -193,19 +189,40 @@ public class ServerSessionDelegate extends SessionDelegate QueueRegistry queueRegistry = getQueueRegistry(session); - AMQQueue queue = queueRegistry.getQueue(queueName); + final AMQQueue queue = queueRegistry.getQueue(queueName); if(queue == null) { exception(session,method,ExecutionErrorCode.NOT_FOUND, "Queue: " + queueName + " not found"); } - else if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) { exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); } else { + if(queue.isExclusive()) + { + if(queue.getPrincipalHolder() == null) + { + queue.setPrincipalHolder((ServerSession)session); + ((ServerSession) session).addSessionCloseTask(new ServerSession.Task() + { + + public void doTask(ServerSession session) + { + if(queue.getPrincipalHolder() == session) + { + queue.setPrincipalHolder(null); + } + } + }); + } + + + } + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); // TODO filters @@ -349,7 +366,12 @@ public class ServerSessionDelegate extends SessionDelegate } else { + AMQQueue queue = sub.getQueue(); ((ServerSession)session).unregister(sub); + if(!queue.isDeleted() && queue.isExclusive() && queue.getConsumerCount() == 0) + { + queue.setPrincipalHolder(null); + } } } @@ -850,8 +872,7 @@ public class ServerSessionDelegate extends SessionDelegate queue = createQueue(queueName, method, virtualHost, (ServerSession)session); if(method.getExclusive()) { - queue.setPrincipalHolder((ServerSession)session); - queue.setExclusiveOwningSession((AMQSessionModel) session); + queue.setExclusive(true); } else if(method.getAutoDelete()) { @@ -989,45 +1010,11 @@ public class ServerSessionDelegate extends SessionDelegate final ServerSession session) throws AMQException { - final QueueRegistry registry = virtualHost.getQueueRegistry(); - String owner = body.getExclusive() ? session.getClientID() : null; final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), body.getExclusive(), virtualHost, body.getArguments()); - if (body.getExclusive() && !body.getDurable()) - { - final ServerSession.Task deleteQueueTask = - new ServerSession.Task() - { - public void doTask(ServerSession session) - { - if (registry.getQueue(queueName) == queue) - { - try - { - queue.delete(); - } - catch (AMQException e) - { - exception(session, body, e, "Cannot delete queue '" + body.getQueue()); - } - } - } - }; - - session.addSessionCloseTask(deleteQueueTask); - - queue.addQueueDeleteTask(new AMQQueue.Task() - { - public void doTask(AMQQueue queue) - { - session.removeSessionCloseTask(deleteQueueTask); - } - }); - }// if exclusive and not durable - return queue; } -- cgit v1.2.1 From f18aee9ca723fe5e5820123999b7f76f30f18acd Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 12 Sep 2010 12:46:11 +0000 Subject: QPID-2855 : Broker Transport should not block on awaiting session close confirmation git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@996303 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerSession.java | 6 ++++++ .../qpid/server/transport/ServerSessionDelegate.java | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 42ccee3b3f..7393b17243 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -336,6 +336,12 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo } + @Override + protected void awaitClose() + { + // Broker shouldn't block awaiting close - thus do override this method to do nothing + } + public void acknowledge(final Subscription_0_10 sub, final QueueEntry entry) { _transaction.dequeue(entry.getQueue(), entry.getMessage(), diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 73eebec7bc..b4bb6eb0b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -101,11 +101,14 @@ public class ServerSessionDelegate extends SessionDelegate public void command(Session session, Method method) { SecurityManager.setThreadPrincipal(session.getConnection().getAuthorizationID()); - - super.command(session, method); - if (method.isSync()) + + if(!session.isClosing()) { - session.flushProcessed(); + super.command(session, method); + if (method.isSync()) + { + session.flushProcessed(); + } } } @@ -1189,6 +1192,12 @@ public class ServerSessionDelegate extends SessionDelegate ((ServerSession)session).onClose(); } + @Override + public void detached(Session session) + { + closed(session); + } + public Collection getSubscriptions(Session session) { return ((ServerSession)session).getSubscriptions(); -- cgit v1.2.1 From 8a4c51f79be29149fa30a01e7fab6f36301f24bb Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 12 Sep 2010 13:03:00 +0000 Subject: QPID-2856 : Attempting deltion of a default exchange should cause 530 not-allowed git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@996308 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transport/ServerSessionDelegate.java | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index b4bb6eb0b4..117be3e3b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -569,10 +569,18 @@ public class ServerSessionDelegate extends SessionDelegate { Exchange exchange = getExchange(session, method.getExchange()); - if(exchange != null && exchange.hasReferrers()) + if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "No such exchange '" + method.getExchange() + "'"); + } + else if(exchange.hasReferrers()) { exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); } + else if(isStandardExchange(exchange, virtualHost.getExchangeFactory().getRegisteredTypes())) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange '"+method.getExchange()+"' cannot be deleted"); + } else { exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); @@ -594,6 +602,18 @@ public class ServerSessionDelegate extends SessionDelegate } } + private boolean isStandardExchange(Exchange exchange, Collection> registeredTypes) + { + for(ExchangeType type : registeredTypes) + { + if(type.getDefaultExchangeName().toString().equals( exchange.getName() )) + { + return true; + } + } + return false; + } + @Override public void exchangeQuery(Session session, ExchangeQuery method) { -- cgit v1.2.1 From 8c8130d0288446f88deef393823cccffcaed474d Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 12 Sep 2010 22:40:40 +0000 Subject: QPID-2857 : Address issues found by running FindBugs against the Java codebase git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@996393 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/log4j/QpidCompositeRollingAppender.java | 42 +- .../apache/log4j/xml/QpidLog4JConfigurator.java | 9 +- .../apache/qpid/configuration/Configuration.java | 2 +- .../org/apache/qpid/qmf/ManagementExchange.java | 1 - .../main/java/org/apache/qpid/qmf/QMFMessage.java | 2 +- .../main/java/org/apache/qpid/qmf/QMFService.java | 2 +- .../apache/qpid/server/AMQBrokerManagerMBean.java | 12 +- .../src/main/java/org/apache/qpid/server/Main.java | 13 +- .../qpid/server/configuration/ConfigStore.java | 12 +- .../server/configuration/ServerConfiguration.java | 6 +- .../apache/qpid/server/exchange/TopicExchange.java | 2 +- .../server/exchange/headers/HeadersParser.java | 2 + .../org/apache/qpid/server/federation/Bridge.java | 4 + .../qpid/server/filter/ArithmeticExpression.java | 22 +- .../qpid/server/filter/ComparisonExpression.java | 86 +- .../qpid/server/filter/ConstantExpression.java | 12 +- .../apache/qpid/server/filter/UnaryExpression.java | 19 +- .../logging/management/LoggingManagementMBean.java | 5 +- .../server/logging/subjects/BindingLogSubject.java | 2 +- .../server/logging/subjects/ChannelLogSubject.java | 2 +- .../logging/subjects/ConnectionLogSubject.java | 2 +- .../logging/subjects/ExchangeLogSubject.java | 2 +- .../logging/subjects/MessageStoreLogSubject.java | 2 +- .../server/logging/subjects/QueueLogSubject.java | 2 +- .../logging/subjects/SubscriptionLogSubject.java | 2 +- .../management/JMXManagedObjectRegistry.java | 6 +- .../qpid/server/management/MBeanIntrospector.java | 10 +- .../management/MBeanInvocationHandlerImpl.java | 4 +- .../qpid/server/message/MessageMetaData.java | 1 - .../qpid/server/message/MessageTransferHeader.java | 2 +- .../qpid/server/protocol/AMQProtocolEngine.java | 2 +- .../protocol/MultiVersionProtocolEngine.java | 2 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 19 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 44 +- .../qpid/server/queue/SimpleQueueEntryList.java | 2 +- .../server/security/access/ObjectProperties.java | 7 +- .../Base64MD5PasswordFilePrincipalDatabase.java | 25 +- .../PlainPasswordFilePrincipalDatabase.java | 20 +- .../auth/management/AMQUserManagementMBean.java | 31 +- .../auth/sasl/UsernamePasswordInitialiser.java | 2 +- .../auth/sasl/crammd5/CRAMMD5HexInitialiser.java | 2 +- .../qpid/server/store/DerbyMessageStore.java | 935 ++++++++++++++------- .../qpid/server/subscription/SubscriptionList.java | 4 +- .../server/transport/ServerSessionDelegate.java | 17 +- .../qpid/server/virtualhost/HouseKeepingTask.java | 10 +- .../qpid/server/virtualhost/VirtualHostImpl.java | 18 +- .../virtualhost/plugins/SlowConsumerDetection.java | 9 +- .../plugins/VirtualHostHouseKeepingPlugin.java | 7 - .../virtualhost/plugins/VirtualHostPlugin.java | 2 - .../qpid/tools/messagestore/MessageStoreTool.java | 4 +- .../qpid/tools/messagestore/commands/Dump.java | 8 +- .../org/apache/qpid/tools/utils/SimpleConsole.java | 7 +- 52 files changed, 863 insertions(+), 604 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java index 83a6ff705d..4426a7aeec 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java @@ -106,9 +106,6 @@ public class QpidCompositeRollingAppender extends FileAppender /** Helper class to determine next rollover time */ RollingCalendar rc = new RollingCalendar(); - /** Current period for roll overs */ - int checkPeriod = TOP_OF_TROUBLE; - /** The default maximum file size is 10MB. */ protected long maxFileSize = 10 * 1024 * 1024; @@ -1037,23 +1034,32 @@ public class QpidCompositeRollingAppender extends FileAppender { // Create the GZIP output stream GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(target)); + try + { + // Open the input file + FileInputStream in = new FileInputStream(from); + try + { + // Transfer bytes from the input file to the GZIP output stream + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + } + finally + { + in.close(); + } - // Open the input file - FileInputStream in = new FileInputStream(from); - - // Transfer bytes from the input file to the GZIP output stream - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) + // Complete the GZIP file + out.finish(); + } + finally { - out.write(buf, 0, len); + out.close(); } - - in.close(); - - // Complete the GZIP file - out.finish(); - out.close(); // Remove old file. from.delete(); } @@ -1068,7 +1074,7 @@ public class QpidCompositeRollingAppender extends FileAppender } } - private class CompressJob + private static class CompressJob { File _from, _to; diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java index 6fa412cce6..1200ba6e0b 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -166,7 +166,7 @@ public class QpidLog4JConfigurator private static String constructMessage(final String msg, final SAXParseException ex) { - return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); + return msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage(); } } @@ -252,10 +252,11 @@ public class QpidLog4JConfigurator loggersLevels.put("Root", rootLoggerlevelString); - for (String loggerName : loggersLevels.keySet()) + for (Map.Entry entry : loggersLevels.entrySet()) { - String levelString = loggersLevels.get(loggerName); - + String loggerName = entry.getKey(); + String levelString = entry.getValue(); + //let log4j replace any properties in the string String log4jConfiguredString = domConfig.subst(levelString); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java index 40ff590a0a..0b63c68854 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/configuration/Configuration.java @@ -178,7 +178,7 @@ public class Configuration } - public class InitException extends Exception + public static class InitException extends Exception { InitException(String msg, Throwable cause) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index 67620d384b..593c1616fb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -90,7 +90,6 @@ public class ManagementExchange implements Exchange, QMFService.Listener public void enqueue(ServerMessage message) throws AMQException { - AMQMessageHeader h = message.getMessageHeader(); long size = message.getSize(); ByteBuffer buf = ByteBuffer.allocate((int) size); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java index de9bf1e9cb..895ff643a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -185,7 +185,7 @@ public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHead return len; } - private class QMFMessageReference extends MessageReference + private static class QMFMessageReference extends MessageReference { public QMFMessageReference(QMFMessage message) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 7e999a720b..7ed6a9114a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -467,7 +467,7 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable classObjectsById.put(object.getId(),qmfObject); - if(classObjects.putIfAbsent(object, qmfObject) == null); + if(classObjects.putIfAbsent(object, qmfObject) == null) { objectAdded(qmfObject); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 811e45f4ae..a612f280d6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -106,15 +106,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr */ public List retrieveQueueAttributeNames() throws IOException { - List attributeList = new ArrayList(); - for(String attr : ManagedQueue.QUEUE_ATTRIBUTES) - { - attributeList.add(attr); - } - - Collections.sort(attributeList); - - return attributeList; + return ManagedQueue.QUEUE_ATTRIBUTES; } /** @@ -153,7 +145,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (Exception e) { - attributeValues.add(new String("-")); + attributeValues.add("-"); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 13927f28ab..452ddf5895 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -592,9 +592,16 @@ public class Main } else { - Properties fallbackProps = new Properties(); - fallbackProps.load(propsFile); - PropertyConfigurator.configure(fallbackProps); + try + { + Properties fallbackProps = new Properties(); + fallbackProps.load(propsFile); + PropertyConfigurator.configure(fallbackProps); + } + finally + { + propsFile.close(); + } } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java index 572d886c18..0e03e33be8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; public class ConfigStore { @@ -36,14 +37,14 @@ public class ConfigStore private ConcurrentHashMap> _listenerMap = new ConcurrentHashMap>(); - private SystemConfig _root; + private AtomicReference _root = new AtomicReference(null); private final AtomicLong _objectIdSource = new AtomicLong(0l); public enum Event { - CREATED, DELETED; + CREATED, DELETED } public interface ConfigEventListener, C extends ConfiguredObject> @@ -151,11 +152,10 @@ public class ConfigStore } } - public synchronized boolean setRoot(SystemConfig object) + public boolean setRoot(SystemConfig object) { - if(_root == null) + if(_root.compareAndSet(null,object)) { - _root = object; addConfiguredObject(object); return true; } @@ -173,7 +173,7 @@ public class ConfigStore public SystemConfig getRoot() { - return _root; + return _root.get(); } public static ConfigStore newInstance() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 7681354f19..45c52a8891 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -339,7 +339,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa locale = new Locale(parts[0], parts[1]); break; default: - String variant = parts[2]; + StringBuilder variant = new StringBuilder(parts[2]); // If we have a variant such as the Java doc suggests for Spanish // Traditional_WIN we may end up with more than 3 parts on a // split with '_'. So we should recombine the variant. @@ -347,11 +347,11 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa { for (int index = 3; index < parts.length; index++) { - variant = variant + "_" + parts[index]; + variant.append('_').append(parts[index]); } } - locale = new Locale(parts[0], parts[1], variant); + locale = new Locale(parts[0], parts[1], variant.toString()); } return locale; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 1245efdafa..e523eb24fb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -251,7 +251,7 @@ public class TopicExchange extends AbstractExchange { for(Binding b : _bindings.keySet()) { - if(b.getBindingKey().equals(routingKey)) + if(b.getBindingKey().equals(routingKey.toString())) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java index 85e74122c3..0e3a3894fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java @@ -425,6 +425,8 @@ public class HeadersParser public boolean equals(Object o) { + assert o != null; + assert o instanceof KeyValuePair; KeyValuePair other = (KeyValuePair)o; return (_key == other._key) && (_value == null ? other._value == null : _value.equals(other._value)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index a4974c75ff..befa979d37 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -662,6 +662,8 @@ public class Bridge implements BridgeConfig public void setSession(final Session session) { + assert session instanceof ServerSession; + session.setSessionListener(this); ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); @@ -750,6 +752,8 @@ public class Bridge implements BridgeConfig public void setSession(final Session session) { + assert session instanceof ServerSession; + session.setSessionListener(this); QueueRegistry queueRegistry = getVirtualHost().getQueueRegistry(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index 2ead9e57af..221d23ef0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -163,13 +163,13 @@ public abstract class ArithmeticExpression extends BinaryExpression { case INTEGER: - return new Integer(left.intValue() + right.intValue()); + return Integer.valueOf(left.intValue() + right.intValue()); case LONG: - return new Long(left.longValue() + right.longValue()); + return Long.valueOf(left.longValue() + right.longValue()); default: - return new Double(left.doubleValue() + right.doubleValue()); + return Double.valueOf(left.doubleValue() + right.doubleValue()); } } @@ -179,13 +179,13 @@ public abstract class ArithmeticExpression extends BinaryExpression { case INTEGER: - return new Integer(left.intValue() - right.intValue()); + return Integer.valueOf(left.intValue() - right.intValue()); case LONG: - return new Long(left.longValue() - right.longValue()); + return Long.valueOf(left.longValue() - right.longValue()); default: - return new Double(left.doubleValue() - right.doubleValue()); + return Double.valueOf(left.doubleValue() - right.doubleValue()); } } @@ -195,24 +195,24 @@ public abstract class ArithmeticExpression extends BinaryExpression { case INTEGER: - return new Integer(left.intValue() * right.intValue()); + return Integer.valueOf(left.intValue() * right.intValue()); case LONG: - return new Long(left.longValue() * right.longValue()); + return Long.valueOf(left.longValue() * right.longValue()); default: - return new Double(left.doubleValue() * right.doubleValue()); + return Double.valueOf(left.doubleValue() * right.doubleValue()); } } protected Number divide(Number left, Number right) { - return new Double(left.doubleValue() / right.doubleValue()); + return Double.valueOf(left.doubleValue() / right.doubleValue()); } protected Number mod(Number left, Number right) { - return new Double(left.doubleValue() % right.doubleValue()); + return Double.valueOf(left.doubleValue() % right.doubleValue()); } private int numberType(Number left, Number right) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index f0650cb642..aad9d41174 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -45,30 +45,30 @@ public abstract class ComparisonExpression extends BinaryExpression implements B return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); } - private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); + private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); static { - REGEXP_CONTROL_CHARS.add(new Character('.')); - REGEXP_CONTROL_CHARS.add(new Character('\\')); - REGEXP_CONTROL_CHARS.add(new Character('[')); - REGEXP_CONTROL_CHARS.add(new Character(']')); - REGEXP_CONTROL_CHARS.add(new Character('^')); - REGEXP_CONTROL_CHARS.add(new Character('$')); - REGEXP_CONTROL_CHARS.add(new Character('?')); - REGEXP_CONTROL_CHARS.add(new Character('*')); - REGEXP_CONTROL_CHARS.add(new Character('+')); - REGEXP_CONTROL_CHARS.add(new Character('{')); - REGEXP_CONTROL_CHARS.add(new Character('}')); - REGEXP_CONTROL_CHARS.add(new Character('|')); - REGEXP_CONTROL_CHARS.add(new Character('(')); - REGEXP_CONTROL_CHARS.add(new Character(')')); - REGEXP_CONTROL_CHARS.add(new Character(':')); - REGEXP_CONTROL_CHARS.add(new Character('&')); - REGEXP_CONTROL_CHARS.add(new Character('<')); - REGEXP_CONTROL_CHARS.add(new Character('>')); - REGEXP_CONTROL_CHARS.add(new Character('=')); - REGEXP_CONTROL_CHARS.add(new Character('!')); + REGEXP_CONTROL_CHARS.add('.'); + REGEXP_CONTROL_CHARS.add('\\'); + REGEXP_CONTROL_CHARS.add('['); + REGEXP_CONTROL_CHARS.add(']'); + REGEXP_CONTROL_CHARS.add('^'); + REGEXP_CONTROL_CHARS.add('$'); + REGEXP_CONTROL_CHARS.add('?'); + REGEXP_CONTROL_CHARS.add('*'); + REGEXP_CONTROL_CHARS.add('+'); + REGEXP_CONTROL_CHARS.add('{'); + REGEXP_CONTROL_CHARS.add('}'); + REGEXP_CONTROL_CHARS.add('|'); + REGEXP_CONTROL_CHARS.add('('); + REGEXP_CONTROL_CHARS.add(')'); + REGEXP_CONTROL_CHARS.add(':'); + REGEXP_CONTROL_CHARS.add('&'); + REGEXP_CONTROL_CHARS.add('<'); + REGEXP_CONTROL_CHARS.add('>'); + REGEXP_CONTROL_CHARS.add('='); + REGEXP_CONTROL_CHARS.add('!'); } static class LikeExpression extends UnaryExpression implements BooleanExpression @@ -109,7 +109,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { regexp.append("."); // match one } - else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) + else if (REGEXP_CONTROL_CHARS.contains(c)) { regexp.append("\\x"); regexp.append(Integer.toHexString(0xFFFF & c)); @@ -415,23 +415,23 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Short.class) { - lv = new Short(((Number) lv).shortValue()); + lv = ((Number) lv).shortValue(); } else if (rc == Integer.class) { - lv = new Integer(((Number) lv).intValue()); + lv = ((Number) lv).intValue(); } else if (rc == Long.class) { - lv = new Long(((Number) lv).longValue()); + lv = ((Number) lv).longValue(); } else if (rc == Float.class) { - lv = new Float(((Number) lv).floatValue()); + lv = ((Number) lv).floatValue(); } else if (rc == Double.class) { - lv = new Double(((Number) lv).doubleValue()); + lv = ((Number) lv).doubleValue(); } else { @@ -442,19 +442,19 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Integer.class) { - lv = new Integer(((Number) lv).intValue()); + lv = ((Number) lv).intValue(); } else if (rc == Long.class) { - lv = new Long(((Number) lv).longValue()); + lv = ((Number) lv).longValue(); } else if (rc == Float.class) { - lv = new Float(((Number) lv).floatValue()); + lv = ((Number) lv).floatValue(); } else if (rc == Double.class) { - lv = new Double(((Number) lv).doubleValue()); + lv = ((Number) lv).doubleValue(); } else { @@ -465,15 +465,15 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Long.class) { - lv = new Long(((Number) lv).longValue()); + lv = ((Number) lv).longValue(); } else if (rc == Float.class) { - lv = new Float(((Number) lv).floatValue()); + lv = ((Number) lv).floatValue(); } else if (rc == Double.class) { - lv = new Double(((Number) lv).doubleValue()); + lv = ((Number) lv).doubleValue(); } else { @@ -484,15 +484,15 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Integer.class) { - rv = new Long(((Number) rv).longValue()); + rv = ((Number) rv).longValue(); } else if (rc == Float.class) { - lv = new Float(((Number) lv).floatValue()); + lv = ((Number) lv).floatValue(); } else if (rc == Double.class) { - lv = new Double(((Number) lv).doubleValue()); + lv = ((Number) lv).doubleValue(); } else { @@ -503,15 +503,15 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Integer.class) { - rv = new Float(((Number) rv).floatValue()); + rv = ((Number) rv).floatValue(); } else if (rc == Long.class) { - rv = new Float(((Number) rv).floatValue()); + rv = ((Number) rv).floatValue(); } else if (rc == Double.class) { - lv = new Double(((Number) lv).doubleValue()); + lv = ((Number) lv).doubleValue(); } else { @@ -522,15 +522,15 @@ public abstract class ComparisonExpression extends BinaryExpression implements B { if (rc == Integer.class) { - rv = new Double(((Number) rv).doubleValue()); + rv = ((Number) rv).doubleValue(); } else if (rc == Long.class) { - rv = new Double(((Number) rv).doubleValue()); + rv = ((Number) rv).doubleValue(); } else if (rc == Float.class) { - rv = new Float(((Number) rv).doubleValue()); + rv = ((Number) rv).doubleValue(); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 15cb770216..5cc9ca8ef2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -77,7 +77,7 @@ public class ConstantExpression implements Expression long l = value.longValue(); if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { - value = new Integer(value.intValue()); + value = value.intValue(); } return new ConstantExpression(value); @@ -85,11 +85,11 @@ public class ConstantExpression implements Expression public static ConstantExpression createFromHex(String text) { - Number value = new Long(Long.parseLong(text.substring(2), 16)); + Number value = Long.parseLong(text.substring(2), 16); long l = value.longValue(); if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { - value = new Integer(value.intValue()); + value = value.intValue(); } return new ConstantExpression(value); @@ -97,11 +97,11 @@ public class ConstantExpression implements Expression public static ConstantExpression createFromOctal(String text) { - Number value = new Long(Long.parseLong(text, 8)); + Number value = Long.parseLong(text, 8); long l = value.longValue(); if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) { - value = new Integer(value.intValue()); + value = value.intValue(); } return new ConstantExpression(value); @@ -141,7 +141,7 @@ public class ConstantExpression implements Expression if (value instanceof Boolean) { - return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; + return ((Boolean) value) ? "TRUE" : "FALSE"; } if (value instanceof String) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 9e03ecd8bd..557af95001 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -110,19 +110,19 @@ public abstract class UnaryExpression implements Expression Class clazz = left.getClass(); if (clazz == Integer.class) { - return new Integer(-left.intValue()); + return -left.intValue(); } else if (clazz == Long.class) { - return new Long(-left.longValue()); + return -left.longValue(); } else if (clazz == Float.class) { - return new Float(-left.floatValue()); + return -left.floatValue(); } else if (clazz == Double.class) { - return new Double(-left.doubleValue()); + return -left.doubleValue(); } else if (clazz == BigDecimal.class) { @@ -135,7 +135,7 @@ public abstract class UnaryExpression implements Expression if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { - return new Long(Long.MIN_VALUE); + return Long.MIN_VALUE; } return bd; @@ -186,14 +186,7 @@ public abstract class UnaryExpression implements Expression */ public boolean equals(Object o) { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - + return ((o != null) && this.getClass().equals(o.getClass())) && toString().equals(o.toString()); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 36e8f6cf84..258552f2f5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -528,9 +528,10 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM Map levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); - for (String loggerName : levels.keySet()) + for (Map.Entry entry : levels.entrySet()) { - String level = levels.get(loggerName); + String loggerName = entry.getKey(); + String level = entry.getValue(); try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java index 69139d38a3..536c5cdb0a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java @@ -37,7 +37,7 @@ public class BindingLogSubject extends AbstractLogSubject * 3 - Queue Name * 4 - Binding RoutingKey */ - protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})"; + protected static final String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})"; /** * Create a BindingLogSubject that Logs in the following format. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index dc6e79a214..7660804b19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -36,7 +36,7 @@ public class ChannelLogSubject extends AbstractLogSubject * 3 - Virtualhost * 4 - Channel ID */ - public static String CHANNEL_FORMAT = ConnectionLogSubject.CONNECTION_FORMAT + public static final String CHANNEL_FORMAT = ConnectionLogSubject.CONNECTION_FORMAT + "/ch:{4}"; public ChannelLogSubject(AMQChannel channel) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index 6c41718177..eec7888b2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -32,7 +32,7 @@ public class ConnectionLogSubject extends AbstractLogSubject * 0 - Connection ID * 1 - Remote Address */ - public static String SOCKET_FORMAT = "con:{0}({1})"; + public static final String SOCKET_FORMAT = "con:{0}({1})"; /** * LOG FORMAT for the ConnectionLogSubject, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java index 0fc2d7392f..d954ff64d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java @@ -35,7 +35,7 @@ public class ExchangeLogSubject extends AbstractLogSubject * 1 - Exchange Type * 2 - Exchange Name */ - protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})"; + protected static final String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})"; /** Create an ExchangeLogSubject that Logs in the following format. */ public ExchangeLogSubject(Exchange exchange, VirtualHost vhost) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java index e11cbba4f4..0417a218ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java @@ -34,7 +34,7 @@ public class MessageStoreLogSubject extends AbstractLogSubject * 0 - Virtualhost Name * 1 - Message Store Type */ - protected static String BINDING_FORMAT = "vh(/{0})/ms({1})"; + protected static final String BINDING_FORMAT = "vh(/{0})/ms({1})"; /** Create an ExchangeLogSubject that Logs in the following format. */ public MessageStoreLogSubject(VirtualHost vhost, MessageStore store) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java index b132d9e93f..be96f66074 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -33,7 +33,7 @@ public class QueueLogSubject extends AbstractLogSubject * 0 - Virtualhost name * 1 - queue name */ - public static String LOG_FORMAT = "vh(/{0})/qu({1})"; + public static final String LOG_FORMAT = "vh(/{0})/qu({1})"; /** Create an QueueLogSubject that Logs in the following format. */ public QueueLogSubject(AMQQueue queue) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java index 0683c8e361..5d82e97768 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -34,7 +34,7 @@ public class SubscriptionLogSubject extends AbstractLogSubject * * 0 - Subscription ID */ - public static String SUBSCRIPTION_FORMAT = "sub:{0}"; + public static final String SUBSCRIPTION_FORMAT = "sub:{0}"; /** * Create an QueueLogSubject that Logs in the following format. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 03e1d1fcaa..0334a856c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -326,7 +326,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * made using the object reference will not be affected and continue to operate normally. */ - private class CustomRMIServerSocketFactory implements RMIServerSocketFactory + private static class CustomRMIServerSocketFactory implements RMIServerSocketFactory { public ServerSocket createServerSocket(int port) throws IOException @@ -334,7 +334,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry return new NoLocalAddressServerSocket(port); } - private class NoLocalAddressServerSocket extends ServerSocket + private static class NoLocalAddressServerSocket extends ServerSocket { NoLocalAddressServerSocket(int port) throws IOException { @@ -350,7 +350,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } } - private class NoLocalAddressSocket extends Socket + private static class NoLocalAddressSocket extends Socket { @Override public InetAddress getInetAddress() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java index 9c2a455897..17a6851abc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java @@ -361,19 +361,21 @@ class MBeanIntrospector { */ private static MBeanConstructorInfo getMBeanConstructorInfo(Constructor cons) { - String desc = null; + String desc = _defaultConstructorDescription; Annotation anno = cons.getAnnotation(MBeanConstructor.class); if (anno != null && MBeanConstructor.class.isInstance(anno)) { desc = MBeanConstructor.class.cast(anno).value(); + if(desc == null) + { + desc = _defaultConstructorDescription; + } } //MBeanParameterInfo[] paramsInfo = getParametersInfo(cons.getParameterAnnotations(), // cons.getParameterTypes()); - return new MBeanConstructorInfo(cons.getName(), - desc != null ? _defaultConstructorDescription : desc , - null); + return new MBeanConstructorInfo(cons.getName(), desc, null); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 19b4586017..964b5ed5a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -294,7 +294,9 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati public void handleNotification(Notification notification, Object handback) { - // only RMI Connections are serviced here, Local API atta + assert notification instanceof JMXConnectionNotification; + + // only RMI Connections are serviced here, Local API atta // rmi://169.24.29.116 guest 3 String[] connectionData = ((JMXConnectionNotification) notification).getConnectionId().split(" "); String user = connectionData[1]; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java index 2f8c2e09a2..30bea7b6e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -110,7 +110,6 @@ public class MessageMetaData implements StorableMessageMetaData public int getStorableSize() { - BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); int size = _contentHeaderBody.getSize(); size += 4; size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getExchange()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index a15e16a64f..0296735699 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -56,7 +56,7 @@ class MessageTransferHeader implements AMQMessageHeader public long getExpiration() { - return _deliveryProps == null ? null : _deliveryProps.getExpiration(); + return _deliveryProps == null ? 0L : _deliveryProps.getExpiration(); } public String getMessageId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 5a7c9923f8..c55c07a145 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -652,7 +652,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol // InvalidArgument and if they then decide to close the session/connection then the there will be time // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed. //removeChannel(channelId); - _closingChannelsList.remove(new Integer(channelId)); + _closingChannelsList.remove(channelId); } private void markChannelAwaitingCloseOk(int channelId) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java index b3cb90fc6e..e894dda341 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -382,7 +382,7 @@ private static final byte[] AMQP_0_9_1_HEADER = { _networkDriver.send(ByteBuffer.wrap(newestSupported)); - newDelegate = new ClosedDelegateProtocolEngine(); + _delegate = new ClosedDelegateProtocolEngine(); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 6bfd7470ac..bee55118ba 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -170,9 +170,9 @@ public class AMQQueueFactory conflationKey = QPID_LVQ_KEY; } } - else if(arguments.containsKey(X_QPID_PRIORITIES)) + else if(arguments.containsKey(X_QPID_PRIORITIES.toString())) { - Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); + Object prioritiesObj = arguments.get(X_QPID_PRIORITIES.toString()); if(prioritiesObj instanceof Number) { priorities = ((Number)prioritiesObj).intValue(); @@ -202,9 +202,9 @@ public class AMQQueueFactory { for(QueueProperty p : DECLAREABLE_PROPERTIES) { - if(arguments.containsKey(p.getArgumentName())) + if(arguments.containsKey(p.getArgumentName().toString())) { - p.setPropertyValue(q, arguments.get(p.getArgumentName())); + p.setPropertyValue(q, arguments.get(p.getArgumentName().toString())); } } } @@ -225,10 +225,8 @@ public class AMQQueueFactory Map arguments = null; if(config.isLVQ() || config.getLVQKey() != null) { - if(arguments == null) - { - arguments = new HashMap(); - } + + arguments = new HashMap(); arguments.put(QPID_LAST_VALUE_QUEUE, 1); arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey()); } @@ -238,10 +236,7 @@ public class AMQQueueFactory int priorities = config.getPriorities(); if(priority || priorities > 0) { - if(arguments == null) - { - arguments = new HashMap(); - } + arguments = new HashMap(); if (priorities < 0) { priorities = 10; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 484dd5971d..fc04e1382e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -162,7 +162,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); - private AtomicReference _asynchronousRunner = new AtomicReference(null); + private AtomicReference _asynchronousRunner = new AtomicReference(null); private final Executor _asyncDelivery; private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); @@ -1085,23 +1085,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener */ public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) { - List entries = getMessagesOnTheQueue(new QueueEntryFilter() - { - private long position = 0; + return getMessagesOnTheQueue(new QueueEntryFilter() + { + private long position = 0; - public boolean accept(QueueEntry entry) - { - position++; - return (position >= fromPosition) && (position <= toPosition); - } + public boolean accept(QueueEntry entry) + { + position++; + return (position >= fromPosition) && (position <= toPosition); + } - public boolean filterComplete() - { - return position >= toPosition; - } - }); + public boolean filterComplete() + { + return position >= toPosition; + } + }); - return entries; } public void moveMessagesToAnotherQueue(final long fromMessageId, @@ -1410,7 +1409,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener adapter.setEntry(entry); final List rerouteQueues = _alternateExchange.route(adapter); final ServerMessage message = entry.getMessage(); - if(rerouteQueues != null & rerouteQueues.size() != 0) + if(rerouteQueues != null && rerouteQueues.size() != 0) { txn.enqueue(rerouteQueues, entry.getMessage(), new ServerTransaction.Action() @@ -1801,7 +1800,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean deliveryIncomplete = true; int extraLoops = 1; - Long iterations = new Long(MAX_ASYNC_DELIVERIES); + long iterations = MAX_ASYNC_DELIVERIES; _asynchronousRunner.compareAndSet(runner, null); @@ -1823,7 +1822,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener previousStateChangeCount = stateChangeCount; deliveryIncomplete = _subscriptionList.size() != 0; - boolean done = true; + boolean done; SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); //iterate over the subscribers and try to advance their pointer @@ -1833,10 +1832,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.getSendLock(); try { - if (sub != null) - { - done = attemptDelivery(sub); - } + + done = attemptDelivery(sub); + if (done) { if (extraLoops == 0) @@ -2050,6 +2048,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean equals(Object o) { + assert o != null; + assert o instanceof QueueEntryListener; return _sub == ((QueueEntryListener) o)._sub; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index 8721da0f78..334b7f4ea9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -164,7 +164,7 @@ public class SimpleQueueEntryList implements QueueEntryList } - public class QueueEntryIteratorImpl implements QueueEntryIterator + public static class QueueEntryIteratorImpl implements QueueEntryIterator { private QueueEntryImpl _lastNode; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java index af47ed6bf9..70a9ea5356 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.access; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.qpid.framing.AMQShortString; @@ -288,9 +289,11 @@ public class ObjectProperties extends HashMap return false; } - for (Property key : properties.keySet()) + for (Map.Entry entry : properties.entrySet()) { - String ruleValue = properties.get(key); + Property key = entry.getKey(); + String ruleValue = entry.getValue(); + String thisValue = get(key); if (!valueMatches(thisValue, ruleValue)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 6ca9c8e762..5a92b33e43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -250,10 +250,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } catch (Exception e) @@ -300,10 +297,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } @@ -335,10 +329,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } return true; @@ -420,10 +411,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } @@ -567,10 +555,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index cea4e90c31..76ebea0321 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -232,10 +232,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } @@ -267,10 +264,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } return true; @@ -369,10 +363,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } @@ -501,10 +492,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } finally { - if (_userUpdate.isHeldByCurrentThread()) - { - _userUpdate.unlock(); - } + _userUpdate.unlock(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java index 153b8c25db..a9bee4466f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -192,10 +192,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } finally { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } + _accessRightsUpdate.unlock(); } return true; @@ -256,10 +253,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } finally { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } + _accessRightsUpdate.unlock(); } } } @@ -409,16 +403,22 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana _accessRightsUpdate.lock(); Properties accessRights = new Properties(); - accessRights.load(new FileInputStream(_accessFile)); + FileInputStream inStream = new FileInputStream(_accessFile); + try + { + accessRights.load(inStream); + } + finally + { + inStream.close(); + } + checkAccessRights(accessRights); setAccessRights(accessRights); } finally { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } + _accessRightsUpdate.unlock(); } } else @@ -494,10 +494,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } finally { - if (_accessRightsUpdate.isHeldByCurrentThread()) - { - _accessRightsUpdate.unlock(); - } + _accessRightsUpdate.unlock(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java index dd0bd096c3..5c13e03886 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -46,7 +46,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi private ServerCallbackHandler _callbackHandler; - private class ServerCallbackHandler implements CallbackHandler + private static class ServerCallbackHandler implements CallbackHandler { private final PrincipalDatabase _principalDatabase; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java index 38e84c799b..8020d97364 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java @@ -55,7 +55,7 @@ public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser } - private class HexifyPrincipalDatabase implements PrincipalDatabase + private static class HexifyPrincipalDatabase implements PrincipalDatabase { private PrincipalDatabase _realPricipalDatabase; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 838867f233..0865165925 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.store; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.sql.Blob; @@ -277,14 +278,25 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(DB_VERSION_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - - stmt.execute(CREATE_DB_VERSION_TABLE); - stmt.close(); + try + { + stmt.execute(CREATE_DB_VERSION_TABLE); + } + finally + { + stmt.close(); + } PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION); - pstmt.setInt(1, DB_VERSION); - pstmt.execute(); - pstmt.close(); + try + { + pstmt.setInt(1, DB_VERSION); + pstmt.execute(); + } + finally + { + pstmt.close(); + } } } @@ -295,9 +307,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(EXCHANGE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - - stmt.execute(CREATE_EXCHANGE_TABLE); - stmt.close(); + try + { + stmt.execute(CREATE_EXCHANGE_TABLE); + } + finally + { + stmt.close(); + } } } @@ -306,8 +323,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_TABLE); - stmt.close(); + try + { + stmt.execute(CREATE_QUEUE_TABLE); + } + finally + { + stmt.close(); + } } } @@ -316,9 +339,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(BINDINGS_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_BINDINGS_TABLE); - - stmt.close(); + try + { + stmt.execute(CREATE_BINDINGS_TABLE); + } + finally + { + stmt.close(); + } } } @@ -328,9 +356,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_QUEUE_ENTRY_TABLE); - - stmt.close(); + try + { + stmt.execute(CREATE_QUEUE_ENTRY_TABLE); + } + finally + { + stmt.close(); + } } } @@ -340,9 +373,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(META_DATA_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_META_DATA_TABLE); - - stmt.close(); + try + { + stmt.execute(CREATE_META_DATA_TABLE); + } + finally + { + stmt.close(); + } } } @@ -353,9 +391,14 @@ public class DerbyMessageStore implements MessageStore if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); + try + { stmt.execute(CREATE_MESSAGE_CONTENT_TABLE); - - stmt.close(); + } + finally + { + stmt.close(); + } } } @@ -365,12 +408,24 @@ public class DerbyMessageStore implements MessageStore private boolean tableExists(final String tableName, final Connection conn) throws SQLException { PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY); - stmt.setString(1, tableName); - ResultSet rs = stmt.executeQuery(); - boolean exists = rs.next(); - rs.close(); - stmt.close(); - return exists; + try + { + stmt.setString(1, tableName); + ResultSet rs = stmt.executeQuery(); + try + { + return rs.next(); + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + } public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQException @@ -382,7 +437,7 @@ public class DerbyMessageStore implements MessageStore try { ConfigurationRecoveryHandler.QueueRecoveryHandler qrh = recoveryHandler.begin(this); - List queues = loadQueues(qrh); + loadQueues(qrh); ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh = qrh.completeQueueRecovery(); List exchanges = loadExchanges(erh); @@ -399,42 +454,57 @@ public class DerbyMessageStore implements MessageStore } - private List loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException + private void loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException { Connection conn = newAutoCommitConnection(); + try + { + Statement stmt = conn.createStatement(); + try + { + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); + try + { - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); - List queues = new ArrayList(); + while(rs.next()) + { + String queueName = rs.getString(1); + String owner = rs.getString(2); + boolean exclusive = rs.getBoolean(3); + Blob argumentsAsBlob = rs.getBlob(4); + + byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length()); + FieldTable arguments; + if(dataAsBytes.length > 0) + { + org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.wrap(dataAsBytes); - while(rs.next()) - { - String queueName = rs.getString(1); - String owner = rs.getString(2); - boolean exclusive = rs.getBoolean(3); - Blob argumentsAsBlob = rs.getBlob(4); + arguments = new FieldTable(buffer,buffer.limit()); + } + else + { + arguments = null; + } - byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length()); - FieldTable arguments; - if(dataAsBytes.length > 0) - { - org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.wrap(dataAsBytes); + qrh.queue(queueName, owner, exclusive, arguments); - arguments = new FieldTable(buffer,buffer.limit()); + } + + } + finally + { + rs.close(); + } } - else + finally { - arguments = null; + stmt.close(); } - - qrh.queue(queueName, owner, exclusive, arguments); - - queues.add(queueName); } - - conn.close(); - - return queues; + finally + { + conn.close(); + } } @@ -448,21 +518,33 @@ public class DerbyMessageStore implements MessageStore conn = newAutoCommitConnection(); Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); - - while(rs.next()) + try { - String exchangeName = rs.getString(1); - String type = rs.getString(2); - boolean autoDelete = rs.getShort(3) != 0; + ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); + try + { + while(rs.next()) + { + String exchangeName = rs.getString(1); + String type = rs.getString(2); + boolean autoDelete = rs.getShort(3) != 0; - exchanges.add(exchangeName); + exchanges.add(exchangeName); - erh.exchange(exchangeName, type, autoDelete); + erh.exchange(exchangeName, type, autoDelete); + } + return exchanges; + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); } - return exchanges; - } finally { @@ -485,31 +567,44 @@ public class DerbyMessageStore implements MessageStore PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); - ResultSet rs = stmt.executeQuery(); - - - while(rs.next()) + try { - String exchangeName = rs.getString(1); - String queueName = rs.getString(2); - String bindingKey = rs.getString(3); - Blob arguments = rs.getBlob(4); - java.nio.ByteBuffer buf; + ResultSet rs = stmt.executeQuery(); - if(arguments != null && arguments.length() != 0) + try { - byte[] argumentBytes = arguments.getBytes(1, (int) arguments.length()); - buf = java.nio.ByteBuffer.wrap(argumentBytes); + + while(rs.next()) + { + String exchangeName = rs.getString(1); + String queueName = rs.getString(2); + String bindingKey = rs.getString(3); + Blob arguments = rs.getBlob(4); + java.nio.ByteBuffer buf; + + if(arguments != null && arguments.length() != 0) + { + byte[] argumentBytes = arguments.getBytes(1, (int) arguments.length()); + buf = java.nio.ByteBuffer.wrap(argumentBytes); + } + else + { + buf = null; + } + + brh.binding(exchangeName, queueName, bindingKey, buf); + } } - else + finally { - buf = null; + rs.close(); } - - brh.binding(exchangeName, queueName, bindingKey, buf); } - - stmt.close(); + finally + { + stmt.close(); + } + } finally { @@ -529,7 +624,10 @@ public class DerbyMessageStore implements MessageStore try { - DriverManager.getConnection(_connectionURL + ";shutdown=true"); + Connection conn = DriverManager.getConnection(_connectionURL + ";shutdown=true"); + // Shouldn't reach this point - shutdown=true should throw SQLException + conn.close(); + _logger.error("Unable to shut down the store"); } catch (SQLException e) { @@ -563,48 +661,59 @@ public class DerbyMessageStore implements MessageStore public void removeMessage(long messageId) { - Connection conn = null; try { - conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA); - stmt.setLong(1,messageId); - int results = stmt.executeUpdate(); - stmt.close(); - - if (results == 0) + Connection conn = newConnection(); + try { - throw new RuntimeException("Message metadata not found for message id " + messageId); - } + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA); + try + { + stmt.setLong(1,messageId); + int results = stmt.executeUpdate(); + stmt.close(); - if (_logger.isDebugEnabled()) - { - _logger.debug("Deleted metadata for message " + messageId); - } + if (results == 0) + { + throw new RuntimeException("Message metadata not found for message id " + messageId); + } - stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - results = stmt.executeUpdate(); - stmt.close(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Deleted metadata for message " + messageId); + } - conn.commit(); - conn.close(); - } - catch (SQLException e) - { - if ((conn != null)) + stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + results = stmt.executeUpdate(); + } + finally + { + stmt.close(); + } + conn.commit(); + } + catch(SQLException e) { try { conn.rollback(); - conn.close(); } - catch (SQLException e1) + catch(SQLException t) { - + // ignore - we are re-throwing underlying exception } - } + throw e; + + } + finally + { + conn.close(); + } + } + catch (SQLException e) + { throw new RuntimeException("Error removing message with id " + messageId + " from database: " + e.getMessage(), e); } @@ -616,37 +725,52 @@ public class DerbyMessageStore implements MessageStore { try { - Connection conn = null; + Connection conn = newAutoCommitConnection(); try { - conn = newAutoCommitConnection(); - PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); - stmt.setString(1, exchange.getNameShortString().toString()); - ResultSet rs = stmt.executeQuery(); + PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); + try + { + stmt.setString(1, exchange.getNameShortString().toString()); + ResultSet rs = stmt.executeQuery(); + try + { - // If we don't have any data in the result set then we can add this exchange - if (!rs.next()) + // If we don't have any data in the result set then we can add this exchange + if (!rs.next()) + { + + PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); + try + { + insertStmt.setString(1, exchange.getName().toString()); + insertStmt.setString(2, exchange.getTypeShortString().asString()); + insertStmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); + insertStmt.execute(); + } + finally + { + insertStmt.close(); + } + } + } + finally + { + rs.close(); + } + } + finally { stmt.close(); - - stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); - stmt.setString(2, exchange.getTypeShortString().asString()); - stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0); - stmt.execute(); - stmt.close(); } } finally { - if(conn != null) - { - conn.close(); - } + conn.close(); } } catch (SQLException e) @@ -659,39 +783,37 @@ public class DerbyMessageStore implements MessageStore public void removeExchange(Exchange exchange) throws AMQStoreException { - Connection conn = null; try { - conn = newAutoCommitConnection(); - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); - stmt.setString(1, exchange.getNameShortString().toString()); - int results = stmt.executeUpdate(); - stmt.close(); - if(results == 0) + Connection conn = newAutoCommitConnection(); + try + { + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); + try + { + stmt.setString(1, exchange.getNameShortString().toString()); + int results = stmt.executeUpdate(); + stmt.close(); + if(results == 0) + { + throw new AMQStoreException("Exchange " + exchange.getNameShortString() + " not found"); + } + } + finally + { + stmt.close(); + } + } + finally { - throw new AMQStoreException("Exchange " + exchange.getNameShortString() + " not found"); + conn.close(); } } catch (SQLException e) { throw new AMQStoreException("Error deleting Exchange with name " + exchange.getNameShortString() + " from database: " + e.getMessage(), e); } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } } public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) @@ -699,44 +821,69 @@ public class DerbyMessageStore implements MessageStore { if (_state != State.RECOVERING) { - Connection conn = null; - try { - conn = newAutoCommitConnection(); - - PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); - stmt.setString(1, exchange.getNameShortString().toString() ); - stmt.setString(2, queue.getNameShortString().toString()); - stmt.setString(3, routingKey == null ? null : routingKey.toString()); - - ResultSet rs = stmt.executeQuery(); + Connection conn = newAutoCommitConnection(); - // If this binding is not already in the store then create it. - if (!rs.next()) + try { - stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); - stmt.setString(1, exchange.getNameShortString().toString() ); - stmt.setString(2, queue.getNameShortString().toString()); - stmt.setString(3, routingKey == null ? null : routingKey.toString()); - if(args != null) + + PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); + try { - /* This would be the Java 6 way of setting a Blob - Blob blobArgs = conn.createBlob(); - blobArgs.setBytes(0, args.getDataAsBytes()); - stmt.setBlob(4, blobArgs); - */ - byte[] bytes = args.getDataAsBytes(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - stmt.setBinaryStream(4, bis, bytes.length); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); + stmt.setString(3, routingKey == null ? null : routingKey.toString()); + + ResultSet rs = stmt.executeQuery(); + try + { + // If this binding is not already in the store then create it. + if (!rs.next()) + { + PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_BINDINGS); + try + { + insertStmt.setString(1, exchange.getNameShortString().toString() ); + insertStmt.setString(2, queue.getNameShortString().toString()); + insertStmt.setString(3, routingKey == null ? null : routingKey.toString()); + if(args != null) + { + /* This would be the Java 6 way of setting a Blob + Blob blobArgs = conn.createBlob(); + blobArgs.setBytes(0, args.getDataAsBytes()); + stmt.setBlob(4, blobArgs); + */ + byte[] bytes = args.getDataAsBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + insertStmt.setBinaryStream(4, bis, bytes.length); + } + else + { + insertStmt.setNull(4, Types.BLOB); + } + + insertStmt.executeUpdate(); + } + finally + { + insertStmt.close(); + } + } + } + finally + { + rs.close(); + } } - else + finally { - stmt.setNull(4, Types.BLOB); + stmt.close(); } - - stmt.executeUpdate(); - stmt.close(); + } + finally + { + conn.close(); } } catch (SQLException e) @@ -744,21 +891,6 @@ public class DerbyMessageStore implements MessageStore throw new AMQStoreException("Error writing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + exchange.getNameShortString() + " to database: " + e.getMessage(), e); } - finally - { - if(conn != null) - { - try - { - conn.close(); - } - catch (SQLException e) - { - _logger.error(e); - } - } - - } } @@ -828,39 +960,58 @@ public class DerbyMessageStore implements MessageStore Connection conn = newAutoCommitConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); - stmt.setString(1, queue.getNameShortString().toString()); - - ResultSet rs = stmt.executeQuery(); - - // If we don't have any data in the result set then we can add this queue - if (!rs.next()) + try { - stmt = conn.prepareStatement(INSERT_INTO_QUEUE); - - String owner = queue.getOwner() == null ? null : queue.getOwner().toString(); - stmt.setString(1, queue.getNameShortString().toString()); - stmt.setString(2, owner); - stmt.setBoolean(3,queue.isExclusive()); - - final byte[] underlying; - if(arguments != null) + ResultSet rs = stmt.executeQuery(); + try { - underlying = arguments.getDataAsBytes(); + + // If we don't have any data in the result set then we can add this queue + if (!rs.next()) + { + PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_QUEUE); + + try + { + String owner = queue.getOwner() == null ? null : queue.getOwner().toString(); + + insertStmt.setString(1, queue.getNameShortString().toString()); + insertStmt.setString(2, owner); + insertStmt.setBoolean(3,queue.isExclusive()); + + final byte[] underlying; + if(arguments != null) + { + underlying = arguments.getDataAsBytes(); + } + else + { + underlying = new byte[0]; + } + + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + insertStmt.setBinaryStream(4,bis,underlying.length); + + insertStmt.execute(); + } + finally + { + insertStmt.close(); + } + } } - else + finally { - underlying = new byte[0]; + rs.close(); } - - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(4,bis,underlying.length); - - stmt.execute(); + } + finally + { stmt.close(); - - conn.close(); } + conn.close(); + } catch (SQLException e) { @@ -886,24 +1037,46 @@ public class DerbyMessageStore implements MessageStore { Connection conn = newAutoCommitConnection(); - PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); - stmt.setString(1, queue.getNameShortString().toString()); - - ResultSet rs = stmt.executeQuery(); - - if (rs.next()) + try { - PreparedStatement stmt2 = conn.prepareStatement(UPDATE_QUEUE_EXCLUSIVITY); - - stmt2.setBoolean(1,queue.isExclusive()); - stmt2.setString(2, queue.getNameShortString().toString()); + PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); + try + { + stmt.setString(1, queue.getNameShortString().toString()); - stmt2.execute(); - stmt2.close(); + ResultSet rs = stmt.executeQuery(); + try + { + if (rs.next()) + { + PreparedStatement stmt2 = conn.prepareStatement(UPDATE_QUEUE_EXCLUSIVITY); + try + { + stmt2.setBoolean(1,queue.isExclusive()); + stmt2.setString(2, queue.getNameShortString().toString()); + + stmt2.execute(); + } + finally + { + stmt2.close(); + } + } + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + } + finally + { + conn.close(); } - - stmt.close(); - conn.close(); } catch (SQLException e) { @@ -920,7 +1093,22 @@ public class DerbyMessageStore implements MessageStore private Connection newAutoCommitConnection() throws SQLException { final Connection connection = newConnection(); - connection.setAutoCommit(true); + try + { + connection.setAutoCommit(true); + } + catch (SQLException sqlEx) + { + + try + { + connection.close(); + } + finally + { + throw sqlEx; + } + } return connection; } @@ -932,8 +1120,22 @@ public class DerbyMessageStore implements MessageStore private Connection newConnection() throws SQLException { final Connection connection = DriverManager.getConnection(_connectionURL); - connection.setAutoCommit(false); - connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + try + { + connection.setAutoCommit(false); + connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + } + catch (SQLException sqlEx) + { + try + { + connection.close(); + } + finally + { + throw sqlEx; + } + } return connection; } @@ -999,10 +1201,16 @@ public class DerbyMessageStore implements MessageStore } PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); - stmt.setString(1,name); - stmt.setLong(2,messageId); - stmt.executeUpdate(); - stmt.close(); + try + { + stmt.setString(1,name); + stmt.setLong(2,messageId); + stmt.executeUpdate(); + } + finally + { + stmt.close(); + } } catch (SQLException e) { @@ -1024,19 +1232,27 @@ public class DerbyMessageStore implements MessageStore try { PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); - stmt.setString(1,name); - stmt.setLong(2,messageId); - int results = stmt.executeUpdate(); - stmt.close(); - - if(results != 1) + try { - throw new AMQStoreException("Unable to find message with id " + messageId + " on queue " + name); - } + stmt.setString(1,name); + stmt.setLong(2,messageId); + int results = stmt.executeUpdate(); - if (_logger.isDebugEnabled()) + + + if(results != 1) + { + throw new AMQStoreException("Unable to find message with id " + messageId + " on queue " + name); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]"); + } + } + finally { - _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]"); + stmt.close(); } } catch (SQLException e) @@ -1147,25 +1363,48 @@ public class DerbyMessageStore implements MessageStore } PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_META_DATA); - stmt.setLong(1,messageId); - - final int bodySize = 1 + metaData.getStorableSize(); - byte[] underlying = new byte[bodySize]; - underlying[0] = (byte) metaData.getType().ordinal(); - java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(underlying); - buf.position(1); - buf = buf.slice(); - - metaData.writeToBuffer(0, buf); - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(2,bis,underlying.length); - int result = stmt.executeUpdate(); - stmt.close(); - - if(result == 0) + try { - throw new RuntimeException("Unable to add meta data for message " +messageId); + stmt.setLong(1,messageId); + + final int bodySize = 1 + metaData.getStorableSize(); + byte[] underlying = new byte[bodySize]; + underlying[0] = (byte) metaData.getType().ordinal(); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(underlying); + buf.position(1); + buf = buf.slice(); + + metaData.writeToBuffer(0, buf); + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + try + { + stmt.setBinaryStream(2,bis,underlying.length); + int result = stmt.executeUpdate(); + + if(result == 0) + { + throw new RuntimeException("Unable to add meta data for message " +messageId); + } + } + finally + { + try + { + bis.close(); + } + catch (IOException e) + { + + throw new SQLException(e); + } + } + } + finally + { + stmt.close(); + } + } @@ -1174,38 +1413,58 @@ public class DerbyMessageStore implements MessageStore private void recoverMessages(MessageStoreRecoveryHandler recoveryHandler) throws SQLException { Connection conn = newAutoCommitConnection(); + try + { + MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin(); - MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin(); + Statement stmt = conn.createStatement(); + try + { + ResultSet rs = stmt.executeQuery(SELECT_ALL_FROM_META_DATA); + try + { - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_ALL_FROM_META_DATA); + long maxId = 0; - long maxId = 0; + while(rs.next()) + { - while(rs.next()) - { + long messageId = rs.getLong(1); + Blob dataAsBlob = rs.getBlob(2); + + if(messageId > maxId) + { + maxId = messageId; + } + + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); + StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false); + messageHandler.message(message); + } - long messageId = rs.getLong(1); - Blob dataAsBlob = rs.getBlob(2); + _messageId.set(maxId); - if(messageId > maxId) + messageHandler.completeMessageRecovery(); + } + finally + { + rs.close(); + } + } + finally { - maxId = messageId; + stmt.close(); } - - byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); - java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); - buf.position(1); - buf = buf.slice(); - MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; - StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); - StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false); - messageHandler.message(message); } - - _messageId.set(maxId); - - messageHandler.completeMessageRecovery(); + finally + { + conn.close(); + } } @@ -1213,23 +1472,40 @@ public class DerbyMessageStore implements MessageStore private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws SQLException { Connection conn = newAutoCommitConnection(); + try + { + TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this); - TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this); + Statement stmt = conn.createStatement(); + try + { + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + try + { + while(rs.next()) + { - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + String queueName = rs.getString(1); + long messageId = rs.getLong(2); + queueEntryHandler.queueEntry(queueName,messageId); + } + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } - while(rs.next()) + queueEntryHandler.completeQueueEntryRecovery(); + } + finally { - - String queueName = rs.getString(1); - long messageId = rs.getLong(2); - queueEntryHandler.queueEntry(queueName,messageId); + conn.close(); } - - stmt.close(); - - queueEntryHandler.completeQueueEntryRecovery(); } StorableMessageMetaData getMetaData(long messageId) throws SQLException @@ -1239,31 +1515,40 @@ public class DerbyMessageStore implements MessageStore try { PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_META_DATA); - stmt.setLong(1,messageId); - ResultSet rs = stmt.executeQuery(); - - if(rs.next()) + try { - stmt.close(); - - Blob dataAsBlob = rs.getBlob(1); + stmt.setLong(1,messageId); + ResultSet rs = stmt.executeQuery(); + try + { + + if(rs.next()) + { + Blob dataAsBlob = rs.getBlob(1); - byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); - java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); - buf.position(1); - buf = buf.slice(); - MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; - StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); - return metaData; + return metaData; + } + else + { + throw new RuntimeException("Meta data not found for message with id " + messageId); + } + } + finally + { + rs.close(); + } } - else + finally { stmt.close(); - - throw new RuntimeException("Meta data not found for message with id " + messageId); } - } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java index 3fbb6bfa4a..9ea81660c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java @@ -34,7 +34,6 @@ public class SubscriptionList private final SubscriptionNode _head = new SubscriptionNode(); private AtomicReference _tail = new AtomicReference(_head); - private final AMQQueue _queue; private AtomicInteger _size = new AtomicInteger(); @@ -115,7 +114,6 @@ public class SubscriptionList public SubscriptionList(AMQQueue queue) { - _queue = queue; } private void advanceHead() @@ -176,7 +174,7 @@ public class SubscriptionList } - public class SubscriptionNodeIterator + public static class SubscriptionNodeIterator { private SubscriptionNode _lastNode; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 117be3e3b7..84601b1b7a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -198,7 +198,7 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session,method,ExecutionErrorCode.NOT_FOUND, "Queue: " + queueName + " not found"); } - if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + else if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) { exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); } @@ -1162,8 +1162,7 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, sfm, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); } - - if(sub.isStopped()) + else if(sub.isStopped()) { sub.setFlowMode(sfm.getFlowMode()); } @@ -1180,8 +1179,10 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, stop, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); } - - sub.stop(); + else + { + sub.stop(); + } } @@ -1196,8 +1197,10 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, flow, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); } - - sub.addCredit(flow.getUnit(), flow.getValue()); + else + { + sub.addCredit(flow.getUnit(), flow.getValue()); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java index 45d4be9340..2db1944cd1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/HouseKeepingTask.java @@ -29,15 +29,15 @@ public abstract class HouseKeepingTask implements Runnable { Logger _logger = Logger.getLogger(this.getClass()); - protected VirtualHost _virtualhost; + private VirtualHost _virtualHost; private String _name; private RootMessageLogger _rootLogger; public HouseKeepingTask(VirtualHost vhost) { - _virtualhost = vhost; - _name = _virtualhost.getName() + ":" + this.getClass().getSimpleName(); + _virtualHost = vhost; + _name = _virtualHost.getName() + ":" + this.getClass().getSimpleName(); _rootLogger = CurrentActor.get().getRootMessageLogger(); } @@ -65,6 +65,10 @@ public abstract class HouseKeepingTask implements Runnable } } + public VirtualHost getVirtualHost() + { + return _virtualHost; + } /** Execute the plugin. */ public abstract void execute(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index f2444718af..6ec1c512e5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -299,11 +299,13 @@ public class VirtualHostImpl implements VirtualHost if (plugins != null) { - for (String pluginName : plugins.keySet()) + for (Map.Entry entry : plugins.entrySet()) { + String pluginName = entry.getKey(); + VirtualHostPluginFactory factory = entry.getValue(); try { - VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); + VirtualHostPlugin plugin = factory.newInstance(this); // If we had configuration for the plugin the schedule it. if (plugin != null) @@ -636,8 +638,10 @@ public class VirtualHostImpl implements VirtualHost final String password) { BrokerLink blink = new BrokerLink(this, transport, host, port, vhost, durable, authMechanism, username, password); - _links.putIfAbsent(blink,blink); - getConfigStore().addConfiguredObject(blink); + if(_links.putIfAbsent(blink,blink) != null) + { + getConfigStore().addConfiguredObject(blink); + } } public void removeBrokerConnection(final String transport, @@ -671,7 +675,7 @@ public class VirtualHostImpl implements VirtualHost * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. * This should be removed after the _RT has been fully split from the the TL */ - private class StartupRoutingTable implements DurableConfigurationStore + private static class StartupRoutingTable implements DurableConfigurationStore { public List exchange = new LinkedList(); public List queue = new LinkedList(); @@ -740,7 +744,7 @@ public class VirtualHostImpl implements VirtualHost } - private class CreateQueueTuple + private static class CreateQueueTuple { public AMQQueue queue; public FieldTable arguments; @@ -752,7 +756,7 @@ public class VirtualHostImpl implements VirtualHost } } - private class CreateBindingTuple + private static class CreateBindingTuple { public AMQQueue queue; public FieldTable arguments; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java index ddc55652a8..5c4fe0aab8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java @@ -19,7 +19,6 @@ */ package org.apache.qpid.server.virtualhost.plugins; -import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -32,8 +31,6 @@ import org.apache.qpid.server.plugins.Plugin; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.plugins.logging.SlowConsumerDetectionMessages; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin { @@ -67,10 +64,10 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin public void configure(ConfigurationPlugin config) { _config = (SlowConsumerDetectionConfiguration) config; - _listener = new ConfiguredQueueBindingListener(_virtualhost.getName()); - for (AMQShortString exchangeName : _virtualhost.getExchangeRegistry().getExchangeNames()) + _listener = new ConfiguredQueueBindingListener(getVirtualHost().getName()); + for (AMQShortString exchangeName : getVirtualHost().getExchangeRegistry().getExchangeNames()) { - _virtualhost.getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener); + getVirtualHost().getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java index d119190842..3798f47f0b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostHouseKeepingPlugin.java @@ -30,18 +30,11 @@ public abstract class VirtualHostHouseKeepingPlugin extends HouseKeepingTask imp { protected final Logger _logger = Logger.getLogger(getClass()); - protected VirtualHost _virtualhost; - public VirtualHostHouseKeepingPlugin(VirtualHost vhost) { super(vhost); - setVirtualHost(vhost); } - public void setVirtualHost(VirtualHost vhost) - { - _virtualhost = vhost; - } /** * Long value representing the delay between repeats diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java index 26eb5bbd7f..1886c2d01d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -27,8 +27,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public interface VirtualHostPlugin extends Runnable, Plugin { - public void setVirtualHost(VirtualHost vhost); - /** * Long value representing the delay between repeats * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java index f26611f0bc..dca165fa7e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -171,7 +171,7 @@ public class MessageStoreTool /** * Simple ShutdownHook to cleanly shutdown the databases */ - class ShutdownHook implements Runnable + static class ShutdownHook implements Runnable { MessageStoreTool _tool; @@ -443,7 +443,7 @@ public class MessageStoreTool * * */ - public class State + public static class State { private VirtualHost _vhost = null; private AMQQueue _queue = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java index a7d58dc6dd..8bb5d02b01 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -127,7 +127,7 @@ public class Dump extends Show addShowInformation(hex, ascii, msg, null, false, false, true); } - // Add Content Body seciont + // Add Content Body section hex.add("Content Body"); ascii.add(""); hex.add(Console.ROW_DIVIDER); @@ -182,12 +182,12 @@ public class Dump extends Show String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); String hexLine = ""; - int strKength = encStr.length(); - for (int c = 0; c < strKength; c++) + int strLength = encStr.length(); + for (int c = 0; c < strLength; c++) { hexLine += encStr.charAt(c); - if (c % 2 == 1 && SPACE_BYTES) + if ((c & 1) == 1 && SPACE_BYTES) { hexLine += BYTE_SPACER; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java index ec080a4611..2791a39f92 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -35,10 +36,10 @@ public class SimpleConsole implements Console private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class); /** Console Writer. */ - protected static BufferedWriter _consoleWriter; + protected BufferedWriter _consoleWriter; /** Console Reader. */ - protected static BufferedReader _consoleReader; + protected BufferedReader _consoleReader; /** Parser for command-line input. */ protected CommandParser _parser; @@ -62,7 +63,7 @@ public class SimpleConsole implements Console } catch (IOException e) { - _devlog.error(e.getMessage() + ": Occured whilst trying to write:" + message); + _devlog.error(e.getMessage() + ": Occurred whilst trying to write:" + Arrays.asList(message)); } } -- cgit v1.2.1 From 2ee8be40abc81649c0f0e29ea912ddc061dafb8a Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 17 Sep 2010 13:41:11 +0000 Subject: QPID-2832: Collate all the LogSubject formatting strings in a static class Applying patch from git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998125 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/logging/subjects/BindingLogSubject.java | 14 +-- .../server/logging/subjects/ChannelLogSubject.java | 15 +-- .../logging/subjects/ConnectionLogSubject.java | 79 +++++---------- .../logging/subjects/ExchangeLogSubject.java | 14 +-- .../server/logging/subjects/LogSubjectFormat.java | 107 +++++++++++++++++++++ .../logging/subjects/MessageStoreLogSubject.java | 13 +-- .../server/logging/subjects/QueueLogSubject.java | 13 +-- .../logging/subjects/SubscriptionLogSubject.java | 13 +-- 8 files changed, 144 insertions(+), 124 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java index 536c5cdb0a..088b59ae68 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java @@ -22,23 +22,11 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.BINDING_FORMAT; public class BindingLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the ChannelLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Virtualhost Name - * 1 - Exchange Type - * 2 - Exchange Name - * 3 - Queue Name - * 4 - Binding RoutingKey - */ - protected static final String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})"; - /** * Create a BindingLogSubject that Logs in the following format. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index 7660804b19..f28873940b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -22,22 +22,10 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; public class ChannelLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the ChannelLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost - * 4 - Channel ID - */ - public static final String CHANNEL_FORMAT = ConnectionLogSubject.CONNECTION_FORMAT - + "/ch:{4}"; public ChannelLogSubject(AMQChannel channel) { @@ -64,4 +52,5 @@ public class ChannelLogSubject extends AbstractLogSubject session.getVirtualHost().getName(), channel.getChannelId()); } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index eec7888b2d..a697029d24 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -24,43 +24,17 @@ import org.apache.qpid.server.protocol.AMQProtocolSession; import java.text.MessageFormat; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTION_FORMAT; + /** The Connection LogSubject */ public class ConnectionLogSubject extends AbstractLogSubject { - /** - * 0 - Connection ID - * 1 - Remote Address - */ - public static final String SOCKET_FORMAT = "con:{0}({1})"; - - /** - * LOG FORMAT for the ConnectionLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - */ - public static final String USER_FORMAT = "con:{0}({1}@{2})"; - - /** - * LOG FORMAT for the ConnectionLogSubject, - * Uses a MessageFormat call to insert the required values according to - * these indices: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost - */ - public static final String CONNECTION_FORMAT = "con:{0}({1}@{2}/{3})"; - - public ConnectionLogSubject(AMQProtocolSession session) { - _session = session; + _session = session; } // The Session this Actor is representing @@ -71,9 +45,9 @@ public class ConnectionLogSubject extends AbstractLogSubject /** * Update the LogString as the Connection process proceeds. - * + * * When the Session has an authorized ID add that to the string. - * + * * When the Session then gains a Vhost add that to the string, at this point * we can set upToDate = true as the _logString will not need to be updated * from this point onwards. @@ -90,40 +64,37 @@ public class ConnectionLogSubject extends AbstractLogSubject * LOG FORMAT used by the AMQPConnectorActor follows * ConnectionLogSubject.CONNECTION_FORMAT : * con:{0}({1}@{2}/{3}) - * - * Uses a MessageFormat call to insert the required values according to - * these indices: - * - * 0 - Connection ID - * 1 - User ID - * 2 - IP - * 3 - Virtualhost + * + * Uses a MessageFormat call to insert the required values + * according to these indices: + * + * 0 - Connection ID 1 - User ID 2 - IP 3 - Virtualhost */ - _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, - _session.getSessionID(), - _session.getPrincipal().getName(), + _logString = "[" + MessageFormat.format(CONNECTION_FORMAT, + _session.getSessionID(), + _session.getPrincipal().getName(), _session.getRemoteAddress(), - _session.getVirtualHost().getName()) + _session.getVirtualHost().getName()) + "] "; _upToDate = true; - } + } else { - _logString = "[" + MessageFormat.format(USER_FORMAT, - _session.getSessionID(), - _session.getPrincipal().getName(), + _logString = "[" + MessageFormat.format(USER_FORMAT, + _session.getSessionID(), + _session.getPrincipal().getName(), _session.getRemoteAddress()) + "] "; } - } + } else { - _logString = "[" + MessageFormat.format(SOCKET_FORMAT, - _session.getSessionID(), - _session.getRemoteAddress()) - + "] "; + _logString = "[" + MessageFormat.format(SOCKET_FORMAT, + _session.getSessionID(), + _session.getRemoteAddress()) + + "] "; } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java index d954ff64d7..6ab44a92b9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java @@ -22,25 +22,15 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.virtualhost.VirtualHost; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.EXCHANGE_FORMAT; public class ExchangeLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the ExchangeLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Virtualhost Name - * 1 - Exchange Type - * 2 - Exchange Name - */ - protected static final String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})"; - /** Create an ExchangeLogSubject that Logs in the following format. */ public ExchangeLogSubject(Exchange exchange, VirtualHost vhost) { - setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), + setLogStringWithFormat(EXCHANGE_FORMAT, vhost.getName(), exchange.getTypeShortString(), exchange.getNameShortString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java new file mode 100644 index 0000000000..ff2bb90140 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java @@ -0,0 +1,107 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.logging.subjects; + +/** + * LogSubjectFormat class contains a list of formatting string + * that can be statically imported where needed. + * The formatting strings are to be used via a MessageFormat call + * to insert the required values at the corresponding place holder + * indices. + * + */ + +public class LogSubjectFormat +{ + + /** + * LOG FORMAT for the Subscription Log Subject + * 0 - Subscription ID + */ + public static final String SUBSCRIPTION_FORMAT = "sub:{0}"; + + /** + * LOG FORMAT for Connection Log Subject - SOCKET format + * 0 - Connection ID + * 1 - Remote Address + */ + public static final String SOCKET_FORMAT = "con:{0}({1})"; + + /** + * LOG FORMAT for Connection Log Subject - USER format + * 0 - Connection ID + * 1 - User ID + * 2 - IP + */ + public static final String USER_FORMAT = "con:{0}({1}@{2})"; + + /** + * LOG FORMAT for the Connection Log Subject - CON format + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + */ + public static final String CONNECTION_FORMAT = "con:{0}({1}@{2}/{3})"; + + /** + * LOG FORMAT for the Channel LogSubject + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + * 4 - Channel ID + */ + public static final String CHANNEL_FORMAT = CONNECTION_FORMAT + "/ch:{4}"; + + /** + * LOG FORMAT for the Exchange LogSubject, + * 0 - Virtualhost Name + * 1 - Exchange Type + * 2 - Exchange Name + */ + public static final String EXCHANGE_FORMAT = "vh(/{0})/ex({1}/{2})"; + + /** + * LOG FORMAT for a Binding LogSubject + * 0 - Virtualhost Name + * 1 - Exchange Type + * 2 - Exchange Name + * 3 - Queue Name + * 4 - Binding RoutingKey + */ + public static final String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})"; + + /** + * LOG FORMAT for the MessagesStore LogSubject + * 0 - Virtualhost Name + * 1 - Message Store Type + */ + public static final String STORE_FORMAT = "vh(/{0})/ms({1})"; + + /** + * LOG FORMAT for the Queue LogSubject, + * 0 - Virtualhost name + * 1 - queue name + */ + public static final String QUEUE_FORMAT = "vh(/{0})/qu({1})"; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java index 0417a218ee..3fce13bcb5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java @@ -22,24 +22,15 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.store.MessageStore; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.STORE_FORMAT; public class MessageStoreLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the MessagesStoreLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Virtualhost Name - * 1 - Message Store Type - */ - protected static final String BINDING_FORMAT = "vh(/{0})/ms({1})"; - /** Create an ExchangeLogSubject that Logs in the following format. */ public MessageStoreLogSubject(VirtualHost vhost, MessageStore store) { - setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), + setLogStringWithFormat(STORE_FORMAT, vhost.getName(), store.getClass().getSimpleName()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java index be96f66074..bfe12f1a60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -21,24 +21,15 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.queue.AMQQueue; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.QUEUE_FORMAT; public class QueueLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the ExchangeLogSubject, - * Uses a MessageFormat call to insert the requried values according to - * these indicies: - * - * 0 - Virtualhost name - * 1 - queue name - */ - public static final String LOG_FORMAT = "vh(/{0})/qu({1})"; - /** Create an QueueLogSubject that Logs in the following format. */ public QueueLogSubject(AMQQueue queue) { - setLogStringWithFormat(LOG_FORMAT, + setLogStringWithFormat(QUEUE_FORMAT, queue.getVirtualHost().getName(), queue.getName()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java index 5d82e97768..8b57647046 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java @@ -24,18 +24,11 @@ import org.apache.qpid.server.subscription.Subscription; import java.text.MessageFormat; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SUBSCRIPTION_FORMAT; + public class SubscriptionLogSubject extends AbstractLogSubject { - /** - * LOG FORMAT for the SubscriptionLogSubject, - * Uses a MessageFormat call to insert the required values according to - * these indices: - * - * 0 - Subscription ID - */ - public static final String SUBSCRIPTION_FORMAT = "sub:{0}"; - /** * Create an QueueLogSubject that Logs in the following format. * @@ -49,7 +42,7 @@ public class SubscriptionLogSubject extends AbstractLogSubject String queueString = new QueueLogSubject(subscription.getQueue()).toLogString(); - _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT, + _logString = "[" + MessageFormat.format(SUBSCRIPTION_FORMAT, subscription.getSubscriptionID()) + "(" // queueString is [vh(/{0})/qu({1}) ] so need to trim -- cgit v1.2.1 From b2248cf03878965fb26d117eed764fe38c3bc982 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 17 Sep 2010 13:42:35 +0000 Subject: QPID-2858: Implement FilterManager for 0-10 subscriptions Applying patch from git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998126 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ServerSessionDelegate.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 84601b1b7a..04337c08df 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -30,6 +30,8 @@ import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.*; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.flow.FlowCreditManager_0_10; import org.apache.qpid.server.flow.WindowCreditManager; import org.apache.qpid.server.message.MessageMetaData_0_10; @@ -228,7 +230,22 @@ public class ServerSessionDelegate extends SessionDelegate FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); - // TODO filters + FieldTable filters = new FieldTable(); + Map fields = method.getFields(); + for (String key: fields.keySet()) + { + filters.setObject(key, fields.get(key)); + } + FilterManager filterManager = null; + try + { + filterManager = FilterManagerFactory.createManager(filters); + } + catch (AMQException amqe) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "Exception Creating FilterManager"); + return; + } Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, destination, -- cgit v1.2.1 From 0137301436e2c8ad42bd4c04ef6ff76484391aa2 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 17 Sep 2010 14:44:10 +0000 Subject: QPID-2858: Implement FilterManager for 0-10 subscriptions Only the selector property should be copied to the FilterManager FieldTable. Patch from git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998154 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerSessionDelegate.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 04337c08df..d57424dd32 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -27,6 +27,7 @@ import java.util.Map; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.*; @@ -234,7 +235,10 @@ public class ServerSessionDelegate extends SessionDelegate Map fields = method.getFields(); for (String key: fields.keySet()) { - filters.setObject(key, fields.get(key)); + if (key.equals(AMQPFilterTypes.JMS_SELECTOR.getValue().asString())) + { + filters.setObject(key, fields.get(key)); + } } FilterManager filterManager = null; try -- cgit v1.2.1 From f54cd2b5bacb97e89d0582a3f7b2348d7bdb9494 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 17 Sep 2010 14:56:47 +0000 Subject: QPID-2857 : Address issues found by running FindBugs against the Java codebase git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998162 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java | 3 ++- .../java/org/apache/qpid/server/exchange/DirectExchangeMBean.java | 4 +++- .../java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java | 4 +++- .../java/org/apache/qpid/server/exchange/TopicExchangeMBean.java | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index c69d499674..626ceb5d84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -71,7 +71,8 @@ public abstract class AbstractExchangeMBean extends _bindingItemTypes[0] = SimpleType.STRING; _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]), _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), _bindingDataType, TABULAR_UNIQUE_INDEX); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java index 086832c045..94fc44d9c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java @@ -67,7 +67,9 @@ final class DirectExchangeMBean extends AbstractExchangeMBean for(Map.Entry> entry : bindingMap.entrySet()) { Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + bindingItemValues); bindingList.put(bindingData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java index d5734f76a5..2c85b7f787 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java @@ -58,7 +58,9 @@ final class FanoutExchangeMBean extends AbstractExchangeMBean } Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + bindingItemValues); bindingList.put(bindingData); return bindingList; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java index de39822ff7..620c3ce140 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java @@ -64,7 +64,10 @@ final class TopicExchangeMBean extends AbstractExchangeMBean for(Map.Entry> entry : bindingData.entrySet()) { Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + CompositeData bindingCompositeData = + new CompositeDataSupport(_bindingDataType, + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + bindingItemValues); bindingList.put(bindingCompositeData); } -- cgit v1.2.1 From 115fe345c725794b7db9f2f05497fd4897069154 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:17:01 +0000 Subject: Remove old commented out conflict marker, erroneous println debugging statement. Correct exception message. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998542 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/exchange/AbstractExchange.java | 8 -------- .../org/apache/qpid/server/exchange/AbstractExchangeMBean.java | 4 ++-- .../java/org/apache/qpid/server/exchange/HeadersExchange.java | 6 ++++-- 3 files changed, 6 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 3aa9178d5d..d0231e4d80 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -91,14 +91,6 @@ public abstract class AbstractExchange implements Exchange, Managable private final AtomicLong _routedMessageSize = new AtomicLong(); private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); -/* -======= - public ExchangeMBean() throws NotCompliantMBeanException - { - super(ManagedExchange.class, ManagedExchange.TYPE); - } ->>>>>>> .r902547 -*/ //TODO : persist creation time private long _createTime = System.currentTimeMillis(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index 626ceb5d84..b33a83672b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -137,7 +137,7 @@ public abstract class AbstractExchangeMBean extends AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost."); } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); @@ -164,7 +164,7 @@ public abstract class AbstractExchangeMBean extends AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost."); } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index e98a603d12..f9cbfeb78b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -251,8 +251,10 @@ public class HeadersExchange extends AbstractExchange bindings.remove(binding); } - _logger.debug("==============="); - _logger.debug("Removing Binding: " + _bindingHeaderMatchers.remove(new HeadersBinding(binding))); + if(_logger.isDebugEnabled()) + { + _logger.debug("Removing Binding: " + _bindingHeaderMatchers.remove(new HeadersBinding(binding))); + } } } -- cgit v1.2.1 From d383fb9a4a8905676e62d97a467cc2ffe6b0ea09 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:14:44 +0000 Subject: QPID-2704: simplify the implementation of SQEL scavenge() ability and add test. Incorporates changes for QPID-2597 from 0.5.x-dev branch revisions 943240, 943534, 943576, and 943845. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998543 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/queue/SimpleQueueEntryList.java | 65 +++++----------------- 1 file changed, 14 insertions(+), 51 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index 334b7f4ea9..b97c2c55c5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -45,7 +45,9 @@ public class SimpleQueueEntryList implements QueueEntryList _nextUpdater = AtomicReferenceFieldUpdater.newUpdater (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); - private AtomicLong _deletes = new AtomicLong(0L); + + private AtomicLong _scavenges = new AtomicLong(0L); + private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50); public SimpleQueueEntryList(AMQQueue queue) @@ -55,71 +57,32 @@ public class SimpleQueueEntryList implements QueueEntryList _tail = _head; } - - void advanceHead() { - _deletes.incrementAndGet(); - QueueEntryImpl head = _head.nextNode(); - while(head._next != null && head.isDeleted()) - { + QueueEntryImpl next = _head.nextNode(); + QueueEntryImpl newNext = _head.getNext(); - final QueueEntryImpl newhead = head.nextNode(); - if(newhead != null) + if (next == newNext) + { + if (_scavenges.incrementAndGet() > _scavengeCount) { - if(_nextUpdater.compareAndSet(_head,head, newhead)) - { - _deletes.decrementAndGet(); - } + _scavenges.set(0L); + scavenge(); } - head = _head.nextNode(); - } - - if(_deletes.get() > 1000L) - { - _deletes.set(0L); - scavenge(); } } void scavenge() { - QueueEntryImpl root = _head; - QueueEntryImpl next = root.nextNode(); + QueueEntryImpl next = _head.getNext(); - do + while (next != null) { - - - while(next._next != null && next.isDeleted()) - { - - final QueueEntryImpl newhead = next.nextNode(); - if(newhead != null) - { - _nextUpdater.compareAndSet(root,next, newhead); - } - next = root.nextNode(); - } - if(next._next != null) - { - if(!next.isDeleted()) - { - root = next; - next = root.nextNode(); - } - } - else - { - break; - } - - } while (next != null && next._next != null); - + next = next.getNext(); + } } - public AMQQueue getQueue() { return _queue; -- cgit v1.2.1 From 4a54b75b21fc7bff044b2c7730521bfec61c989b Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:17:55 +0000 Subject: QPID-2695: use exchangeName variable instead of exchange variable when logging during binding recovery to guard against NPEs, and check for exchange presence to prevent the BindingFactory incorrectly binding to the default exchange git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998544 13f79535-47bb-0310-9956-ffa450edef68 --- .../virtualhost/VirtualHostConfigRecoveryHandler.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 635155d1b0..96a9ac729e 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -219,18 +219,20 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa _actions = new ArrayList(); try { - QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); Exchange exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeName); - AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); + if (exchange == null) + { + _logger.error("Unknown exchange: " + exchangeName + ", cannot bind queue : " + queueName); + return; + } + + AMQQueue queue = _virtualHost.getQueueRegistry().getQueue(new AMQShortString(queueName)); if (queue == null) { - _logger.error("Unknown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getNameShortString()); + _logger.error("Unknown queue: " + queueName + ", cannot be bound to exchange: " + exchangeName); } else { - - FieldTable argumentsFT = null; if(buf != null) { @@ -249,7 +251,6 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa bf.restoreBinding(bindingKey, queue, exchange, argumentMap); } - } } catch (AMQException e) -- cgit v1.2.1 From 8d2d2765dbd55647aee0fad8db3bafecf99062d3 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:18:19 +0000 Subject: QPID-2870: move the authorisation check outside the AtomicBoolean wrapped queue deletion process to prevent an unauthorised attempt from barring all future deletion attempts git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998545 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index fc04e1382e..112f682fdc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1357,13 +1357,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // TODO list all thrown exceptions public int delete() throws AMQSecurityException, AMQException { + // Check access + if (!_virtualHost.getSecurityManager().authoriseDelete(this)) + { + throw new AMQSecurityException("Permission denied: " + getName()); + } + if (!_deleted.getAndSet(true)) { - // Check access - if (!_virtualHost.getSecurityManager().authoriseDelete(this)) - { - throw new AMQSecurityException("Permission denied: " + getName()); - } for (Binding b : getBindings()) { -- cgit v1.2.1 From d737e450bfcbd0f85db0117f4110a5f42ec85a28 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:19:18 +0000 Subject: QPID-2868: guard against non-existent destinations when moving/copying git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998547 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 112f682fdc..6fece81e88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1106,11 +1106,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void moveMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - ServerTransaction txn) + ServerTransaction txn) throws IllegalArgumentException { final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - + if (toQueue == null) + { + throw new IllegalArgumentException("Queue '" + queueName + "' is not registered with the virtualhost."); + } List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -1178,9 +1181,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void copyMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - final ServerTransaction txn) + final ServerTransaction txn) throws IllegalArgumentException { final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (toQueue == null) + { + throw new IllegalArgumentException("Queue '" + queueName + "' is not registered with the virtualhost."); + } List entries = getMessagesOnTheQueue(new QueueEntryFilter() { -- cgit v1.2.1 From d5a744ea500a3d043eebab637c283ee3fbf7c5db Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 18 Sep 2010 21:19:48 +0000 Subject: QPID-2869: prevent entering the source queue as destination git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998548 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 6fece81e88..ec6fb1f8de 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1114,6 +1114,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { throw new IllegalArgumentException("Queue '" + queueName + "' is not registered with the virtualhost."); } + else if (toQueue == this) + { + throw new IllegalArgumentException("The destination queue cant be the same as the source queue"); + } List entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -1188,6 +1192,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { throw new IllegalArgumentException("Queue '" + queueName + "' is not registered with the virtualhost."); } + else if (toQueue == this) + { + throw new IllegalArgumentException("The destination queue cant be the same as the source queue"); + } List entries = getMessagesOnTheQueue(new QueueEntryFilter() { -- cgit v1.2.1 From 3083052e161f357b3746ab2af2d837570cb8594f Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 19 Sep 2010 16:59:50 +0000 Subject: QPID-2857: address a further 60 or so issues identified by running FindBugs across the Java codebase git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998700 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/exchange/AbstractExchangeMBean.java | 2 +- .../qpid/server/exchange/HeadersExchangeMBean.java | 8 +++-- .../logging/management/LoggingManagementMBean.java | 13 ++++--- .../server/protocol/AMQProtocolSessionMBean.java | 9 ++--- .../apache/qpid/server/queue/AMQQueueMBean.java | 41 ++++++++++++---------- .../auth/management/AMQUserManagementMBean.java | 7 ++-- 6 files changed, 47 insertions(+), 33 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index b33a83672b..7aeff2561e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -74,7 +74,7 @@ public abstract class AbstractExchangeMBean extends COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]), _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, TABULAR_UNIQUE_INDEX); + _bindingDataType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); } public ManagedObject getParentObject() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java index 2c7985b480..66c9b5b552 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java @@ -56,9 +56,10 @@ final class HeadersExchangeMBean extends AbstractExchangeMBean _bindingItemTypes[1] = SimpleType.STRING; _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); + HEADERS_COMPOSITE_ITEM_NAMES.toArray(new String[HEADERS_COMPOSITE_ITEM_NAMES.size()]), + HEADERS_COMPOSITE_ITEM_DESC.toArray(new String[HEADERS_COMPOSITE_ITEM_DESC.size()]), _bindingItemTypes); _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); + _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX.toArray(new String[HEADERS_TABULAR_UNIQUE_INDEX.size()])); } public TabularData bindings() throws OpenDataException @@ -85,7 +86,8 @@ final class HeadersExchangeMBean extends AbstractExchangeMBean Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + HEADERS_COMPOSITE_ITEM_NAMES.toArray(new String[HEADERS_COMPOSITE_ITEM_NAMES.size()]), bindingItemValues); bindingList.put(bindingData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 258552f2f5..a823fb7cb1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -95,10 +95,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING}; _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes); + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]), + loggerLevelItemTypes); _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels", - _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX); + _loggerLevelCompositeType, + TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); } catch (OpenDataException e) { @@ -198,7 +201,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM level = logger.getEffectiveLevel().toString(); Object[] itemData = {loggerName, level}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), itemData); loggerLevelList.put(loggerData); } } @@ -536,7 +540,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { Object[] itemData = {loggerName, level.toUpperCase()}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); + CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), itemData); loggerLevelList.put(loggerData); } catch (OpenDataException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 6d3a41fbe9..f4f2cab2c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -118,9 +118,9 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed private static void init() throws OpenDataException { _channelType = - new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, - _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX); + new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), + COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes); + _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); } public String getClientId() @@ -256,7 +256,8 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed channel.getUnacknowledgedMessageMap().size(), channel.getBlocking() }; - CompositeData channelData = new CompositeDataSupport(_channelType, COMPOSITE_ITEM_NAMES, itemValues); + CompositeData channelData = new CompositeDataSupport(_channelType, + COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); channelsList.put(channelData); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 32b71a554b..b5294b6d2f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -128,7 +128,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content _msgContentType = new CompositeType("Message Content", "AMQ Message Content", - VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS, + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), _msgContentAttributeTypes); _msgAttributeTypes[0] = SimpleType.LONG; // For message id @@ -137,10 +138,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered _msgAttributeTypes[4] = SimpleType.LONG; // For queue position - _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, - VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes); + _messageDataType = new CompositeType("Message", "AMQ Message", + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), _msgAttributeTypes); _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, - VIEW_MSGS_TABULAR_UNIQUE_INDEX); + VIEW_MSGS_TABULAR_UNIQUE_INDEX.toArray(new String[VIEW_MSGS_TABULAR_UNIQUE_INDEX.size()])); } public String getObjectInstanceName() @@ -410,7 +412,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); + return new CompositeDataSupport(_msgContentType, + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray( + new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); } @@ -456,16 +460,17 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que long position = startPosition + i; final QueueEntry queueEntry = list.get(i); ServerMessage serverMsg = queueEntry.getMessage(); + + String[] headerAttributes = null; + Object[] itemValues = null; + if(serverMsg instanceof AMQMessage) { AMQMessage msg = (AMQMessage) serverMsg; ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); - + headerAttributes = getMessageHeaderProperties(headerBody); + itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; } else if(serverMsg instanceof MessageTransferMessage) { @@ -473,19 +478,19 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que MessageTransferMessage msg = (MessageTransferMessage) serverMsg; // Create header attributes list - String[] headerAttributes = getMessageTransferMessageHeaderProps(msg); - Object[] itemValues = {msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); + headerAttributes = getMessageTransferMessageHeaderProps(msg); + itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position}; } else { //unknown message - String[] headerAttributes = new String[]{"N/A"}; - Object[] itemValues = { serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); + headerAttributes = new String[]{"N/A"}; + itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position}; } + + CompositeData messageData = new CompositeDataSupport(_messageDataType, + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); + _messageList.put(messageData); } } catch (AMQException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java index a9bee4466f..ee4336055b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -85,9 +85,10 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana try { _userDataType = - new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, userItemTypes); + new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), + COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]), userItemTypes); - _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX); + _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); } catch (OpenDataException e) { @@ -326,7 +327,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } Object[] itemData = {user.getName(), read, write, admin}; - CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES, itemData); + CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), itemData); userList.put(messageData); } } -- cgit v1.2.1 From 4b7bc0b5a9a2ce0d263139dc40d20e3a08ca3023 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 20 Sep 2010 11:31:04 +0000 Subject: QPID-2858: Implement FilterManager for 0-10 subscriptions Implementation of review changes. Patch from git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@998891 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/filter/FilterManagerFactory.java | 12 ++++++++++-- .../qpid/server/transport/ServerSessionDelegate.java | 15 +++------------ 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index a7f49d0566..dac517150a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -20,15 +20,18 @@ */ package org.apache.qpid.server.filter; +import java.util.Map; + import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.FieldTable; +import org.apache.log4j.Logger; public class FilterManagerFactory { - //private final static Logger _logger = LoggerFactory.getLogger(FilterManagerFactory.class); - private final static org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(FilterManagerFactory.class); + + private final static Logger _logger = Logger.getLogger(FilterManagerFactory.class); //fixme move to a common class so it can be refered to from client code. @@ -64,4 +67,9 @@ public class FilterManagerFactory return manager; } + + public static FilterManager createManager(Map map) throws AMQException + { + return createManager(FieldTable.convertToFieldTable(map)); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index d57424dd32..53dad0fcfe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -230,20 +230,11 @@ public class ServerSessionDelegate extends SessionDelegate } FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); - - FieldTable filters = new FieldTable(); - Map fields = method.getFields(); - for (String key: fields.keySet()) - { - if (key.equals(AMQPFilterTypes.JMS_SELECTOR.getValue().asString())) - { - filters.setObject(key, fields.get(key)); - } - } + FilterManager filterManager = null; try { - filterManager = FilterManagerFactory.createManager(filters); + filterManager = FilterManagerFactory.createManager(method.getArguments()); } catch (AMQException amqe) { @@ -256,7 +247,7 @@ public class ServerSessionDelegate extends SessionDelegate method.getAcceptMode(), method.getAcquireMode(), MessageFlowMode.WINDOW, - creditManager, null); + creditManager, filterManager); ((ServerSession)session).register(destination, sub); try -- cgit v1.2.1 From a36dca8d3f04c94443896a97bd9df2a65b2cd1d0 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 26 Sep 2010 22:15:16 +0000 Subject: QPID-2833: Add a Generic Actor for 0-10 Logging Patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001536 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/Main.java | 3 + .../qpid/server/logging/actors/GenericActor.java | 85 ++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 452ddf5895..71cf17ed60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -49,6 +49,7 @@ import org.apache.qpid.server.information.management.ServerInformationMBean; import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; @@ -309,6 +310,8 @@ public class Main // for the remainder of the startup, and the default actor if the stack is empty CurrentActor.set(new BrokerActor(config.getCompositeStartupMessageLogger())); CurrentActor.setDefault(new BrokerActor(config.getRootMessageLogger())); + GenericActor.setDefaultMessageLogger(config.getRootMessageLogger()); + try { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java new file mode 100644 index 0000000000..09db81e7e5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java @@ -0,0 +1,85 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.logging.actors; + +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class GenericActor extends AbstractActor +{ + + private static RootMessageLogger _defaultMessageLogger; + + private LogSubject _logSubject; + + public static RootMessageLogger getDefaultMessageLogger() + { + return _defaultMessageLogger; + } + + public static void setDefaultMessageLogger(RootMessageLogger defaultMessageLogger) + { + _defaultMessageLogger = defaultMessageLogger; + } + + public GenericActor(LogSubject logSubject, RootMessageLogger rootLogger) + { + super(rootLogger); + _logSubject = logSubject; + } + + public String getLogMessage() + { + return _logSubject.toLogString(); + } + + public static LogActor getInstance(final String logMessage, RootMessageLogger rootLogger) + { + return new GenericActor(new LogSubject() + { + public String toLogString() + { + return logMessage; + } + + }, rootLogger); + } + + public static LogActor getInstance(final String subjectMessage) + { + return new GenericActor(new LogSubject() + { + public String toLogString() + { + return "[" + subjectMessage + "]"; + } + + }, _defaultMessageLogger); + } + + public static LogActor getInstance(LogSubject logSubject) + { + return new GenericActor(logSubject, _defaultMessageLogger); + } +} -- cgit v1.2.1 From 20a74846a893350f81c941e9bee1f0ab5eacb4aa Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 26 Sep 2010 22:17:21 +0000 Subject: QPID-2884: Pass the method arguments on Subscription_0_10 upon creation Patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001537 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/federation/Bridge.java | 8 ++++++-- .../org/apache/qpid/server/subscription/Subscription_0_10.java | 8 +++++--- .../org/apache/qpid/server/transport/ServerSessionDelegate.java | 4 +++- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index befa979d37..fbc5387daf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -694,12 +694,14 @@ public class Bridge implements BridgeConfig FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + //TODO Handle the passing of non-null Filters and Arguments here + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, _destination, MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, MessageFlowMode.WINDOW, - creditManager, null); + creditManager, null,null); ((ServerSession)session).register(_destination, sub); @@ -764,12 +766,14 @@ public class Bridge implements BridgeConfig FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + //TODO Handle the passing of non-null Filters and Arguments here + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, _destination, MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, MessageFlowMode.WINDOW, - creditManager, null); + creditManager, null,null); ((ServerSession)session).register(_destination, sub); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 8b5064e19d..2510c12eae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -102,13 +102,14 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private String _trace; private long _createTime = System.currentTimeMillis(); private final AtomicLong _deliveredCount = new AtomicLong(0); + private final Map _arguments; public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode, MessageFlowMode flowMode, FlowCreditManager_0_10 creditManager, - FilterManager filters) + FilterManager filters,Map arguments) { _session = session; _destination = destination; @@ -118,6 +119,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _flowMode = flowMode; _filters = filters; _creditManager.addStateListener(this); + _arguments = arguments == null ? Collections. emptyMap() : + Collections. unmodifiableMap(arguments); _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED); } @@ -859,8 +862,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr public Map getArguments() { - //TODO - return Collections.EMPTY_MAP; + return _arguments; } public boolean isSessionTransactional() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 53dad0fcfe..209bee4565 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -247,7 +247,9 @@ public class ServerSessionDelegate extends SessionDelegate method.getAcceptMode(), method.getAcquireMode(), MessageFlowMode.WINDOW, - creditManager, filterManager); + creditManager, + filterManager, + method.getArguments()); ((ServerSession)session).register(destination, sub); try -- cgit v1.2.1 From 3ec75c48f36f6302ce94f835183ebe778634a402 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 26 Sep 2010 22:33:38 +0000 Subject: add some missing Apache licence headers to files in the Java tree git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001542 13f79535-47bb-0310-9956-ffa450edef68 --- .../logging/CompositeStartupMessageLogger.java | 20 ++++++++++++++++++++ .../plugins/ConfiguredQueueBindingListener.java | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java index d2838f0789..e0a51b3a3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/CompositeStartupMessageLogger.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ package org.apache.qpid.server.logging; public class CompositeStartupMessageLogger extends AbstractRootMessageLogger diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java index 259f8574e0..12206013eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/ConfiguredQueueBindingListener.java @@ -1,3 +1,23 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ package org.apache.qpid.server.virtualhost.plugins; import java.util.Collections; -- cgit v1.2.1 From b89747e29966e0d78e59974ae54ee5ee5a91c669 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 26 Sep 2010 22:34:40 +0000 Subject: QPID-2872: make the broker indicate a heartbeat max of 0sec to cause the client disable heartbeating, as it otherwise enables the connection idle timeout by default and the broker cant generate them. Needed until QPID-2796 is undertaken to implement broker support for generating heartbeats. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001544 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerConnectionDelegate.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index 429e4b5976..a95f4e5c42 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -121,4 +121,11 @@ public class ServerConnectionDelegate extends ServerDelegate sconn.setState(Connection.State.CLOSING); } } + + @Override + protected int getHeartbeatMax() + { + //TODO: implement broker support for actually sending heartbeats + return 0; + } } -- cgit v1.2.1 From e1c164dd219a1d81dba0ad7f9ac185b0292a5660 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 27 Sep 2010 15:23:04 +0000 Subject: QPID-2801: Implement LogSubject Interface in 0-10 Subscription/ServerConnection/ServerSession Objects Committed patch from Sorins git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001779 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/subscription/Subscription_0_10.java | 84 +++++++++++++++++++--- .../qpid/server/transport/ServerConnection.java | 42 +++++++++++ .../qpid/server/transport/ServerSession.java | 27 ++++--- 3 files changed, 135 insertions(+), 18 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 2510c12eae..9f97d479e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -20,41 +20,64 @@ */ package org.apache.qpid.server.subscription; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SUBSCRIPTION_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.QUEUE_FORMAT; + import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfigType; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.CreditCreditManager; import org.apache.qpid.server.flow.WindowCreditManager; import org.apache.qpid.server.flow.FlowCreditManager_0_10; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.SubscriptionActor; -import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; -import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.messages.SubscriptionMessages; import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.transport.ServerSession; -import org.apache.qpid.server.configuration.*; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCreditUnit; +import org.apache.qpid.transport.MessageDeliveryPriority; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.Struct; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; -import org.apache.qpid.transport.*; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.ConcurrentHashMap; -import java.util.*; import java.nio.ByteBuffer; -public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig +public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig, LogSubject { private static final AtomicLong idGenerator = new AtomicLong(0); @@ -94,7 +117,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private ConcurrentHashMap _sentMap = new ConcurrentHashMap(); private static final Struct[] EMPTY_STRUCT_ARRAY = new Struct[0]; - private LogSubject _logSubject; private LogActor _logActor; private Map _properties = new ConcurrentHashMap(); private UUID _id; @@ -157,7 +179,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _trace = (String) arguments.get("qpid.trace.id"); _id = getConfigStore().createId(); getConfigStore().addConfiguredObject(this); - _logSubject = new SubscriptionLogSubject(this); _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); } @@ -874,4 +895,49 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { return _createTime; } + + public String toLogString() + { + String queueInfo = MessageFormat.format(QUEUE_FORMAT, _queue.getVirtualHost().getName(), + _queue.getNameShortString()); + String result = "[" + MessageFormat.format(SUBSCRIPTION_FORMAT, getSubscriptionID()) + "(" + // queueString is "vh(/{0})/qu({1}) " so need to trim + + queueInfo.substring(0, queueInfo.length() - 1) + ")" + "] "; + return result; + } + + private String getFilterLogString() + { + StringBuilder filterLogString = new StringBuilder(); + String delimiter = ", "; + boolean hasEntries = false; + if (_filters != null && _filters.hasFilters()) + { + filterLogString.append(_filters.toString()); + hasEntries = true; + } + + if (isBrowser()) + { + if (hasEntries) + { + filterLogString.append(delimiter); + } + filterLogString.append("Browser"); + hasEntries = true; + } + + if (isDurable()) + { + if (hasEntries) + { + filterLogString.append(delimiter); + } + filterLogString.append("Durable"); + hasEntries = true; + } + + return filterLogString.toString(); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 8c7b374791..3c924f3231 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -20,6 +20,11 @@ */ package org.apache.qpid.server.transport; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTION_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT; + import org.apache.qpid.server.configuration.ConnectionConfig; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.protocol.AMQConnectionModel; @@ -38,6 +43,8 @@ import org.apache.qpid.transport.ExecutionErrorCode; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.AMQException; +import java.text.MessageFormat; + public class ServerConnection extends Connection implements AMQConnectionModel { private ConnectionConfig _config; @@ -120,4 +127,39 @@ public class ServerConnection extends Connection implements AMQConnectionModel ((ServerSession)session).close(); } + + public String toLogString() { + boolean hasVirtualHost = (null != this.getVirtualHost()); + boolean hasPrincipal = (null != getAuthorizationID()); + + if (hasPrincipal && hasVirtualHost) + { + return " [" + + MessageFormat.format(CONNECTION_FORMAT, + getConnectionId(), + getAuthorizationID(), + _config.getAddress(), + getVirtualHost().getName()) + + "] "; + } + else if (hasPrincipal) + { + return " [" + + MessageFormat.format(USER_FORMAT, + getConnectionId(), + getAuthorizationID(), + _config.getAddress()) + + "] "; + + } + else + { + return " [" + + MessageFormat.format(SOCKET_FORMAT, + this.getConnectionId(), + _config.getAddress()) + + "] "; + } + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 7393b17243..1f4e32a3e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -20,9 +20,13 @@ */ package org.apache.qpid.server.transport; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; +import static org.apache.qpid.util.Serial.gt; + import com.sun.security.auth.UserPrincipal; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.ConnectionConfig; @@ -51,10 +55,10 @@ import org.apache.qpid.transport.Range; import org.apache.qpid.transport.RangeSet; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionDelegate; -import static org.apache.qpid.util.Serial.gt; import java.lang.ref.WeakReference; import java.security.Principal; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -67,7 +71,7 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; -public class ServerSession extends Session implements PrincipalHolder, SessionConfig, AMQSessionModel +public class ServerSession extends Session implements PrincipalHolder, SessionConfig, AMQSessionModel, LogSubject { private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); @@ -581,14 +585,19 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public LogSubject getLogSubject() { - return new LogSubject() - { - public String toLogString() - { - return "[ ]"; - } + return (LogSubject) this; + } + + @Override + public String toLogString() + { + return " [" + + MessageFormat.format(CHANNEL_FORMAT, getId().toString(), getClientID(), + ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString(), + this.getVirtualHost().getName(), + this.getChannel()) + + "] "; - }; } } -- cgit v1.2.1 From ad992d967371b001c77c1c79e2b701948d1c5775 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Mon, 27 Sep 2010 16:17:39 +0000 Subject: QPID-2834: Implement subscriptions (SUB) operational logging on 0-10 Committing patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1001804 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/subscription/Subscription_0_10.java | 14 +++++++++++--- .../qpid/server/transport/ServerSessionDelegate.java | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 9f97d479e3..cbc8664574 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -102,7 +102,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr public void stateChange(Subscription sub, State oldState, State newState) { - // TODO something ? log a message here ? + CurrentActor.get().message(SubscriptionMessages.STATE(newState.toString())); } }; private AMQQueue _queue; @@ -179,8 +179,15 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _trace = (String) arguments.get("qpid.trace.id"); _id = getConfigStore().createId(); getConfigStore().addConfiguredObject(this); - _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); - + String filterLogString = null; + LogActor _logActor = CurrentActor.get(); + if (_logActor.getRootMessageLogger().isMessageEnabled(_logActor, this, SubscriptionMessages.CREATE_LOG_HIERARCHY)) + { + filterLogString = getFilterLogString(); + _logActor.message(SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive, + filterLogString.length() > 0)); + } + } public AMQShortString getConsumerTag() @@ -268,6 +275,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } _creditManager.removeListener(this); getConfigStore().removeConfiguredObject(this); + CurrentActor.get().message(SubscriptionMessages.CLOSE()); } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 209bee4565..7715f70f0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -35,6 +35,8 @@ import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.flow.FlowCreditManager_0_10; import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.message.MessageMetaData_0_10; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.protocol.AMQSessionModel; @@ -251,6 +253,8 @@ public class ServerSessionDelegate extends SessionDelegate filterManager, method.getArguments()); + CurrentActor.set(GenericActor.getInstance(sub)); + ((ServerSession)session).register(destination, sub); try { -- cgit v1.2.1 From 7a95bb91bf4f7e85f0490ddf92141e464c0571ac Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Tue, 28 Sep 2010 09:18:45 +0000 Subject: QPID-2834: Implement subscriptions (SUB) operational logging on 0-10 Add correct LogSubject and helper method to set upo LogActor Committed patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1002063 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/subscription/Subscription_0_10.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index cbc8664574..0e19b17a50 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -275,7 +275,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } _creditManager.removeListener(this); getConfigStore().removeConfiguredObject(this); - CurrentActor.get().message(SubscriptionMessages.CLOSE()); + CurrentActor.get().message(getLogSubject(), SubscriptionMessages.CLOSE()); } finally { @@ -948,4 +948,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr return filterLogString.toString(); } + public LogSubject getLogSubject() + { + return (LogSubject) this; + } + } -- cgit v1.2.1 From a5b1a1073e2596da8b5fbcd24769aec87107d212 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 3 Oct 2010 16:00:24 +0000 Subject: QPID-2835 Implement CON Operational Logging on 0-10 Committed patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1003984 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/GenericActor.java | 2 +- .../qpid/server/protocol/AMQConnectionModel.java | 1 + .../qpid/server/protocol/AMQProtocolEngine.java | 5 ++ .../protocol/MultiVersionProtocolEngine.java | 2 +- .../qpid/server/protocol/ProtocolEngine_0_10.java | 7 ++- .../qpid/server/transport/ServerConnection.java | 59 ++++++++++++---------- .../server/transport/ServerConnectionDelegate.java | 7 ++- .../qpid/server/transport/ServerSession.java | 4 +- 8 files changed, 52 insertions(+), 35 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java index 09db81e7e5..9afc76ce78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/GenericActor.java @@ -72,7 +72,7 @@ public class GenericActor extends AbstractActor { public String toLogString() { - return "[" + subjectMessage + "]"; + return "[" + subjectMessage + "] "; } }, _defaultMessageLogger); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java index 448c8508a5..bcda385f64 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java @@ -35,4 +35,5 @@ public interface AMQConnectionModel */ public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException; + public long getConnectionId(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index c55c07a145..5368dfe532 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -1151,6 +1151,11 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _id; } + public long getConnectionId() + { + return getSessionID(); + } + public String getAddress() { return String.valueOf(getRemoteAddress()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java index e894dda341..eb957ee33c 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.protocol; -import org.apache.log4j.Logger; +import org.apache.log4j.Logger; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; import org.apache.qpid.server.registry.IApplicationRegistry; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java index f1e79839c9..1fe4ec792e 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -22,12 +22,13 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.transport.NetworkDriver; -import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.network.InputHandler; import org.apache.qpid.transport.network.Assembler; import org.apache.qpid.transport.network.Disassembler; import org.apache.qpid.server.configuration.*; import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.registry.IApplicationRegistry; import java.net.SocketAddress; @@ -55,6 +56,10 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine _networkDriver = networkDriver; _id = appRegistry.getConfigStore().createId(); _appRegistry = appRegistry; + + // FIXME Two log messages to maintain compatinbility with earlier protocol versions + CurrentActor.get().message(ConnectionMessages.OPEN(null, null, false, false)); + CurrentActor.get().message(ConnectionMessages.OPEN(null, "0-10", false, true)); } public void setNetworkDriver(NetworkDriver driver) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 3c924f3231..a1a7bd119b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -20,38 +20,33 @@ */ package org.apache.qpid.server.transport; -import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; -import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTION_FORMAT; -import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT; -import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*; +import java.text.MessageFormat; + +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.configuration.ConnectionConfig; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; +import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.Method; -import org.apache.qpid.transport.ConnectionCloseCode; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionDetachCode; -import org.apache.qpid.transport.SessionDetach; -import org.apache.qpid.transport.Binary; -import org.apache.qpid.transport.SessionDetached; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.ExecutionException; import org.apache.qpid.transport.ExecutionErrorCode; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.AMQException; - -import java.text.MessageFormat; +import org.apache.qpid.transport.ExecutionException; +import org.apache.qpid.transport.Method; -public class ServerConnection extends Connection implements AMQConnectionModel +public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject { private ConnectionConfig _config; private Runnable _onOpenTask; public ServerConnection() { + CurrentActor.set(GenericActor.getInstance(this)); } @Override @@ -64,9 +59,19 @@ public class ServerConnection extends Connection implements AMQConnectionModel protected void setState(State state) { super.setState(state); - if(state == State.OPEN && _onOpenTask != null) + + if (state == State.OPEN) + { + if (_onOpenTask != null) + { + _onOpenTask.run(); + } + CurrentActor.get().message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true)); + } + + if (state == State.CLOSED) { - _onOpenTask.run(); + CurrentActor.get().message(this, ConnectionMessages.CLOSE()); } } @@ -137,8 +142,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel return " [" + MessageFormat.format(CONNECTION_FORMAT, getConnectionId(), - getAuthorizationID(), - _config.getAddress(), + getClientId(), + getConfig().getAddress(), getVirtualHost().getName()) + "] "; } @@ -147,8 +152,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel return " [" + MessageFormat.format(USER_FORMAT, getConnectionId(), - getAuthorizationID(), - _config.getAddress()) + getClientId(), + getConfig().getAddress()) + "] "; } @@ -156,8 +161,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel { return " [" + MessageFormat.format(SOCKET_FORMAT, - this.getConnectionId(), - _config.getAddress()) + getConnectionId(), + getConfig().getAddress()) + "] "; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index a95f4e5c42..4a304b3e66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -21,7 +21,9 @@ package org.apache.qpid.server.transport; import org.apache.qpid.transport.*; - +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; +import org.apache.qpid.common.ClientProperties; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.registry.IApplicationRegistry; @@ -71,7 +73,7 @@ public class ServerConnectionDelegate extends ServerDelegate SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry); ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0); - //ssn.setSessionListener(new Echo()); + return ssn; } @@ -112,6 +114,7 @@ public class ServerConnectionDelegate extends ServerDelegate else { sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); + CurrentActor.set(GenericActor.getInstance(sconn)); sconn.setState(Connection.State.OPEN); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 1f4e32a3e0..71add9c097 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -578,9 +578,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public String getClientID() { - //fixme this will only work for 0-10 connections - // In 0-8 there is an explicit ClientID property that is != Principal. - return getPrincipal().getName(); + return getConnection().getClientId(); } public LogSubject getLogSubject() -- cgit v1.2.1 From a3625d8ed5d7edfbd41acf38130d3f574f1c0aa5 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 3 Oct 2010 16:02:42 +0000 Subject: QPID-2839 Add channel (CHN) Operational Loggin on 0-10 Committed patch from SorinS git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1003985 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ServerSession.java | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 71add9c097..c53f65f302 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -33,7 +33,9 @@ import org.apache.qpid.server.configuration.ConnectionConfig; import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.configuration.SessionConfigType; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; +import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; @@ -55,6 +57,7 @@ import org.apache.qpid.transport.Range; import org.apache.qpid.transport.RangeSet; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionDelegate; +import org.apache.qpid.transport.Session.State; import java.lang.ref.WeakReference; import java.security.Principal; @@ -121,6 +124,16 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo this(connection, delegate, name, expiry, ((ServerConnection)connection).getConfig()); } + protected void setState(State state) + { + super.setState(state); + + if (state == State.OPEN) + { + GenericActor.getInstance(this).message(ChannelMessages.CREATE()); + } + } + public ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry, ConnectionConfig connConfig) { super(connection, delegate, name, expiry); @@ -337,7 +350,8 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo { task.doTask(this); } - + + CurrentActor.get().message(getLogSubject(), ChannelMessages.CLOSE()); } @Override @@ -590,10 +604,12 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public String toLogString() { return " [" + - MessageFormat.format(CHANNEL_FORMAT, getId().toString(), getClientID(), + MessageFormat.format(CHANNEL_FORMAT, + getConnection().getConnectionId(), + getClientID(), ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString(), - this.getVirtualHost().getName(), - this.getChannel()) + getVirtualHost().getName(), + getChannel()) + "] "; } -- cgit v1.2.1 From cb5a819bd841c0af36ab4d13053a001a600a64d5 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 3 Oct 2010 16:15:21 +0000 Subject: QPID-2892: Catch Exception on signal handler failure git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1003988 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/ServerConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 45c52a8891..a0f5f9fa4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -145,7 +145,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa Signal sig = new sun.misc.Signal("HUP"); sun.misc.Signal.handle(sig, this); } - catch (IllegalArgumentException e) + catch (Exception e) { _logger.error("Signal HUP not supported for OS: " + System.getProperty("os.name")); // We're on something that doesn't handle SIGHUP, how sad, Windows. -- cgit v1.2.1 From 44f7d864ee9fb58a8186740d0045a744c0d5b922 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 11 Oct 2010 17:38:48 +0000 Subject: QPID-2898: when UUID is null, return null instead of doing String.valueOf() git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1021441 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/message/MessageTransferHeader.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index 0296735699..31cf223428 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -26,6 +26,7 @@ import org.apache.qpid.transport.MessageDeliveryPriority; import java.util.Set; import java.util.Map; +import java.util.UUID; class MessageTransferHeader implements AMQMessageHeader { @@ -61,7 +62,9 @@ class MessageTransferHeader implements AMQMessageHeader public String getMessageId() { - return _messageProps == null ? null : String.valueOf(_messageProps.getMessageId()); + UUID id = _messageProps == null ? null : _messageProps.getMessageId(); + + return id == null ? null : String.valueOf(id); } public String getMimeType() -- cgit v1.2.1 From 1ebf810b8cec52fdf6f067a90ae44e76300a67c3 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 24 Oct 2010 23:57:50 +0000 Subject: QPID-2887: Remove the System.out.println statements from SlowConsumerDetectionConfiguration Patch from Sorin S git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1026918 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/plugins/SlowConsumerDetectionConfiguration.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java index c5fbb6efd9..7a2632d923 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionConfiguration.java @@ -85,8 +85,5 @@ public class SlowConsumerDetectionConfiguration extends ConfigurationPlugin } } - System.out.println("Configured SCDC"); - System.out.println("Delay:" + getDelay()); - System.out.println("TimeUnit:" + getTimeUnit()); } } -- cgit v1.2.1 From d916d4097901aab3e0c20dde550ad83851d5dc4e Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 7 Nov 2010 14:51:05 +0000 Subject: QPID-2931: update MessageReference to stop nulling out the ServerMessage reference upon release for now, preventing NPE's experienced due to race conditions resulting in use of getMessage() after release. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1032291 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/message/MessageReference.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java index 055403ff08..399f8f9327 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.message; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicBoolean; public abstract class MessageReference { - private static final AtomicReferenceFieldUpdater _messageUpdater = - AtomicReferenceFieldUpdater.newUpdater(MessageReference.class, ServerMessage.class,"_message"); + private final AtomicBoolean _released = new AtomicBoolean(false); private volatile M _message; @@ -47,10 +46,12 @@ public abstract class MessageReference public void release() { - M message = (M) _messageUpdater.getAndSet(this,null); - if(message != null) + if(!_released.getAndSet(true)) { - onRelease(message); + if(_message != null) + { + onRelease(_message); + } } } -- cgit v1.2.1 From 98a4aeaca2a9d0811f1750e53b84e02942c3f816 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 7 Nov 2010 19:28:23 +0000 Subject: reduce the amount of change required to update the icky hardcoded version information git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1032357 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/plugins/PluginManager.java | 55 +++++++++++----------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index b61da12b05..4c8c1e4b0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -63,6 +63,7 @@ public class PluginManager implements Closeable private static final Logger _logger = Logger.getLogger(PluginManager.class); private static final int FELIX_STOP_TIMEOUT = 30000; + private static final String QPID_VER_SUFFIX = "version=0.7,"; private Framework _felix; @@ -133,33 +134,33 @@ public class PluginManager implements Closeable "org.osgi.service.startlevel; version=1.0.0," + "org.osgi.service.url; version=1.0.0," + "org.osgi.util.tracker; version=1.0.0," + - "org.apache.qpid.junit.extensions.util; version=0.7," + - "org.apache.qpid; version=0.7," + - "org.apache.qpid.common; version=0.7," + - "org.apache.qpid.exchange; version=0.7," + - "org.apache.qpid.framing; version=0.7," + - "org.apache.qpid.management.common.mbeans.annotations; version=0.7," + - "org.apache.qpid.protocol; version=0.7," + - "org.apache.qpid.server.binding; version=0.7," + - "org.apache.qpid.server.configuration; version=0.7," + - "org.apache.qpid.server.configuration.plugins; version=0.7," + - "org.apache.qpid.server.configuration.management; version=0.7," + - "org.apache.qpid.server.exchange; version=0.7," + - "org.apache.qpid.server.logging; version=0.7," + - "org.apache.qpid.server.logging.actors; version=0.7," + - "org.apache.qpid.server.logging.subjects; version=0.7," + - "org.apache.qpid.server.management; version=0.7," + - "org.apache.qpid.server.persistent; version=0.7," + - "org.apache.qpid.server.plugins; version=0.7," + - "org.apache.qpid.server.protocol; version=0.7," + - "org.apache.qpid.server.queue; version=0.7," + - "org.apache.qpid.server.registry; version=0.7," + - "org.apache.qpid.server.security; version=0.7," + - "org.apache.qpid.server.security.access; version=0.7," + - "org.apache.qpid.server.security.access.plugins; version=0.7," + - "org.apache.qpid.server.virtualhost; version=0.7," + - "org.apache.qpid.server.virtualhost.plugins; version=0.7," + - "org.apache.qpid.util; version=0.7," + + "org.apache.qpid.junit.extensions.util; " + QPID_VER_SUFFIX + + "org.apache.qpid; " + QPID_VER_SUFFIX + + "org.apache.qpid.common; " + QPID_VER_SUFFIX + + "org.apache.qpid.exchange; " + QPID_VER_SUFFIX + + "org.apache.qpid.framing; " + QPID_VER_SUFFIX + + "org.apache.qpid.management.common.mbeans.annotations; " + QPID_VER_SUFFIX + + "org.apache.qpid.protocol; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.binding; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.configuration; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.configuration.plugins; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.configuration.management; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.exchange; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.logging; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.logging.actors; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.logging.subjects; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.management; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.persistent; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.plugins; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.protocol; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.queue; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.registry; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.security; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.security.access; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.security.access.plugins; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.virtualhost; " + QPID_VER_SUFFIX + + "org.apache.qpid.server.virtualhost.plugins; " + QPID_VER_SUFFIX + + "org.apache.qpid.util; " + QPID_VER_SUFFIX + "org.apache.commons.configuration; version=1.0.0," + "org.apache.commons.lang; version=1.0.0," + "org.apache.commons.lang.builder; version=1.0.0," + -- cgit v1.2.1 From bc2c12eac6c30848f97803c1985c71800f81083b Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 7 Nov 2010 20:04:02 +0000 Subject: Increment version numbers from 0.7 to 0.8(docs) and 0.9(code) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1032374 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 4c8c1e4b0d..a6bab017a1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -63,7 +63,7 @@ public class PluginManager implements Closeable private static final Logger _logger = Logger.getLogger(PluginManager.class); private static final int FELIX_STOP_TIMEOUT = 30000; - private static final String QPID_VER_SUFFIX = "version=0.7,"; + private static final String QPID_VER_SUFFIX = "version=0.9,"; private Framework _felix; -- cgit v1.2.1 From b90c6c0d72ca9224953cd941825012c36adee63f Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 17 Nov 2010 00:31:02 +0000 Subject: QPID-2950: correct the shutdown exception check to verify the SQLCode is for single-db shutdown rather than full Derby engine shutdown git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1035880 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/store/DerbyMessageStore.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 0865165925..2e694b24ea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -134,6 +134,8 @@ public class DerbyMessageStore implements MessageStore private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME; + private static final String DERBY_SINGLE_DB_SHUTDOWN_CODE = "08006"; + private LogSubject _logSubject; private boolean _configured; @@ -631,9 +633,9 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - if (e.getSQLState().equalsIgnoreCase("XJ015")) + if (e.getSQLState().equalsIgnoreCase(DERBY_SINGLE_DB_SHUTDOWN_CODE)) { - //XJ015 is expected and represents a clean shutdown, do nothing. + //expected and represents a clean shutdown of this database only, do nothing. } else { -- cgit v1.2.1 From e05e135fa042be4a6bb20d742dba925c68c063d6 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sat, 11 Dec 2010 16:15:18 +0000 Subject: QPID-2966: add 'not implemented' stumps for the recently added get/setLogLevel QMF methods to allow the Java tree build to complete git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1044674 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 7ed6a9114a..04960adb4b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -700,6 +700,18 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } + public BrokerSchema.BrokerClass.GetLogLevelMethodResponseCommand getLogLevel(final BrokerSchema.BrokerClass.GetLogLevelMethodResponseCommandFactory factory) + { + // TODO: The Java broker has numerous loggers, so we can't really implement this method properly. + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); + } + + public BrokerSchema.BrokerClass.SetLogLevelMethodResponseCommand setLogLevel(final BrokerSchema.BrokerClass.SetLogLevelMethodResponseCommandFactory factory, String level) + { + // TODO: The Java broker has numerous loggers, so we can't really implement this method properly. + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); + } + public UUID getId() { return _obj.getId(); -- cgit v1.2.1 From 02148c8eb0abf489a5052173272c609761a60e7f Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Tue, 11 Jan 2011 11:02:05 +0000 Subject: QPID-2991: added message counts to connection stats; fixed xxxToClient stats git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1057578 13f79535-47bb-0310-9956-ffa450edef68 --- .../broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 04960adb4b..c0afae0773 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1249,6 +1249,18 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable return 0l; } + public Long getMsgsFromClient() + { + // TODO + return 0l; + } + + public Long getMsgsToClient() + { + // TODO + return 0l; + } + public BrokerSchema.ConnectionClass.CloseMethodResponseCommand close(final BrokerSchema.ConnectionClass.CloseMethodResponseCommandFactory factory) { _obj.mgmtClose(); -- cgit v1.2.1 From 9f6ff547a00e2c5414c7de48ebf716b0adf26ba3 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 21 Jan 2011 15:55:44 +0000 Subject: QPID-3010: ensure the SimpleByteBufferAllocator is always used and non-direct ByteBuffers are the default, remove the old and now unused configuration methods from ServerConfiguration and update the example config.xml accordingly git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1061865 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/configuration/ServerConfiguration.java | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index a0f5f9fa4c..c6a8818d90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -704,16 +704,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return getBooleanValue("advanced.filterchain[@enableExecutorPool]"); } - public boolean getEnablePooledAllocator() - { - return getBooleanValue("advanced.enablePooledAllocator"); - } - - public boolean getEnableDirectBuffers() - { - return getBooleanValue("advanced.enableDirectBuffers"); - } - public boolean getEnableSSL() { return getBooleanValue("connector.ssl.enabled"); -- cgit v1.2.1 From d08867d72f0120cbf33824459ad5d96e48610227 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 24 Jan 2011 10:36:16 +0000 Subject: QPID-3014: create and use a connection actor directly, it doesnt need to be put on the CurrentActor stack for the open messages git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1062722 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/protocol/ProtocolEngine_0_10.java | 4 ++-- .../org/apache/qpid/server/transport/ServerConnection.java | 10 ++++++++-- .../apache/qpid/server/transport/ServerConnectionDelegate.java | 1 - 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java index 1fe4ec792e..30d506a89b 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -58,8 +58,8 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine _appRegistry = appRegistry; // FIXME Two log messages to maintain compatinbility with earlier protocol versions - CurrentActor.get().message(ConnectionMessages.OPEN(null, null, false, false)); - CurrentActor.get().message(ConnectionMessages.OPEN(null, "0-10", false, true)); + _connection.getLogActor().message(ConnectionMessages.OPEN(null, null, false, false)); + _connection.getLogActor().message(ConnectionMessages.OPEN(null, "0-10", false, true)); } public void setNetworkDriver(NetworkDriver driver) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index a1a7bd119b..e301996113 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -27,6 +27,7 @@ import java.text.MessageFormat; import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; @@ -43,10 +44,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel, { private ConnectionConfig _config; private Runnable _onOpenTask; + private LogActor _actor = GenericActor.getInstance(this); public ServerConnection() { - CurrentActor.set(GenericActor.getInstance(this)); + } @Override @@ -66,7 +68,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel, { _onOpenTask.run(); } - CurrentActor.get().message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true)); + _actor.message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true)); } if (state == State.CLOSED) @@ -167,4 +169,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } } + public LogActor getLogActor() + { + return _actor; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index 4a304b3e66..a9b7d99503 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -114,7 +114,6 @@ public class ServerConnectionDelegate extends ServerDelegate else { sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); - CurrentActor.set(GenericActor.getInstance(sconn)); sconn.setState(Connection.State.OPEN); } } -- cgit v1.2.1 From 1854199d60a0517cf99eab294b488f3eb89f4bc8 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 25 Jan 2011 15:55:31 +0000 Subject: QPID-3020: fix _logActor variable shadowing, use CurrentActor to log Sub creation, dont put the created Sub actor onto the stack as the SubFlushRunner does this already when required git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1063328 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/subscription/Subscription_0_10.java | 10 ++++++---- .../apache/qpid/server/transport/ServerSessionDelegate.java | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 0e19b17a50..b36ac84cdd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -36,6 +36,7 @@ import org.apache.qpid.server.flow.WindowCreditManager; import org.apache.qpid.server.flow.FlowCreditManager_0_10; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; @@ -179,12 +180,13 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _trace = (String) arguments.get("qpid.trace.id"); _id = getConfigStore().createId(); getConfigStore().addConfiguredObject(this); - String filterLogString = null; - LogActor _logActor = CurrentActor.get(); - if (_logActor.getRootMessageLogger().isMessageEnabled(_logActor, this, SubscriptionMessages.CREATE_LOG_HIERARCHY)) + String filterLogString = null; + + _logActor = GenericActor.getInstance(this); + if (CurrentActor.get().getRootMessageLogger().isMessageEnabled(_logActor, this, SubscriptionMessages.CREATE_LOG_HIERARCHY)) { filterLogString = getFilterLogString(); - _logActor.message(SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive, + CurrentActor.get().message(this, SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive, filterLogString.length() > 0)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 7715f70f0d..17d7dc90e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -253,8 +253,6 @@ public class ServerSessionDelegate extends SessionDelegate filterManager, method.getArguments()); - CurrentActor.set(GenericActor.getInstance(sub)); - ((ServerSession)session).register(destination, sub); try { -- cgit v1.2.1 From f033f35e60156891d48cb4b9897e51642defd542 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 27 Jan 2011 11:18:39 +0000 Subject: QPID-3021: set the session/connection actor when the connection recieves new events, ensure the correct thread logs close git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1064084 13f79535-47bb-0310-9956-ffa450edef68 --- .../ConfigurationFileApplicationRegistry.java | 2 +- .../qpid/server/transport/ServerConnection.java | 42 +++++++++++++++++++--- .../server/transport/ServerConnectionDelegate.java | 17 ++++++++- .../qpid/server/transport/ServerSession.java | 12 +++++-- .../server/transport/ServerSessionDelegate.java | 1 - 5 files changed, 64 insertions(+), 10 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index b1172a880e..ff2a8c959b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -41,7 +41,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void close() { //Set the Actor for Broker Shutdown - CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); + CurrentActor.set(new BrokerActor(_rootMessageLogger)); try { super.close(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index e301996113..d8b7c2e80e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.transport; import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*; import java.text.MessageFormat; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; @@ -39,11 +40,13 @@ import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.ExecutionErrorCode; import org.apache.qpid.transport.ExecutionException; import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.ProtocolEvent; public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject { private ConnectionConfig _config; private Runnable _onOpenTask; + private AtomicBoolean _logClosed = new AtomicBoolean(false); private LogActor _actor = GenericActor.getInstance(this); public ServerConnection() @@ -72,6 +75,14 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } if (state == State.CLOSED) + { + logClosed(); + } + } + + protected void logClosed() + { + if(_logClosed.compareAndSet(false, true)) { CurrentActor.get().message(this, ConnectionMessages.CLOSE()); } @@ -135,13 +146,36 @@ public class ServerConnection extends Connection implements AMQConnectionModel, ((ServerSession)session).close(); } - public String toLogString() { + @Override + public void received(ProtocolEvent event) + { + ServerSession channel = (ServerSession) getSession(event.getChannel()); + LogActor channelActor = null; + + if (channel != null) + { + channelActor = channel.getLogActor(); + } + + CurrentActor.set(channelActor == null ? _actor : channelActor); + try + { + super.received(event); + } + finally + { + CurrentActor.remove(); + } + } + + public String toLogString() + { boolean hasVirtualHost = (null != this.getVirtualHost()); boolean hasPrincipal = (null != getAuthorizationID()); if (hasPrincipal && hasVirtualHost) { - return " [" + + return "[" + MessageFormat.format(CONNECTION_FORMAT, getConnectionId(), getClientId(), @@ -151,7 +185,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } else if (hasPrincipal) { - return " [" + + return "[" + MessageFormat.format(USER_FORMAT, getConnectionId(), getClientId(), @@ -161,7 +195,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } else { - return " [" + + return "[" + MessageFormat.format(SOCKET_FORMAT, getConnectionId(), getConfig().getAddress()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index a9b7d99503..7ba85ffe14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -84,7 +84,22 @@ public class ServerConnectionDelegate extends ServerDelegate } - @Override public void connectionOpen(Connection conn, ConnectionOpen open) + @Override + public void connectionClose(Connection conn, ConnectionClose close) + { + try + { + ((ServerConnection) conn).logClosed(); + } + finally + { + super.connectionClose(conn, close); + } + + } + + @Override + public void connectionOpen(Connection conn, ConnectionOpen open) { ServerConnection sconn = (ServerConnection) conn; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index c53f65f302..540ad3fffd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -32,6 +32,7 @@ import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.ConnectionConfig; import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.configuration.SessionConfigType; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; @@ -57,7 +58,6 @@ import org.apache.qpid.transport.Range; import org.apache.qpid.transport.RangeSet; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionDelegate; -import org.apache.qpid.transport.Session.State; import java.lang.ref.WeakReference; import java.security.Principal; @@ -81,6 +81,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo private final UUID _id; private ConnectionConfig _connectionConfig; private long _createTime = System.currentTimeMillis(); + private LogActor _actor = GenericActor.getInstance(this); public static interface MessageDispositionChangeListener { @@ -130,7 +131,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo if (state == State.OPEN) { - GenericActor.getInstance(this).message(ChannelMessages.CREATE()); + _actor.message(ChannelMessages.CREATE()); } } @@ -595,6 +596,11 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo return getConnection().getClientId(); } + public LogActor getLogActor() + { + return _actor; + } + public LogSubject getLogSubject() { return (LogSubject) this; @@ -603,7 +609,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo @Override public String toLogString() { - return " [" + + return "[" + MessageFormat.format(CHANNEL_FORMAT, getConnection().getConnectionId(), getClientID(), diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 17d7dc90e3..42a3975e24 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -1223,7 +1223,6 @@ public class ServerSessionDelegate extends SessionDelegate @Override public void closed(Session session) { - super.closed(session); for(Subscription_0_10 sub : getSubscriptions(session)) { ((ServerSession)session).unregister(sub); -- cgit v1.2.1 From 3edf381aae19bd212ef4d33f33abdd944da00bcf Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 27 Jan 2011 11:18:59 +0000 Subject: QPID-3023: enable using the ServerConfiguration directly instead of leveraging an internal broker (via IBBC) to load the vhost config required for the tests git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1064085 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/ServerConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index c6a8818d90..d7dcfa7dc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -212,7 +212,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa * both, as a fix for QPID-2360 and QPID-2361. */ @SuppressWarnings("unchecked") - private void setupVirtualHosts(Configuration conf) throws ConfigurationException + protected void setupVirtualHosts(Configuration conf) throws ConfigurationException { List vhostFiles = conf.getList("virtualhosts"); Configuration vhostConfig = conf.subset("virtualhosts"); -- cgit v1.2.1 From eb257d87dd7420516e481cc38983053b0eb9ebf2 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 28 Jan 2011 11:20:35 +0000 Subject: QPID-3017: improve error handling for the new transaction classes, add some logging, add unit tests Applied patches from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1064629 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 6 +- .../qpid/server/txn/AutoCommitTransaction.java | 172 +++++++++++++++------ .../apache/qpid/server/txn/LocalTransaction.java | 143 ++++++++++------- .../apache/qpid/server/txn/ServerTransaction.java | 76 +++++++-- 4 files changed, 274 insertions(+), 123 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 3e31115dcb..4f86c82578 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -281,7 +281,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel routeCurrentMessage(); - _transaction.addPostCommitAction(new ServerTransaction.Action() + _transaction.addPostTransactionAction(new ServerTransaction.Action() { public void postCommit() @@ -313,7 +313,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel if(!checkMessageUserId(_currentMessage.getContentHeader())) { - _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage)); + _transaction.addPostTransactionAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage)); } else { @@ -321,7 +321,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { if (_currentMessage.isMandatory() || _currentMessage.isImmediate()) { - _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage)); + _transaction.addPostTransactionAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage)); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java index f674741057..db781ead96 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -20,19 +20,28 @@ */ package org.apache.qpid.server.txn; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.BaseQueue; +import java.util.Collection; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.AMQException; - -import java.util.List; -import java.util.Collection; +/** + * An implementation of ServerTransaction where each enqueue/dequeue + * operation takes place within it own transaction. + * + * Since there is no long-lived transaction, the commit and rollback methods of + * this implementation are empty. + */ public class AutoCommitTransaction implements ServerTransaction { + protected static final Logger _logger = Logger.getLogger(AutoCommitTransaction.class); private final TransactionLog _transactionLog; @@ -41,52 +50,69 @@ public class AutoCommitTransaction implements ServerTransaction _transactionLog = transactionLog; } - - public void addPostCommitAction(Action postCommitAction) + /** + * Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered + * by the caller are executed immediately. + */ + public void addPostTransactionAction(Action immediateAction) { - postCommitAction.postCommit(); + immediateAction.postCommit(); } - public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { - + TransactionLog.Transaction txn = null; try { if(message.isPersistent() && queue.isDurable()) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString()); + } - TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn = _transactionLog.newTransaction(); txn.dequeueMessage(queue, message.getMessageNumber()); - // store.remove enqueue - // store.commit txn.commitTran(); + txn = null; } - postCommitAction.postCommit(); + postTransactionAction.postCommit(); + postTransactionAction = null; } catch (AMQException e) { - //TODO - postCommitAction.onRollback(); - throw new RuntimeException(e); + _logger.error("Error during message dequeue", e); + throw new RuntimeException("Error during message dequeue", e); + } + finally + { + rollbackIfNecessary(postTransactionAction, txn); } + } - public void dequeue(Collection ackedMessages, Action postCommitAction) + public void dequeue(Collection queueEntries, Action postTransactionAction) { + TransactionLog.Transaction txn = null; try { - TransactionLog.Transaction txn = null; - for(QueueEntry entry : ackedMessages) + for(QueueEntry entry : queueEntries) { ServerMessage message = entry.getMessage(); - AMQQueue queue = entry.getQueue(); + BaseQueue queue = entry.getQueue(); if(message.isPersistent() && queue.isDurable()) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString()); + } + if(txn == null) { txn = _transactionLog.newTransaction(); } + txn.dequeueMessage(queue, message.getMessageNumber()); } @@ -94,78 +120,134 @@ public class AutoCommitTransaction implements ServerTransaction if(txn != null) { txn.commitTran(); + txn = null; } - postCommitAction.postCommit(); + postTransactionAction.postCommit(); + postTransactionAction = null; } catch (AMQException e) { - //TODO - postCommitAction.onRollback(); - throw new RuntimeException(e); + _logger.error("Error during message dequeues", e); + throw new RuntimeException("Error during message dequeues", e); + } + finally + { + rollbackIfNecessary(postTransactionAction, txn); } + } - public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { + TransactionLog.Transaction txn = null; try { if(message.isPersistent() && queue.isDurable()) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString()); + } - TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn = _transactionLog.newTransaction(); txn.enqueueMessage(queue, message.getMessageNumber()); txn.commitTran(); + txn = null; } - postCommitAction.postCommit(); + postTransactionAction.postCommit(); + postTransactionAction = null; } catch (AMQException e) { - //TODO - e.printStackTrace(); - postCommitAction.onRollback(); - throw new RuntimeException(e); + _logger.error("Error during message enqueue", e); + throw new RuntimeException("Error during message enqueue", e); } + finally + { + rollbackIfNecessary(postTransactionAction, txn); + } + } - public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List queues, EnqueableMessage message, Action postTransactionAction) { + TransactionLog.Transaction txn = null; try { if(message.isPersistent()) { - TransactionLog.Transaction txn = _transactionLog.newTransaction(); Long id = message.getMessageNumber(); - for(BaseQueue q : queues) + for(BaseQueue queue : queues) { - if(q.isDurable()) + if (queue.isDurable()) { - txn.enqueueMessage(q, id); + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString()); + } + if (txn == null) + { + txn = _transactionLog.newTransaction(); + } + + txn.enqueueMessage(queue, id); } } - txn.commitTran(); + + if (txn != null) + { + txn.commitTran(); + txn = null; + } } - postCommitAction.postCommit(); + postTransactionAction.postCommit(); + postTransactionAction = null; } catch (AMQException e) { - //TODO - postCommitAction.onRollback(); - throw new RuntimeException(e); + _logger.error("Error during message enqueues", e); + throw new RuntimeException("Error during message enqueues", e); + } + finally + { + rollbackIfNecessary(postTransactionAction, txn); } } + public void commit() { - } public void rollback() { + } + private void rollbackIfNecessary(Action postTransactionAction, TransactionLog.Transaction txn) + { + if (txn != null) + { + try + { + txn.abortTran(); + } + catch (AMQStoreException e) + { + _logger.error("Abort transaction failed", e); + // Deliberate decision not to re-throw this exception. Rationale: we can only reach here if a previous + // TransactionLog method has ended in Exception. If we were to re-throw here, we would prevent + // our caller from receiving the original exception (which is likely to be more revealing of the underlying error). + } + } + if (postTransactionAction != null) + { + postTransactionAction.onRollback(); + } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index 7c9276dbdc..a04c743be1 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -21,21 +21,29 @@ package org.apache.qpid.server.txn; */ -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.BaseQueue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.AMQException; - -import java.util.List; -import java.util.ArrayList; -import java.util.Collection; +/** + * A concrete implementation of ServerTransaction where enqueue/dequeue + * operations share a single long-lived transaction. + * + * The caller is responsible for invoking commit() (or rollback()) as necessary. + */ public class LocalTransaction implements ServerTransaction { - private final List _postCommitActions = new ArrayList(); + protected static final Logger _logger = Logger.getLogger(LocalTransaction.class); + + private final List _postTransactionActions = new ArrayList(); private volatile TransactionLog.Transaction _transaction; private TransactionLog _transactionLog; @@ -45,17 +53,23 @@ public class LocalTransaction implements ServerTransaction _transactionLog = transactionLog; } - public void addPostCommitAction(Action postCommitAction) + public void addPostTransactionAction(Action postTransactionAction) { - _postCommitActions.add(postCommitAction); + _postTransactionActions.add(postTransactionAction); } - public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { + _postTransactionActions.add(postTransactionAction); + if(message.isPersistent() && queue.isDurable()) { try { + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString()); + } beginTranIfNecessary(); _transaction.dequeueMessage(queue, message.getMessageNumber()); @@ -63,23 +77,31 @@ public class LocalTransaction implements ServerTransaction } catch(AMQException e) { + _logger.error("Error during message dequeues", e); tidyUpOnError(e); } } - _postCommitActions.add(postCommitAction); } - public void dequeue(Collection queueEntries, Action postCommitAction) + public void dequeue(Collection queueEntries, Action postTransactionAction) { + _postTransactionActions.add(postTransactionAction); + try { for(QueueEntry entry : queueEntries) { ServerMessage message = entry.getMessage(); - AMQQueue queue = entry.getQueue(); + BaseQueue queue = entry.getQueue(); + if(message.isPersistent() && queue.isDurable()) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString()); + } + beginTranIfNecessary(); _transaction.dequeueMessage(queue, message.getMessageNumber()); } @@ -88,9 +110,9 @@ public class LocalTransaction implements ServerTransaction } catch(AMQException e) { + _logger.error("Error during message dequeues", e); tidyUpOnError(e); } - _postCommitActions.add(postCommitAction); } @@ -98,7 +120,7 @@ public class LocalTransaction implements ServerTransaction { try { - for(Action action : _postCommitActions) + for(Action action : _postTransactionActions) { action.onRollback(); } @@ -107,14 +129,20 @@ public class LocalTransaction implements ServerTransaction { try { - _transaction.abortTran(); + if (_transaction != null) + { + _transaction.abortTran(); + } } - catch (Exception e1) + catch (Exception abortException) { - // TODO could try to chain the information to the original error + _logger.error("Abort transaction failed while trying to handle previous error", abortException); + } + finally + { + _transaction = null; + _postTransactionActions.clear(); } - _transaction = null; - _postCommitActions.clear(); } throw new RuntimeException(e); @@ -122,6 +150,7 @@ public class LocalTransaction implements ServerTransaction private void beginTranIfNecessary() { + if(_transaction == null) { try @@ -135,52 +164,50 @@ public class LocalTransaction implements ServerTransaction } } - public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { + _postTransactionActions.add(postTransactionAction); + if(message.isPersistent() && queue.isDurable()) { - beginTranIfNecessary(); try { + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString()); + } + + beginTranIfNecessary(); _transaction.enqueueMessage(queue, message.getMessageNumber()); } catch (Exception e) { + _logger.error("Error during message enqueue", e); + tidyUpOnError(e); } } - _postCommitActions.add(postCommitAction); - - } - public void enqueue(List queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List queues, EnqueableMessage message, Action postTransactionAction) { - + _postTransactionActions.add(postTransactionAction); if(message.isPersistent()) { - if(_transaction == null) - { - for(BaseQueue queue : queues) - { - if(queue.isDurable()) - { - beginTranIfNecessary(); - break; - } - } - - - } - - try { for(BaseQueue queue : queues) { if(queue.isDurable()) { + if (_logger.isDebugEnabled()) + { + _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString() ); + } + + + beginTranIfNecessary(); _transaction.enqueueMessage(queue, message.getMessageNumber()); } } @@ -188,12 +215,11 @@ public class LocalTransaction implements ServerTransaction } catch (Exception e) { + _logger.error("Error during message enqueue", e); + tidyUpOnError(e); } } - _postCommitActions.add(postCommitAction); - - } public void commit() @@ -202,55 +228,52 @@ public class LocalTransaction implements ServerTransaction { if(_transaction != null) { - _transaction.commitTran(); } - for(Action action : _postCommitActions) + for(Action action : _postTransactionActions) { action.postCommit(); } } catch (Exception e) { - for(Action action : _postCommitActions) + _logger.error("Failed to commit transaction", e); + + for(Action action : _postTransactionActions) { action.onRollback(); } - //TODO - throw new RuntimeException(e); + throw new RuntimeException("Failed to commit transaction", e); } finally { _transaction = null; - _postCommitActions.clear(); + _postTransactionActions.clear(); } } public void rollback() { - try { if(_transaction != null) { - _transaction.abortTran(); } } catch (AMQException e) { - //TODO - e.printStackTrace(); - throw new RuntimeException(e); + _logger.error("Failed to rollback transaction", e); + throw new RuntimeException("Failed to rollback transaction", e); } finally { try { - for(Action action : _postCommitActions) + for(Action action : _postTransactionActions) { action.onRollback(); } @@ -258,7 +281,7 @@ public class LocalTransaction implements ServerTransaction finally { _transaction = null; - _postCommitActions.clear(); + _postTransactionActions.clear(); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java index f3ef6569f3..b61b8a5c64 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -27,14 +27,24 @@ import org.apache.qpid.server.queue.QueueEntry; import java.util.Collection; import java.util.List; + +/** + * The ServerTransaction interface allows a set enqueue/dequeue operations to be + * performed against the transaction belonging the underlying TransactionLog object. + * + * Typically all ServerTransaction implementations decide if a message should be enlisted + * into a store transaction by examining the durable property of the queue, and the persistence + * property of the message. + * + * A caller may register a list of post transaction Actions to be + * performed on commit() (or rollback()). + * + */ public interface ServerTransaction { - - void addPostCommitAction(Action postCommitAction); - - - - + /** + * Represents an action to be performed on transaction commit or rollback + */ public static interface Action { public void postCommit(); @@ -42,16 +52,52 @@ public interface ServerTransaction public void onRollback(); } - void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); - - void dequeue(Collection ackedMessages, Action postCommitAction); - - void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); - - void enqueue(List queues, EnqueableMessage message, Action postCommitAction); - - + /** + * Register an Action for execution after transaction commit or rollback. Actions + * will be executed in the order in which they are registered. + */ + void addPostTransactionAction(Action postTransactionAction); + + /** + * Dequeue a message from a queue registering a post transaction action. + * + * A store operation will result only for a persistent message on a durable queue. + */ + void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction); + + /** + * Dequeue a message(s) from queue(s) registering a post transaction action. + * + * Store operations will result only for a persistent messages on durable queues. + */ + void dequeue(Collection messages, Action postTransactionAction); + + /** + * Enqueue a message to a queue registering a post transaction action. + * + * A store operation will result only for a persistent message on a durable queue. + */ + void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction); + + /** + * Enqueue a message(s) to queue(s) registering a post transaction action. + * + * Store operations will result only for a persistent messages on durable queues. + */ + void enqueue(List queues, EnqueableMessage message, Action postTransactionAction); + + /** + * Commit the transaction represented by this object. + * + * If the caller has registered one or more Actions, the postCommit() method on each will + * be executed immediately after the underlying transaction has committed. + */ void commit(); + /** Rollback the transaction represented by this object. + * + * If the caller has registered one or more Actions, the onRollback() method on each will + * be executed immediately after the underlying transaction has rolled-back. + */ void rollback(); } -- cgit v1.2.1 From 5e34c79ab85ff75a929353590cd1b90ce1b91b67 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 4 Feb 2011 16:14:46 +0000 Subject: QPID-3021: ensure the connection actor is used for connection control events regardless of a particular sessions existence git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1067208 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/transport/ServerConnection.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index d8b7c2e80e..d2addfde0c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -149,15 +149,23 @@ public class ServerConnection extends Connection implements AMQConnectionModel, @Override public void received(ProtocolEvent event) { - ServerSession channel = (ServerSession) getSession(event.getChannel()); - LogActor channelActor = null; - - if (channel != null) + if (event.isConnectionControl()) + { + CurrentActor.set(_actor); + } + else { - channelActor = channel.getLogActor(); + ServerSession channel = (ServerSession) getSession(event.getChannel()); + LogActor channelActor = null; + + if (channel != null) + { + channelActor = channel.getLogActor(); + } + + CurrentActor.set(channelActor == null ? _actor : channelActor); } - CurrentActor.set(channelActor == null ? _actor : channelActor); try { super.received(event); -- cgit v1.2.1 From d79e40667ca674d9c206b43f1ffbb1dcbecfc7ff Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 4 Feb 2011 16:15:27 +0000 Subject: QPID-3029: actually set and negotiate the supported max num channels per connection during connection handshake. Enable/make the 0-10 client use channel numbers 0 to N-1 in line with the spec, rather than 1-N. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1067210 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/configuration/ServerConfiguration.java | 6 ++++++ .../qpid/server/handler/ConnectionSecureOkMethodHandler.java | 2 +- .../apache/qpid/server/handler/ConnectionStartOkMethodHandler.java | 2 +- .../apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java | 5 ++++- .../java/org/apache/qpid/server/protocol/AMQProtocolEngine.java | 2 +- .../org/apache/qpid/server/transport/ServerConnectionDelegate.java | 7 +++++++ 6 files changed, 20 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index d7dcfa7dc8..7197ec8cdc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -108,6 +108,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount"); envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth"); envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize"); + envVarMap.put("QPID_MAXIMUMCHANNELCOUNT", "maximumChannelCount"); envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap"); envVarMap.put("QPID_QUEUECAPACITY", "capacity"); envVarMap.put("QPID_FLOWRESUMECAPACITY", "flowResumeCapacity"); @@ -818,4 +819,9 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } }; } + + public int getMaxChannelCount() + { + return getIntValue("maximumChannelCount", 256); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index cda8cff25a..d4b79134a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -92,7 +92,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); ConnectionTuneBody tuneBody = - methodRegistry.createConnectionTuneBody(0xFFFF, + methodRegistry.createConnectionTuneBody(ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount(), ConnectionStartOkMethodHandler.getConfiguredFrameSize(), ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 6512ff1a14..4442f969c4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -113,7 +113,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF, + ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount(), getConfiguredFrameSize(), ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java index 9f392ffc44..1da2760639 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -23,7 +23,6 @@ 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.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; @@ -51,5 +50,9 @@ public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener Date: Tue, 8 Feb 2011 10:23:05 +0000 Subject: QPID-2900: Changed SimpleAMQQueue to avoid race condition in the updating atomic QueueContext._releasedEntry. Race was between thread SubFlushRunner (or QueueRunner) executing method SimpleAMQQueue.setLastSeenEntry and the thread executing the MessageRelase command executing method SimpleAMQQueue.updateSubRequeueEntry. Bolstered the unit tests surrounding the area of change to reduce risk of regression. Overrode TestableMemoryMessageStore#close() to avoid a NPE during tearDown silently cluttering some unit test logs (including SimpleAMQQueueTest). Applied patch from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1068315 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index ec6fb1f8de..b003152db6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -54,7 +54,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -742,12 +741,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void deliverMessage(final Subscription sub, final QueueEntry entry) throws AMQException { + setLastSeenEntry(sub, entry); + _deliveredMessages.incrementAndGet(); incrementUnackedMsgCount(); sub.send(entry); - - setLastSeenEntry(sub,entry); } private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) throws AMQException -- cgit v1.2.1 From 2c57f31bac8684f0897b5ec9759eaf8192560e4d Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Thu, 17 Feb 2011 00:57:59 +0000 Subject: QPID-3048: InternalBrokerBasecase not removing all log actors git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1071465 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/logging/actors/CurrentActor.java | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java index 3d31a705fe..2ebbfeb734 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java @@ -21,9 +21,6 @@ package org.apache.qpid.server.logging.actors; import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogMessage; -import org.apache.qpid.server.logging.RootMessageLogger; import java.util.EmptyStackException; import java.util.Stack; @@ -72,7 +69,7 @@ public class CurrentActor private static LogActor _defaultActor; /** - * Set a new LogActor to be the Current Actor + * Set a new {@link LogActor} to be the Current Actor *

      * This pushes the Actor in to the LIFO Queue * @@ -85,7 +82,16 @@ public class CurrentActor } /** - * Remove the current LogActor. + * Remove all {@link LogActor}s + */ + public static void removeAll() + { + Stack stack = _currentActor.get(); + stack.clear(); + } + + /** + * Remove the current {@link LogActor}. *

      * Calling remove without calling set will result in an EmptyStackException. */ @@ -96,9 +102,7 @@ public class CurrentActor } /** - * Return the current head of the list of LogActors. - *

      - * If there has been no set call then this will return Null. + * Return the current head of the list of {@link LogActor}s. * * @return Current LogActor */ -- cgit v1.2.1 From 9de60b44364c99806877e82dce12b8cf7497cef2 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Fri, 18 Feb 2011 22:38:05 +0000 Subject: QPID-3015: Added create and delete methods to management schema for broker git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1072179 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/qmf/QMFService.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index c0afae0773..2c8fd737c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -712,6 +712,25 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); } + public BrokerSchema.BrokerClass.CreateMethodResponseCommand create(final BrokerSchema.BrokerClass.CreateMethodResponseCommandFactory factory, + final String type, + final String name, + final Map properties, + final java.lang.Boolean lenient) + { + //TODO: + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); + } + + public BrokerSchema.BrokerClass.DeleteMethodResponseCommand delete(final BrokerSchema.BrokerClass.DeleteMethodResponseCommandFactory factory, + final String type, + final String name, + final Map options) + { + //TODO: + return factory.createResponseCommand(CompletionCode.NOT_IMPLEMENTED); + } + public UUID getId() { return _obj.getId(); -- cgit v1.2.1 From 3d7df7067b2824d64f4c9193e7416eace56495be Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Mon, 21 Feb 2011 15:53:43 +0000 Subject: Fix build broken by change to QMF management schema from QPID-2935 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1073038 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 2c8fd737c3..a6f319cb1f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1091,6 +1091,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable return 0l; } + public Boolean getFlowStopped() + { + return Boolean.FALSE; + } + public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, final Long request) { -- cgit v1.2.1 From 2caae48af88d3070f9ca08b2b0b61bff71b28c18 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 1 Mar 2011 09:34:53 +0000 Subject: QPID-3090: quote the MBean ObjectName key values for the names of Queues, Connections, Exchanges, and VirtualHosts instead of just remapping characters. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1075744 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/exchange/AbstractExchangeMBean.java | 4 ++-- .../server/management/DefaultManagedObject.java | 28 ---------------------- .../management/MBeanInvocationHandlerImpl.java | 14 +++++++++++ .../server/protocol/AMQProtocolSessionMBean.java | 6 ++--- .../apache/qpid/server/queue/AMQQueueMBean.java | 5 ++-- .../qpid/server/virtualhost/VirtualHostImpl.java | 5 ++-- 6 files changed, 25 insertions(+), 37 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index 7aeff2561e..0f1b709475 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -90,12 +90,12 @@ public abstract class AbstractExchangeMBean extends public String getObjectInstanceName() { - return _exchange.getNameShortString().toString(); + return ObjectName.quote(_exchange.getName()); } public String getName() { - return _exchange.getNameShortString().toString(); + return _exchange.getName(); } public String getExchangeType() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 0a739af695..7924964fdf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -153,32 +153,4 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana 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; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 964b5ed5a0..380f51e308 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -213,6 +213,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati ObjectName object = (ObjectName) args[0]; String vhost = object.getKeyProperty("VirtualHost"); + if(vhost != null) + { + try + { + //if the name is quoted in the ObjectName, unquote it + vhost = ObjectName.unquote(vhost); + } + catch(IllegalArgumentException e) + { + //ignore, this just means the name is not quoted + //and can be left unchanged + } + } + return vhost; } return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index f4f2cab2c2..9d0d63b18e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -56,6 +56,7 @@ import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.management.Notification; +import javax.management.ObjectName; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -94,8 +95,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed super(ManagedConnection.class, ManagedConnection.TYPE); _protocolSession = amqProtocolSession; String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); + _name = "anonymous".equals(remote) ? (remote + hashCode()) : remote; init(); } @@ -175,7 +175,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public String getObjectInstanceName() { - return _name; + return ObjectName.quote(_name); } /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index b5294b6d2f..77c4e8fc23 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -43,6 +43,7 @@ import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; +import javax.management.ObjectName; import javax.management.OperationsException; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.ArrayType; @@ -97,7 +98,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; - _queueName = jmxEncode(new StringBuffer(queue.getNameShortString()), 0).toString(); + _queueName = queue.getName(); } public ManagedObject getParentObject() @@ -147,7 +148,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public String getObjectInstanceName() { - return _queueName; + return ObjectName.quote(_queueName); } public String getName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 6ec1c512e5..a550283a38 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -31,6 +31,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -161,12 +162,12 @@ public class VirtualHostImpl implements VirtualHost public String getObjectInstanceName() { - return _name.toString(); + return ObjectName.quote(_name); } public String getName() { - return _name.toString(); + return _name; } public VirtualHostImpl getVirtualHost() -- cgit v1.2.1 From bfc890b6dbfc25211dfd9639f76df46e47e0e129 Mon Sep 17 00:00:00 2001 From: Kenneth Anthony Giusti Date: Wed, 2 Mar 2011 19:02:00 +0000 Subject: QPID-3081: add statistic for queue flow control transitions git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1076329 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index a6f319cb1f..5192d5be6f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1096,6 +1096,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable return Boolean.FALSE; } + public Long getFlowStoppedCount() + { + return 0L; + } + public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, final Long request) { -- cgit v1.2.1 From 0869544671f7cf7e01970477b277e8830bea7bf8 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Fri, 4 Mar 2011 15:07:28 +0000 Subject: QPID-3114: Record the owner session for exclusive queues in 0-10 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1077989 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/transport/ServerSessionDelegate.java | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 42a3975e24..d12ab6d474 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -209,26 +209,27 @@ public class ServerSessionDelegate extends SessionDelegate } else { - if(queue.isExclusive()) { + ServerSession s = (ServerSession) session; + queue.setExclusiveOwningSession(s); if(queue.getPrincipalHolder() == null) { - queue.setPrincipalHolder((ServerSession)session); + queue.setPrincipalHolder(s); + queue.setExclusiveOwningSession(s); ((ServerSession) session).addSessionCloseTask(new ServerSession.Task() { - public void doTask(ServerSession session) { if(queue.getPrincipalHolder() == session) { queue.setPrincipalHolder(null); + queue.setExclusiveOwningSession(null); } } }); } - } FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); @@ -969,10 +970,10 @@ public class ServerSessionDelegate extends SessionDelegate } - if(method.hasAutoDelete() - && method.getAutoDelete() - && method.hasExclusive() - && method.getExclusive()) + if (method.hasAutoDelete() + && method.getAutoDelete() + && method.hasExclusive() + && method.getExclusive()) { final AMQQueue q = queue; final ServerSession.Task deleteQueueTask = new ServerSession.Task() @@ -999,12 +1000,12 @@ public class ServerSessionDelegate extends SessionDelegate } }); } - else if(method.getExclusive()) + if (method.hasExclusive() + && method.getExclusive()) { final AMQQueue q = queue; final ServerSession.Task removeExclusive = new ServerSession.Task() { - public void doTask(ServerSession session) { q.setPrincipalHolder(null); @@ -1012,10 +1013,10 @@ public class ServerSessionDelegate extends SessionDelegate } }; final ServerSession s = (ServerSession) session; + q.setExclusiveOwningSession(s); s.addSessionCloseTask(removeExclusive); queue.addQueueDeleteTask(new AMQQueue.Task() { - public void doTask(AMQQueue queue) throws AMQException { s.removeSessionCloseTask(removeExclusive); @@ -1029,7 +1030,7 @@ public class ServerSessionDelegate extends SessionDelegate } } } - else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session))) + else if (method.getExclusive() && (queue.getExclusiveOwningSession() != null && !queue.getExclusiveOwningSession().equals(session))) { String description = "Cannot declare queue('" + queueName + "')," + " as exclusive queue with same name " -- cgit v1.2.1 From 2122db7644ad41417ac83c51222f1c194b8acd71 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 7 Mar 2011 10:21:47 +0000 Subject: NO-JIRA: increment version numbers from 0.9 to 0.11 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1078729 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/server/plugins/PluginManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index a6bab017a1..4e8d64a136 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -63,7 +63,7 @@ public class PluginManager implements Closeable private static final Logger _logger = Logger.getLogger(PluginManager.class); private static final int FELIX_STOP_TIMEOUT = 30000; - private static final String QPID_VER_SUFFIX = "version=0.9,"; + private static final String QPID_VER_SUFFIX = "version=0.11,"; private Framework _felix; -- cgit v1.2.1 From 5c797b1f2ebce8b79f118dc64cd0c1b3b9efd23c Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Tue, 8 Mar 2011 00:11:30 +0000 Subject: QPID-2985: Add producer configurable transaction timeouts Port of QPID-2864 changes from 0.5.x-dev branch to trunk. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1079042 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 53 ++++++++++- .../configuration/VirtualHostConfiguration.java | 20 ++++ .../qpid/server/connection/ConnectionRegistry.java | 52 +++++------ .../server/connection/IConnectionRegistry.java | 15 ++- .../messages/Channel_logmessages.properties | 4 + .../qpid/server/protocol/AMQConnectionModel.java | 34 ++++++- .../qpid/server/protocol/AMQProtocolEngine.java | 38 +++++--- .../qpid/server/protocol/AMQProtocolSession.java | 2 - .../qpid/server/protocol/AMQSessionModel.java | 28 +++++- .../server/subscription/Subscription_0_10.java | 1 - .../qpid/server/transport/ServerConnection.java | 43 +++++++++ .../server/transport/ServerConnectionDelegate.java | 1 + .../qpid/server/transport/ServerSession.java | 101 ++++++++++++++++----- .../server/transport/ServerSessionDelegate.java | 1 - .../qpid/server/txn/AutoCommitTransaction.java | 5 + .../apache/qpid/server/txn/LocalTransaction.java | 59 +++++++++--- .../apache/qpid/server/txn/ServerTransaction.java | 7 ++ .../qpid/server/virtualhost/VirtualHostImpl.java | 31 +++++-- 18 files changed, 391 insertions(+), 104 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 4f86c82578..1c91de6d15 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -22,6 +22,7 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQMethodBody; @@ -141,6 +142,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel private final AtomicLong _txnCommits = new AtomicLong(0); private final AtomicLong _txnRejects = new AtomicLong(0); private final AtomicLong _txnCount = new AtomicLong(0); + private final AtomicLong _txnUpdateTime = new AtomicLong(0); private final AMQProtocolSession _session; private AtomicBoolean _closing = new AtomicBoolean(false); @@ -200,6 +202,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return !(_transaction instanceof AutoCommitTransaction); } + public boolean inTransaction() + { + return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0; + } + private void incrementOutstandingTxnsIfNecessary() { if(isTransactional()) @@ -295,7 +302,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel }); deliverCurrentMessageIfComplete(); - } } @@ -333,6 +339,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues, isTransactional())); incrementOutstandingTxnsIfNecessary(); + updateTransactionalActivity(); } } } @@ -794,6 +801,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { Collection ackedMessages = getAckedMessages(deliveryTag, multiple); _transaction.dequeue(ackedMessages, new MessageAcknowledgeAction(ackedMessages)); + updateTransactionalActivity(); } private Collection getAckedMessages(long deliveryTag, boolean multiple) @@ -968,6 +976,17 @@ public class AMQChannel implements SessionConfig, AMQSessionModel } + /** + * Update last transaction activity timestamp + */ + private void updateTransactionalActivity() + { + if (isTransactional()) + { + _txnUpdateTime.set(System.currentTimeMillis()); + } + } + public String toString() { return "["+_session.toString()+":"+_channelId+"]"; @@ -1407,4 +1426,36 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { _session.mgmtCloseChannel(_channelId); } + + public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException + { + if (inTransaction()) + { + long currentTime = System.currentTimeMillis(); + long openTime = currentTime - _transaction.getTransactionStartTime(); + long idleTime = currentTime - _txnUpdateTime.get(); + + // Log a warning on idle or open transactions + if (idleWarn > 0L && idleTime > idleWarn) + { + CurrentActor.get().message(_logSubject, ChannelMessages.IDLE_TXN(idleTime)); + _logger.warn("IDLE TRANSACTION ALERT " + _logSubject.toString() + " " + idleTime + " ms"); + } + else if (openWarn > 0L && openTime > openWarn) + { + CurrentActor.get().message(_logSubject, ChannelMessages.OPEN_TXN(openTime)); + _logger.warn("OPEN TRANSACTION ALERT " + _logSubject.toString() + " " + openTime + " ms"); + } + + // Close connection for idle or open transactions that have timed out + if (idleClose > 0L && idleTime > idleClose) + { + getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Idle transaction timed out"); + } + else if (openClose > 0L && openTime > openClose) + { + getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Open transaction timed out"); + } + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index d9d7083543..48f2d776bb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -313,4 +313,24 @@ public class VirtualHostConfiguration extends ConfigurationPlugin { return getIntValue("housekeeping.poolSize", Runtime.getRuntime().availableProcessors()); } + + public long getTransactionTimeoutOpenWarn() + { + return getLongValue("transactionTimeout.openWarn", 0L); + } + + public long getTransactionTimeoutOpenClose() + { + return getLongValue("transactionTimeout.openClose", 0L); + } + + public long getTransactionTimeoutIdleWarn() + { + return getLongValue("transactionTimeout.idleWarn", 0L); + } + + public long getTransactionTimeoutIdleClose() + { + return getLongValue("transactionTimeout.idleClose", 0L); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java index bac751e0c8..c06305ee4e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -20,19 +20,19 @@ */ package org.apache.qpid.server.connection; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.log4j.Logger; -import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.common.Closeable; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQConnectionModel; public class ConnectionRegistry implements IConnectionRegistry, Closeable { - private List _registry = new CopyOnWriteArrayList(); + private List _registry = new CopyOnWriteArrayList(); private Logger _logger = Logger.getLogger(ConnectionRegistry.class); @@ -40,44 +40,42 @@ public class ConnectionRegistry implements IConnectionRegistry, Closeable { // None required } - - public void expireClosedChannels() - { - for (AMQProtocolSession connection : _registry) - { - connection.closeIfLingeringClosedChannels(); - } - } /** Close all of the currently open connections. */ public void close() { while (!_registry.isEmpty()) { - AMQProtocolSession connection = _registry.get(0); - - try - { - connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down", - 0, 0, - connection.getProtocolOutputConverter().getProtocolMajorVersion(), - connection.getProtocolOutputConverter().getProtocolMinorVersion(), - (Throwable) null), true); - } - catch (AMQException e) - { - _logger.warn("Error closing connection:" + e.getMessage()); - } + AMQConnectionModel connection = _registry.get(0); + closeConnection(connection, AMQConstant.INTERNAL_ERROR, "Broker is shutting down"); + } + } + + public void closeConnection(AMQConnectionModel connection, AMQConstant cause, String message) + { + try + { + connection.close(cause, message); + } + catch (AMQException e) + { + _logger.warn("Error closing connection:" + e.getMessage()); } } - public void registerConnection(AMQProtocolSession connnection) + public void registerConnection(AMQConnectionModel connnection) { _registry.add(connnection); } - public void deregisterConnection(AMQProtocolSession connnection) + public void deregisterConnection(AMQConnectionModel connnection) { _registry.remove(connnection); } + + @Override + public List getConnections() + { + return new ArrayList(_registry); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java index 002269bbaa..b4f5bffa57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java @@ -20,18 +20,23 @@ */ package org.apache.qpid.server.connection; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import java.util.List; + import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.protocol.AMQConnectionModel; public interface IConnectionRegistry { - public void initialise(); public void close() throws AMQException; + + public void closeConnection(AMQConnectionModel connection, AMQConstant cause, String message); + + public List getConnections(); - public void registerConnection(AMQProtocolSession connnection); - - public void deregisterConnection(AMQProtocolSession connnection); + public void registerConnection(AMQConnectionModel connnection); + public void deregisterConnection(AMQConnectionModel connnection); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties index 53bcd712f2..ed8c0d0ce9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties @@ -28,3 +28,7 @@ PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} # 0 - queue causing flow control FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0}) FLOW_REMOVED = CHN-1006 : Flow Control Removed +# Channel Transactions +# 0 - time in milliseconds +OPEN_TXN = CHN-1007 : Open Transaction : {0,number} ms +IDLE_TXN = CHN-1008 : Idle Transaction : {0,number} ms diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java index bcda385f64..4ef84631b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java @@ -20,14 +20,34 @@ */ package org.apache.qpid.server.protocol; -import org.apache.qpid.protocol.AMQConstant; +import java.util.List; +import java.util.UUID; + import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.logging.LogSubject; public interface AMQConnectionModel { + /** + * get a unique id for this connection. + * + * @return a {@link UUID} representing the connection + */ + public UUID getId(); + + /** + * Close the underlying Connection + * + * @param cause + * @param message + * @throws org.apache.qpid.AMQException + */ + public void close(AMQConstant cause, String message) throws AMQException; /** * Close the given requested Session + * * @param session * @param cause * @param message @@ -36,4 +56,16 @@ public interface AMQConnectionModel public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException; public long getConnectionId(); + + /** + * Get a list of all sessions using this connection. + * + * @return a list of {@link AMQSessionModel}s + */ + public List getSessionModels(); + + /** + * Return a {@link LogSubject} for the connection. + */ + public LogSubject getLogSubject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index a1ffe272fd..aef905772a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; @@ -1078,19 +1077,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return (_clientVersion == null) ? null : _clientVersion.toString(); } - public void closeIfLingeringClosedChannels() - { - for (Entryid : _closingChannelsList.entrySet()) - { - if (id.getValue() + 30000 > System.currentTimeMillis()) - { - // We have a channel that we closed 30 seconds ago. Client's dead, kill the connection - _logger.error("Closing connection as channel was closed more than 30 seconds ago and no ChannelCloseOk has been processed"); - closeProtocolSession(); - } - } - } - public Boolean isIncoming() { return true; @@ -1263,7 +1249,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException { - closeChannel((Integer)session.getID()); MethodRegistry methodRegistry = getMethodRegistry(); @@ -1274,5 +1259,28 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol 0,0); writeFrame(responseBody.generateFrame((Integer)session.getID())); + } + + public void close(AMQConstant cause, String message) throws AMQException + { + closeConnection(0, new AMQConnectionException(cause, message, 0, 0, + getProtocolOutputConverter().getProtocolMajorVersion(), + getProtocolOutputConverter().getProtocolMinorVersion(), + (Throwable) null), true); + } + + public List getSessionModels() + { + List sessions = new ArrayList(); + for (AMQChannel channel : getChannels()) + { + sessions.add((AMQSessionModel) channel); + } + return sessions; + } + + public LogSubject getLogSubject() + { + return _logSubject; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index f48a214933..c64ed4ad5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -231,7 +231,5 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Prin List getChannels(); - void closeIfLingeringClosedChannels(); - void mgmtCloseChannel(int channelId); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java index a9b2354d75..bc63403a86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java @@ -20,15 +20,35 @@ */ package org.apache.qpid.server.protocol; +import org.apache.qpid.AMQException; import org.apache.qpid.server.logging.LogSubject; public interface AMQSessionModel { - Object getID(); + public Object getID(); - AMQConnectionModel getConnectionModel(); + public AMQConnectionModel getConnectionModel(); - String getClientID(); + public String getClientID(); + + public void close() throws AMQException; - LogSubject getLogSubject(); + public LogSubject getLogSubject(); + + /** + * This method is called from the housekeeping thread to check the status of + * transactions on this session and react appropriately. + * + * If a transaction is open for too long or idle for too long then a warning + * is logged or the connection is closed, depending on the configuration. An open + * transaction is one that has recent activity. The transaction age is counted + * from the time the transaction was started. An idle transaction is one that + * has had no activity, such as publishing or acknowledgeing messages. + * + * @param openWarn time in milliseconds before alerting on open transaction + * @param openClose time in milliseconds before closing connection with open transaction + * @param idleWarn time in milliseconds before alerting on idle transaction + * @param idleClose time in milliseconds before closing connection with idle transaction + */ + public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index b36ac84cdd..a20436f029 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -97,7 +97,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private FlowCreditManager_0_10 _creditManager; - private StateListener _stateListener = new StateListener() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index d2addfde0c..e635ad0188 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -24,6 +24,9 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*; import java.text.MessageFormat; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; @@ -37,10 +40,12 @@ import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionCloseCode; import org.apache.qpid.transport.ExecutionErrorCode; import org.apache.qpid.transport.ExecutionException; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.ProtocolEvent; +import org.apache.qpid.transport.Session; public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject { @@ -54,6 +59,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } + public UUID getId() + { + return _config.getId(); + } + @Override protected void invoke(Method method) { @@ -110,6 +120,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel, public void setVirtualHost(VirtualHost virtualHost) { _virtualHost = virtualHost; + _virtualHost.getConnectionRegistry().registerConnection(this); } public void setConnectionConfig(final ConnectionConfig config) @@ -145,6 +156,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel, ((ServerSession)session).close(); } + + public LogSubject getLogSubject() + { + return (LogSubject) this; + } @Override public void received(ProtocolEvent event) @@ -215,4 +231,31 @@ public class ServerConnection extends Connection implements AMQConnectionModel, { return _actor; } + + @Override + public void close(AMQConstant cause, String message) throws AMQException + { + ConnectionCloseCode replyCode = ConnectionCloseCode.NORMAL; + try + { + replyCode = ConnectionCloseCode.get(cause.getCode()); + } + catch (IllegalArgumentException iae) + { + // Ignore + } + close(replyCode, message); + getVirtualHost().getConnectionRegistry().deregisterConnection(this); + } + + @Override + public List getSessionModels() + { + List sessions = new ArrayList(); + for (Session ssn : getChannels()) + { + sessions.add((AMQSessionModel) ssn); + } + return sessions; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index 2b9e92f685..fb27dec949 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -138,6 +138,7 @@ public class ServerConnectionDelegate extends ServerDelegate sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'")); sconn.setState(Connection.State.CLOSING); } + } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 540ad3fffd..714b2aa61f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -20,12 +20,26 @@ */ package org.apache.qpid.server.transport; -import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; -import static org.apache.qpid.util.Serial.gt; +import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*; +import static org.apache.qpid.util.Serial.*; -import com.sun.security.auth.UserPrincipal; +import java.lang.ref.WeakReference; +import java.security.Principal; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; @@ -38,6 +52,8 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; @@ -48,8 +64,6 @@ import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.transport.Binary; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.MessageTransfer; @@ -58,24 +72,15 @@ import org.apache.qpid.transport.Range; import org.apache.qpid.transport.RangeSet; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionDelegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.lang.ref.WeakReference; -import java.security.Principal; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicLong; +import com.sun.security.auth.UserPrincipal; public class ServerSession extends Session implements PrincipalHolder, SessionConfig, AMQSessionModel, LogSubject { + private static final Logger _logger = LoggerFactory.getLogger(ServerSession.class); + private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); private final UUID _id; @@ -111,6 +116,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo private final AtomicLong _txnCommits = new AtomicLong(0); private final AtomicLong _txnRejects = new AtomicLong(0); private final AtomicLong _txnCount = new AtomicLong(0); + private final AtomicLong _txnUpdateTime = new AtomicLong(0); private Principal _principal; @@ -141,7 +147,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo _connectionConfig = connConfig; _transaction = new AutoCommitTransaction(this.getMessageStore()); _principal = new UserPrincipal(connection.getAuthorizationID()); - _reference = new WeakReference(this); + _reference = new WeakReference(this); _id = getConfigStore().createId(); getConfigStore().addConfiguredObject(this); } @@ -160,8 +166,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public void enqueue(final ServerMessage message, final ArrayList queues) { - - _transaction.enqueue(queues,message, new ServerTransaction.Action() + _transaction.enqueue(queues,message, new ServerTransaction.Action() { BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); @@ -189,6 +194,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo }); incrementOutstandingTxnsIfNecessary(); + updateTransactionalActivity(); } @@ -377,6 +383,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo entry.release(); } }); + updateTransactionalActivity(); } public Collection getSubscriptions() @@ -425,6 +432,11 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo // theory return !(_transaction instanceof AutoCommitTransaction); } + + public boolean inTransaction() + { + return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0; + } public void selectTx() { @@ -471,6 +483,17 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo } } + /** + * Update last transaction activity timestamp + */ + public void updateTransactionalActivity() + { + if (isTransactional()) + { + _txnUpdateTime.set(System.currentTimeMillis()); + } + } + public Long getTxnStarts() { return _txnStarts.get(); @@ -606,6 +629,38 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo return (LogSubject) this; } + public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException + { + if (inTransaction()) + { + long currentTime = System.currentTimeMillis(); + long openTime = currentTime - _transaction.getTransactionStartTime(); + long idleTime = currentTime - _txnUpdateTime.get(); + + // Log a warning on idle or open transactions + if (idleWarn > 0L && idleTime > idleWarn) + { + CurrentActor.get().message(getLogSubject(), ChannelMessages.IDLE_TXN(openTime)); + _logger.warn("IDLE TRANSACTION ALERT " + getLogSubject().toString() + " " + idleTime + " ms"); + } + else if (openWarn > 0L && openTime > openWarn) + { + CurrentActor.get().message(getLogSubject(), ChannelMessages.OPEN_TXN(openTime)); + _logger.warn("OPEN TRANSACTION ALERT " + getLogSubject().toString() + " " + openTime + " ms"); + } + + // Close connection for idle or open transactions that have timed out + if (idleClose > 0L && idleTime > idleClose) + { + getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Idle transaction timed out"); + } + else if (openClose > 0L && openTime > openClose) + { + getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Open transaction timed out"); + } + } + } + @Override public String toLogString() { @@ -617,7 +672,5 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo getVirtualHost().getName(), getChannel()) + "] "; - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index d12ab6d474..be659c87ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -370,7 +370,6 @@ public class ServerSessionDelegate extends SessionDelegate } ssn.processed(xfr); - } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java index db781ead96..36e9d78440 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -50,6 +50,11 @@ public class AutoCommitTransaction implements ServerTransaction _transactionLog = transactionLog; } + public long getTransactionStartTime() + { + return 0L; + } + /** * Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered * by the caller are executed immediately. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index a04c743be1..f9dac782a6 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -20,18 +20,23 @@ package org.apache.qpid.server.txn; * */ - import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.TransactionLog; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A concrete implementation of ServerTransaction where enqueue/dequeue @@ -41,17 +46,28 @@ import org.apache.qpid.server.store.TransactionLog; */ public class LocalTransaction implements ServerTransaction { - protected static final Logger _logger = Logger.getLogger(LocalTransaction.class); + protected static final Logger _logger = LoggerFactory.getLogger(LocalTransaction.class); private final List _postTransactionActions = new ArrayList(); private volatile TransactionLog.Transaction _transaction; private TransactionLog _transactionLog; + private long _txnStartTime = 0L; public LocalTransaction(TransactionLog transactionLog) { _transactionLog = transactionLog; } + + public boolean inTransaction() + { + return _transaction != null; + } + + public long getTransactionStartTime() + { + return _txnStartTime; + } public void addPostTransactionAction(Action postTransactionAction) { @@ -89,7 +105,6 @@ public class LocalTransaction implements ServerTransaction try { - for(QueueEntry entry : queueEntries) { ServerMessage message = entry.getMessage(); @@ -113,7 +128,6 @@ public class LocalTransaction implements ServerTransaction _logger.error("Error during message dequeues", e); tidyUpOnError(e); } - } private void tidyUpOnError(Exception e) @@ -140,8 +154,7 @@ public class LocalTransaction implements ServerTransaction } finally { - _transaction = null; - _postTransactionActions.clear(); + resetDetails(); } } @@ -193,8 +206,25 @@ public class LocalTransaction implements ServerTransaction { _postTransactionActions.add(postTransactionAction); + if (_txnStartTime == 0L) + { + _txnStartTime = System.currentTimeMillis(); + } + if(message.isPersistent()) { + if(_transaction == null) + { + for(BaseQueue queue : queues) + { + if(queue.isDurable()) + { + beginTranIfNecessary(); + break; + } + } + } + try { for(BaseQueue queue : queues) @@ -248,17 +278,14 @@ public class LocalTransaction implements ServerTransaction } finally { - _transaction = null; - _postTransactionActions.clear(); + resetDetails(); } - } public void rollback() { try { - if(_transaction != null) { _transaction.abortTran(); @@ -280,9 +307,15 @@ public class LocalTransaction implements ServerTransaction } finally { - _transaction = null; - _postTransactionActions.clear(); + resetDetails(); } } } + + private void resetDetails() + { + _transaction = null; + _postTransactionActions.clear(); + _txnStartTime = 0L; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java index b61b8a5c64..b3c6e1ac3a 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -52,6 +52,13 @@ public interface ServerTransaction public void onRollback(); } + /** + * Return the time the current transaction started. + * + * @return the time this transaction started or 0 if not in a transaction + */ + long getTransactionStartTime(); + /** * Register an Action for execution after transaction commit or rollback. Actions * will be executed in the order in which they are registered. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index a550283a38..a1566917dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; @@ -37,7 +36,6 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInternalException; import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -64,6 +62,8 @@ import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; @@ -282,19 +282,30 @@ public class VirtualHostImpl implements VirtualHost // house keeping task from running. } } + for (AMQConnectionModel connection : getConnectionRegistry().getConnections()) + { + _logger.debug("Checking for long running open transactions on connection " + connection); + for (AMQSessionModel session : connection.getSessionModels()) + { + _logger.debug("Checking for long running open transactions on session " + session); + try + { + session.checkTransactionStatus(_configuration.getTransactionTimeoutOpenWarn(), + _configuration.getTransactionTimeoutOpenClose(), + _configuration.getTransactionTimeoutIdleWarn(), + _configuration.getTransactionTimeoutIdleClose()); + } + catch (Exception e) + { + _logger.error("Exception in housekeeping for connection: " + connection.toString(), e); + } + } + } } } scheduleHouseKeepingTask(period, new ExpiredMessagesTask(this)); - class ForceChannelClosuresTask extends TimerTask - { - public void run() - { - _connectionRegistry.expireClosedChannels(); - } - } - Map plugins = ApplicationRegistry.getInstance().getPluginManager().getVirtualHostPlugins(); -- cgit v1.2.1 From b387fc19a0dc062e95659ad34360ea942790e49e Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Tue, 8 Mar 2011 00:14:59 +0000 Subject: QPID-2984: Add statistics generation for broker message delivery Port of QPID-2932 changes from 0.5.x-dev branch to trunk. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1079043 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/AMQBrokerManagerMBean.java | 70 +++++++++ .../java/org/apache/qpid/server/AMQChannel.java | 4 + .../src/main/java/org/apache/qpid/server/Main.java | 3 +- .../server/configuration/ServerConfiguration.java | 30 ++++ .../management/ServerInformationMBean.java | 81 +++++++++- .../logging/messages/Broker_logmessages.properties | 5 +- .../messages/VirtualHost_logmessages.properties | 5 +- .../qpid/server/protocol/AMQConnectionModel.java | 3 +- .../qpid/server/protocol/AMQProtocolEngine.java | 79 +++++++++- .../server/protocol/AMQProtocolSessionMBean.java | 107 ++++++++++++-- .../qpid/server/registry/ApplicationRegistry.java | 156 +++++++++++++++++++- .../qpid/server/registry/IApplicationRegistry.java | 5 +- .../qpid/server/stats/StatisticsCounter.java | 163 +++++++++++++++++++++ .../qpid/server/stats/StatisticsGatherer.java | 118 +++++++++++++++ .../qpid/server/transport/ServerConnection.java | 77 ++++++++++ .../server/transport/ServerConnectionDelegate.java | 22 +-- .../qpid/server/transport/ServerSession.java | 2 + .../qpid/server/virtualhost/VirtualHost.java | 32 ++-- .../qpid/server/virtualhost/VirtualHostImpl.java | 79 ++++++++++ 19 files changed, 986 insertions(+), 55 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index a612f280d6..d1ea5dba69 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -327,4 +327,74 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { return getObjectNameForSingleInstanceMBean(); } + + public void resetStatistics() throws Exception + { + getVirtualHost().resetStatistics(); + } + + public double getPeakMessageDeliveryRate() + { + return getVirtualHost().getMessageDeliveryStatistics().getPeak(); + } + + public double getPeakDataDeliveryRate() + { + return getVirtualHost().getDataDeliveryStatistics().getPeak(); + } + + public double getMessageDeliveryRate() + { + return getVirtualHost().getMessageDeliveryStatistics().getRate(); + } + + public double getDataDeliveryRate() + { + return getVirtualHost().getDataDeliveryStatistics().getRate(); + } + + public long getTotalMessagesDelivered() + { + return getVirtualHost().getMessageDeliveryStatistics().getTotal(); + } + + public long getTotalDataDelivered() + { + return getVirtualHost().getDataDeliveryStatistics().getTotal(); + } + + public double getPeakMessageReceiptRate() + { + return getVirtualHost().getMessageReceiptStatistics().getPeak(); + } + + public double getPeakDataReceiptRate() + { + return getVirtualHost().getDataReceiptStatistics().getPeak(); + } + + public double getMessageReceiptRate() + { + return getVirtualHost().getMessageReceiptStatistics().getRate(); + } + + public double getDataReceiptRate() + { + return getVirtualHost().getDataReceiptStatistics().getRate(); + } + + public long getTotalMessagesReceived() + { + return getVirtualHost().getMessageReceiptStatistics().getTotal(); + } + + public long getTotalDataReceived() + { + return getVirtualHost().getDataReceiptStatistics().getTotal(); + } + + public boolean isStatisticsEnabled() + { + return getVirtualHost().isStatisticsEnabled(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 1c91de6d15..dd3046cd01 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -345,6 +345,9 @@ public class AMQChannel implements SessionConfig, AMQSessionModel } finally { + long bodySize = _currentMessage.getSize(); + long timestamp = ((BasicContentHeaderProperties) _currentMessage.getContentHeader().properties).getTimestamp(); + _session.registerMessageReceived(bodySize, timestamp); _currentMessage = null; } } @@ -1037,6 +1040,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), deliveryTag, sub.getConsumerTag()); + _session.registerMessageDelivered(entry.getMessage().getSize()); } }; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 71cf17ed60..9d3c4dd2e8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -320,8 +320,7 @@ public class Main ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); configMBean.register(); - ServerInformationMBean sysInfoMBean = - new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion()); + ServerInformationMBean sysInfoMBean = new ServerInformationMBean(config); sysInfoMBean.register(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 7197ec8cdc..43be0611a5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -767,6 +767,36 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa DEFAULT_HOUSEKEEPING_PERIOD)); } + public long getStatisticsSamplePeriod() + { + return getConfig().getLong("statistics.sample.period", 5000L); + } + + public boolean isStatisticsGenerationBrokerEnabled() + { + return getConfig().getBoolean("statistics.generation.broker", false); + } + + public boolean isStatisticsGenerationVirtualhostsEnabled() + { + return getConfig().getBoolean("statistics.generation.virtualhosts", false); + } + + public boolean isStatisticsGenerationConnectionsEnabled() + { + return getConfig().getBoolean("statistics.generation.connections", false); + } + + public long getStatisticsReportingPeriod() + { + return getConfig().getLong("statistics.reporting.period", 0L); + } + + public boolean isStatisticsReportResetEnabled() + { + return getConfig().getBoolean("statistics.reporting.reset", false); + } + public NetworkDriverConfiguration getNetworkConfiguration() { return new NetworkDriverConfiguration() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java index db2cc970b2..5e6a143d52 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java @@ -22,9 +22,11 @@ package org.apache.qpid.server.information.management; import java.io.IOException; +import org.apache.qpid.common.QpidProperties; import org.apache.qpid.management.common.mbeans.ServerInformation; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.registry.ApplicationRegistry; import javax.management.JMException; @@ -34,12 +36,15 @@ public class ServerInformationMBean extends AMQManagedObject implements ServerIn { private String buildVersion; private String productVersion; + private ApplicationRegistry registry; - public ServerInformationMBean(String buildVersion, String productVersion) throws JMException + public ServerInformationMBean(ApplicationRegistry applicationRegistry) throws JMException { super(ServerInformation.class, ServerInformation.TYPE); - this.buildVersion = buildVersion; - this.productVersion = productVersion; + + registry = applicationRegistry; + buildVersion = QpidProperties.getBuildVersion(); + productVersion = QpidProperties.getReleaseVersion(); } public String getObjectInstanceName() @@ -67,5 +72,75 @@ public class ServerInformationMBean extends AMQManagedObject implements ServerIn return productVersion; } + + public void resetStatistics() throws Exception + { + registry.resetStatistics(); + } + + public double getPeakMessageDeliveryRate() + { + return registry.getMessageDeliveryStatistics().getPeak(); + } + + public double getPeakDataDeliveryRate() + { + return registry.getDataDeliveryStatistics().getPeak(); + } + + public double getMessageDeliveryRate() + { + return registry.getMessageDeliveryStatistics().getRate(); + } + + public double getDataDeliveryRate() + { + return registry.getDataDeliveryStatistics().getRate(); + } + + public long getTotalMessagesDelivered() + { + return registry.getMessageDeliveryStatistics().getTotal(); + } + + public long getTotalDataDelivered() + { + return registry.getDataDeliveryStatistics().getTotal(); + } + + public double getPeakMessageReceiptRate() + { + return registry.getMessageReceiptStatistics().getPeak(); + } + + public double getPeakDataReceiptRate() + { + return registry.getDataReceiptStatistics().getPeak(); + } + + public double getMessageReceiptRate() + { + return registry.getMessageReceiptStatistics().getRate(); + } + + public double getDataReceiptRate() + { + return registry.getDataReceiptStatistics().getRate(); + } + + public long getTotalMessagesReceived() + { + return registry.getMessageReceiptStatistics().getTotal(); + } + + public long getTotalDataReceived() + { + return registry.getDataReceiptStatistics().getTotal(); + } + + public boolean isStatisticsEnabled() + { + return registry.isStatisticsEnabled(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties index 6b83a7e7a5..5d1e85fe41 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties @@ -32,4 +32,7 @@ STOPPED = BRK-1005 : Stopped # 0 - path CONFIG = BRK-1006 : Using configuration : {0} # 0 - path -LOG_CONFIG = BRK-1007 : Using logging configuration : {0} \ No newline at end of file +LOG_CONFIG = BRK-1007 : Using logging configuration : {0} + +STATS_DATA = BRK-1008 : {0,choice,0#delivered|1#received} : {1,number,#.###} kB/s peak : {2,number,#} bytes total +STATS_MSGS = BRK-1009 : {0,choice,0#delivered|1#received} : {1,number,#.###} msg/s peak : {2,number,#} msgs total \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties index 66bbefacb0..3e640c7929 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties @@ -20,4 +20,7 @@ # # 0 - name CREATED = VHT-1001 : Created : {0} -CLOSED = VHT-1002 : Closed \ No newline at end of file +CLOSED = VHT-1002 : Closed + +STATS_DATA = VHT-1003 : {0} : {1,choice,0#delivered|1#received} : {2,number,#.###} kB/s peak : {3,number,#} bytes total +STATS_MSGS = VHT-1004 : {0} : {1,choice,0#delivered|1#received} : {2,number,#.###} msg/s peak : {3,number,#} msgs total` \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java index 4ef84631b4..061ebf50cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java @@ -26,8 +26,9 @@ import java.util.UUID; import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.stats.StatisticsGatherer; -public interface AMQConnectionModel +public interface AMQConnectionModel extends StatisticsGatherer { /** * get a unique id for this connection. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index aef905772a..449f698c48 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -91,6 +91,7 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.NetworkDriver; @@ -171,6 +172,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private final UUID _id; private final ConfigStore _configStore; private long _createTime = System.currentTimeMillis(); + + private ApplicationRegistry _registry; + private boolean _statisticsEnabled = false; + private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; public ManagedObject getManagedObject() { @@ -194,9 +199,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _configStore = virtualHostRegistry.getConfigStore(); _id = _configStore.createId(); - _actor.message(ConnectionMessages.OPEN(null, null, false, false)); + _registry = virtualHostRegistry.getApplicationRegistry(); + initialiseStatistics(); } private AMQProtocolSessionMBean createMBean() throws JMException @@ -1282,5 +1288,74 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public LogSubject getLogSubject() { return _logSubject; - } + } + + public void registerMessageDelivered(long messageSize) + { + if (isStatisticsEnabled()) + { + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); + } + _virtualHost.registerMessageDelivered(messageSize); + } + + public void registerMessageReceived(long messageSize, long timestamp) + { + if (isStatisticsEnabled()) + { + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); + } + _virtualHost.registerMessageReceived(messageSize, timestamp); + } + + public StatisticsCounter getMessageReceiptStatistics() + { + return _messagesReceived; + } + + public StatisticsCounter getDataReceiptStatistics() + { + return _dataReceived; + } + + public StatisticsCounter getMessageDeliveryStatistics() + { + return _messagesDelivered; + } + + public StatisticsCounter getDataDeliveryStatistics() + { + return _dataDelivered; + } + + public void resetStatistics() + { + _messagesDelivered.reset(); + _dataDelivered.reset(); + _messagesReceived.reset(); + _dataReceived.reset(); + } + + public void initialiseStatistics() + { + setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && + _registry.getConfiguration().isStatisticsGenerationConnectionsEnabled()); + + _messagesDelivered = new StatisticsCounter("messages-delivered-" + getSessionID()); + _dataDelivered = new StatisticsCounter("data-delivered-" + getSessionID()); + _messagesReceived = new StatisticsCounter("messages-received-" + getSessionID()); + _dataReceived = new StatisticsCounter("data-received-" + getSessionID()); + } + + public boolean isStatisticsEnabled() + { + return _statisticsEnabled; + } + + public void setStatisticsEnabled(boolean enabled) + { + _statisticsEnabled = enabled; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 9d0d63b18e..fcac78fafa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,19 +37,8 @@ */ package org.apache.qpid.server.protocol; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; +import java.util.Date; +import java.util.List; import javax.management.JMException; import javax.management.MBeanException; @@ -67,8 +56,20 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import java.util.Date; -import java.util.List; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; /** * This MBean class implements the management interface. In order to make more attributes, operations and notifications @@ -339,4 +340,78 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed _broadcaster.sendNotification(n); } -} // End of MBean class + public void resetStatistics() throws Exception + { + _protocolSession.resetStatistics(); + } + + public double getPeakMessageDeliveryRate() + { + return _protocolSession.getMessageDeliveryStatistics().getPeak(); + } + + public double getPeakDataDeliveryRate() + { + return _protocolSession.getDataDeliveryStatistics().getPeak(); + } + + public double getMessageDeliveryRate() + { + return _protocolSession.getMessageDeliveryStatistics().getRate(); + } + + public double getDataDeliveryRate() + { + return _protocolSession.getDataDeliveryStatistics().getRate(); + } + + public long getTotalMessagesDelivered() + { + return _protocolSession.getMessageDeliveryStatistics().getTotal(); + } + + public long getTotalDataDelivered() + { + return _protocolSession.getDataDeliveryStatistics().getTotal(); + } + + public double getPeakMessageReceiptRate() + { + return _protocolSession.getMessageReceiptStatistics().getPeak(); + } + + public double getPeakDataReceiptRate() + { + return _protocolSession.getDataReceiptStatistics().getPeak(); + } + + public double getMessageReceiptRate() + { + return _protocolSession.getMessageReceiptStatistics().getRate(); + } + + public double getDataReceiptRate() + { + return _protocolSession.getDataReceiptStatistics().getRate(); + } + + public long getTotalMessagesReceived() + { + return _protocolSession.getMessageReceiptStatistics().getTotal(); + } + + public long getTotalDataReceived() + { + return _protocolSession.getDataReceiptStatistics().getTotal(); + } + + public boolean isStatisticsEnabled() + { + return _protocolSession.isStatisticsEnabled(); + } + + public void setStatisticsEnabled(boolean enabled) + { + _protocolSession.setStatisticsEnabled(enabled); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 78a642f22f..72b2a68450 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.registry; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.UUID; import org.apache.commons.configuration.ConfigurationException; @@ -41,11 +43,12 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.CompositeStartupMessageLogger; import org.apache.qpid.server.logging.Log4jMessageLogger; import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.AbstractRootMessageLogger; import org.apache.qpid.server.logging.SystemOutMessageLogger; +import org.apache.qpid.server.logging.actors.AbstractActor; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -54,6 +57,7 @@ import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalD import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostImpl; @@ -104,6 +108,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private ConfigStore _configStore; protected String _registryName; + + private Timer _reportingTimer; + private boolean _statisticsEnabled = false; + private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; static { @@ -294,6 +302,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { initialiseVirtualHosts(); + initialiseStatistics(); + initialiseStatisticsReporting(); } finally { @@ -320,6 +330,72 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _managedObjectRegistry = new NoopManagedObjectRegistry(); } + + public void initialiseStatisticsReporting() + { + long report = _configuration.getStatisticsReportingPeriod() * 1000; // convert to ms + final boolean broker = _configuration.isStatisticsGenerationBrokerEnabled(); + final boolean virtualhost = _configuration.isStatisticsGenerationVirtualhostsEnabled(); + final boolean reset = _configuration.isStatisticsReportResetEnabled(); + + /* add a timer task to report statistics if generation is enabled for broker or virtualhosts */ + if (report > 0L && (broker || virtualhost)) + { + _reportingTimer = new Timer("Statistics-Reporting", true); + + class StatisticsReportingTask extends TimerTask + { + private final int DELIVERED = 0; + private final int RECEIVED = 1; + + public void run() + { + CurrentActor.set(new AbstractActor(ApplicationRegistry.getInstance().getRootMessageLogger()) { + public String getLogMessage() + { + return "[" + Thread.currentThread().getName() + "] "; + } + }); + + if (broker) + { + CurrentActor.get().message(BrokerMessages.STATS_DATA(DELIVERED, _dataDelivered.getPeak() / 1024.0, _dataDelivered.getTotal())); + CurrentActor.get().message(BrokerMessages.STATS_MSGS(DELIVERED, _messagesDelivered.getPeak(), _messagesDelivered.getTotal())); + CurrentActor.get().message(BrokerMessages.STATS_DATA(RECEIVED, _dataReceived.getPeak() / 1024.0, _dataReceived.getTotal())); + CurrentActor.get().message(BrokerMessages.STATS_MSGS(RECEIVED, _messagesReceived.getPeak(), _messagesReceived.getTotal())); + } + + if (virtualhost) + { + for (VirtualHost vhost : getVirtualHostRegistry().getVirtualHosts()) + { + String name = vhost.getName(); + StatisticsCounter dataDelivered = vhost.getDataDeliveryStatistics(); + StatisticsCounter messagesDelivered = vhost.getMessageDeliveryStatistics(); + StatisticsCounter dataReceived = vhost.getDataReceiptStatistics(); + StatisticsCounter messagesReceived = vhost.getMessageReceiptStatistics(); + + CurrentActor.get().message(VirtualHostMessages.STATS_DATA(name, DELIVERED, dataDelivered.getPeak() / 1024.0, dataDelivered.getTotal())); + CurrentActor.get().message(VirtualHostMessages.STATS_MSGS(name, DELIVERED, messagesDelivered.getPeak(), messagesDelivered.getTotal())); + CurrentActor.get().message(VirtualHostMessages.STATS_DATA(name, RECEIVED, dataReceived.getPeak() / 1024.0, dataReceived.getTotal())); + CurrentActor.get().message(VirtualHostMessages.STATS_MSGS(name, RECEIVED, messagesReceived.getPeak(), messagesReceived.getTotal())); + } + } + + if (reset) + { + resetStatistics(); + } + + CurrentActor.remove(); + } + } + + _reportingTimer.scheduleAtFixedRate(new StatisticsReportingTask(), + report / 2, + report); + } + } public static IApplicationRegistry getInstance() { @@ -369,6 +445,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _logger.info("Shutting down ApplicationRegistry:" + this); } + + //Stop Statistics Reporting + if (_reportingTimer != null) + { + _reportingTimer.cancel(); + } //Stop incoming connections unbind(); @@ -498,4 +580,76 @@ public abstract class ApplicationRegistry implements IApplicationRegistry getBroker().addVirtualHost(virtualHost); return virtualHost; } + + public void registerMessageDelivered(long messageSize) + { + if (isStatisticsEnabled()) + { + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); + } + } + + public void registerMessageReceived(long messageSize, long timestamp) + { + if (isStatisticsEnabled()) + { + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); + } + } + + public StatisticsCounter getMessageReceiptStatistics() + { + return _messagesReceived; + } + + public StatisticsCounter getDataReceiptStatistics() + { + return _dataReceived; + } + + public StatisticsCounter getMessageDeliveryStatistics() + { + return _messagesDelivered; + } + + public StatisticsCounter getDataDeliveryStatistics() + { + return _dataDelivered; + } + + public void resetStatistics() + { + _messagesDelivered.reset(); + _dataDelivered.reset(); + _messagesReceived.reset(); + _dataReceived.reset(); + + for (VirtualHost vhost : _virtualHostRegistry.getVirtualHosts()) + { + vhost.resetStatistics(); + } + } + + public void initialiseStatistics() + { + setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && + getConfiguration().isStatisticsGenerationBrokerEnabled()); + + _messagesDelivered = new StatisticsCounter("messages-delivered"); + _dataDelivered = new StatisticsCounter("bytes-delivered"); + _messagesReceived = new StatisticsCounter("messages-received"); + _dataReceived = new StatisticsCounter("bytes-received"); + } + + public boolean isStatisticsEnabled() + { + return _statisticsEnabled; + } + + public void setStatisticsEnabled(boolean enabled) + { + _statisticsEnabled = enabled; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 228c3b9112..0ef55097ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -35,11 +35,12 @@ import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.stats.StatisticsGatherer; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -public interface IApplicationRegistry +public interface IApplicationRegistry extends StatisticsGatherer { /** * Initialise the application registry. All initialisation must be done in this method so that any components @@ -97,4 +98,6 @@ public interface IApplicationRegistry ConfigStore getConfigStore(); void setConfigStore(ConfigStore store); + + void initialiseStatisticsReporting(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java new file mode 100644 index 0000000000..b732121180 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.stats; + +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class collects statistics and counts the total, rate per second and + * peak rate per second values for the events that are registered with it. + */ +public class StatisticsCounter +{ + private static final Logger _log = LoggerFactory.getLogger(StatisticsCounter.class); + + public static final long DEFAULT_SAMPLE_PERIOD = Long.getLong("qpid.statistics.samplePeriod", 2000L); // 2s + public static final boolean DISABLE_STATISTICS = Boolean.getBoolean("qpid.statistics.disable"); + + private static final String COUNTER = "counter"; + private static final AtomicLong _counterIds = new AtomicLong(0L); + + private long _peak = 0L; + private long _total = 0L; + private long _temp = 0L; + private long _last = 0L; + private long _rate = 0L; + + private long _start; + + private final long _period; + private final String _name; + + public StatisticsCounter() + { + this(COUNTER); + } + + public StatisticsCounter(String name) + { + this(name, DEFAULT_SAMPLE_PERIOD); + } + + public StatisticsCounter(String name, long period) + { + _period = period; + _name = name + "-" + + _counterIds.incrementAndGet(); + reset(); + } + + public void registerEvent() + { + registerEvent(1L); + } + + public void registerEvent(long value) + { + registerEvent(value, System.currentTimeMillis()); + } + + public void registerEvent(long value, long timestamp) + { + if (DISABLE_STATISTICS) + { + return; + } + + long thisSample = (timestamp / _period); + synchronized (this) + { + if (thisSample > _last) + { + _last = thisSample; + _rate = _temp; + _temp = 0L; + if (_rate > _peak) + { + _peak = _rate; + } + } + + _total += value; + _temp += value; + } + } + + /** + * Update the current rate and peak - may reset rate to zero if a new + * sample period has started. + */ + private void update() + { + registerEvent(0L, System.currentTimeMillis()); + } + + /** + * Reset + */ + public void reset() + { + _log.info("Resetting statistics for counter: " + _name); + _peak = 0L; + _rate = 0L; + _total = 0L; + _start = System.currentTimeMillis(); + _last = _start / _period; + } + + public double getPeak() + { + update(); + return (double) _peak / ((double) _period / 1000.0d); + } + + public double getRate() + { + update(); + return (double) _rate / ((double) _period / 1000.0d); + } + + public long getTotal() + { + return _total; + } + + public long getStart() + { + return _start; + } + + public Date getStartTime() + { + return new Date(_start); + } + + public String getName() + { + return _name; + } + + public long getPeriod() + { + return _period; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java new file mode 100644 index 0000000000..36fec4025a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.stats; + +/** + * This interface is to be implemented by any broker business object that + * wishes to gather statistics about messages delivered through it. + * + * These statistics are exposed using a separate JMX Mbean interface, which + * calls these methods to retrieve the underlying {@link StatisticsCounter}s + * and return their attributes. This interface gives a standard way for + * parts of the broker to set up and configure statistics generation. + *

      + * When creating these objects, there should be a parent/child relationship + * between them, such that the lowest level gatherer can record staticics if + * enabled, and pass on the notification to the parent object to allow higher + * level aggregation. When resetting statistics, this works in the opposite + * direction, with higher level gatherers also resetting all of their children. + */ +public interface StatisticsGatherer +{ + /** + * Initialise the statistics gathering for this object. + * + * This method is responsible for creating any {@link StatisticsCounter} + * objects and for determining whether statistics generation should be + * enabled, by checking broker and system configuration. + * + * @see StatisticsCounter#DISABLE_STATISTICS + */ + void initialiseStatistics(); + + /** + * This method is responsible for registering the receipt of a message + * with the counters, and also for passing this notification to any parent + * {@link StatisticsGatherer}s. If statistics generation is not enabled, + * then this method should simple delegate to the parent gatherer. + * + * @param messageSize the size in bytes of the delivered message + * @param timestamp the time the message was delivered + */ + void registerMessageReceived(long messageSize, long timestamp); + + /** + * This method is responsible for registering the delivery of a message + * with the counters. Message delivery is recorded by the counter using + * the current system time, as opposed to the message timestamp. + * + * @param messageSize the size in bytes of the delivered message + * @see #registerMessageReceived(long, long) + */ + void registerMessageDelivered(long messageSize); + + /** + * Gives access to the {@link StatisticsCounter} that is used to count + * delivered message statistics. + * + * @return the {@link StatisticsCounter} that counts delivered messages + */ + StatisticsCounter getMessageDeliveryStatistics(); + + /** + * Gives access to the {@link StatisticsCounter} that is used to count + * received message statistics. + * + * @return the {@link StatisticsCounter} that counts received messages + */ + StatisticsCounter getMessageReceiptStatistics(); + + /** + * Gives access to the {@link StatisticsCounter} that is used to count + * delivered message size statistics. + * + * @return the {@link StatisticsCounter} that counts delivered bytes + */ + StatisticsCounter getDataDeliveryStatistics(); + + /** + * Gives access to the {@link StatisticsCounter} that is used to count + * received message size statistics. + * + * @return the {@link StatisticsCounter} that counts received bytes + */ + StatisticsCounter getDataReceiptStatistics(); + + /** + * Reset the counters for this, and any child {@link StatisticsGatherer}s. + */ + void resetStatistics(); + + /** + * Check if this object has statistics generation enabled. + * + * @return true if statistics generation is enabled + */ + boolean isStatisticsEnabled(); + + /** + * Enable or disable statistics generation for this object. + */ + void setStatisticsEnabled(boolean enabled); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index e635ad0188..75bd50e3a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -38,6 +38,8 @@ import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.ConnectionCloseCode; @@ -54,6 +56,10 @@ public class ServerConnection extends Connection implements AMQConnectionModel, private AtomicBoolean _logClosed = new AtomicBoolean(false); private LogActor _actor = GenericActor.getInstance(this); + private ApplicationRegistry _registry; + private boolean _statisticsEnabled = false; + private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; + public ServerConnection() { @@ -121,6 +127,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel, { _virtualHost = virtualHost; _virtualHost.getConnectionRegistry().registerConnection(this); + + initialiseStatistics(); } public void setConnectionConfig(final ConnectionConfig config) @@ -258,4 +266,73 @@ public class ServerConnection extends Connection implements AMQConnectionModel, } return sessions; } + + public void registerMessageDelivered(long messageSize) + { + if (isStatisticsEnabled()) + { + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); + } + _virtualHost.registerMessageDelivered(messageSize); + } + + public void registerMessageReceived(long messageSize, long timestamp) + { + if (isStatisticsEnabled()) + { + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); + } + _virtualHost.registerMessageReceived(messageSize, timestamp); + } + + public StatisticsCounter getMessageReceiptStatistics() + { + return _messagesReceived; + } + + public StatisticsCounter getDataReceiptStatistics() + { + return _dataReceived; + } + + public StatisticsCounter getMessageDeliveryStatistics() + { + return _messagesDelivered; + } + + public StatisticsCounter getDataDeliveryStatistics() + { + return _dataDelivered; + } + + public void resetStatistics() + { + _messagesDelivered.reset(); + _dataDelivered.reset(); + _messagesReceived.reset(); + _dataReceived.reset(); + } + + public void initialiseStatistics() + { + setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && + _virtualHost.getApplicationRegistry().getConfiguration().isStatisticsGenerationConnectionsEnabled()); + + _messagesDelivered = new StatisticsCounter("messages-delivered-" + getConnectionId()); + _dataDelivered = new StatisticsCounter("data-delivered-" + getConnectionId()); + _messagesReceived = new StatisticsCounter("messages-received-" + getConnectionId()); + _dataReceived = new StatisticsCounter("data-received-" + getConnectionId()); + } + + public boolean isStatisticsEnabled() + { + return _statisticsEnabled; + } + + public void setStatisticsEnabled(boolean enabled) + { + _statisticsEnabled = enabled; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index fb27dec949..174dcbfa69 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -20,26 +20,28 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.transport.*; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.GenericActor; -import org.apache.qpid.common.ClientProperties; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import java.util.*; +import org.apache.qpid.transport.*; public class ServerConnectionDelegate extends ServerDelegate { private String _localFQDN; private final IApplicationRegistry _appRegistry; - public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN) { this(new HashMap(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 714b2aa61f..60c94b43c0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -166,6 +166,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo public void enqueue(final ServerMessage message, final ArrayList queues) { + getConnectionModel().registerMessageReceived(message.getSize(), message.getArrivalTime()); _transaction.enqueue(queues,message, new ServerTransaction.Action() { @@ -202,6 +203,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo Runnable postIdSettingAction) { invoke(xfr, postIdSettingAction); + getConnectionModel().registerMessageDelivered(xfr.getBodySize()); } public void onMessageDispositionChange(MessageTransfer xfr, MessageDispositionChangeListener acceptListener) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 4ed0507228..04f19b79bb 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,30 +20,28 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.UUID; + import org.apache.qpid.common.Closeable; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.VirtualHostConfig; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.federation.BrokerLink; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfig; -import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.binding.BindingFactory; - -import java.util.List; -import java.util.UUID; -import java.util.TimerTask; -import java.util.concurrent.FutureTask; +import org.apache.qpid.server.stats.StatisticsGatherer; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.TransactionLog; -public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable +public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable, StatisticsGatherer { IConnectionRegistry getConnectionRegistry(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index a1566917dd..5374a56f06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -73,6 +73,7 @@ import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; @@ -112,6 +113,8 @@ public class VirtualHostImpl implements VirtualHost private BrokerConfig _broker; private UUID _id; + private boolean _statisticsEnabled = false; + private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private final long _createTime = System.currentTimeMillis(); private final ConcurrentHashMap _links = new ConcurrentHashMap(); @@ -250,6 +253,8 @@ public class VirtualHostImpl implements VirtualHost _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); + + initialiseStatistics(); } private void initialiseHouseKeeping(long period) @@ -639,6 +644,80 @@ public class VirtualHostImpl implements VirtualHost { return _bindingFactory; } + + public void registerMessageDelivered(long messageSize) + { + if (isStatisticsEnabled()) + { + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); + } + _appRegistry.registerMessageDelivered(messageSize); + } + + public void registerMessageReceived(long messageSize, long timestamp) + { + if (isStatisticsEnabled()) + { + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); + } + _appRegistry.registerMessageReceived(messageSize, timestamp); + } + + public StatisticsCounter getMessageReceiptStatistics() + { + return _messagesReceived; + } + + public StatisticsCounter getDataReceiptStatistics() + { + return _dataReceived; + } + + public StatisticsCounter getMessageDeliveryStatistics() + { + return _messagesDelivered; + } + + public StatisticsCounter getDataDeliveryStatistics() + { + return _dataDelivered; + } + + public void resetStatistics() + { + _messagesDelivered.reset(); + _dataDelivered.reset(); + _messagesReceived.reset(); + _dataReceived.reset(); + + for (AMQConnectionModel connection : _connectionRegistry.getConnections()) + { + connection.resetStatistics(); + } + } + + public void initialiseStatistics() + { + setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && + _appRegistry.getConfiguration().isStatisticsGenerationVirtualhostsEnabled()); + + _messagesDelivered = new StatisticsCounter("messages-delivered-" + getName()); + _dataDelivered = new StatisticsCounter("bytes-delivered-" + getName()); + _messagesReceived = new StatisticsCounter("messages-received-" + getName()); + _dataReceived = new StatisticsCounter("bytes-received-" + getName()); + } + + public boolean isStatisticsEnabled() + { + return _statisticsEnabled; + } + + public void setStatisticsEnabled(boolean enabled) + { + _statisticsEnabled = enabled; + } public void createBrokerConnection(final String transport, final String host, -- cgit v1.2.1 From e135de42dc525a8da132ba20b32d0ddc31e44946 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 27 Mar 2011 21:31:32 +0000 Subject: QPID-3165: ensure all subscriptions are checked before making the decision on whether to stop delivering. Use a boolean instead of doing a 0/1 toggle and update variables to generally clarify logic. Use an int instead of a long for the iteration decrementing git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1086040 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/server/queue/SimpleAMQQueue.java | 91 ++++++++++++++++------ 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index b003152db6..0e3f7b2625 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1808,14 +1808,40 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + /** + * Used by queue Runners to asynchronously deliver messages to consumers. + * + * A queue Runner is started whenever a state change occurs, e.g when a new + * message arrives on the queue and cannot be immediately delivered to a + * subscription (i.e. asynchronous delivery is required). Unless there are + * SubFlushRunners operating (due to subscriptions unsuspending) which are + * capable of accepting/delivering all messages then these messages would + * otherwise remain on the queue. + * + * processQueue should be running while there are messages on the queue AND + * there are subscriptions that can deliver them. If there are no + * subscriptions capable of delivering the remaining messages on the queue + * then processQueue should stop to prevent spinning. + * + * Since processQueue is runs in a fixed size Executor, it should not run + * indefinitely to prevent starving other tasks of CPU (e.g jobs to process + * incoming messages may not be able to be scheduled in the thread pool + * because all threads are working on clearing down large queues). To solve + * this problem, after an arbitrary number of message deliveries the + * processQueue job stops iterating, resubmits itself to the executor, and + * ends the current instance + * + * @param runner the Runner to schedule + * @throws AMQException + */ private void processQueue(Runnable runner) throws AMQException { long stateChangeCount; long previousStateChangeCount = Long.MIN_VALUE; boolean deliveryIncomplete = true; - int extraLoops = 1; - long iterations = MAX_ASYNC_DELIVERIES; + boolean lastLoop = false; + int iterations = MAX_ASYNC_DELIVERIES; _asynchronousRunner.compareAndSet(runner, null); @@ -1832,12 +1858,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (previousStateChangeCount != stateChangeCount) { - extraLoops = 1; + //further asynchronous delivery is required since the + //previous loop. keep going if iteration slicing allows. + lastLoop = false; } previousStateChangeCount = stateChangeCount; - deliveryIncomplete = _subscriptionList.size() != 0; - boolean done; + boolean allSubscriptionsDone = true; + boolean subscriptionDone; SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); //iterate over the subscribers and try to advance their pointer @@ -1847,30 +1875,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.getSendLock(); try { - - done = attemptDelivery(sub); - - if (done) + //attempt delivery. returns true if no further delivery currently possible to this sub + subscriptionDone = attemptDelivery(sub); + if (subscriptionDone) { - if (extraLoops == 0) + //close autoClose subscriptions if we are not currently intent on continuing + if (lastLoop && sub.isAutoClose()) { - deliveryIncomplete = false; - if (sub.isAutoClose()) - { - unregisterSubscription(sub); + unregisterSubscription(sub); - sub.confirmAutoClose(); - } - } - else - { - extraLoops--; + sub.confirmAutoClose(); } } else { + //this subscription can accept additional deliveries, so we must + //keep going after this (if iteration slicing allows it) + allSubscriptionsDone = false; + lastLoop = false; iterations--; - extraLoops = 1; } } finally @@ -1878,10 +1901,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.releaseSendLock(); } } + + if(allSubscriptionsDone && lastLoop) + { + //We have done an extra loop already and there are again + //again no further delivery attempts possible, only + //keep going if state change demands it. + deliveryIncomplete = false; + } + else if(allSubscriptionsDone) + { + //All subscriptions reported being done, but we have to do + //an extra loop if the iterations are not exhausted and + //there is still any work to be done + deliveryIncomplete = _subscriptionList.size() != 0; + lastLoop = true; + } + else + { + //some subscriptions can still accept more messages, + //keep going if iteration count allows. + lastLoop = false; + deliveryIncomplete = true; + } + _asynchronousRunner.set(null); } - // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit + // If iterations == 0 then the limiting factor was the time-slicing rather than available messages or credit // therefore we should schedule this runner again (unless someone beats us to it :-) ). if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner)) { -- cgit v1.2.1 From 2c0724ea3c4fe95276320a071469eaba870fdf51 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Sun, 27 Mar 2011 21:32:02 +0000 Subject: QPID-3162: move unregistration of ServerConnections from the ConnectionRegistry into the setState() method to ensure it occurs in all cases. Also move registration into setState(). git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1086041 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/transport/ServerConnection.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 75bd50e3a2..54cd709af3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -88,8 +88,18 @@ public class ServerConnection extends Connection implements AMQConnectionModel, _onOpenTask.run(); } _actor.message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true)); + + getVirtualHost().getConnectionRegistry().registerConnection(this); } - + + if (state == State.CLOSE_RCVD || state == State.CLOSED || state == State.CLOSING) + { + if(_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + } + if (state == State.CLOSED) { logClosed(); @@ -126,7 +136,6 @@ public class ServerConnection extends Connection implements AMQConnectionModel, public void setVirtualHost(VirtualHost virtualHost) { _virtualHost = virtualHost; - _virtualHost.getConnectionRegistry().registerConnection(this); initialiseStatistics(); } @@ -253,7 +262,6 @@ public class ServerConnection extends Connection implements AMQConnectionModel, // Ignore } close(replyCode, message); - getVirtualHost().getConnectionRegistry().deregisterConnection(this); } @Override -- cgit v1.2.1 From 49d7dad9c00ff89ebfb61c5ce66c2e4300ccd846 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 30 Mar 2011 16:01:23 +0000 Subject: QPID-3167: add a unit test of SimpleAMQQueue#processQueue to check delivery when subscriptions with unique selectors are in use git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1087000 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 6 +- .../server/message/ContentHeaderBodyAdapter.java | 2 +- .../qpid/server/message/MessageMetaData.java | 4 +- .../apache/qpid/server/queue/AMQQueueMBean.java | 2 +- .../apache/qpid/server/queue/IncomingMessage.java | 8 +-- .../org/apache/qpid/server/queue/QueueRunner.java | 79 ++++++++++++++++++++++ .../apache/qpid/server/queue/SimpleAMQQueue.java | 55 ++------------- .../server/subscription/Subscription_0_10.java | 2 +- .../qpid/tools/messagestore/commands/Show.java | 2 +- 9 files changed, 99 insertions(+), 61 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index dd3046cd01..08eb05680c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -346,7 +346,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel finally { long bodySize = _currentMessage.getSize(); - long timestamp = ((BasicContentHeaderProperties) _currentMessage.getContentHeader().properties).getTimestamp(); + long timestamp = ((BasicContentHeaderProperties) _currentMessage.getContentHeader().getProperties()).getTimestamp(); _session.registerMessageReceived(bodySize, timestamp); _currentMessage = null; } @@ -1079,8 +1079,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel private boolean checkMessageUserId(ContentHeaderBody header) { AMQShortString userID = - header.properties instanceof BasicContentHeaderProperties - ? ((BasicContentHeaderProperties) header.properties).getUserId() + header.getProperties() instanceof BasicContentHeaderProperties + ? ((BasicContentHeaderProperties) header.getProperties()).getUserId() : null; return (!MSG_AUTH || _session.getPrincipal().getName().equals(userID == null? "" : userID.toString())); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java index 194835ac02..84a1642578 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -37,7 +37,7 @@ public class ContentHeaderBodyAdapter implements AMQMessageHeader private BasicContentHeaderProperties getProperties() { - return (BasicContentHeaderProperties) _contentHeaderBody.properties; + return (BasicContentHeaderProperties) _contentHeaderBody.getProperties(); } public String getCorrelationId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java index 30bea7b6e6..66cb7ed83b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -161,7 +161,7 @@ public class MessageMetaData implements StorableMessageMetaData public boolean isPersistent() { - BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.getProperties()); return properties.getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; } @@ -229,7 +229,7 @@ public class MessageMetaData implements StorableMessageMetaData { private BasicContentHeaderProperties getProperties() { - return (BasicContentHeaderProperties) getContentHeaderBody().properties; + return (BasicContentHeaderProperties) getContentHeaderBody().getProperties(); } public String getCorrelationId() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index 77c4e8fc23..c8eb118b11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -507,7 +507,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) { List list = new ArrayList(); - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.properties; + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.getProperties(); list.add("reply-to = " + headerProperties.getReplyToAsString()); list.add("propertyFlags = " + headerProperties.getPropertyFlags()); list.add("ApplicationID = " + headerProperties.getAppIdAsString()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index 2d2fb3a214..3e3288404f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -96,9 +96,9 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes public void setExpiration() { long expiration = - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getExpiration(); + ((BasicContentHeaderProperties) _contentHeaderBody.getProperties()).getExpiration(); long timestamp = - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getTimestamp(); + ((BasicContentHeaderProperties) _contentHeaderBody.getProperties()).getTimestamp(); if (SYNCHED_CLOCKS) { @@ -193,8 +193,8 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes public boolean isPersistent() { - return getContentHeader().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeader().properties).getDeliveryMode() == + return getContentHeader().getProperties() instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) getContentHeader().getProperties()).getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java new file mode 100644 index 0000000000..44b7c95535 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.queue.QueueRunner; +import org.apache.qpid.server.queue.SimpleAMQQueue; + + +public class QueueRunner implements ReadWriteRunnable +{ + private static final Logger _logger = Logger.getLogger(QueueRunner.class); + + private String _name; + private SimpleAMQQueue _queue; + + public QueueRunner(SimpleAMQQueue queue, long count) + { + _queue = queue; + _name = "QueueRunner-" + count + "-" + queue.getLogActor(); + } + + public void run() + { + String originalName = Thread.currentThread().getName(); + try + { + Thread.currentThread().setName(_name); + CurrentActor.set(_queue.getLogActor()); + + _queue.processQueue(this); + } + catch (AMQException e) + { + _logger.error(e); + } + finally + { + CurrentActor.remove(); + Thread.currentThread().setName(originalName); + } + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } + + public String toString() + { + return _name; + } +} \ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 0e3f7b2625..4890c00047 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1585,7 +1585,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void deliverAsync() { - Runner runner = new Runner(_stateChangeCount.incrementAndGet()); + QueueRunner runner = new QueueRunner(this, _stateChangeCount.incrementAndGet()); if (_asynchronousRunner.compareAndSet(null, runner)) { @@ -1604,52 +1604,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery.execute(flusher); } - - private class Runner implements ReadWriteRunnable - { - String _name; - public Runner(long count) - { - _name = "QueueRunner-" + count + "-" + _logActor; - } - - public void run() - { - String originalName = Thread.currentThread().getName(); - try - { - Thread.currentThread().setName(_name); - CurrentActor.set(_logActor); - - processQueue(this); - } - catch (AMQException e) - { - _logger.error(e); - } - finally - { - CurrentActor.remove(); - Thread.currentThread().setName(originalName); - } - } - - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - - public String toString() - { - return _name; - } - } - public void flushSubscription(Subscription sub) throws AMQException { // Access control @@ -1834,7 +1788,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener * @param runner the Runner to schedule * @throws AMQException */ - private void processQueue(Runnable runner) throws AMQException + public void processQueue(QueueRunner runner) throws AMQException { long stateChangeCount; long previousStateChangeCount = Long.MIN_VALUE; @@ -2289,4 +2243,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } } + + public LogActor getLogActor() + { + return _logActor; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index a20436f029..68e47fd86a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -441,7 +441,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr Struct[] headers = new Struct[] { deliveryProps, messageProps }; BasicContentHeaderProperties properties = - (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().properties; + (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().getProperties(); final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange(); if(exchange != null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index 4fd4999b19..806e161bbc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -364,7 +364,7 @@ public class Show extends AbstractCommand { if(msg instanceof AMQMessage) { - headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().properties); + headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().getProperties()); } } catch (AMQException e) -- cgit v1.2.1 From 0829f289a465c74904144191a11d77c1a132a416 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 31 Mar 2011 10:59:14 +0000 Subject: QPID-3158 - Defect in the CRAM-MD5-HEX mechanism - CRAMMD5HexInitialiser fails to pad bytes in range 0A-0F with leading zero. Add testcase to test CRAM-MD5-HEX mechanism. Guard against nulls in SASL SaslServerFactory.getMechanismNames implementations to avoid dependency on mechanism registration order. Applied patch from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1087249 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java | 7 ++++--- .../security/auth/sasl/anonymous/AnonymousSaslServerFactory.java | 9 +++++---- .../server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java | 2 +- .../server/security/auth/sasl/plain/PlainSaslServerFactory.java | 7 ++++--- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java index 67d20136bf..17d123eb0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java @@ -45,9 +45,10 @@ public class AmqPlainSaslServerFactory implements SaslServerFactory public String[] getMechanismNames(Map props) { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) + if (props != null && + (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]; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java index 6032255870..8a5ff7df2d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java @@ -47,10 +47,11 @@ public class AnonymousSaslServerFactory implements SaslServerFactory public String[] getMechanismNames(Map props) { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE) || - props.containsKey(Sasl.POLICY_NOANONYMOUS)) + if (props != null && + (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE) || + props.containsKey(Sasl.POLICY_NOANONYMOUS))) { // returned array must be non null according to interface documentation return new String[0]; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java index 8020d97364..139818735f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java @@ -70,7 +70,7 @@ public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser for (char c : password) { //toHexString does not prepend 0 so we have to - if (((byte) c > -1) && (byte) c < 10) + if (((byte) c > -1) && (byte) c < 0x10 ) { sb.append(0); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java index f0dd9eeb6d..3144bfbce6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -45,9 +45,10 @@ public class PlainSaslServerFactory implements SaslServerFactory public String[] getMechanismNames(Map props) { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) + if (props != null && + (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]; -- cgit v1.2.1 From 7b959d850841538083e0ac1617db14e9b6c0d976 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 4 Apr 2011 11:32:50 +0000 Subject: QPID-3164 - Remove dead methods SimpleAMQQueue.requeue(QueueEntryImpl, Subscription) and QueueEntryImpl.requeue(QueueEntryImp, Subscription subscription). SimpleAMQQueue.requeue(QueueEntryImpl, Subscription) was last used from SubscriptionImpl.java, but this was removed on 2009-10-25. Applied patch from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1088561 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/queue/AMQQueue.java | 10 ---------- .../java/org/apache/qpid/server/queue/QueueEntry.java | 2 -- .../org/apache/qpid/server/queue/QueueEntryImpl.java | 9 --------- .../org/apache/qpid/server/queue/SimpleAMQQueue.java | 18 ------------------ 4 files changed, 39 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index de9dc42de8..9b9de8333b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,16 +21,13 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.QueueConfig; -import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.management.Managable; @@ -108,23 +105,16 @@ public interface AMQQueue extends Managable, Comparable, ExchangeRefer boolean isDeleted(); - int delete() throws AMQException; - void requeue(QueueEntry entry); - void requeue(QueueEntryImpl storeContext, Subscription subscription); - void dequeue(QueueEntry entry, Subscription sub); void decrementUnackedMsgCount(); - boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - - void addQueueDeleteTask(final Task task); void removeQueueDeleteTask(final Task task); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index edd1e0bdc3..79ede2694e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -195,8 +195,6 @@ public interface QueueEntry extends Comparable, Filterable boolean isRejectedBy(Subscription subscription); - void requeue(Subscription subscription); - void dequeue(); void dispose(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 1ba4f4d89b..809ba3277e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -358,15 +358,6 @@ public class QueueEntryImpl implements QueueEntry } } - public void requeue(Subscription subscription) - { - getQueue().requeue(this, subscription); - if(_stateChangeListeners != null) - { - notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); - } - } - public void dequeue() { EntryState state = _state; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 4890c00047..b02d03a1ad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -805,24 +805,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void requeue(QueueEntryImpl entry, Subscription subscription) - { - SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); - // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards - while (subscriberIter.advance()) - { - Subscription sub = subscriberIter.getNode().getSubscription(); - - // we don't make browsers send the same stuff twice - if (sub.seesRequeues() && (!sub.acquires() && sub == subscription)) - { - updateSubRequeueEntry(sub, entry); - } - } - - deliverAsync(); - } - public void dequeue(QueueEntry entry, Subscription sub) { decrementQueueCount(); -- cgit v1.2.1 From a9bec14623229056fc983934da71d046cabfc1ec Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 4 Apr 2011 14:35:59 +0000 Subject: QPID-3183: some minor improvements to the recently seperated QueueRunner class, based on review feedback from Keith Wall for QPID-3167 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1088639 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/server/queue/QueueRunner.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java index 44b7c95535..7e1d57e205 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java @@ -27,13 +27,18 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.queue.QueueRunner; import org.apache.qpid.server.queue.SimpleAMQQueue; - +/** + * QueueRunners are Runnables used to process a queue when requiring + * asynchronous message delivery to subscriptions, which is necessary + * when straight-through delivery of a message to a subscription isn't + * possible during the enqueue operation. + */ public class QueueRunner implements ReadWriteRunnable { private static final Logger _logger = Logger.getLogger(QueueRunner.class); - private String _name; - private SimpleAMQQueue _queue; + private final String _name; + private final SimpleAMQQueue _queue; public QueueRunner(SimpleAMQQueue queue, long count) { @@ -53,7 +58,7 @@ public class QueueRunner implements ReadWriteRunnable } catch (AMQException e) { - _logger.error(e); + _logger.error("Exception during asynchronous delivery by " + _name, e); } finally { -- cgit v1.2.1 From 7b72bf31f73a810ccca6a9c8f6bc4e9730017934 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Fri, 22 Apr 2011 15:15:46 +0000 Subject: QPID-2985: remove duplicate logic to begin store transaction, which seems to have been merged back into place after a previous removal git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1095942 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/txn/LocalTransaction.java | 12 ------------ .../org/apache/qpid/server/virtualhost/VirtualHostImpl.java | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index f9dac782a6..946dbd7c28 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -213,18 +213,6 @@ public class LocalTransaction implements ServerTransaction if(message.isPersistent()) { - if(_transaction == null) - { - for(BaseQueue queue : queues) - { - if(queue.isDurable()) - { - beginTranIfNecessary(); - break; - } - } - } - try { for(BaseQueue queue : queues) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 5374a56f06..8ce4121b97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -299,7 +299,7 @@ public class VirtualHostImpl implements VirtualHost _configuration.getTransactionTimeoutOpenClose(), _configuration.getTransactionTimeoutIdleWarn(), _configuration.getTransactionTimeoutIdleClose()); - } + } catch (Exception e) { _logger.error("Exception in housekeeping for connection: " + connection.toString(), e); -- cgit v1.2.1 From 1a9e6dd078987667557e48a0a1b754484555447a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Tue, 10 May 2011 14:43:19 +0000 Subject: QPID-2759: Remove defunct jmxremote.access file user management rights manipulation abilities. 1) Removed remaining jmx access functionality. 2) Removed references to security/jmx/access from all existing configuration files. 3) Made ServerConfiguration#validateConfiguration reject config files that still contain the security/jmx/access element in order to promote good end-user understanding of configuration. For JMX: 1) setRights now throws UnsupportedOperationException with message. 2) createUser(string,string,bool,bool,bool) throws UnsupportedOperationException iff any of the bool args are true i.e. the user attempts to give a user access JMX rights 3) Deprecated createUser(string,string,bool,bool,bool) in favour of new two arg form createUser(string,string) 4) viewUsers changes to always return admin, read, and write items as false. Applied patch from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1101483 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 15 +- .../ConfigurationFilePrincipalDatabaseManager.java | 27 -- .../auth/management/AMQUserManagementMBean.java | 404 ++------------------- 3 files changed, 48 insertions(+), 398 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 43be0611a5..7fc91c817b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -205,7 +205,15 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa @Override public void validateConfiguration() throws ConfigurationException { - //Currently doesn't do validation + // Support for security.jmx.access was removed when JMX access rights were incorporated into the main ACL. + // This ensure that users remove the element from their configuration file. + + if (getListValue("security.jmx.access").size() > 0) + { + String message = "Validation error : security/jmx/access is no longer a supported element within the configuration xml." + + (_configFile == null ? "" : " Configuration file : " + _configFile); + throw new ConfigurationException(message); + } } /* @@ -530,11 +538,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return getListValue("security.jmx.principal-database"); } - public List getManagementAccessList() - { - return getListValue("security.jmx.access"); - } - public int getFrameSize() { return getIntValue("advanced.framesize", DEFAULT_FRAME_SIZE); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 5cebb7d2d8..e9276e1b0e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -184,33 +184,6 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab } _mbean.setPrincipalDatabase(database); - - List jmxaccesslist = config.getManagementAccessList(); - if (jmxaccesslist.isEmpty()) - { - throw new ConfigurationException("No access control files specified for jmx security"); - } - - String jmxaccesssFile = null; - - try - { - jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); - } - catch (PropertyException e) - { - throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); - } - - try - { - _mbean.setAccessFile(jmxaccesssFile); - } - catch (IOException e) - { - _logger.warn("Unable to load access file:" + jmxaccesssFile); - } - _mbean.register(); } catch (JMException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java index ee4336055b..a839315bcc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -20,19 +20,9 @@ */ package org.apache.qpid.server.security.auth.management; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.security.AccessControlContext; -import java.security.AccessController; import java.security.Principal; -import java.util.Enumeration; import java.util.List; -import java.util.Properties; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; import javax.management.JMException; import javax.management.openmbean.CompositeData; @@ -44,17 +34,13 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import javax.management.remote.JMXPrincipal; -import javax.security.auth.Subject; import javax.security.auth.login.AccountNotFoundException; -import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.management.common.mbeans.UserManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; @@ -65,22 +51,18 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); private PrincipalDatabase _principalDatabase; - private Properties _accessRights; - private File _accessFile; - - private ReentrantLock _accessRightsUpdate = new ReentrantLock(); // Setup for the TabularType - static TabularType _userlistDataType; // Datatype for representing User Lists - static CompositeType _userDataType; // Composite type for representing User + private static final TabularType _userlistDataType; // Datatype for representing User Lists + private static final CompositeType _userDataType; // Composite type for representing User static { OpenType[] userItemTypes = new OpenType[4]; // User item types. userItemTypes[0] = SimpleType.STRING; // For Username - userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read - userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write - userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read - No longer in use + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write - No longer in use + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin - No longer is use try { @@ -92,12 +74,11 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } catch (OpenDataException e) { - _logger.error("Tabular data setup for viewing users incorrect."); - _userlistDataType = null; + _logger.error("Tabular data setup for viewing users incorrect.", e); + throw new ExceptionInInitializerError("Tabular data setup for viewing users incorrect"); } } - public AMQUserManagementMBean() throws JMException { super(UserManagement.class, UserManagement.TYPE); @@ -122,141 +103,45 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } catch (AccountNotFoundException e) { - _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + _logger.warn("Attempt to set password of non-existent user'" + username + "'"); return false; } } public boolean setRights(String username, boolean read, boolean write, boolean admin) { - - Object oldRights = null; - if ((oldRights =_accessRights.get(username)) == null) - { - // If the user doesn't exist in the access rights file check that they at least have an account. - if (_principalDatabase.getUser(username) == null) - { - return false; - } - } - - try - { - _accessRightsUpdate.lock(); - - // Update the access rights - if (admin) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); - } - else - { - if (read | write) - { - if (read) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); - } - if (write) - { - _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); - } - } - else - { - _accessRights.remove(username); - } - } - - //save the rights file - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - - //the rights file was not successfully saved, restore user rights to previous value - _logger.warn("Reverting attempted rights update for user'" + username + "'"); - if (oldRights != null) - { - _accessRights.put(username, oldRights); - } - else - { - _accessRights.remove(username); - } - - return false; - } - } - finally + throw new UnsupportedOperationException("Support for setting access rights no longer supported."); + } + + public boolean createUser(String username, String password) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password.toCharArray())) { - _accessRightsUpdate.unlock(); + return true; } - return true; + return false; } public boolean createUser(String username, String password, boolean read, boolean write, boolean admin) { - return createUser(username, password.toCharArray(), read, write, admin); + if (read || write || admin) + { + throw new UnsupportedOperationException("Support for setting access rights to true no longer supported."); + } + return createUser(username, password); } public boolean createUser(String username, char[] password, boolean read, boolean write, boolean admin) { - if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) - { - if (!setRights(username, read, write, admin)) - { - //unable to set rights for user, remove account - try - { - _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); - } - catch (AccountNotFoundException e) - { - //ignore - } - return false; - } - else - { - return true; - } - } - - return false; + return createUser(username, new String(password), read, write, admin); } public boolean deleteUser(String username) { try { - if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) - { - try - { - _accessRightsUpdate.lock(); - - _accessRights.remove(username); - - try - { - saveAccessFile(); - } - catch (IOException e) - { - _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e); - return false; - } - } - finally - { - _accessRightsUpdate.unlock(); - } - } + _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); } catch (AccountNotFoundException e) { @@ -269,38 +154,23 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana public boolean reloadData() { - try - { - loadAccessFile(); - _principalDatabase.reload(); - } - catch (ConfigurationException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - catch (IOException e) - { - _logger.warn("Reload failed due to:" + e); - return false; - } - // Reload successful - return true; + try + { + _principalDatabase.reload(); + } + catch (IOException e) + { + _logger.warn("Reload failed due to:", e); + return false; + } + // Reload successful + return true; } - @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + @MBeanOperation(name = "viewUsers", description = "All users that are currently available to the system.") public TabularData viewUsers() { - // Table of users - // Username(string), Access rights Read,Write,Admin(bool,bool,bool) - - if (_userlistDataType == null) - { - _logger.warn("TabluarData not setup correctly"); - return null; - } - List users = _principalDatabase.getUsers(); TabularDataSupport userList = new TabularDataSupport(_userlistDataType); @@ -311,29 +181,16 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana for (Principal user : users) { // Create header attributes list - - String rights = (String) _accessRights.get(user.getName()); - - Boolean read = false; - Boolean write = false; - Boolean admin = false; - - if (rights != null) - { - read = rights.equals(MBeanInvocationHandlerImpl.READONLY) - || rights.equals(MBeanInvocationHandlerImpl.READWRITE); - write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); - admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); - } - - Object[] itemData = {user.getName(), read, write, admin}; + + // Read,Write,Admin items are depcreated and we return always false. + Object[] itemData = {user.getName(), false, false, false}; CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), itemData); userList.put(messageData); } } catch (OpenDataException e) { - _logger.warn("Unable to create user list due to :" + e); + _logger.warn("Unable to create user list due to :", e); return null; } @@ -351,187 +208,4 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana { _principalDatabase = database; } - - /** - * setAccessFile - * - * @param accessFile the file to use for updating. - * - * @throws java.io.IOException If the file cannot be accessed - * @throws org.apache.commons.configuration.ConfigurationException - * if checks on the file fail. - */ - public void setAccessFile(String accessFile) throws IOException, ConfigurationException - { - if (accessFile != null) - { - _accessFile = new File(accessFile); - if (!_accessFile.exists()) - { - throw new ConfigurationException("'" + _accessFile + "' does not exist"); - } - - if (!_accessFile.canRead()) - { - throw new ConfigurationException("Cannot read '" + _accessFile + "'."); - } - - if (!_accessFile.canWrite()) - { - _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved."); - } - - loadAccessFile(); - } - else - { - _logger.warn("Access rights file specified is null. Access rights not changed."); - } - } - - private void loadAccessFile() throws IOException, ConfigurationException - { - if(_accessFile == null) - { - _logger.error("No jmx access rights file has been specified."); - return; - } - - if(_accessFile.exists()) - { - try - { - _accessRightsUpdate.lock(); - - Properties accessRights = new Properties(); - FileInputStream inStream = new FileInputStream(_accessFile); - try - { - accessRights.load(inStream); - } - finally - { - inStream.close(); - } - - checkAccessRights(accessRights); - setAccessRights(accessRights); - } - finally - { - _accessRightsUpdate.unlock(); - } - } - else - { - _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist."); - } - } - - private void checkAccessRights(Properties accessRights) - { - Enumeration values = accessRights.propertyNames(); - - while (values.hasMoreElements()) - { - String user = (String) values.nextElement(); - - if (_principalDatabase.getUser(user) == null) - { - _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); - } - } - } - - private void saveAccessFile() throws IOException - { - try - { - _accessRightsUpdate.lock(); - - // Create temporary file - Random r = new Random(); - File tmp; - do - { - tmp = new File(_accessFile.getPath() + r.nextInt() + ".tmp"); - } - while(tmp.exists()); - - tmp.deleteOnExit(); - - FileOutputStream output = new FileOutputStream(tmp); - _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser()); - output.close(); - - // Swap temp file to main rights file. - File old = new File(_accessFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - - if(!_accessFile.renameTo(old)) - { - //unable to rename the existing file to the backup name - _logger.error("Could not backup the existing management rights file"); - throw new IOException("Could not backup the existing management rights file"); - } - - if(!tmp.renameTo(_accessFile)) - { - //failed to rename the new file to the required filename - - if(!old.renameTo(_accessFile)) - { - //unable to return the backup to required filename - _logger.error("Could not rename the new management rights file into place, and unable to restore original file"); - throw new IOException("Could not rename the new management rights file into place, and unable to restore original file"); - } - - _logger.error("Could not rename the new management rights file into place"); - throw new IOException("Could not rename the new management rights file into place"); - } - } - finally - { - _accessRightsUpdate.unlock(); - } - - } - - private String getCurrentJMXUser() - { - AccessControlContext acc = AccessController.getContext(); - - Subject subject = Subject.getSubject(acc); - if (subject == null) - { - return "Unknown user, authentication Subject was null"; - } - - // Retrieve JMXPrincipal from Subject - Set principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - return "Unknown user principals were null"; - } - - Principal principal = principals.iterator().next(); - return principal.getName(); - } - - /** - * user=read user=write user=readwrite user=admin - * - * @param accessRights The properties list of access rights to process - */ - private void setAccessRights(Properties accessRights) - { - _logger.debug("Setting Access Rights:" + accessRights); - _accessRights = accessRights; - - // TODO check where this is used - // MBeanInvocationHandlerImpl.setAccessRights(_accessRights); - } } -- cgit v1.2.1 From ff7167be41036edf73fc4725591f8a0ad2a45f29 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 12 May 2011 12:10:52 +0000 Subject: QPID-3249: Remove incomplete support for authentication at virtualhost level. Applied patch from Keith Wall git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1102258 13f79535-47bb-0310-9956-ffa450edef68 --- .../configuration/VirtualHostConfiguration.java | 8 ++- .../qpid/server/registry/ApplicationRegistry.java | 2 +- .../auth/manager/AuthenticationManager.java | 4 ++ .../PrincipalDatabaseAuthenticationManager.java | 83 ++++------------------ .../qpid/server/virtualhost/VirtualHostImpl.java | 4 +- 5 files changed, 29 insertions(+), 72 deletions(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java index 48f2d776bb..a710230616 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -306,7 +306,13 @@ public class VirtualHostConfiguration extends ConfigurationPlugin @Override public void validateConfiguration() throws ConfigurationException { - //Currently doesn't do validation + // QPID-3249. Support for specifying authentication name at vhost level is no longer supported. + if (getListValue("security.authentication.name").size() > 0) + { + String message = "Validation error : security/authentication/name is no longer a supported element within the configuration xml." + + " It appears in virtual host definition : " + _name; + throw new ConfigurationException(message); + } } public int getHouseKeepingThreadCount() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 72b2a68450..b6df0cc0a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -287,7 +287,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry createDatabaseManager(_configuration); - _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + _authenticationManager = new PrincipalDatabaseAuthenticationManager(); _databaseManager.initialiseManagement(_configuration); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index bc771162fd..39e1e07c57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -26,6 +26,10 @@ import javax.security.sasl.SaslServer; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.security.auth.AuthenticationResult; +/** + * The AuthenticationManager class is the entity responsible for + * determining the authenticity of user credentials. + */ public interface AuthenticationManager extends Closeable { String getMechanisms(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 2a967f02af..d10ad2c170 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -21,9 +21,6 @@ package org.apache.qpid.server.security.auth.manager; import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; @@ -41,6 +38,11 @@ import java.util.HashMap; import java.util.TreeMap; import java.security.Security; +/** + * Concrete implementation of the AuthenticationManager that determines if supplied + * user credentials match those appearing in a PrincipalDatabase. + * + */ public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager { private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.class); @@ -57,47 +59,17 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan */ private Map> _serverCreationProperties = new HashMap>(); - private AuthenticationManager _default = null; /** The name for the required SASL Server mechanisms */ public static final String PROVIDER_NAME= "AMQSASLProvider-Server"; - public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception + public PrincipalDatabaseAuthenticationManager() { - _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") - + " PrincipalDatabase authentication manager."); - - // Fixme This should be done per Vhost but allowing global hack isn't right but ... - // required as authentication is done before Vhost selection + _logger.info("Initialising PrincipalDatabase authentication manager."); Map> providerMap = new TreeMap>(); - if (name == null || hostConfig == null) - { - initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); - } - else - { - String databaseName = hostConfig.getAuthenticationDatabase(); - - if (databaseName == null) - { - - _default = ApplicationRegistry.getInstance().getAuthenticationManager(); - return; - } - else - { - PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); - - if (database == null) - { - throw new ConfigurationException("Requested database:" + databaseName + " was not found"); - } - - initialiseAuthenticationMechanisms(providerMap, database); - } - } + initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); if (providerMap.size() > 0) { @@ -116,11 +88,9 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { _logger.warn("No additional SASL providers registered."); } - } - - private void initialiseAuthenticationMechanisms(Map> providerMap, Map databases) throws Exception + private void initialiseAuthenticationMechanisms(Map> providerMap, Map databases) { if (databases.size() > 1) { @@ -136,7 +106,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan } } - private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) throws Exception + private void initialiseAuthenticationMechanisms(Map> providerMap, PrincipalDatabase database) { if (database == null || database.getMechanisms().size() == 0) { @@ -152,7 +122,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, Map> providerMap) - throws Exception + { if (_mechanisms == null) { @@ -175,41 +145,17 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public String getMechanisms() { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.getMechanisms(); - } - else - { - return _mechanisms; - } + return _mechanisms; } public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException { - if (_default != null) - { - // Use the default AuthenticationManager if present - return _default.createSaslServer(mechanism, localFQDN); - } - else - { - return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), - _callbackHandlerMap.get(mechanism)); - } - + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); } public AuthenticationResult authenticate(SaslServer server, byte[] response) { - // Use the default AuthenticationManager if present - if (_default != null) - { - return _default.authenticate(server, response); - } - - try { // Process response from the client @@ -232,6 +178,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public void close() { + _mechanisms = null; Security.removeProvider(PROVIDER_NAME); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 8ce4121b97..33c713c62a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -101,7 +101,7 @@ public class VirtualHostImpl implements VirtualHost private AMQBrokerManagerMBean _brokerMBean; - private AuthenticationManager _authenticationManager; + private final AuthenticationManager _authenticationManager; private SecurityManager _securityManager; @@ -248,7 +248,7 @@ public class VirtualHostImpl implements VirtualHost initialiseMessageStore(hostConfig); } - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, _configuration); + _authenticationManager = ApplicationRegistry.getInstance().getAuthenticationManager(); _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); -- cgit v1.2.1 From 9edbda4f8744a45aec18bdfafddf8e3879d14c9c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 16 May 2011 21:26:31 +0000 Subject: QPID-3261: decrease severity / improve clarity of log messages. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1103899 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/configuration/ServerConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker/src/main/java/org') diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 7fc91c817b..297f7abdb8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -148,7 +148,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } catch (Exception e) { - _logger.error("Signal HUP not supported for OS: " + System.getProperty("os.name")); + _logger.info("Signal HUP not supported for OS: " + System.getProperty("os.name")); // We're on something that doesn't handle SIGHUP, how sad, Windows. } } -- cgit v1.2.1